UNPKG

4.92 kBJavaScriptView Raw
1// Copyright IBM Corp. 2014,2019. All Rights Reserved.
2// Node module: loopback-datasource-juggler
3// This file is licensed under the MIT License.
4// License text available at https://opensource.org/licenses/MIT
5
6// This test written in mocha+should.js
7'use strict';
8const should = require('./init.js');
9
10const jdb = require('../');
11const ModelBuilder = jdb.ModelBuilder;
12const DataSource = jdb.DataSource;
13const Memory = require('../lib/connectors/memory');
14
15const modelBuilder = new ModelBuilder();
16const mixins = modelBuilder.mixins;
17
18function timestamps(Model, options) {
19 Model.defineProperty('createdAt', {type: Date});
20 Model.defineProperty('updatedAt', {type: Date});
21
22 const originalBeforeSave = Model.beforeSave;
23 Model.beforeSave = function(next, data) {
24 Model.applyTimestamps(data, this.isNewRecord());
25 if (data.createdAt) {
26 this.createdAt = data.createdAt;
27 }
28 if (data.updatedAt) {
29 this.updatedAt = data.updatedAt;
30 }
31 if (originalBeforeSave) {
32 originalBeforeSave.apply(this, arguments);
33 } else {
34 next();
35 }
36 };
37
38 Model.applyTimestamps = function(data, creation) {
39 data.updatedAt = new Date();
40 if (creation) {
41 data.createdAt = data.updatedAt;
42 }
43 };
44}
45
46mixins.define('TimeStamp', timestamps);
47
48describe('Model class', function() {
49 it('should define mixins', function() {
50 mixins.define('Example', function(Model, options) {
51 Model.prototype.example = function() {
52 return options;
53 };
54 });
55 mixins.define('Demo', function(Model, options) {
56 Model.demoMixin = options.value;
57 });
58 mixins.define('Multi', function(Model, options) {
59 Model.multiMixin = Model.multiMixin || {};
60 Model.multiMixin[options.key] = options.value;
61 });
62 });
63
64 it('should apply a mixin class', function() {
65 const Address = modelBuilder.define('Address', {
66 street: {type: 'string', required: true},
67 city: {type: 'string', required: true},
68 });
69
70 const memory = new DataSource('mem', {connector: Memory}, modelBuilder);
71 const Item = memory.createModel('Item', {name: 'string'}, {
72 mixins: {Address: true},
73 });
74
75 const properties = Item.definition.properties;
76
77 properties.street.should.eql({type: String, required: true});
78 properties.city.should.eql({type: String, required: true});
79 });
80
81 it('should fail to apply an undefined mixin class', function() {
82 const memory = new DataSource('mem', {connector: Memory}, modelBuilder);
83 function applyMixin() {
84 memory.createModel('Item', {name: 'string'}, {
85 mixins: {UndefinedMixin: true},
86 });
87 }
88 should.throws(applyMixin, 'failed to apply undefined mixin class');
89 });
90
91 it('should apply mixins', function(done) {
92 const memory = new DataSource('mem', {connector: Memory}, modelBuilder);
93 const Item = memory.createModel('Item', {name: 'string'}, {
94 mixins: {
95 TimeStamp: true,
96 Demo: {value: true},
97 Multi: [
98 {key: 'foo', value: 'bar'},
99 {key: 'fox', value: 'baz'},
100 ],
101 },
102 });
103
104 Item.mixin('Example', {foo: 'bar'});
105
106 Item.demoMixin.should.be.true;
107
108 Item.multiMixin.foo.should.equal('bar');
109 Item.multiMixin.fox.should.equal('baz');
110
111 const properties = Item.definition.properties;
112 properties.createdAt.should.eql({type: Date});
113 properties.updatedAt.should.eql({type: Date});
114
115 Item.create({name: 'Item 1'}, function(err, inst) {
116 inst.createdAt.should.be.a.date;
117 inst.updatedAt.should.be.a.date;
118 inst.example().should.eql({foo: 'bar'});
119 done();
120 });
121 });
122
123 it('should fail to apply undefined mixin', function() {
124 const memory = new DataSource('mem', {connector: Memory}, modelBuilder);
125 const Item = memory.createModel('Item', {name: 'string'});
126
127 function applyMixin() {
128 Item.mixin('UndefinedMixin', {foo: 'bar'});
129 }
130 should.throws(applyMixin, 'failed to apply undefined mixin');
131 });
132
133 describe('#mixin()', function() {
134 let Person, Author, Address;
135
136 beforeEach(function() {
137 Address = modelBuilder.define('Address', {
138 street: {type: 'string', required: true},
139 city: {type: 'string', required: true},
140 });
141 const memory = new DataSource('mem', {connector: Memory}, modelBuilder);
142 Person = memory.createModel('Person', {name: 'string'});
143 Author = memory.createModel('Author', {name: 'string'});
144 });
145
146 it('should register mixin class into _mixins', function() {
147 Person.mixin(Address);
148 Person._mixins.should.containEql(Address);
149 });
150
151 it('should NOT share mixins registry', function() {
152 Person.mixin(Address);
153 Author._mixins.should.not.containEql(Address);
154 });
155
156 it('should able to mixin same class', function() {
157 Person.mixin(Address);
158 Author.mixin(Address);
159 Author._mixins.should.containEql(Address);
160 });
161 });
162});