ember-data-model-fragments
ember-data-model-fragments copied to clipboard
Integration test: Uncaught TypeError: store.createFragment is not a function
I am trying to write an integration test for a component that manipulates a model called spot.
Here is the spot model:
// models/spot.js
// imports...
// some validations rules...
const Validations = buildValidations({ ... });
export default Model.extend( Validations, {
customMeta : fragmentArray('custom-meta'),
name: attr("string"),
location: fragment('location', {
defaultValue: {
lat: null,
lon: null
}
}),
I am trying to create a spot record in such an integration test:
test('should render card displaying name, content, status correctly', function(assert) {
let spotMock;
const store = this.container.lookup('service:store');
run(()=>{
spotMock = store.createRecord('spot', {
isMoving: true,
name: 'spot-name',
// no matter whether the following is present or absent, the error persists
// location: store.createFragment('location', {
// lat: 1,
// lon: 1
// })
});
});
//...
store.createRecord() fails due to:
Uncaught TypeError: store.createFragment is not a function
This is the place which calls store.createFragment():
// fragment.js
// Creates a fragment and sets its owner to the given record
function createFragment(store, declaredModelName, record, key, options, data) {
var actualModelName = getActualFragmentType(declaredModelName, options, data);
var fragment = store.createFragment(actualModelName); // error
setFragmentOwner(fragment, record, key);
setFragmentData(fragment, data);
return fragment;
}
Maybe a screenshot helps:

Apparently, createFragment() is not set up upon the store yet. Do I have to set it up anyhow for the purposes of integration testing? I could not find any hint about it in the docs, however, I guess I am missing something simple in here.
@xamoom-pali Sorry for the delayed response. I just saw this issue (I missed the email :( ). I suspect what's happening is that because it's an integration test (not an acceptance test) that our initializers were not fired. The result of that is we did not reopen the store class and add our createFragment. I'm guessing you've figured out most of this already.
So what to do about it? In my production app's testsuite, I ended up writing a utility function (setupEmberData), that among other things, manually invokes ember-data-model-fragment's initializer to get things primed up. I call this utility function in my test setup. Here is an example:
// app/tests/helpers/setup-ember-data.js
// NOTE: This is really from the addon, but it's injected into the app space
import fragmentTransformInitializer from 'buttercup/initializers/model-fragments';
export function setupEmberData(owner) {
fragmentTransformInitializer.initialize(owner);
}
// app/tests/integration/component-grid-system-tests.js
import { setupEmberData } from '../helpers/setup-ember-data';
moduleForComponent('grid-system', 'Integration: Grid System', {
beforeEach() {
let owner = Ember.getOwner(this);
setupEmberData(owner);
}
});
So yea, this isn't great at all. Integration tests with ember can be a little weird because the app is "half setup". But come to think of it, ember-data has a setupContainer function they invoke in an initializer, so I wonder if there is another trick to this that I'm not aware of.
Yeap, I'm not crazy 😜 . Ember-test-helpers actually invoke ember-data's setupContainer initializer manually. See: ember-test-helpers/build-registry.js.
So unfortunately that means there isn't some alternative way for ember-data-model-fragments to make this work for you out of the box. You'll need to manually invoke the initializer.
@xamoom-pali I'm going to close this issue. If you have any further questions or concerns let me know.
I've similar issue. When I test serializer for a model which is composed with MF.fragments, I run into store is null at testing method normalizeUpdateRecordResponse.
test('it normalizeUpdateRecordResponse', function(assert) {
assert.expect(0);
Ember.run(() => {
let store = this.container.lookup('service:store');
let serializer = this.container.lookup('serializer:myModel');
let data = Object.assign({}, myModelResponse);
let record = this.subject(data);
let snapshot = record._createSnapshot();
let primaryModelClass = store.modelFor('myModel');
let requestType = 'updateRecord';
let id = myModelResponse.id;
let payload = { data: data };
try {
let response = serializer.normalizeUpdateRecordResponse(store, primaryModelClass, payload, id, requestType);
} catch (err) {}
});
});
Please take a look thanks.
@ldong What kind of tests are you doing? It looks like integration, is that right? Can you please try manually invoking the initializer in your test setup as I mentioned in a prior comment.
import fragmentTransformInitializer from 'buttercup/initializers/model-fragments';
test('it normalizeUpdateRecordResponse', function(assert) {
assert.expect(0);
Ember.run(() => {
fragmentTransformInitializer.initialize(this.container.owner);
let store = this.container.lookup('service:store');
// ....
});
});
If that doesn't work, can you provide me with a stack trace.
@workmanw I tried your workaround but also could not get it to work. Manually looking up the store using this.container.lookup('service:store') and then calling createFragment works even without manually initializing the fragmentTransformInitializer.
I'm guessing this.store does not point to the actual store somehow?
edit: Gah... it's this.store(). Don't mind me.
So I was wondering why it's unique problem to ember-data-model-fragments. I think maybe we could actually do without the initializer if we just added those files into the app directory. Initializer dated back to before we had convert this to an ember CLI add-on.
I'm going to reopen it and see what can be done about this. Its definitely a gotcha.
I ran into this issue and couldn't solve it using the advice above, so, for posterity's sake, here's what fixed it for me:
I got the "store.createFragment is not a function" error on an old Ember project that had been upgraded from Ember 2 to 3, and I have a new Ember project that started out on version 3, which did not have this issue. So I went through all test-setup-related files in both projects and compared them.
Then I made the following changes:
In /tests/test-helper.js, I changed this:
import resolver from './helpers/resolver';
import {
setResolver,
} from '@ember/test-helpers';
import { start } from 'ember-cli-qunit';
setResolver(resolver);
start();
to that:
import Application from '../app';
import config from '../config/environment';
import { setApplication } from '@ember/test-helpers';
import { start } from 'ember-qunit';
setApplication(Application.create(config.APP));
start();
And in /config/environment.js, I added
if (environment === 'test') {
ENV.APP.autoboot = false;
}
After those changes, I didn't need to do any manual setup to get the fragments to work in testing.
Hope this helps someone.