1 | 'use strict';
|
2 |
|
3 | const expect = require('chai').expect;
|
4 | const Method = require('../lib/Method');
|
5 |
|
6 | describe('class Method', function() {
|
7 | let method;
|
8 |
|
9 | beforeEach(function() {
|
10 | method = new Method('test', {}, function() {});
|
11 | });
|
12 |
|
13 | describe('constructor(name, options, fn)', function() {
|
14 | [
|
15 | ['name', 'test'],
|
16 | ['stack', null],
|
17 | ['adapters', ['express', 'socketio', 'rpc']],
|
18 | ['skipHooks', false],
|
19 | ['parent', null],
|
20 | ['params', []],
|
21 | ['description', 'test'],
|
22 | ['notes', undefined],
|
23 | ['documented', true],
|
24 | ['route', { path: '/', verb: 'all' }],
|
25 | ['upload', {}],
|
26 | ['extra', {}],
|
27 | ['options', {}]
|
28 | ].forEach(function(prop) {
|
29 | it(`should have property '${prop[0]}' and corresponding value`, function() {
|
30 | expect(method).to.have.property(prop[0]).deep.eq(prop[1]);
|
31 | });
|
32 | });
|
33 |
|
34 | it('should be a valid instance of Method class', function() {
|
35 | expect(method).to.be.an.instanceof(Method);
|
36 | });
|
37 |
|
38 | it('should raise error when params missing `name` property', function() {
|
39 | expect(function() {
|
40 | new Method('test', { params: [{ type: 'any' }] }, function() {});
|
41 | }).to.throw(Error).have.property('message', '`name` is missing for params of `test` method at position [0]');
|
42 | });
|
43 |
|
44 | it('should raise error when params missing inner params\' deep `name` property', function() {
|
45 | expect(function() {
|
46 | new Method('test', { params: [{ name: 'profile', type: 'any', params: { type: 'string' } }] }, function() {});
|
47 | }).to.throw(Error).have.property('message', '`name` is missing for params of `test` method at position [0].params[0]');
|
48 | });
|
49 |
|
50 | it('should raise an error if there is no function to be executed', function() {
|
51 | expect(function() {
|
52 | new Method('test', { params: [{ type: 'any' }] });
|
53 | }).to.throw(Error).have.property('message', 'Method fn must be a valid function');
|
54 | });
|
55 |
|
56 | it('should raise an error if there is no function to be executed', function() {
|
57 | expect(function() {
|
58 | new Method(null, { params: [{ type: 'any' }] }, function() {});
|
59 | }).to.throw(Error).have.property('message', 'Method name must be a valid string');
|
60 | });
|
61 |
|
62 | it('should parse options.skipHooks by conditions', function() {
|
63 | let method = new Method('test', { route: { verb: 'use' } }, function() {});
|
64 | expect(method).to.have.property('skipHooks', true);
|
65 |
|
66 | let method1 = new Method('test', { route: { verb: 'get' } }, function() {});
|
67 | expect(method1).to.have.property('skipHooks', false);
|
68 |
|
69 | let method2 = new Method('test', { skipHooks: true }, function() {});
|
70 | expect(method2).to.have.property('skipHooks', true);
|
71 |
|
72 | let method3 = new Method('test', { skipHooks: '' }, function() {});
|
73 | expect(method3).to.have.property('skipHooks', false);
|
74 | });
|
75 | });
|
76 |
|
77 | describe('prototype', function() {
|
78 | describe('isSupport(adapterName)', function() {
|
79 | it('should return false if invalid adapter name passed', function() {
|
80 | expect(method.isSupport('abc')).to.be.false;
|
81 | });
|
82 |
|
83 | [
|
84 | 'express',
|
85 | 'rpc',
|
86 | 'socketio'
|
87 | ].forEach(function(adapterName) {
|
88 | it(`should return true if '${adapterName}' passed`, function() {
|
89 | expect(method.isSupport(adapterName)).to.be.true;
|
90 | });
|
91 | });
|
92 | });
|
93 |
|
94 | describe('fullPath()', function() {
|
95 | it('should return expected full path with or without parent object', function() {
|
96 | expect(method.fullPath()).to.be.eq('/');
|
97 |
|
98 | method.parent = {
|
99 | fullPath: function() {
|
100 | return '/users';
|
101 | }
|
102 | };
|
103 |
|
104 | method.route.path = '/profile';
|
105 |
|
106 | expect(method.fullPath()).to.be.eq('/users/profile');
|
107 | });
|
108 | });
|
109 |
|
110 | describe('clone()', function() {
|
111 | it('should clone as a new method with all same properties', function() {
|
112 | let method = new Method('clone', {
|
113 | description: 'clone method test',
|
114 | params: [{ name: 'user' }],
|
115 | route: { path: '/clone' }
|
116 | }, function(next) {
|
117 | next();
|
118 | });
|
119 |
|
120 | let methodCloned = method.clone();
|
121 |
|
122 | expect(methodCloned).to.not.eq(method);
|
123 |
|
124 | [
|
125 | 'name',
|
126 | 'stack',
|
127 | 'adapters',
|
128 | 'skipHooks',
|
129 | 'parent',
|
130 | 'params',
|
131 | 'description',
|
132 | 'notes',
|
133 | 'documented',
|
134 | 'route',
|
135 | 'upload',
|
136 | 'extra',
|
137 | 'options'
|
138 | ].forEach(function(key) {
|
139 | expect(methodCloned).to.have.property(key).to.deep.eq(method[key]);
|
140 | });
|
141 | });
|
142 | });
|
143 |
|
144 | describe('fullName()', function() {
|
145 | it('should return expected full name with or without parent object', function() {
|
146 | expect(method.fullName()).to.be.eq('test');
|
147 |
|
148 | method.parent = {
|
149 | fullName: function() {
|
150 | return 'users';
|
151 | }
|
152 | };
|
153 |
|
154 | method.route.path = '/profile';
|
155 |
|
156 | expect(method.fullName()).to.be.eq('users.test');
|
157 | });
|
158 | });
|
159 |
|
160 | describe('invoke() && compose(beforeStack, afterStack, errorStack)', function() {
|
161 | it('should raise an error if method is not composed', function() {
|
162 | expect(function() {
|
163 | method.invoke();
|
164 | }).to.throw(Error).to.have.property('message', 'Method: \'test\' must be composed before invoking');
|
165 | });
|
166 |
|
167 | it('should invoke composed function stack by predefined order without error', function(cb) {
|
168 | let array = [];
|
169 | let beforeStack = [
|
170 | function(context, next) { array.push(1); next(); },
|
171 | function(context, next) { array.push(2); next(); }
|
172 | ];
|
173 |
|
174 | method.fn = function(context, next) { array.push(3); next(); };
|
175 |
|
176 | let afterStack = [
|
177 | function(context, next) { array.push(4); next(); },
|
178 | function(context, next) { array.push(5); next(); }
|
179 | ];
|
180 |
|
181 | let errorStack = [
|
182 | function(context, next) { array.push(6); next(); },
|
183 | ];
|
184 |
|
185 | method.compose(beforeStack, afterStack, errorStack);
|
186 |
|
187 | method.invoke().then(function() {
|
188 | expect(array).to.deep.eq([1, 2, 3, 4, 5]);
|
189 | }).then(cb, cb);
|
190 | });
|
191 |
|
192 | it('should invoke composed function stack by predefined order with error', function(cb) {
|
193 | let array = [];
|
194 | let beforeStack = [
|
195 | function(context, next) { array.push(1); next(); },
|
196 | function(context, next) { array.push(2); next(); }
|
197 | ];
|
198 |
|
199 | method.fn = function() { array.push(3); throw new Error('test'); };
|
200 |
|
201 | let afterStack = [
|
202 | function(context, next) { array.push(4); next(); },
|
203 | function(context, next) { array.push(5); next(); }
|
204 | ];
|
205 |
|
206 | let errorStack = [
|
207 | function(context, next) { array.push(6); next(); }
|
208 | ];
|
209 |
|
210 | method.compose(beforeStack, afterStack, errorStack);
|
211 |
|
212 | method.invoke().then(function() {
|
213 | expect(array).to.deep.eq([1, 2, 3, 6]);
|
214 | }).then(cb, cb);
|
215 | });
|
216 | });
|
217 | });
|
218 | });
|