Skip to content

Commit

Permalink
Provided a pushMirageIntoStore import for tests and standalone
Browse files Browse the repository at this point in the history
  • Loading branch information
cah-brian-gantzler committed Jan 23, 2022
1 parent 37d91a4 commit c669c31
Show file tree
Hide file tree
Showing 5 changed files with 346 additions and 0 deletions.
32 changes: 32 additions & 0 deletions addon-test-support/push-mirage-into-store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { getContext } from '@ember/test-helpers';

import { pushMirageIntoStore as _pushMirageIntoStore } from 'ember-cli-mirage';

/**
* This utility pushes the mirage store into the ember store
*
* If you call this method with no parameters, it will push the entire mirage store into ember store
*
* You may also call this method with an array of resource names. ['accounts', 'accountTypes']. These must
* be the resource names camelized.
*
* You may also call it with a hash. This hash will have the resource names as the keys and the values will either
* be true (push all records for that resource) or a where hash or function that will be applied to the that resource.
* {
* accounts: true,
* accountTypes: { state: 'OH' }
* users: item => item.name.includes("Joe")
* }
*
* @param config undefined means push all resources
* An array will push only the resources in the array
* hash in the form of resource=value Value may be true, all records, or a where hash or function
*/
let pushMirageIntoStore = function (config) {
let context = getContext();
let store = context.owner.lookup('service:store');

_pushMirageIntoStore(context.server, store, config);
};

export { pushMirageIntoStore };
1 change: 1 addition & 0 deletions addon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export {
applyEmberDataSerializers,
} from './ember-data';
export { default as EmberDataSerializer } from 'ember-cli-mirage/serializers/ember-data-serializer';
export * from './utils/push-mirage-into-store';
84 changes: 84 additions & 0 deletions addon/utils/push-mirage-into-store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { run } from '@ember/runloop';
import assert from '../assert';

let pushMirageRecordsIntoStore = function (store, server, resource, where) {
let models = server.schema[resource].all();
let modelName = models.modelName;
if (typeof where === 'object' || typeof where === 'function') {
models = server.schema[resource].where(where);
}

if (models.length > 0) {
let serializer = server.serializerOrRegistry.serializerFor(modelName);

let originalAlwaysIncludeLinkageData = serializer.alwaysIncludeLinkageData;
serializer.alwaysIncludeLinkageData = true;

let json = serializer.serialize(models);

serializer.alwaysIncludeLinkageData = originalAlwaysIncludeLinkageData;
run(() => {
store.pushPayload(modelName, json);
});
}

return models;
};

/**
* This utility pushes the mirage store into the ember store
*
* If you call this method passing no parameters, it will push the entire mirage store into ember store
*
* You may also call this method with an array of resource names. ['accounts', 'accountTypes']. These must
* be the resource names camelized.
*
* You may also call it with a hash. This hash will have the resource names as the keys and the values will either
* be true (push all records for that resource) or a where hash or function that will be applied to the that resource.
* {
* accounts: true,
* accountTypes: { state: 'OH' }
* users: item => item.name.includes("Joe")
* }
*
* @param server The mirage server
* @param store the store you wish mirage to push to
* @param config undefined means push all resources
* An array will push only the resources in the array
* hash in the form of resource=value Value may be true, all records, or a where hash or function
*/
let pushMirageIntoStore = function (server, store, config) {
assert(store, 'You must supply a store to pushMirageIntoStore');
assert(server, 'You must supply a mirage server to pushMirageIntoStore');

let resources = Object.keys(server.schema).filter(
(key) => server.schema[key].all !== undefined
); // Get the resources

let where = {};

if (config) {
let includes;
if (Array.isArray(config)) {
includes = config;
} else {
includes = Object.keys(config);
where = config;
}

resources = includes.filter((item) => {
let found = resources.includes(item);
assert(
found,
`Model of type '${item}' does not exist for push mirage into store.`
);
return found;
});
}

resources.forEach((resource) => {
pushMirageRecordsIntoStore(store, server, resource, where[resource]);
});
};

export { pushMirageIntoStore, pushMirageRecordsIntoStore };
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,73 @@ module('Integration | Component | ArticleForm', function(hooks) {
});
```

### Helper to push Mirage's database

A helper has been provided to push mirage's database into the ember data store following the same name and pattern that was published below under writing your own helper. You may now import this from `ember-cli-mirage/test-suport`

```js
import { module } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { click, fillIn } from '@ember/test-helpers';
import { pushMirageIntoStore } from 'ember-cli-mirage/test-support';

module('Integration | Component | ArticleForm', function(hooks) {
setupRenderingTest(hooks);
setupMirage(hooks);

test('it can edit an article', async function(assert) {
// ✅ Option 2: Use the store to find the record
let serverArticle = this.server.create('article', {
title: 'Old title'
});
pushMirageIntoStore();
let store = this.owner.lookup('service:store');
let article = store.peekRecord('article', serverArticle.id);
this.set('article', article);

await render(hbs`
<ArticleForm @article={{article}}>
`);

await fillIn('input', 'New title');
await click('.save');

// assert the model was saved
});
});
```

If you do not wish to push all the resources, this helper has an optional parameter to define which resources to push.

This parameter can be an array of all the resources in the form of `['users', 'blogs']`.

For a finer control, this can also be a hash
```js
{
accounts: true, // Push all records for this resource
accountTypes: { state: 'OH' } // push the matching records using mirage's hash form of where
users: item => item.name.includes("Joe") // push the matching records using mirage's function form of where
}
```

The pushMirageIntoStore is imported from `ember-cli-mirage/test-support` and is only usable within ember tests. If you wish to use the pushMirageIntoStore outside of tests, another version is also importable from `ember-cli-mirage`. This version has the following signature
```js
import { pushMirageIntoStore } from 'ember-cli-mirage';

pushMirageIntoStore(
mirageServer,
emberDataStore,
config // optional, same values as above
);
```

This version can also be used inside your tests, but you will have to supply the two required parameters.

### Writing a helper to push Mirage's database

(You no longer need to do this as one has been provided, this documentation is kept for historical purposes)

The second approach is to make a helper that serializers Mirage's database into JSON and pushes that JSON into your Ember Data store.

The actual logic might depend on the configuration of your Mirage server, but if you're following all of Mirage's conventions it should look roughly like this:
Expand Down
164 changes: 164 additions & 0 deletions tests/unit/utils/push-mirage-into-store-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import { Server, Model, JSONAPISerializer } from 'miragejs';
import EDModel, { attr } from '@ember-data/model';
import { pushMirageIntoStore as pushMirageIntoStoreTestSupport } from 'ember-cli-mirage/test-support';
import { pushMirageIntoStore } from 'ember-cli-mirage';

module('Unit | Utils | Push Mirage Into Store', function (hooks) {
hooks.beforeEach(function () {
this.server = new Server({
serializers: {
application: JSONAPISerializer,
},
models: {
user: Model,
blog: Model,
},
});

this.server.create('user', {
id: '1',
name: 'Joe Brown',
});

this.server.create('user', {
id: '2',
name: 'Joe Black',
});

this.server.create('user', {
id: '3',
name: 'Jane Doe',
});

this.server.create('blog', {
id: '1',
name: 'Post 1',
});

this.server.create('blog', {
id: '2',
name: 'Post 2',
});
});

hooks.afterEach(function () {
this.server.shutdown();
});

module('from test support', function (hooks) {
setupTest(hooks);
hooks.beforeEach(function () {
this.owner.register(
'model:user',
EDModel.extend({
name: attr(),
})
);

this.owner.register(
'model:blog',
EDModel.extend({
text: attr(),
})
);

this.store = this.owner.lookup('service:store');
});

test('can push records all the records without a config', function (assert) {
pushMirageIntoStoreTestSupport();
assert.strictEqual(this.store.peekAll('user').length, 3);
assert.strictEqual(this.store.peekAll('blog').length, 2);
});

test('can push one resource as array', function (assert) {
pushMirageIntoStoreTestSupport(['users']);
assert.strictEqual(this.store.peekAll('user').length, 3);
assert.strictEqual(this.store.peekAll('blog').length, 0);
});

test('can push one resource as config true', function (assert) {
pushMirageIntoStoreTestSupport({
users: true,
});
assert.strictEqual(this.store.peekAll('user').length, 3);
assert.strictEqual(this.store.peekAll('blog').length, 0);
});

test('can push one resource as config where hash', function (assert) {
pushMirageIntoStoreTestSupport({
users: { name: 'Joe Brown' },
});
assert.strictEqual(this.store.peekAll('user').length, 1);
assert.strictEqual(this.store.peekAll('blog').length, 0);
});

test('can push one resource as config where function', function (assert) {
pushMirageIntoStoreTestSupport({
users: (item) => item.name.includes('Joe'),
});
assert.strictEqual(this.store.peekAll('user').length, 2);
assert.strictEqual(this.store.peekAll('blog').length, 0);
});
});

module('direct import', function (hooks) {
setupTest(hooks);

hooks.beforeEach(function () {
this.owner.register(
'model:user',
EDModel.extend({
name: attr(),
})
);

this.owner.register(
'model:blog',
EDModel.extend({
text: attr(),
})
);

this.store = this.owner.lookup('service:store');
});

test('can push records all the records without a config', function (assert) {
pushMirageIntoStore(this.server, this.store);
assert.strictEqual(this.store.peekAll('user').length, 3);
assert.strictEqual(this.store.peekAll('blog').length, 2);
});

test('can push one resource as array', function (assert) {
pushMirageIntoStore(this.server, this.store, ['users']);
assert.strictEqual(this.store.peekAll('user').length, 3);
assert.strictEqual(this.store.peekAll('blog').length, 0);
});

test('can push one resource as config true', function (assert) {
pushMirageIntoStore(this.server, this.store, {
users: true,
});
assert.strictEqual(this.store.peekAll('user').length, 3);
assert.strictEqual(this.store.peekAll('blog').length, 0);
});

test('can push one resource as config where hash', function (assert) {
pushMirageIntoStore(this.server, this.store, {
users: { name: 'Joe Brown' },
});
assert.strictEqual(this.store.peekAll('user').length, 1);
assert.strictEqual(this.store.peekAll('blog').length, 0);
});

test('can push one resource as config where function', function (assert) {
pushMirageIntoStore(this.server, this.store, {
users: (item) => item.name.includes('Joe'),
});
assert.strictEqual(this.store.peekAll('user').length, 2);
assert.strictEqual(this.store.peekAll('blog').length, 0);
});
});
});

0 comments on commit c669c31

Please sign in to comment.