Skip to content

Instantly share code, notes, and snippets.

@alexander-alvarez
Last active October 31, 2018 08:41
Show Gist options
  • Save alexander-alvarez/18b4abd73e53f5cccbe6e28925fcc704 to your computer and use it in GitHub Desktop.
Save alexander-alvarez/18b4abd73e53f5cccbe6e28925fcc704 to your computer and use it in GitHub Desktop.
Ember Data Tests QUnit Improvement

BACKGROUND

In the RFC-232 , RFC-268 style tests we wanted to simplify some of the abstractions around testing, so it is simpler to implement, and the ecosystem gets out of the way more. This led to a paradigm shift from "I'm doing an x-style test", to "I'm testing X and need Y and Z configured in order to do it". E.g moduleForComponent -> setupRenderingTest, moduleForAcceptance -> setupApplicationTest.

In implementing the new style blueprints for ember-data, I'd like to understand where we'd like the ember-data testing story to go, and if this is the right point to do so, since we will be modifying those files.

As such, what are analagous concepts we could introduce for ember-data? Does it make sense to introduce these analagous concepts?

Ember Data Classes Who's Testing Use Cases We Need To Ensure We Address

  • Adapters, Models, Serializers, Transforms

Classes who's testing style is addressed by APIs provided by ember-qunit

  • Transforms -> setupTest (testing these has no dependency on ember or ember-data internals, similar to helpers)

Classes who's testing style needs to be discussed:

  • Adapters
  • Models
  • Serializers

Notes

Adapters

Most adapater methods operate on snapshots. Should we provide an API to create snapshots from models, since models are the public API users are used to?

Internal models required for implementing/testing public methods: Snapshot and SnapshotRecordArray

Models

When testing models, it's mostly about testing user computed properties. In which the user needs to setup the store.

Serializers

Should we bootstrap the store onto this.store for testing? Example implementation

function setupStoreTest(hooks) {
  setupTest(hooks); // sets up container/owner
  hooks.beforeEach(function() {
    this.store = this.owner.lookup('service:store');
  });
  hooks.beforeEach(function() {
    this.store = null;
  });
};

JSONSerializer.serialze* methods

  • serialize(snapshot, json)

JSONSerializer.serialze* methods

  • serializeAttribute(snapshot, json, key, attribute)
  • serializeBelongsTo(snapshot, json, relationship)
  • serializeHasMany(snapshot, json, relationship)
  • serializeId(snapshot, json, primaryKey)
  • serializeIntoHash(hash, typeClass, snapshot, options)
  • serializePolymorphicType(snapshot, json, relationship)
  • shouldSerializeHasMany(snapshot, key, relationshipType)

All the serialze methods require a snapshot. Should we prove a testing API that can create these snapshots?

// this is an example of a explicit test setup
// we could imagine an "needs" based setup method would be called `setupSnapshotTest` for example
setupSerializerTest(hooks); // this hypothetical API adds `this.createSnapshot`

test('my-model -- serializeId', function(assert) {
  let model = this.store.createRecord('my-model');
  let snapshot = this.createSnapshot(model);
});
test('We can normalize strata-and-values attributes appropriately ', function(assert) {
let store = this.owner.lookup(`service:store`);
let serializer = this.owner.lookup(`serializer:pool-subset`);
serializer.store = store; // serializer.store needs to be patched because it doesn't happen automatically and tests fail on something unrelated w/o it
let primaryModelClass = store.modelFor('pool-subset'); // should we be looking this up via the store, or using this.owner.lookup?
let requestType = 'find';
let id = 'abc123';
const basePayload = {
data: {
attributes: {
'foo': 'bar'
},
relationships: {
// relationships
},
id,
type: 'pool-subset'
},
};
let payload = { ...basePayload };
// WHEN
let normalizedResponse = serializer.normalizeSingleResponse(store, primaryModelClass, payload, id, requestType);
});
test('A JSON-API Document is returned within the data hash', function(assert) {
let poolModelClass = this.owner.factoryFor(`model:my-model`).class;
let serializer = this.owner.lookup(`serializer:my-model`);
let resourceHash = {
attributes: {
name: 'ABC',
category: '12345',
},
relationships: {},
type: 'my-model',
id: 'abc1234'
};
let expectedOutput = {
data: { ...resourceHash }
};
let serializedRecord = serializer.normalize(poolModelClass, resourceHash);
assert.deepEqual(serializedRecord, expectedOutput);
});
test('It serializes basic filters', function(assert) {
let store = this.owner.lookup('service:store');
let serializer = store.serializerFor('my-model');
run(() => {
let myModel = store.createRecord('my-model', {
id: 123,
name: 'foo'
});
let snapshot = myModel._internalModel.createSnapshot();
let options = {};
let result = serializer.serialize(snapshot, options);
// ...
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment