-
Notifications
You must be signed in to change notification settings - Fork 39
Description
I've been hacking around with setting up and tearing down Orbit around (acceptance) tests. More specifically I'm building a demo app that only use IDB as backup and no remote JSON:API source.
To be able to access the store in an acceptance context I had to manually construct the whole store within the moduleForAcceptance helper.
The second thing is that it looks like when using Orbit's store like that, the acceptance test helpers don't pickup on the Promises that Orbit's actions create, so it will just not wait for them. I had to create a simple waitFor async helper that takes Orbit's promises and queues them up properly.
What I'm alluding to is that it would be awesome if Ember-Orbit contained a few test helpers that stream lines the test experience.
Below is part of the Orbit setup I wrote for the tests:
example acceptance test
test('It displays existing planets', function(assert) {
waitFor(() => this.store.update((t) => [
t.addRecord({ type: 'planet', attributes: { name: 'Mars'} }),
t.addRecord({ type: 'planet', attributes: { name: 'Venus'} })
]));
visit('/planets');
andThen(() => {
assert.dom('[data-test-planet]').exists({ count: 2 });
});
});tests/helpers/module-for-acceptance.js
import { module } from 'qunit';
import { resolve, all } from 'rsvp';
import startApp from '../helpers/start-app';
import destroyObject from '../helpers/destroy-app';
import createOrbitStore from './create-orbit-store';
export default function(name, options = {}) {
module(name, {
beforeEach() {
this.application = startApp();
return createOrbitStore(this.application)
.then(([store, coordinator]) => {
this.store = store;
this.coordinator = coordinator;
})
.then(() => options.beforeEach && options.beforeEach.apply(this, arguments));
},
afterEach() {
let afterEach = options.afterEach && options.afterEach.apply(this, arguments);
return resolve(afterEach)
.then(() => {
let backup = this.coordinator.getSource('backup');
let modelNames = Object.keys(this.store.source.schema.models);
return all(modelNames.map((modelName) => backup.clearRecords(modelName)));
})
.then(() => this.coordinator.deactivate())
.then(() => destroyObject(this.store))
.then(() => destroyObject(this.application));
}
});
}tests/helpers/create-orbit-store.js
import { get } from '@ember/object';
import { camelize } from '@ember/string';
import OrbitStore from '@orbit/store';
import Coordinator from '@orbit/coordinator';
import {
Schema,
KeyMap
} from '@orbit/data';
import modulesOfType from 'ember-orbit/-private/system/modules-of-type';
import { Store } from 'ember-orbit';
function findModulesOfType(application, type) {
return modulesOfType(application.modulePrefix, type).map(camelize);
}
function createSchema(application) {
let modelSchemas = {};
let modelNames = findModulesOfType(application, 'models');
modelNames.forEach(name => {
let model = application.resolveRegistration(`model:${name}`);
modelSchemas[name] = {
id: get(model, 'id'),
keys: get(model, 'keys'),
attributes: get(model, 'attributes'),
relationships: get(model, 'relationships')
};
});
return new Schema({ models: modelSchemas });
}
function createSources(application, injections) {
return findModulesOfType(application, 'data-sources').map((name) => {
let sourceFactory = application.resolveRegistration(`data-source:${name}`);
return sourceFactory.create(injections);
});
}
function createStrategies(application) {
return findModulesOfType(application, 'data-strategies').map((name) => {
let strategyFactory = application.resolveRegistration(`data-strategy:${name}`);
return strategyFactory.create();
});
}
export default function createOrbitStore(application) {
let schema = createSchema(application);
let orbitStore = new OrbitStore({ schema });
let keyMap = new KeyMap();
let sources = createSources(application, { schema, keyMap });
let strategies = createStrategies(application);
let coordinator = new Coordinator({ sources: [orbitStore, ...sources], strategies });
let store = Store.create({ source: orbitStore });
return coordinator.activate()
.then(() => [store, coordinator]);
}tests/helpers/wait-for.js
import { registerAsyncHelper } from "@ember/test"
registerAsyncHelper('waitFor',
function(app, callback) {
return callback();
}
);