From 3435b43a5c8fb41dd7b8ffa85c0a589ab4083dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Tue, 12 Apr 2016 13:42:57 +0200 Subject: [PATCH] test: extract context-test-helpers --- test/helpers/context-test-helpers.js | 71 +++++ test/persistence-hooks.suite.js | 441 ++++++++++++--------------- 2 files changed, 270 insertions(+), 242 deletions(-) create mode 100644 test/helpers/context-test-helpers.js diff --git a/test/helpers/context-test-helpers.js b/test/helpers/context-test-helpers.js new file mode 100644 index 00000000..cb8d0dc4 --- /dev/null +++ b/test/helpers/context-test-helpers.js @@ -0,0 +1,71 @@ +// Copyright IBM Corp. 2016. All Rights Reserved. +// Node module: loopback-datasource-juggler +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +var traverse = require('traverse'); + +exports.ContextRecorder = ContextRecorder; +exports.deepCloneToObject = deepCloneToObject; +exports.aCtxForModel = aCtxForModel; + +function ContextRecorder(initialValue) { + if (!(this instanceof ContextRecorder)) { + return new ContextRecorder(initialValue); + } + this.records = initialValue; +}; + +ContextRecorder.prototype.recordAndNext = function(transformFm) { + var self = this; + return function(context, next) { + if (typeof transformFm === 'function') { + transformFm(context); + } + + context = deepCloneToObject(context); + context.hookState.test = true; + + if (typeof self.records === 'string') { + self.records = context; + return next(); + } + + if (!Array.isArray(self.records)) { + self.records = [self.records]; + } + + self.records.push(context); + next(); + }; +}; + +function deepCloneToObject(obj) { + return traverse(obj).map(function(x) { + if (x === undefined) { + // RDBMSs return null + return null; + } + if (x && x.toObject) + return x.toObject(true); + if (x && typeof x === 'function' && x.modelName) + return '[ModelCtor ' + x.modelName + ']'; + }); +} + +function aCtxForModel(TestModel, ctx) { + ctx.Model = TestModel; + + if (!ctx.hookState) { + ctx.hookState = {}; + } + + if (!('test' in ctx.hookState)) { + ctx.hookState.test = true; + } + + if (!ctx.options) { + ctx.options = {}; + } + return deepCloneToObject(ctx); +} diff --git a/test/persistence-hooks.suite.js b/test/persistence-hooks.suite.js index 77b2fa2e..1fed18e4 100644 --- a/test/persistence-hooks.suite.js +++ b/test/persistence-hooks.suite.js @@ -4,7 +4,11 @@ // License text available at https://opensource.org/licenses/MIT var ValidationError = require('../').ValidationError; -var traverse = require('traverse'); + +var contextTestHelpers = require('./helpers/context-test-helpers'); +var ContextRecorder = contextTestHelpers.ContextRecorder; +var deepCloneToObject = contextTestHelpers.deepCloneToObject; +var aCtxForModel = contextTestHelpers.aCtxForModel; module.exports = function(dataSource, should, connectorCapabilities) { if (!connectorCapabilities) connectorCapabilities = {}; @@ -13,7 +17,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { ' replaceOrCreateReportsNewInstance'); } describe('Persistence hooks', function() { - var observedContexts, expectedError, observersCalled; + var ctxRecorder, expectedError, observersCalled; var TestModel, existingInstance; var migrated = false, lastId; var triggered; @@ -21,7 +25,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { var undefinedValue = undefined; beforeEach(function setupDatabase(done) { - observedContexts = 'hook not called'; + ctxRecorder = new ContextRecorder('hook not called'); expectedError = new Error('test error'); observersCalled = []; @@ -79,11 +83,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `access` hook', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.find({ where: { id: '1' }}, function(err, list) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { query: { where: { id: '1' }}, })); done(); @@ -113,11 +117,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `access` hook for geo queries', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.find({ where: { geo: { near: '10,20' }}}, function(err, list) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { query: { where: { geo: { near: '10,20' }}}, })); done(); @@ -138,7 +142,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('applies updates from `loaded` hook', function(done) { - TestModel.observe('loaded', pushContextAndNext(function(ctx) { + TestModel.observe('loaded', ctxRecorder.recordAndNext(function(ctx) { ctx.data.extra = 'hook data'; })); @@ -147,14 +151,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { function(err, list) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: '1', name: 'first', extra: 'hook data', }, isNewInstance: false, - hookState: { test: true }, options: {}, })); @@ -194,11 +197,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `before save` hook', function(done) { - TestModel.observe('before save', pushContextAndNext()); + TestModel.observe('before save', ctxRecorder.recordAndNext()); TestModel.create({ name: 'created' }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: instance.id, name: 'created', @@ -234,22 +237,22 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('sends `before save` for each model in an array', function(done) { - TestModel.observe('before save', pushContextAndNext()); + TestModel.observe('before save', ctxRecorder.recordAndNext()); TestModel.create( [{ name: '1' }, { name: '2' }], function(err, list) { if (err) return done(err); // Creation of multiple instances is executed in parallel - observedContexts.sort(function(c1, c2) { + ctxRecorder.records.sort(function(c1, c2) { return c1.instance.name - c2.instance.name; }); - observedContexts.should.eql([ - aTestModelCtx({ + ctxRecorder.records.should.eql([ + aCtxForModel(TestModel, { instance: { id: list[0].id, name: '1', extra: undefined }, isNewInstance: true, }), - aTestModelCtx({ + aCtxForModel(TestModel, { instance: { id: list[1].id, name: '2', extra: undefined }, isNewInstance: true, }), @@ -269,14 +272,14 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `persist` hook', function(done) { - TestModel.observe('persist', pushContextAndNext()); + TestModel.observe('persist', ctxRecorder.recordAndNext()); TestModel.create( { id: 'new-id', name: 'a name' }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: 'new-id', name: 'a name' }, isNewInstance: true, currentInstance: { extra: null, id: 'new-id', name: 'a name' }, @@ -287,7 +290,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('applies updates from `persist` hook', function(done) { - TestModel.observe('persist', pushContextAndNext(function(ctx) { + TestModel.observe('persist', ctxRecorder.recordAndNext(function(ctx) { ctx.data.extra = 'hook data'; })); @@ -320,7 +323,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `loaded` hook', function(done) { - TestModel.observe('loaded', pushContextAndNext()); + TestModel.observe('loaded', ctxRecorder.recordAndNext()); // By default, the instance passed to create callback is NOT updated // with the changes made through persist/loaded hooks. To preserve @@ -332,7 +335,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: 'new-id', name: 'a name' }, isNewInstance: true, })); @@ -352,7 +355,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('applies updates from `loaded` hook', function(done) { - TestModel.observe('loaded', pushContextAndNext(function(ctx) { + TestModel.observe('loaded', ctxRecorder.recordAndNext(function(ctx) { ctx.data.extra = 'hook data'; })); @@ -372,11 +375,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `after save` hook', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); TestModel.create({ name: 'created' }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: instance.id, name: 'created', @@ -412,22 +415,22 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('sends `after save` for each model in an array', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); TestModel.create( [{ name: '1' }, { name: '2' }], function(err, list) { if (err) return done(err); // Creation of multiple instances is executed in parallel - observedContexts.sort(function(c1, c2) { + ctxRecorder.records.sort(function(c1, c2) { return c1.instance.name - c2.instance.name; }); - observedContexts.should.eql([ - aTestModelCtx({ + ctxRecorder.records.should.eql([ + aCtxForModel(TestModel, { instance: { id: list[0].id, name: '1', extra: undefined }, isNewInstance: true, }), - aTestModelCtx({ + aCtxForModel(TestModel, { instance: { id: list[1].id, name: '2', extra: undefined }, isNewInstance: true, }), @@ -444,7 +447,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { next(); }); - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); TestModel.create( [{ name: 'ok' }, { name: 'fail' }], @@ -457,7 +460,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { // the models that were not created due to an error. list.map(get('name')).should.eql(['ok', 'fail']); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: list[0].id, name: 'ok', extra: undefined }, isNewInstance: true, })); @@ -468,14 +471,14 @@ module.exports = function(dataSource, should, connectorCapabilities) { describe('PersistedModel.findOrCreate', function() { it('triggers `access` hook', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.findOrCreate( { where: { name: 'new-record' }}, { name: 'new-record' }, function(err, record, created) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ query: { + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { query: { where: { name: 'new-record' }, limit: 1, offset: 0, @@ -487,7 +490,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { if (dataSource.connector.findOrCreate) { it('triggers `before save` hook when found', function(done) { - TestModel.observe('before save', pushContextAndNext()); + TestModel.observe('before save', ctxRecorder.recordAndNext()); TestModel.findOrCreate( { where: { name: existingInstance.name }}, @@ -495,7 +498,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { function(err, record, created) { if (err) return done(err); record.id.should.eql(existingInstance.id); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: getLastGeneratedUid(), name: existingInstance.name, @@ -509,14 +512,14 @@ module.exports = function(dataSource, should, connectorCapabilities) { } it('triggers `before save` hook when not found', function(done) { - TestModel.observe('before save', pushContextAndNext()); + TestModel.observe('before save', ctxRecorder.recordAndNext()); TestModel.findOrCreate( { where: { name: 'new-record' }}, { name: 'new-record' }, function(err, record, created) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: record.id, name: 'new-record', @@ -612,7 +615,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { if (dataSource.connector.findOrCreate) { it('triggers `persist` hook when found', function(done) { - TestModel.observe('persist', pushContextAndNext()); + TestModel.observe('persist', ctxRecorder.recordAndNext()); TestModel.findOrCreate( { where: { name: existingInstance.name }}, @@ -628,7 +631,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { // Hence, the test below asserts both `data.id` and // `currentInstance.id` to match getLastGeneratedUid(). // On same lines, it also asserts `isNewInstance` to be true. - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: getLastGeneratedUid(), name: existingInstance.name, @@ -648,7 +651,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { } it('triggers `persist` hook when not found', function(done) { - TestModel.observe('persist', pushContextAndNext()); + TestModel.observe('persist', ctxRecorder.recordAndNext()); TestModel.findOrCreate( { where: { name: 'new-record' }}, @@ -659,7 +662,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { // `context.where` is present in Optimized connector context, // but, unoptimized connector does NOT have it. if (dataSource.connector.findOrCreate) { - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: record.id, name: 'new-record', @@ -673,7 +676,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { where: { name: 'new-record' }, })); } else { - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: record.id, name: 'new-record', @@ -688,7 +691,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { if (dataSource.connector.findOrCreate) { it('applies updates from `persist` hook when found', function(done) { - TestModel.observe('persist', pushContextAndNext(function(ctx) { + TestModel.observe('persist', ctxRecorder.recordAndNext(function(ctx) { ctx.data.extra = 'hook data'; })); @@ -721,7 +724,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { } it('applies updates from `persist` hook when not found', function(done) { - TestModel.observe('persist', pushContextAndNext(function(ctx) { + TestModel.observe('persist', ctxRecorder.recordAndNext(function(ctx) { ctx.data.extra = 'hook data'; })); @@ -759,7 +762,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { if (dataSource.connector.findOrCreate) { it('triggers `loaded` hook when found', function(done) { - TestModel.observe('loaded', pushContextAndNext()); + TestModel.observe('loaded', ctxRecorder.recordAndNext()); TestModel.findOrCreate( { where: { name: existingInstance.name }}, @@ -772,7 +775,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { // After the call to `connector.findOrCreate`, since the record // already exists, `data.id` matches `existingInstance.id` // as against the behaviour noted for `persist` hook - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: existingInstance.id, name: existingInstance.name, @@ -786,7 +789,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { } it('triggers `loaded` hook when not found', function(done) { - TestModel.observe('loaded', pushContextAndNext()); + TestModel.observe('loaded', ctxRecorder.recordAndNext()); TestModel.findOrCreate( { where: { name: 'new-record' }}, @@ -794,7 +797,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { function(err, record, created) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: record.id, name: 'new-record', @@ -819,7 +822,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { if (dataSource.connector.findOrCreate) { it('applies updates from `loaded` hook when found', function(done) { - TestModel.observe('loaded', pushContextAndNext(function(ctx) { + TestModel.observe('loaded', ctxRecorder.recordAndNext(function(ctx) { ctx.data.extra = 'hook data'; })); @@ -837,7 +840,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { } it('applies updates from `loaded` hook when not found', function(done) { - TestModel.observe('loaded', pushContextAndNext(function(ctx) { + TestModel.observe('loaded', ctxRecorder.recordAndNext(function(ctx) { ctx.data.extra = 'hook data'; })); @@ -861,14 +864,14 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `after save` hook when not found', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); TestModel.findOrCreate( { where: { name: 'new name' }}, { name: 'new name' }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: instance.id, name: 'new name', @@ -881,14 +884,14 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('does not trigger `after save` hook when found', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); TestModel.findOrCreate( { where: { id: existingInstance.id }}, { name: existingInstance.name }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql('hook not called'); + ctxRecorder.records.should.eql('hook not called'); done(); }); }); @@ -896,11 +899,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { describe('PersistedModel.count', function(done) { it('triggers `access` hook', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.count({ id: existingInstance.id }, function(err, count) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ query: { + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { query: { where: { id: existingInstance.id }, }})); done(); @@ -939,12 +942,12 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `before save` hook', function(done) { - TestModel.observe('before save', pushContextAndNext()); + TestModel.observe('before save', ctxRecorder.recordAndNext()); existingInstance.name = 'changed'; existingInstance.save(function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ instance: { + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: existingInstance.id, name: 'changed', extra: undefined, @@ -987,16 +990,16 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `persist` hook', function(done) { - TestModel.observe('persist', pushContextAndNext()); + TestModel.observe('persist', ctxRecorder.recordAndNext()); existingInstance.name = 'changed'; existingInstance.save(function(err, instance) { if (err) return done(err); // HACK: extra is undefined for NoSQL and null for SQL - delete observedContexts.data.extra; - delete observedContexts.currentInstance.extra; - observedContexts.should.eql(aTestModelCtx({ + delete ctxRecorder.records.data.extra; + delete ctxRecorder.records.currentInstance.extra; + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: existingInstance.id, name: 'changed', @@ -1014,7 +1017,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('applies updates from `persist` hook', function(done) { - TestModel.observe('persist', pushContextAndNext(function(ctx) { + TestModel.observe('persist', ctxRecorder.recordAndNext(function(ctx) { ctx.data.extra = 'hook data'; })); @@ -1026,13 +1029,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `loaded` hook', function(done) { - TestModel.observe('loaded', pushContextAndNext()); + TestModel.observe('loaded', ctxRecorder.recordAndNext()); existingInstance.extra = 'changed'; existingInstance.save(function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: existingInstance.id, name: existingInstance.name, @@ -1056,7 +1059,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('applies updates from `loaded` hook', function(done) { - TestModel.observe('loaded', pushContextAndNext(function(ctx) { + TestModel.observe('loaded', ctxRecorder.recordAndNext(function(ctx) { ctx.data.extra = 'hook data'; })); @@ -1068,12 +1071,12 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `after save` hook on update', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); existingInstance.name = 'changed'; existingInstance.save(function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: existingInstance.id, name: 'changed', @@ -1087,7 +1090,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `after save` hook on create', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); var instance = new TestModel( { id: 'new-id', name: 'created' }, @@ -1095,7 +1098,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { instance.save(function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: instance.id, name: 'created', @@ -1151,14 +1154,14 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `before save` hook', function(done) { - TestModel.observe('before save', pushContextAndNext()); + TestModel.observe('before save', ctxRecorder.recordAndNext()); var currentInstance = deepCloneToObject(existingInstance); existingInstance.updateAttributes({ name: 'changed' }, function(err) { if (err) return done(err); existingInstance.name.should.equal('changed'); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { id: existingInstance.id }, data: { name: 'changed' }, currentInstance: currentInstance, @@ -1211,11 +1214,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `persist` hook', function(done) { - TestModel.observe('persist', pushContextAndNext()); + TestModel.observe('persist', ctxRecorder.recordAndNext()); existingInstance.updateAttributes({ name: 'changed' }, function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { id: existingInstance.id }, data: { name: 'changed' }, currentInstance: { @@ -1231,7 +1234,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('applies updates from `persist` hook', function(done) { - TestModel.observe('persist', pushContextAndNext(function(ctx) { + TestModel.observe('persist', ctxRecorder.recordAndNext(function(ctx) { ctx.data.extra = 'hook data'; })); @@ -1268,7 +1271,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { var existingUser = instance; - User.observe('persist', pushContextAndNext(function(ctx) { + User.observe('persist', ctxRecorder.recordAndNext(function(ctx) { should.exist(ctx.data.address); ctx.data.address.should.be.type('object'); ctx.data.address.should.not.be.instanceOf(Address); @@ -1304,11 +1307,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `loaded` hook', function(done) { - TestModel.observe('loaded', pushContextAndNext()); + TestModel.observe('loaded', ctxRecorder.recordAndNext()); existingInstance.updateAttributes({ name: 'changed' }, function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { name: 'changed' }, })); @@ -1327,7 +1330,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('applies updates from `loaded` hook updateAttributes', function(done) { - TestModel.observe('loaded', pushContextAndNext(function(ctx) { + TestModel.observe('loaded', ctxRecorder.recordAndNext(function(ctx) { ctx.data.extra = 'hook data'; })); @@ -1344,12 +1347,12 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `after save` hook', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); existingInstance.name = 'changed'; existingInstance.updateAttributes({ name: 'changed' }, function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: existingInstance.id, name: 'changed', @@ -1407,11 +1410,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `before save` hook', function(done) { - TestModel.observe('before save', pushContextAndNext()); + TestModel.observe('before save', ctxRecorder.recordAndNext()); existingInstance.replaceAttributes({ name: 'changed' }, function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: existingInstance.id, name: 'changed', @@ -1465,11 +1468,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `persist` hook', function(done) { - TestModel.observe('persist', pushContextAndNext()); + TestModel.observe('persist', ctxRecorder.recordAndNext()); existingInstance.replaceAttributes({ name: 'replacedName' }, function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { id: existingInstance.id }, data: { name: 'replacedName', @@ -1488,7 +1491,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('applies delete from `persist` hook', function(done) { - TestModel.observe('persist', pushContextAndNext(function(ctx) { + TestModel.observe('persist', ctxRecorder.recordAndNext(function(ctx) { delete ctx.data.extra; })); @@ -1520,7 +1523,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { var existingUser = instance; - User.observe('persist', pushContextAndNext(function(ctx) { + User.observe('persist', ctxRecorder.recordAndNext(function(ctx) { should.exist(ctx.data.address); ctx.data.address.should.be.type('object'); ctx.data.address.should.not.be.instanceOf(Address); @@ -1551,11 +1554,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `loaded` hook', function(done) { - TestModel.observe('loaded', pushContextAndNext()); + TestModel.observe('loaded', ctxRecorder.recordAndNext()); existingInstance.replaceAttributes({ name: 'changed' }, function(err, data) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { name: 'changed', id: data.id, @@ -1577,7 +1580,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('applies updates from `loaded` hook replaceAttributes', function(done) { - TestModel.observe('loaded', pushContextAndNext(function(ctx) { + TestModel.observe('loaded', ctxRecorder.recordAndNext(function(ctx) { ctx.data.name = 'changed in hook'; })); @@ -1589,12 +1592,12 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `after save` hook', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); existingInstance.name = 'replaced'; existingInstance.replaceAttributes({ name: 'replaced' }, function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: existingInstance.id, name: 'replaced', @@ -1680,13 +1683,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `access` hook on create', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.updateOrCreate( { id: 'not-found', name: 'not found' }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ query: { + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { query: { where: { id: 'not-found' }, }})); done(); @@ -1694,13 +1697,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `access` hook on update', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.updateOrCreate( { id: existingInstance.id, name: 'new name' }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ query: { + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { query: { where: { id: existingInstance.id }, }})); done(); @@ -1708,13 +1711,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('does not trigger `access` on missing id', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.updateOrCreate( { name: 'new name' }, function(err, instance) { if (err) return done(err); - observedContexts.should.equal('hook not called'); + ctxRecorder.records.should.equal('hook not called'); done(); }); }); @@ -1781,7 +1784,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `before save` hook on update', function(done) { - TestModel.observe('before save', pushContextAndNext()); + TestModel.observe('before save', ctxRecorder.recordAndNext()); TestModel.updateOrCreate( { id: existingInstance.id, name: 'updated name' }, @@ -1791,7 +1794,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { // Atomic implementations of `updateOrCreate` cannot // provide full instance as that depends on whether // UPDATE or CREATE will be triggered - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { id: existingInstance.id }, data: { id: existingInstance.id, name: 'updated name' }, })); @@ -1799,7 +1802,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { // currentInstance is set, because a non-atomic `updateOrCreate` // will use `prototype.updateAttributes` internally, which // exposes this to the context - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { id: existingInstance.id }, data: { id: existingInstance.id, name: 'updated name' }, currentInstance: existingInstance, @@ -1810,7 +1813,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `before save` hook on create', function(done) { - TestModel.observe('before save', pushContextAndNext()); + TestModel.observe('before save', ctxRecorder.recordAndNext()); TestModel.updateOrCreate( { id: 'new-id', name: 'a name' }, @@ -1821,14 +1824,14 @@ module.exports = function(dataSource, should, connectorCapabilities) { // Atomic implementations of `updateOrCreate` cannot // provide full instance as that depends on whether // UPDATE or CREATE will be triggered - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { id: 'new-id' }, data: { id: 'new-id', name: 'a name' }, })); } else { // The default unoptimized implementation runs // `instance.save` and thus a full instance is availalbe - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: 'new-id', name: 'a name', extra: undefined }, isNewInstance: true, })); @@ -1901,7 +1904,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `persist` hook on create', function(done) { - TestModel.observe('persist', pushContextAndNext()); + TestModel.observe('persist', ctxRecorder.recordAndNext()); TestModel.updateOrCreate( { id: 'new-id', name: 'a name' }, @@ -1909,7 +1912,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { if (err) return done(err); if (dataSource.connector.updateOrCreate) { - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { id: 'new-id' }, data: { id: 'new-id', name: 'a name' }, currentInstance: { @@ -1919,7 +1922,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }, })); } else { - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: 'new-id', name: 'a name', @@ -1937,14 +1940,14 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `persist` hook on update', function(done) { - TestModel.observe('persist', pushContextAndNext()); + TestModel.observe('persist', ctxRecorder.recordAndNext()); TestModel.updateOrCreate( { id: existingInstance.id, name: 'updated name' }, function(err, instance) { if (err) return done(err); - var expectedContext = aTestModelCtx({ + var expectedContext = aCtxForModel(TestModel, { where: { id: existingInstance.id }, data: { id: existingInstance.id, @@ -1963,13 +1966,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { expectedContext.isNewInstance = false; } - observedContexts.should.eql(expectedContext); + ctxRecorder.records.should.eql(expectedContext); done(); }); }); it('triggers `loaded` hook on create', function(done) { - TestModel.observe('loaded', pushContextAndNext()); + TestModel.observe('loaded', ctxRecorder.recordAndNext()); TestModel.updateOrCreate( { id: 'new-id', name: 'a name' }, @@ -1977,12 +1980,12 @@ module.exports = function(dataSource, should, connectorCapabilities) { if (err) return done(err); if (dataSource.connector.updateOrCreate) { - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: 'new-id', name: 'a name' }, isNewInstance: true, })); } else { - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: 'new-id', name: 'a name', @@ -1995,7 +1998,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `loaded` hook on update', function(done) { - TestModel.observe('loaded', pushContextAndNext()); + TestModel.observe('loaded', ctxRecorder.recordAndNext()); TestModel.updateOrCreate( { id: existingInstance.id, name: 'updated name' }, @@ -2003,7 +2006,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { if (err) return done(err); if (dataSource.connector.updateOrCreate) { - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { id: existingInstance.id, name: 'updated name', @@ -2011,11 +2014,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { isNewInstance: false, })); } else { - // For Unoptimized connector, the callback function `pushContextAndNext` - // is called twice. As a result, observedContexts + // For Unoptimized connector, the callback function `contextRecorder.recordAndNext` + // is called twice. As a result, contextRecorder.records // returns an array and NOT a single instance. - observedContexts.should.eql([ - aTestModelCtx({ + ctxRecorder.records.should.eql([ + aCtxForModel(TestModel, { data: { id: existingInstance.id, name: 'first', @@ -2023,7 +2026,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { isNewInstance: false, options: { notify: false }, }), - aTestModelCtx({ + aCtxForModel(TestModel, { data: { id: existingInstance.id, name: 'updated name', @@ -2046,13 +2049,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `after save` hook on update', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); TestModel.updateOrCreate( { id: existingInstance.id, name: 'updated name' }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: existingInstance.id, name: 'updated name', @@ -2065,13 +2068,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `after save` hook on create', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); TestModel.updateOrCreate( { id: 'new-id', name: 'a name' }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { instance: { id: instance.id, name: 'a name', @@ -2145,13 +2148,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `access` hook on create', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.replaceOrCreate( { id: 'not-found', name: 'not found' }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ query: { + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { query: { where: { id: 'not-found' }, }})); done(); @@ -2159,13 +2162,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `access` hook on replace', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.replaceOrCreate( { id: existingInstance.id, name: 'new name' }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ query: { + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { query: { where: { id: existingInstance.id }, }})); done(); @@ -2173,13 +2176,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('does not trigger `access` on missing id', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.replaceOrCreate( { name: 'new name' }, function(err, instance) { if (err) return done(err); - observedContexts.should.equal('hook not called'); + ctxRecorder.records.should.equal('hook not called'); done(); }); }); @@ -2246,13 +2249,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `before save` hookon create', function(done) { - TestModel.observe('before save', pushContextAndNext()); + TestModel.observe('before save', ctxRecorder.recordAndNext()); TestModel.replaceOrCreate({ id: existingInstance.id, name: 'new name' }, function(err, instance) { if (err) return done(err); - var expectedContext = aTestModelCtx({ + var expectedContext = aCtxForModel(TestModel, { instance: instance, }); @@ -2264,13 +2267,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `before save` hook on replace', function(done) { - TestModel.observe('before save', pushContextAndNext()); + TestModel.observe('before save', ctxRecorder.recordAndNext()); TestModel.replaceOrCreate( { id: existingInstance.id, name: 'replaced name' }, function(err, instance) { if (err) return done(err); - var expectedContext = aTestModelCtx({ + var expectedContext = aCtxForModel(TestModel, { instance: { id: existingInstance.id, name: 'replaced name', @@ -2281,21 +2284,21 @@ module.exports = function(dataSource, should, connectorCapabilities) { if (!dataSource.connector.replaceOrCreate) { expectedContext.isNewInstance = false; } - observedContexts.should.eql(expectedContext); + ctxRecorder.records.should.eql(expectedContext); done(); }); }); it('triggers `before save` hook on create', function(done) { - TestModel.observe('before save', pushContextAndNext()); + TestModel.observe('before save', ctxRecorder.recordAndNext()); TestModel.replaceOrCreate( { id: 'new-id', name: 'a name' }, function(err, instance) { if (err) return done(err); - var expectedContext = aTestModelCtx({ + var expectedContext = aCtxForModel(TestModel, { instance: { id: 'new-id', name: 'a name', @@ -2306,7 +2309,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { if (!dataSource.connector.replaceOrCreate) { expectedContext.isNewInstance = true; } - observedContexts.should.eql(expectedContext); + ctxRecorder.records.should.eql(expectedContext); done(); }); @@ -2340,14 +2343,14 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `persist` hook on create', function(done) { - TestModel.observe('persist', pushContextAndNext()); + TestModel.observe('persist', ctxRecorder.recordAndNext()); TestModel.replaceOrCreate( { id: 'new-id', name: 'a name' }, function(err, instance) { if (err) return done(err); - var expectedContext = aTestModelCtx({ + var expectedContext = aCtxForModel(TestModel, { currentInstance: { id: 'new-id', name: 'a name', @@ -2369,13 +2372,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { // are not records to match where filter. expectedContext.isNewInstance = true; } - observedContexts.should.eql(expectedContext); + ctxRecorder.records.should.eql(expectedContext); done(); }); }); it('triggers `persist` hook on replace', function(done) { - TestModel.observe('persist', pushContextAndNext()); + TestModel.observe('persist', ctxRecorder.recordAndNext()); TestModel.replaceOrCreate( { id: existingInstance.id, name: 'replaced name' }, @@ -2395,20 +2398,20 @@ module.exports = function(dataSource, should, connectorCapabilities) { }, }; - var expectedContext = aTestModelCtx(expected); + var expectedContext = aCtxForModel(TestModel, expected); var expectedContext; if (!dataSource.connector.replaceOrCreate) { expectedContext.isNewInstance = false; } - observedContexts.should.eql(expectedContext); + ctxRecorder.records.should.eql(expectedContext); done(); }); }); it('triggers `loaded` hook on create', function(done) { - TestModel.observe('loaded', pushContextAndNext()); + TestModel.observe('loaded', ctxRecorder.recordAndNext()); TestModel.replaceOrCreate( { id: 'new-id', name: 'a name' }, @@ -2426,13 +2429,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { connectorCapabilities.replaceOrCreateReportsNewInstance ? true : undefined; - observedContexts.should.eql(aTestModelCtx(expected)); + ctxRecorder.records.should.eql(aCtxForModel(TestModel, expected)); done(); }); }); it('triggers `loaded` hook on replace', function(done) { - TestModel.observe('loaded', pushContextAndNext()); + TestModel.observe('loaded', ctxRecorder.recordAndNext()); TestModel.replaceOrCreate( { id: existingInstance.id, name: 'replaced name' }, @@ -2451,7 +2454,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { false : undefined; if (dataSource.connector.replaceOrCreate) { - observedContexts.should.eql(aTestModelCtx(expected)); + ctxRecorder.records.should.eql(aCtxForModel(TestModel, expected)); } else { // TODO: Please see loopback-datasource-juggler/issues#836 // @@ -2462,8 +2465,8 @@ module.exports = function(dataSource, should, connectorCapabilities) { // loopback-datasource-juggler/issues#836. // 2) It, also, gets triggered in "replaceAttributes()" // in this chain replaceORCreate()->replaceAttributes() - observedContexts.should.eql([ - aTestModelCtx({ + ctxRecorder.records.should.eql([ + aCtxForModel(TestModel, { data: { id: existingInstance.id, name: 'first', @@ -2471,7 +2474,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { isNewInstance: false, options: { notify: false }, }), - aTestModelCtx({ + aCtxForModel(TestModel, { data: { id: existingInstance.id, name: 'replaced name', @@ -2495,7 +2498,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `after save` hook on replace', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); TestModel.replaceOrCreate( { id: existingInstance.id, name: 'replaced name' }, @@ -2514,13 +2517,13 @@ module.exports = function(dataSource, should, connectorCapabilities) { connectorCapabilities.replaceOrCreateReportsNewInstance ? false : undefined; - observedContexts.should.eql(aTestModelCtx(expected)); + ctxRecorder.records.should.eql(aCtxForModel(TestModel, expected)); done(); }); }); it('triggers `after save` hook on create', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); TestModel.replaceOrCreate( { id: 'new-id', name: 'a name' }, @@ -2538,7 +2541,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { connectorCapabilities.replaceOrCreateReportsNewInstance ? true : undefined; - observedContexts.should.eql(aTestModelCtx(expected)); + ctxRecorder.records.should.eql(aCtxForModel(TestModel, expected)); done(); }); }); @@ -2547,11 +2550,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { describe('PersistedModel.deleteAll', function() { it('triggers `access` hook with query', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.deleteAll({ name: existingInstance.name }, function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { query: { where: { name: existingInstance.name }}, })); done(); @@ -2559,11 +2562,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `access` hook without query', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.deleteAll(function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ query: { where: {}}})); + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { query: { where: {}}})); done(); }); }); @@ -2585,11 +2588,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `before delete` hook with query', function(done) { - TestModel.observe('before delete', pushContextAndNext()); + TestModel.observe('before delete', ctxRecorder.recordAndNext()); TestModel.deleteAll({ name: existingInstance.name }, function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { name: existingInstance.name }, })); done(); @@ -2597,11 +2600,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `before delete` hook without query', function(done) { - TestModel.observe('before delete', pushContextAndNext()); + TestModel.observe('before delete', ctxRecorder.recordAndNext()); TestModel.deleteAll(function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ where: {}})); + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: {}})); done(); }); }); @@ -2637,21 +2640,21 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `after delete` hook without query', function(done) { - TestModel.observe('after delete', pushContextAndNext()); + TestModel.observe('after delete', ctxRecorder.recordAndNext()); TestModel.deleteAll(function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ where: {}})); + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: {}})); done(); }); }); it('triggers `after delete` hook without query', function(done) { - TestModel.observe('after delete', pushContextAndNext()); + TestModel.observe('after delete', ctxRecorder.recordAndNext()); TestModel.deleteAll({ name: existingInstance.name }, function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { name: existingInstance.name }, })); done(); @@ -2670,11 +2673,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { describe('PersistedModel.prototype.delete', function() { it('triggers `access` hook', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); existingInstance.delete(function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { query: { where: { id: existingInstance.id }}, })); done(); @@ -2698,11 +2701,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `before delete` hook', function(done) { - TestModel.observe('before delete', pushContextAndNext()); + TestModel.observe('before delete', ctxRecorder.recordAndNext()); existingInstance.delete(function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { id: existingInstance.id }, instance: existingInstance, })); @@ -2741,11 +2744,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `after delete` hook', function(done) { - TestModel.observe('after delete', pushContextAndNext()); + TestModel.observe('after delete', ctxRecorder.recordAndNext()); existingInstance.delete(function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { id: existingInstance.id }, instance: existingInstance, })); @@ -2754,11 +2757,11 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `after delete` hook without query', function(done) { - TestModel.observe('after delete', pushContextAndNext()); + TestModel.observe('after delete', ctxRecorder.recordAndNext()); TestModel.deleteAll({ name: existingInstance.name }, function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { name: existingInstance.name }, })); done(); @@ -2775,24 +2778,24 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('propagates hookState from `before delete` to `after delete`', function(done) { - TestModel.observe('before delete', pushContextAndNext(function(ctx) { + TestModel.observe('before delete', ctxRecorder.recordAndNext(function(ctx) { ctx.hookState.foo = 'bar'; })); - TestModel.observe('after delete', pushContextAndNext(function(ctx) { + TestModel.observe('after delete', ctxRecorder.recordAndNext(function(ctx) { ctx.hookState.foo = ctx.hookState.foo.toUpperCase(); })); existingInstance.delete(function(err) { if (err) return done(err); - observedContexts.should.eql([ - aTestModelCtx({ - hookState: { foo: 'bar', test: true }, + ctxRecorder.records.should.eql([ + aCtxForModel(TestModel, { + hookState: { foo: 'bar' }, where: { id: '1' }, instance: existingInstance, }), - aTestModelCtx({ - hookState: { foo: 'BAR', test: true }, + aCtxForModel(TestModel, { + hookState: { foo: 'BAR' }, where: { id: '1' }, instance: existingInstance, }), @@ -2819,14 +2822,14 @@ module.exports = function(dataSource, should, connectorCapabilities) { describe('PersistedModel.updateAll', function() { it('triggers `access` hook', function(done) { - TestModel.observe('access', pushContextAndNext()); + TestModel.observe('access', ctxRecorder.recordAndNext()); TestModel.updateAll( { name: 'searched' }, { name: 'updated' }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ query: { + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { query: { where: { name: 'searched' }, }})); done(); @@ -2856,14 +2859,14 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `before save` hook', function(done) { - TestModel.observe('before save', pushContextAndNext()); + TestModel.observe('before save', ctxRecorder.recordAndNext()); TestModel.updateAll( { name: 'searched' }, { name: 'updated' }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { name: 'searched' }, data: { name: 'updated' }, })); @@ -2892,7 +2895,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('triggers `persist` hook', function(done) { - TestModel.observe('persist', pushContextAndNext()); + TestModel.observe('persist', ctxRecorder.recordAndNext()); TestModel.updateAll( { name: existingInstance.name }, @@ -2900,7 +2903,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { function(err, instance) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { data: { name: 'changed' }, where: { name: existingInstance.name }, })); @@ -2910,7 +2913,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('applies updates from `persist` hook', function(done) { - TestModel.observe('persist', pushContextAndNext(function(ctx) { + TestModel.observe('persist', ctxRecorder.recordAndNext(function(ctx) { ctx.data.extra = 'hook data'; })); @@ -2927,27 +2930,27 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('does not trigger `loaded`', function(done) { - TestModel.observe('loaded', pushContextAndNext()); + TestModel.observe('loaded', ctxRecorder.recordAndNext()); TestModel.updateAll( { id: existingInstance.id }, { name: 'changed' }, function(err, instance) { if (err) return done(err); - observedContexts.should.eql('hook not called'); + ctxRecorder.records.should.eql('hook not called'); done(); }); }); it('triggers `after save` hook', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); TestModel.updateAll( { id: existingInstance.id }, { name: 'updated name' }, function(err) { if (err) return done(err); - observedContexts.should.eql(aTestModelCtx({ + ctxRecorder.records.should.eql(aCtxForModel(TestModel, { where: { id: existingInstance.id }, data: { name: 'updated name' }, })); @@ -2956,7 +2959,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); it('accepts hookState from options', function(done) { - TestModel.observe('after save', pushContextAndNext()); + TestModel.observe('after save', ctxRecorder.recordAndNext()); TestModel.updateAll( { id: existingInstance.id }, @@ -2964,7 +2967,7 @@ module.exports = function(dataSource, should, connectorCapabilities) { { foo: 'bar' }, function(err) { if (err) return done(err); - observedContexts.options.should.eql({ + ctxRecorder.records.options.should.eql({ foo: 'bar', }); done(); @@ -2973,29 +2976,6 @@ module.exports = function(dataSource, should, connectorCapabilities) { }); - function pushContextAndNext(fn) { - return function(context, next) { - if (typeof fn === 'function') { - fn(context); - } - - context = deepCloneToObject(context); - context.hookState.test = true; - - if (typeof observedContexts === 'string') { - observedContexts = context; - return next(); - } - - if (!Array.isArray(observedContexts)) { - observedContexts = [observedContexts]; - } - - observedContexts.push(context); - next(); - }; - } - function pushNameAndNext(name) { return function(context, next) { observersCalled.push(name); @@ -3020,17 +3000,6 @@ module.exports = function(dataSource, should, connectorCapabilities) { }; } - function aTestModelCtx(ctx) { - ctx.Model = TestModel; - if (!ctx.hookState) { - ctx.hookState = { test: true }; - } - if (!ctx.options) { - ctx.options = {}; - } - return deepCloneToObject(ctx); - } - function findTestModels(query, cb) { if (cb === undefined && typeof query === 'function') { cb = query; @@ -3063,18 +3032,6 @@ module.exports = function(dataSource, should, connectorCapabilities) { } }); - function deepCloneToObject(obj) { - return traverse(obj).map(function(x) { - if (x === undefined) { - // RDBMSs return null - return null; - } - if (x && x.toObject) - return x.toObject(true); - if (x && typeof x === 'function' && x.modelName) - return '[ModelCtor ' + x.modelName + ']'; - }); - } function get(propertyName) { return function(obj) {