-
Notifications
You must be signed in to change notification settings - Fork 4
/
unit.tests.js
225 lines (215 loc) · 11.1 KB
/
unit.tests.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
import { Assertion } from './lib/api/Assertion'
import SecurityException from './lib/SecurityException';
import ValidationException from './lib/ValidationException';
import MethodParamsAssertion from './lib/api/MethodParamsAssertion';
import DefaultAssertion from './lib/api/DefaultAssertion';
import MethodParamsCadenas from './lib/api/MethodParamsCadenas';
import DefaultCadenas from './lib/api/DefaultCadenas';
import cadenas from './lib/cadenas-decorator';
import server from './lib/server-decorator';
import { decoratorMock, once } from 'meteor/svein:serrurier-core/lib/utils';
import { chai } from 'meteor/practicalmeteor:chai';
import { Serrurier } from './lib/main';
const expect = chai.expect;
const getMethodName = () => 'methodName';
const verboseReason = 'This is some verbose reason justifying why the assertion failed';
Serrurier.silence();
const alwaysFailing = {
doesAssertionFails: () => {
return verboseReason;
},
matchPatterns: [ String ]
};
const alwaysPassing = {
doesAssertionFails: () => {
return null;
}
};
const alwaysFailingDefaultCadenas = new DefaultCadenas( Object.assign({
name: 'alwaysFailingDefaultCadenas'
}, alwaysFailing )
);
const alwaysPassingDefaultCadenas = new DefaultCadenas( Object.assign({
name: 'alwaysPassingDefaultCadenas'
}, alwaysPassing )
);
const alwaysFailingMethodParamsAssertor = new MethodParamsCadenas( Object.assign({
name: 'alwaysFailingMethodParamsAssertor'
}, alwaysFailing )
);
const alwaysPassingMethodParamsAssertor = new MethodParamsCadenas( Object.assign({
name: 'alwaysPassingMethodParamsAssertor'
}, alwaysPassing )
);
const methodArgMustBeAStringAssertor = new MethodParamsCadenas({
name: 'methodArgMustBeAStringAssertor',
doesAssertionFails: (methodArg) => {
return typeof methodArg !== 'string';
},
reason:'Target method argument should be a string'
});
describe('svein:serrurier', function() {
describe('in a `DefaultCadenas` instance', function () {
describe('the method `toAssertion`', function () {
let assertion = alwaysFailingDefaultCadenas.toAssertion( [verboseReason], getMethodName );
it( 'should return a `DefaultAssertion` instance', function () {
expect(assertion).to.be.an.instanceof(DefaultAssertion);
});
it( 'should throw a `TypeError` when it is called with a wrong number of elements in `assertorArgs` array argument', function () {
expect(function () {
alwaysFailingDefaultCadenas.toAssertion([], getMethodName)
}).to.throw( TypeError );
});
});
});
describe('in a `MethodParamsAssertor` instance', function () {
describe('the method `toAssertion`', function () {
let alwaysFailing = alwaysFailingMethodParamsAssertor.toAssertion( [verboseReason], getMethodName );
let alwaysPassing = alwaysPassingMethodParamsAssertor.toAssertion( [verboseReason], getMethodName );
it('should return a `MethodParamsAssertion` instance', function () {
expect(alwaysFailing).to.be.an.instanceof( MethodParamsAssertion );
});
it('should throw a `TypeError` when it is called with a wrong number of elements in `assertorArgs` array argument', function () {
expect(function () {
alwaysFailingMethodParamsAssertor.toAssertion( [], getMethodName )
}).to.throw(TypeError);
});
it('should return a falsy value when the `doesAssertionFails` method returns a null value', function () {
let t = expect(alwaysPassing.perform( null, [] )).not.to.be.ok;
});
});
});
describe('in a `DefaultAssertion` instance', function () {
describe('the method `perform`', function () {
let alwaysFailing = alwaysFailingDefaultCadenas.toAssertion( [verboseReason], getMethodName );
let alwaysPassing = alwaysPassingDefaultCadenas.toAssertion( [verboseReason], getMethodName );
it('should return an security report of type object with fields `exceptionId` and `reason` when the `doesAssertionFails` method returns a non null value', function () {
expect(alwaysFailing.perform( null, []) ).to.be.a( 'object' ).to.have.property( 'reason' );
expect(alwaysFailing.perform( null, []) ).to.be.a( 'object' ).to.have.property( 'exceptionId' );
});
it('should return a falsy value when the `doesAssertionFails` method returns a null value', function () {
let t = expect(alwaysPassing.perform(null, [])).not.to.be.ok;
});
});
});
describe('in a `MethodParamsAssertion` instance', function () {
describe('the method `perform`', function () {
let alwaysFailing = alwaysFailingMethodParamsAssertor.toAssertion( [verboseReason], getMethodName );
let alwaysPassing = alwaysPassingMethodParamsAssertor.toAssertion( [verboseReason], getMethodName );
it('should return an security report of type object with fields `exceptionId` and `reason` when the `doesAssertionFails` method returns a non null value', function () {
expect( alwaysFailing.perform(null, []) ).to.be.a( 'object' ).to.have.property( 'reason' );
expect( alwaysFailing.perform(null, []) ).to.be.a( 'object' ).to.have.property( 'exceptionId' );
});
it('should return a falsy value when the `doesAssertionFails` method returns a null value', function () {
let t = expect(alwaysPassing.perform(null, [])).not.to.be.ok;
});
});
});
describe( 'a method decorated with `cadenas`', function () {
describe( 'describing a `DefaultCadenas` instance', function () {
it( 'should throw an error of type `SecurityException` when the bound assertion fails ', function () {
let targetCandidate = {
someMethod: function () { }
};
decoratorMock( targetCandidate, 'someMethod', cadenas( 'alwaysFailingDefaultCadenas', 'assertion argument 1' ));
expect(function () {
targetCandidate.someMethod();
}).to.throw( SecurityException );
});
});
describe( 'describing a `MethodParamsAssertor` instance', function () {
let targetCandidate = {
someMethod: function () { }
};
decoratorMock( targetCandidate, 'someMethod', cadenas( 'methodArgMustBeAStringAssertor' ));
it( 'should throw an error of type `ValidationException` when the bound assertion fails ', function () {
expect(function () {
// must fail because the first argument is not a string
targetCandidate.someMethod( {} );
}).to.throw( ValidationException );
});
it( 'should not throw an error of type `ValidationException` when the bound assertion passes ', function () {
expect(function () {
// must passes because the first argument is a string
targetCandidate.someMethod( 'methodArgument1' );
}).not.to.throw( SecurityException );
});
});
});
describe( 'an async callback as the last argument of an astro method decorated with a cadenas', function() {
describe( 'throwing an unregistered exception', function() {
const thrown = new Meteor.Error( 'SomeException.someDetails', null ) ;
const old = function () { throw thrown; };
let MyClass;
let createClass = once( function() {
let astroClassCandidate = {
name: 'DummyClass1',
methods: {
someMethod1: old
}
};
decoratorMock( astroClassCandidate.methods, 'someMethod1', server());
decoratorMock( astroClassCandidate.methods, 'someMethod1', cadenas( 'alwaysPassingDefaultCadenas', 'assertion argument 1' ));
MyClass = Serrurier.createClass( astroClassCandidate );
});
before( createClass );
it( 'should receive the exception as first argument', function() {
(new MyClass()).someMethod1( function( err ) {
if(Meteor.isClient){
expect( err ).to.have.property( 'error' ).equal( 'SomeException.someDetails' );
expect( err ).to.have.property( 'reason' ).equal( null );
} else {
expect( err ).to.equal( thrown );
}
});
});
});
describe( 'throwing a registered exception', function() {
let MyClas;
let createClass = once( function() {
let astroClassCandidate = {
name: 'DummyClass2',
methods: {
someMethod2: function () { }
}
};
decoratorMock( astroClassCandidate.methods, 'someMethod2', server());
decoratorMock( astroClassCandidate.methods, 'someMethod2', cadenas( 'alwaysFailingDefaultCadenas', 'assertion argument 1' ));
MyClass = Serrurier.createClass( astroClassCandidate );
});
before( createClass );
it( 'should receive the exception as first argument', function() {
(new MyClass()).someMethod2( function( err ) {
if(Meteor.isClient){
expect( err ).to.have.property( 'error' ).equal( 'SecurityException.alwaysFailingDefaultCadenas' );
expect( err ).to.have.property( 'reason' ).equal( verboseReason );
} else {
expect( err ).to.be.instanceof( SecurityException );
}
});
});
});
});
describe( 'a method decorated with multiple `cadenas`s', function () {
it( 'should apply all those cadenas', function () {
let targetCandidate1 = {
someMethod: function () {}
};
// mock the @decorator
decoratorMock( targetCandidate1, 'someMethod', cadenas( 'alwaysFailingDefaultCadenas', 'assertion argument 1' ));
decoratorMock( targetCandidate1, 'someMethod', cadenas( 'alwaysPassingDefaultCadenas', 'assertion argument 1' ));
let targetCandidate2 = {
someMethod: function () {}
};
// mock the @decorator
decoratorMock( targetCandidate2, 'someMethod', cadenas( 'alwaysPassingDefaultCadenas', 'assertion argument 1' ));
decoratorMock( targetCandidate2, 'someMethod', cadenas( 'alwaysFailingDefaultCadenas', 'assertion argument 1' ));
expect( function () {
targetCandidate1.someMethod();
}).to.throw( SecurityException );
expect( function () {
targetCandidate2.someMethod();
}).to.throw( SecurityException );
});
});
});