Skip to content

Commit c7d9cd5

Browse files
authored
Added tests for cleanup and updated test tools (#160)
* Cleanup compile unit tests. Update test framework. * Updated test tools. Added unit test for cleanup. Refactored unit tests. * Added lodash to dependencies * Updated package-lock.json
1 parent f4988de commit c7d9cd5

File tree

9 files changed

+3397
-136
lines changed

9 files changed

+3397
-136
lines changed

package-lock.json

Lines changed: 3050 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,19 @@
3131
"body-parser": "^1.15.2",
3232
"express": "^4.14.0",
3333
"fs-extra": "^0.26.7",
34+
"lodash": "^4.17.4",
3435
"npm-programmatic": "0.0.5",
3536
"ts-node": "^3.2.0"
3637
},
3738
"devDependencies": {
38-
"chai": "^3.5.0",
39-
"istanbul": "^0.4.4",
40-
"mocha": "^3.0.2",
41-
"mockery": "^1.7.0",
42-
"serverless": "^1.0.0-beta.2",
43-
"sinon": "^1.17.5",
44-
"sinon-chai": "^2.8.0"
39+
"chai": "^4.1.0",
40+
"chai-as-promised": "^7.1.1",
41+
"istanbul": "^0.4.5",
42+
"mocha": "^3.4.2",
43+
"mockery": "^2.1.0",
44+
"serverless": "^1.17.0",
45+
"sinon": "^2.3.8",
46+
"sinon-chai": "^2.12.0"
4547
},
4648
"peerDependencies": {
4749
"webpack": "*"

tests/all.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ describe('serverless-webpack', () => {
55
require('./compile.test');
66
require('./run.test');
77
require('./serve.test');
8+
require('./cleanup.test');
89
});

tests/cleanup.test.js

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
'use strict';
2+
3+
const BbPromise = require('bluebird');
4+
const _ = require('lodash');
5+
const chai = require('chai');
6+
const sinon = require('sinon');
7+
const mockery = require('mockery');
8+
const Serverless = require('serverless');
9+
10+
chai.use(require('chai-as-promised'));
11+
chai.use(require('sinon-chai'));
12+
const expect = chai.expect;
13+
14+
const FseMock = sandbox => ({
15+
copy: sandbox.stub(),
16+
removeSync: sandbox.stub()
17+
});
18+
19+
describe('cleanup', () => {
20+
let sandbox;
21+
let fseMock;
22+
let baseModule;
23+
let serverless;
24+
let module;
25+
let dirExistsSyncStub;
26+
27+
before(() => {
28+
sandbox = sinon.sandbox.create();
29+
sandbox.usingPromise(BbPromise);
30+
31+
fseMock = FseMock(sandbox);
32+
33+
mockery.enable({ warnOnUnregistered: false });
34+
mockery.registerMock('fs-extra', fseMock);
35+
36+
baseModule = require('../lib/cleanup');
37+
Object.freeze(baseModule);
38+
});
39+
40+
after(() => {
41+
mockery.disable();
42+
mockery.deregisterAll();
43+
});
44+
45+
beforeEach(() => {
46+
serverless = new Serverless();
47+
serverless.cli = {
48+
log: sandbox.stub(),
49+
consoleLog: sandbox.stub()
50+
};
51+
dirExistsSyncStub = sandbox.stub(serverless.utils, 'dirExistsSync');
52+
53+
module = Object.assign({
54+
serverless,
55+
options: {},
56+
webpackOutputPath: 'my/Output/Path'
57+
}, baseModule);
58+
});
59+
60+
afterEach(() => {
61+
// This will reset the webpackMock too
62+
sandbox.restore();
63+
});
64+
65+
it('should do nothing if no original service path is set', () => {
66+
_.unset(module.originalServicePath);
67+
return expect(module.cleanup()).to.be.fulfilled
68+
.then(() => {
69+
expect(fseMock.copy).to.have.not.been.called;
70+
expect(fseMock.removeSync).to.not.have.been.called;
71+
})
72+
});
73+
74+
it('should remove output dir if it exists', () => {
75+
dirExistsSyncStub.returns(true);
76+
_.unset(module.originalServicePath);
77+
fseMock.removeSync.reset();
78+
79+
return expect(module.cleanup()).to.be.fulfilled
80+
.then(() => {
81+
expect(dirExistsSyncStub).to.have.been.calledOnce;
82+
expect(dirExistsSyncStub).to.have.been.calledWith('my/Output/Path');
83+
expect(fseMock.removeSync).to.have.been.calledOnce;
84+
});
85+
});
86+
87+
it('should not call removeSync if output dir does not exists', () => {
88+
dirExistsSyncStub.returns(false);
89+
_.unset(module.originalServicePath);
90+
fseMock.removeSync.reset();
91+
92+
return expect(module.cleanup()).to.be.fulfilled
93+
.then(() => {
94+
expect(dirExistsSyncStub).to.have.been.calledOnce;
95+
expect(dirExistsSyncStub).to.have.been.calledWith('my/Output/Path');
96+
expect(fseMock.removeSync).to.not.have.been.called;
97+
});
98+
});
99+
100+
it('should call copy with the right parameters with a service artifact', () => {
101+
dirExistsSyncStub.returns(true);
102+
module.originalServicePath = 'my/Original/Service/Path';
103+
fseMock.copy.reset();
104+
fseMock.copy.yields(null, {});
105+
serverless.service.package.artifact = 'artifact.zip';
106+
107+
return expect(module.cleanup()).to.be.fulfilled
108+
.then(() => {
109+
expect(serverless.config.servicePath).to.equal('my/Original/Service/Path');
110+
expect(fseMock.copy).to.have.been.calledOnce;
111+
expect(fseMock.copy).to.have.been
112+
.calledWith('my/Output/Path/.serverless', 'my/Original/Service/Path/.serverless');
113+
expect(serverless.service.package.artifact)
114+
.to.equal('my/Original/Service/Path/.serverless/artifact.zip');
115+
});
116+
});
117+
118+
it('should call copy with the right parameters with individual packaging', () => {
119+
dirExistsSyncStub.returns(true);
120+
module.originalServicePath = 'my/Original/Service/Path';
121+
fseMock.copy.reset();
122+
fseMock.copy.yields(null, {});
123+
serverless.service.package.individually = true;
124+
125+
const testFunctionsConfig = {
126+
func1: {
127+
handler: 'module1.func1handler',
128+
artifact: 'artifact-func1.zip',
129+
events: [{
130+
http: {
131+
method: 'get',
132+
path: 'func1path',
133+
},
134+
}],
135+
},
136+
func2: {
137+
handler: 'module2.func2handler',
138+
artifact: 'artifact-func2.zip',
139+
events: [{
140+
http: {
141+
method: 'POST',
142+
path: 'func2path',
143+
},
144+
}, {
145+
nonhttp: 'non-http',
146+
}],
147+
},
148+
func3: {
149+
handler: 'module2.func3handler',
150+
artifact: 'artifact-func3.zip',
151+
events: [{
152+
nonhttp: 'non-http',
153+
}],
154+
},
155+
};
156+
serverless.service.functions = testFunctionsConfig;
157+
158+
return expect(module.cleanup()).to.be.fulfilled
159+
.then(() => {
160+
expect(serverless.config.servicePath).to.equal('my/Original/Service/Path');
161+
expect(fseMock.copy).to.have.been.calledOnce;
162+
expect(fseMock.copy).to.have.been
163+
.calledWith('my/Output/Path/.serverless', 'my/Original/Service/Path/.serverless');
164+
_.forEach(['func1', 'func2', 'func3'], funcName => {
165+
expect(serverless.service.functions[funcName]).to.have.a.property('artifact')
166+
.that.equals(`my/Original/Service/Path/.serverless/artifact-${funcName}.zip`);
167+
});
168+
});
169+
});
170+
171+
it('should reject if the copy fails', () => {
172+
dirExistsSyncStub.returns(true);
173+
module.originalServicePath = 'my/Original/Service/Path';
174+
fseMock.copy.yields(new Error('Failed'));
175+
serverless.service.package.artifact = 'artifact.zip';
176+
177+
return expect(module.cleanup()).to.be.rejectedWith('Failed');
178+
});
179+
180+
});

tests/compile.test.js

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
'use strict';
22

3+
const BbPromise = require('bluebird');
34
const chai = require('chai');
45
const sinon = require('sinon');
56
const mockery = require('mockery');
67
const Serverless = require('serverless');
78
const makeWebpackMock = require('./webpack.mock');
9+
10+
chai.use(require('chai-as-promised'));
811
chai.use(require('sinon-chai'));
912
const expect = chai.expect;
1013

1114
describe('compile', () => {
15+
let sandbox;
1216
let webpackMock;
1317
let baseModule;
14-
let module;
1518
let serverless;
19+
let module;
1620

1721
before(() => {
22+
sandbox = sinon.sandbox.create();
23+
sandbox.usingPromise(BbPromise);
24+
25+
webpackMock = makeWebpackMock(sandbox);
26+
1827
mockery.enable({ warnOnUnregistered: false });
19-
webpackMock = makeWebpackMock();
2028
mockery.registerMock('webpack', webpackMock);
2129
baseModule = require('../lib/compile');
2230
Object.freeze(baseModule);
@@ -30,39 +38,40 @@ describe('compile', () => {
3038
beforeEach(() => {
3139
serverless = new Serverless();
3240
serverless.cli = {
33-
log: sinon.spy(),
34-
consoleLog: sinon.spy(),
41+
log: sandbox.stub(),
42+
consoleLog: sandbox.stub()
3543
};
36-
webpackMock._resetSpies();
44+
3745
module = Object.assign({
3846
serverless,
3947
options: {},
4048
}, baseModule);
4149
});
4250

51+
afterEach(() => {
52+
// This will reset the webpackMock too
53+
sandbox.restore();
54+
});
55+
4356
it('should expose a `compile` method', () => {
4457
expect(module.compile).to.be.a('function');
4558
});
4659

4760
it('should compile with webpack from a context configuration', () => {
4861
const testWebpackConfig = 'testconfig';
4962
module.webpackConfig = testWebpackConfig;
50-
return module
51-
.compile()
52-
.then(() => {
53-
expect(webpackMock).to.have.been.calledWith(testWebpackConfig);
54-
expect(webpackMock.compilerMock.run).to.have.callCount(1);
55-
});
63+
return expect(module.compile()).to.be.fulfilled
64+
.then(() => {
65+
expect(webpackMock).to.have.been.calledWith(testWebpackConfig);
66+
expect(webpackMock.compilerMock.run).to.have.been.calledOnce;
67+
});
5668
});
5769

5870
it('should fail if there are compilation errors', () => {
5971
module.webpackConfig = 'testconfig';
60-
webpackMock.statsMock.compilation.errors = ['error'];
61-
return module
62-
.compile()
63-
.catch((err) => {
64-
expect(err.toString()).to.match(/compilation error/);
65-
});
72+
// We stub errors here. It will be reset again in afterEach()
73+
sandbox.stub(webpackMock.statsMock.compilation, 'errors').value(['error']);
74+
return expect(module.compile()).to.be.rejectedWith(/compilation error/);
6675
});
6776

6877
it('should set context `webpackOutputPath`, `originalServicePath`, `serverless.config.servicePath`', () => {
@@ -72,12 +81,11 @@ describe('compile', () => {
7281
module.serverless.config.servicePath = testServicePath;
7382
const testOutputPath = 'testOutputPath';
7483
webpackMock.statsMock.compilation.compiler.outputPath = testOutputPath;
75-
return module
76-
.compile()
77-
.then(() => {
78-
expect(module.webpackOutputPath).to.equal(testOutputPath);
79-
expect(module.originalServicePath).to.equal(testServicePath);
80-
expect(module.serverless.config.servicePath).to.equal(testOutputPath);
81-
});
84+
return expect(module.compile()).to.be.fulfilled
85+
.then(() => {
86+
expect(module.webpackOutputPath).to.equal(testOutputPath);
87+
expect(module.originalServicePath).to.equal(testServicePath);
88+
expect(module.serverless.config.servicePath).to.equal(testOutputPath);
89+
});
8290
});
8391
});

tests/express.mock.js

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
11
const sinon = require('sinon');
22

3-
const appMock = {
4-
listen: sinon.spy(),
5-
use: sinon.spy(),
6-
get: sinon.spy(),
7-
post: sinon.spy(),
8-
options: sinon.spy(),
9-
};
3+
const AppMock = sandbox => ({
4+
listen: sandbox.stub(),
5+
use: sandbox.stub(),
6+
get: sandbox.stub(),
7+
post: sandbox.stub(),
8+
options: sandbox.stub(),
9+
});
1010

11-
const expressMock = sinon.stub().returns(appMock);
12-
expressMock.appMock = appMock;
13-
expressMock._resetSpies = () => {
14-
expressMock.reset();
15-
appMock.listen.reset();
16-
appMock.use.reset();
17-
appMock.get.reset();
18-
appMock.post.reset();
19-
appMock.options.reset();
20-
};
11+
const ExpressMock = sandbox => {
12+
const appMock = AppMock(sandbox);
13+
const mock = sandbox.stub().returns(appMock);
14+
mock.appMock = appMock;
15+
return mock;
16+
}
2117

22-
module.exports = () => expressMock;
18+
module.exports = sandbox => ExpressMock(sandbox);

0 commit comments

Comments
 (0)