| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- import {expect} from 'chai';
- import {format} from 'util';
- import {Schema} from '../schema.js';
- import {RepositoryEvent} from './repository-observer.js';
- import {RepositoryObserver} from './repository-observer.js';
- const MODEL_NAME = 'model';
- const EVENT_NAME = RepositoryEvent.AFTER_CREATE;
- const METHOD_NAME = 'methodName';
- const HANDLER_FN = () => undefined;
- describe('RepositoryObserver', function () {
- describe('observe', function () {
- describe('2 arguments', function () {
- it('adds an event handler of the root scope', function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- observer.observe(EVENT_NAME, HANDLER_FN);
- const eventsMap = observer._handlersMap.get(null);
- const listeners = eventsMap.get(EVENT_NAME);
- expect(listeners).to.have.lengthOf(1);
- expect(listeners).to.include(HANDLER_FN);
- });
- it('requires the "eventName" argument to be RepositoryEvent', function () {
- const schema = new Schema();
- const observer = schema.get(RepositoryObserver);
- const throwable = v => () => observer.observe(v, HANDLER_FN);
- const error = v =>
- format(
- 'The parameter "eventName" of RepositoryObserver.observe ' +
- 'must be a non-empty String, but %s given.',
- v,
- );
- expect(throwable()).to.throw(error('undefined'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable(null)).to.throw(error('null'));
- Object.values(RepositoryEvent).forEach(e => throwable(e)());
- });
- it('requires the "handler" argument to be a function', function () {
- const schema = new Schema();
- const observer = schema.get(RepositoryObserver);
- const throwable = v => () => observer.observe(EVENT_NAME, v);
- const error = v =>
- format(
- 'The parameter "handler" of RepositoryObserver.observe ' +
- 'must be a Function, but %s given.',
- v,
- );
- expect(throwable()).to.throw(error('undefined'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable('str')).to.throw(error('"str"'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable(null)).to.throw(error('null'));
- throwable(HANDLER_FN)();
- });
- });
- describe('3 arguments', function () {
- it('adds an event handler of a model scope', function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- observer.observe(MODEL_NAME, EVENT_NAME, HANDLER_FN);
- const eventsMap = observer._handlersMap.get(MODEL_NAME);
- const listeners = eventsMap.get(EVENT_NAME);
- expect(listeners).to.have.lengthOf(1);
- expect(listeners).to.include(HANDLER_FN);
- });
- it('requires the "modelName" argument to be a non-empty string', function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- const throwable = v => () =>
- observer.observe(v, EVENT_NAME, HANDLER_FN);
- const error = v =>
- format(
- 'The parameter "modelName" of RepositoryObserver.observe ' +
- 'must be a non-empty String, but %s given.',
- v,
- );
- expect(throwable()).to.throw(error('undefined'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable(null)).to.throw(error('null'));
- throwable(MODEL_NAME)();
- });
- it('requires the "modelName" argument to be a defined model', function () {
- const schema = new Schema();
- const observer = schema.get(RepositoryObserver);
- const throwable = () =>
- observer.observe('unknown', EVENT_NAME, HANDLER_FN);
- expect(throwable).to.throw(
- 'Cannot observe repository of a not defined model "unknown".',
- );
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- observer.observe(MODEL_NAME, EVENT_NAME, HANDLER_FN);
- });
- it('requires the "eventName" argument to be RepositoryEvent', function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- const throwable = v => () =>
- observer.observe(MODEL_NAME, v, HANDLER_FN);
- const error = v =>
- format(
- 'The parameter "eventName" of RepositoryObserver.observe ' +
- 'must be a non-empty String, but %s given.',
- v,
- );
- expect(throwable()).to.throw(error('undefined'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable(null)).to.throw(error('null'));
- Object.values(RepositoryEvent).forEach(e => throwable(e)());
- });
- it('requires the "handler" argument to be a function', function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- const throwable = v => () =>
- observer.observe(MODEL_NAME, EVENT_NAME, v);
- const error = v =>
- format(
- 'The parameter "handler" of RepositoryObserver.observe ' +
- 'must be a Function, but %s given.',
- v,
- );
- expect(throwable()).to.throw(error('undefined'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable('str')).to.throw(error('"str"'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable(null)).to.throw(error('null'));
- throwable(HANDLER_FN)();
- });
- });
- });
- describe('_getHandlers', function () {
- it('returns an empty array if no handlers', function () {
- const schema = new Schema();
- const observer = schema.get(RepositoryObserver);
- const result = observer._getHandlers(MODEL_NAME, EVENT_NAME);
- expect(result).to.have.lengthOf(0);
- });
- it('returns model handlers that includes root handlers', function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: 'modelA', datasource: 'datasource'});
- schema.defineModel({name: 'modelB', datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- const handler1 = () => undefined;
- const handler2 = () => undefined;
- const handler3 = () => undefined;
- const handler4 = () => undefined;
- const handler5 = () => undefined;
- const handler6 = () => undefined;
- const handler7 = () => undefined;
- const event1 = 'event1';
- const event2 = 'event2';
- observer.observe(event1, handler1);
- observer.observe(event1, handler2);
- observer.observe(event2, handler3);
- observer.observe('modelA', event1, handler4);
- observer.observe('modelA', event1, handler5);
- observer.observe('modelA', event2, handler6);
- observer.observe('modelB', event1, handler7);
- const result = observer._getHandlers('modelA', event1);
- expect(result).to.be.eql([handler1, handler2, handler4, handler5]);
- });
- it('requires the "modelName" argument to be a non-empty string', function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- const throwable = v => () => observer._getHandlers(v, EVENT_NAME);
- const error = v =>
- format(
- 'The parameter "modelName" of RepositoryObserver._getHandlers ' +
- 'must be a non-empty String, but %s given.',
- v,
- );
- expect(throwable()).to.throw(error('undefined'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable(null)).to.throw(error('null'));
- throwable(MODEL_NAME)();
- });
- it('requires the "eventName" argument to be a non-empty string', function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- const throwable = v => () => observer._getHandlers(MODEL_NAME, v);
- const error = v =>
- format(
- 'The parameter "eventName" of RepositoryObserver._getHandlers ' +
- 'must be a non-empty String, but %s given.',
- v,
- );
- expect(throwable()).to.throw(error('undefined'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable(null)).to.throw(error('null'));
- throwable('eventName')();
- });
- });
- describe('emit', function () {
- it('requires the "modelName" argument to be a non-empty string', function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- const throwable = v => () =>
- observer.emit(v, EVENT_NAME, METHOD_NAME, {});
- const error = v =>
- format(
- 'The parameter "modelName" of RepositoryObserver.emit ' +
- 'must be a non-empty String, but %s given.',
- v,
- );
- expect(throwable()).to.throw(error('undefined'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable(null)).to.throw(error('null'));
- throwable(MODEL_NAME)();
- });
- it('requires the "eventName" argument to be a non-empty string', function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- const throwable = v => () =>
- observer.emit(MODEL_NAME, v, METHOD_NAME, {});
- const error = v =>
- format(
- 'The parameter "eventName" of RepositoryObserver.emit ' +
- 'must be a non-empty String, but %s given.',
- v,
- );
- expect(throwable()).to.throw(error('undefined'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable(null)).to.throw(error('null'));
- throwable('eventName')();
- });
- it('requires the "methodName" argument to be a non-empty string', function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- const throwable = v => () => observer.emit(MODEL_NAME, EVENT_NAME, v, {});
- const error = v =>
- format(
- 'The parameter "methodName" of RepositoryObserver.emit ' +
- 'must be a non-empty String, but %s given.',
- v,
- );
- expect(throwable()).to.throw(error('undefined'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable(null)).to.throw(error('null'));
- throwable(METHOD_NAME)();
- });
- it('requires the "context" argument to be a non-empty string', function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- const throwable = v => () =>
- observer.emit(MODEL_NAME, EVENT_NAME, METHOD_NAME, v);
- const error = v =>
- format(
- 'The parameter "context" of RepositoryObserver.emit ' +
- 'must be an Object, but %s given.',
- v,
- );
- expect(throwable()).to.throw(error('undefined'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable(null)).to.throw(error('null'));
- throwable({})();
- });
- it('returns a promise for synchronous handlers', async function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- schema.defineModel({name: 'modelB', datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- const order = [];
- const handler1 = () => order.push(handler1);
- const handler2 = () => order.push(handler2);
- const handler3 = () => order.push(handler3);
- const handler4 = () => order.push(handler4);
- const throwable = () => {
- throw new Error();
- };
- observer.observe(EVENT_NAME, handler1);
- observer.observe(EVENT_NAME, handler2);
- observer.observe('event2', throwable);
- observer.observe(MODEL_NAME, EVENT_NAME, handler3);
- observer.observe(MODEL_NAME, EVENT_NAME, handler4);
- observer.observe(MODEL_NAME, 'event2', throwable);
- observer.observe('modelB', EVENT_NAME, throwable);
- const promise = observer.emit(MODEL_NAME, EVENT_NAME, METHOD_NAME, {});
- expect(promise).to.be.instanceof(Promise);
- await promise;
- expect(order).to.be.eql([handler1, handler2, handler3, handler4]);
- });
- it('returns a promise of asynchronous handlers', async function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- schema.defineModel({name: 'modelB', datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- const order = [];
- const handler0ms = () => {
- order.push(handler0ms);
- return Promise.resolve();
- };
- const handler5ms = () => {
- return new Promise(res => {
- setTimeout(() => {
- order.push(handler5ms);
- res();
- }, 5);
- });
- };
- const syncHandler = () => order.push(syncHandler);
- const handler3ms = () => {
- return new Promise(res => {
- setTimeout(() => {
- order.push(handler3ms);
- res();
- }, 3);
- });
- };
- const throwable = () => {
- throw new Error();
- };
- observer.observe(EVENT_NAME, handler0ms);
- observer.observe(EVENT_NAME, handler5ms);
- observer.observe('event2', throwable);
- observer.observe(MODEL_NAME, EVENT_NAME, syncHandler);
- observer.observe(MODEL_NAME, EVENT_NAME, handler3ms);
- observer.observe(MODEL_NAME, 'event2', throwable);
- observer.observe('modelB', EVENT_NAME, throwable);
- const promise = observer.emit(MODEL_NAME, EVENT_NAME, METHOD_NAME, {});
- expect(promise).to.be.instanceof(Promise);
- await promise;
- expect(order).to.have.lengthOf(4);
- expect(order).to.include(handler0ms);
- expect(order).to.include(handler5ms);
- expect(order).to.include(syncHandler);
- expect(order).to.include(handler3ms);
- });
- it('executes handlers with the context object', async function () {
- const schema = new Schema();
- schema.defineDatasource({name: 'datasource', adapter: 'memory'});
- schema.defineModel({name: MODEL_NAME, datasource: 'datasource'});
- const observer = schema.get(RepositoryObserver);
- const inputContext = {customProp: 'customProp'};
- const context = {
- modelName: MODEL_NAME,
- eventName: EVENT_NAME,
- methodName: METHOD_NAME,
- ...inputContext,
- };
- let counter = 0;
- const handler1 = ctx => {
- expect(ctx).to.be.eql(context);
- counter++;
- };
- const handler2 = ctx => {
- return new Promise(res => {
- setTimeout(() => {
- expect(ctx).to.be.eql(context);
- counter++;
- res();
- }, 3);
- });
- };
- observer.observe(EVENT_NAME, handler1);
- observer.observe(MODEL_NAME, EVENT_NAME, handler2);
- await observer.emit(MODEL_NAME, EVENT_NAME, METHOD_NAME, inputContext);
- expect(counter).to.be.eq(2);
- });
- });
- });
|