Files
serverless-webpack/tests/packageModules.test.js
T
Joseph Lee Hunsaker 5c9f14d53f Make serverless-webpack more extensible (#254)
* Make serverless-webpack more extensible

Use PluginManager to make serverless-webpack more extensible 

Following the advice from serverless blog on Advanced Plugin Development. https://serverless.com/blog/advanced-plugin-development-extending-the-core-lifecycle/

* use sublifecycle with webpack command

* Use new lifecycles and adapt unit tests

* Fixed unit test after merge

* Use new events everywhere

* Added section to README
2017-10-23 15:29:17 +02:00

399 lines
13 KiB
JavaScript

'use strict';
const BbPromise = require('bluebird');
const _ = require('lodash');
const chai = require('chai');
const path = require('path');
const sinon = require('sinon');
const mockery = require('mockery');
const Serverless = require('serverless');
// Mocks
const fsMockFactory = require('./mocks/fs.mock');
const globMockFactory = require('./mocks/glob.mock');
const archiverMockFactory = require('./mocks/archiver.mock');
chai.use(require('chai-as-promised'));
chai.use(require('sinon-chai'));
const expect = chai.expect;
describe('packageModules', () => {
let sandbox;
let baseModule;
let serverless;
let module;
// Mocks
let fsMock;
let globMock;
let archiverMock;
// Serverless stubs
let writeFileDirStub;
let getAllFunctionsStub;
let getFunctionStub;
let getServiceObjectStub;
let getVersionStub;
before(() => {
sandbox = sinon.sandbox.create();
sandbox.usingPromise(BbPromise);
fsMock = fsMockFactory.create(sandbox);
archiverMock = archiverMockFactory.create(sandbox);
globMock = globMockFactory.create(sandbox);
mockery.enable({ warnOnUnregistered: false });
mockery.registerMock('archiver', archiverMock);
mockery.registerMock('fs', fsMock);
mockery.registerMock('glob', globMock);
baseModule = require('../lib/packageModules');
Object.freeze(baseModule);
});
after(() => {
mockery.disable();
mockery.deregisterAll();
});
beforeEach(() => {
serverless = new Serverless();
serverless.cli = {
log: sandbox.stub(),
consoleLog: sandbox.stub()
};
writeFileDirStub = sandbox.stub(serverless.utils, 'writeFileDir');
getAllFunctionsStub = sandbox.stub(serverless.service, 'getAllFunctions');
getFunctionStub = sandbox.stub(serverless.service, 'getFunction');
getServiceObjectStub = sandbox.stub(serverless.service, 'getServiceObject');
getVersionStub = sandbox.stub(serverless, 'getVersion');
module = _.assign({
serverless,
options: {},
}, baseModule);
});
afterEach(() => {
// Reset all counters and restore all stubbed functions
sandbox.reset();
sandbox.restore();
});
describe('packageModules()', () => {
it('should do nothing if no compile stats are available', () => {
module.compileStats = { stats: [] };
return expect(module.packageModules()).to.be.fulfilled
.then(() => BbPromise.all([
expect(archiverMock.create).to.not.have.been.called,
expect(writeFileDirStub).to.not.have.been.called,
expect(fsMock.createWriteStream).to.not.have.been.called,
expect(globMock.sync).to.not.have.been.called
]));
});
describe('with service packaging', () => {
beforeEach(() => {
// Setup behavior for service packaging
_.unset(module, 'entryFunctions');
_.set(serverless.service, 'package.individually', false);
});
it('should package', () => {
// Test data
const stats = {
stats: [
{
compilation: {
compiler: {
outputPath: '/my/Service/Path/.webpack/service'
}
}
}
]
};
const files = [
'README.md', 'src/handler1.js', 'src/handler1.js.map', 'src/handler2.js', 'src/handler2.js.map'
];
const allFunctions = [ 'func1', 'func2' ];
const func1 = {
handler: 'src/handler1',
events: []
};
const func2 = {
handler: 'src/handler2',
events: []
};
// Serverless behavior
sandbox.stub(serverless.config, 'servicePath').value('/my/Service/Path');
getVersionStub.returns('1.18.0');
getServiceObjectStub.returns({
name: 'test-service'
});
getAllFunctionsStub.returns(allFunctions);
getFunctionStub.withArgs('func1').returns(func1);
getFunctionStub.withArgs('func2').returns(func2);
// Mock behavior
globMock.sync.returns(files);
fsMock._streamMock.on.withArgs('open').yields();
fsMock._streamMock.on.withArgs('close').yields();
fsMock._statMock.isDirectory.returns(false);
const expectedArtifactPath = path.join('.serverless', 'test-service.zip');
module.compileStats = stats;
return expect(module.packageModules()).to.be.fulfilled
.then(() => BbPromise.all([
expect(func1).to.have.a.nested.property('package.artifact').that.equals(expectedArtifactPath),
expect(func2).to.have.a.nested.property('package.artifact').that.equals(expectedArtifactPath),
]));
});
describe('with the Google provider', () => {
let oldProviderName;
beforeEach(() => {
oldProviderName = serverless.service.provider.name;
// Imitate Google provider
serverless.service.provider.name = 'google';
});
afterEach(() => {
if (oldProviderName) {
serverless.service.provider.name = oldProviderName;
} else {
_.unset(serverless.service.provider, 'name');
}
});
it('should set the service artifact path', () => {
// Test data
const stats = {
stats: [
{
compilation: {
compiler: {
outputPath: '/my/Service/Path/.webpack/service'
}
}
}
]
};
const files = [
'README.md', 'index.js'
];
const allFunctions = [ 'func1', 'func2' ];
const func1 = {
handler: 'handler1',
events: []
};
const func2 = {
handler: 'handler2',
events: []
};
sandbox.stub(serverless.config, 'servicePath').value('/my/Service/Path');
getVersionStub.returns('1.18.0');
getServiceObjectStub.returns({
name: 'test-service'
});
getAllFunctionsStub.returns(allFunctions);
getFunctionStub.withArgs('func1').returns(func1);
getFunctionStub.withArgs('func2').returns(func2);
// Mock behavior
globMock.sync.returns(files);
fsMock._streamMock.on.withArgs('open').yields();
fsMock._streamMock.on.withArgs('close').yields();
fsMock._statMock.isDirectory.returns(false);
const expectedArtifactPath = path.join('.serverless', 'test-service.zip');
module.compileStats = stats;
return expect(module.packageModules()).to.be.fulfilled
.then(() => expect(serverless.service).to.have.a.nested.property('package.artifact').that.equals(expectedArtifactPath));
});
});
it('should set the function artifact depending on the serverless version', () => {
// Test data
const stats = {
stats: [
{
compilation: {
compiler: {
outputPath: '/my/Service/Path/.webpack/service'
}
}
}
]
};
const files = [
'README.md', 'src/handler1.js', 'src/handler1.js.map', 'src/handler2.js', 'src/handler2.js.map'
];
const allFunctions = [ 'func1', 'func2' ];
const func1 = {
handler: 'src/handler1',
events: []
};
const func2 = {
handler: 'src/handler2',
events: []
};
// Serverless behavior
sandbox.stub(serverless.config, 'servicePath').value('/my/Service/Path');
getServiceObjectStub.returns({
name: 'test-service'
});
getAllFunctionsStub.returns(allFunctions);
getFunctionStub.withArgs('func1').returns(func1);
getFunctionStub.withArgs('func2').returns(func2);
// Mock behavior
globMock.sync.returns(files);
fsMock._streamMock.on.withArgs('open').yields();
fsMock._streamMock.on.withArgs('close').yields();
fsMock._statMock.isDirectory.returns(false);
const expectedArtifactPath = path.join('.serverless', 'test-service.zip');
module.compileStats = stats;
return BbPromise.each([ '1.18.1', '2.17.0', '10.15.3', ], version => {
getVersionStub.returns(version);
return expect(module.packageModules()).to.be.fulfilled
.then(() => BbPromise.all([
expect(func1).to.have.a.nested.property('package.artifact').that.equals(expectedArtifactPath),
expect(func2).to.have.a.nested.property('package.artifact').that.equals(expectedArtifactPath),
]));
})
.then(() => BbPromise.each([ '1.17.0', '1.16.0-alpha', '1.15.3', ], version => {
getVersionStub.returns(version);
return expect(module.packageModules()).to.be.fulfilled
.then(() => BbPromise.all([
expect(func1).to.have.a.nested.property('artifact').that.equals(expectedArtifactPath),
expect(func2).to.have.a.nested.property('artifact').that.equals(expectedArtifactPath),
expect(func1).to.have.a.nested.property('package.disable').that.is.true,
expect(func2).to.have.a.nested.property('package.disable').that.is.true,
]));
}));
});
it('should reject if no files are found', () => {
// Test data
const stats = {
stats: [
{
compilation: {
compiler: {
outputPath: '/my/Service/Path/.webpack/service'
}
}
}
]
};
const files = [];
const allFunctions = [ 'func1', 'func2' ];
const func1 = {
handler: 'src/handler1',
events: []
};
const func2 = {
handler: 'src/handler2',
events: []
};
// Serverless behavior
sandbox.stub(serverless.config, 'servicePath').value('/my/Service/Path');
getVersionStub.returns('1.18.0');
getServiceObjectStub.returns({
name: 'test-service'
});
getAllFunctionsStub.returns(allFunctions);
getFunctionStub.withArgs('func1').returns(func1);
getFunctionStub.withArgs('func2').returns(func2);
// Mock behavior
globMock.sync.returns(files);
fsMock._streamMock.on.withArgs('open').yields();
fsMock._streamMock.on.withArgs('close').yields();
fsMock._statMock.isDirectory.returns(false);
module.compileStats = stats;
return expect(module.packageModules()).to.be.rejectedWith('Packaging: No files found');
});
});
describe('with individual packaging', () => {
// Test data
const stats = {
stats: [
{
compilation: {
compiler: {
outputPath: '/my/Service/Path/.webpack/func1'
}
}
},
{
compilation: {
compiler: {
outputPath: '/my/Service/Path/.webpack/func2'
}
}
}
]
};
const files = [
'README.md', 'src/handler1.js', 'src/handler1.js.map', 'src/handler2.js', 'src/handler2.js.map'
];
const allFunctions = [ 'func1', 'func2' ];
const func1 = {
handler: 'src/handler1',
events: []
};
const func2 = {
handler: 'src/handler2',
events: []
};
const entryFunctions = [
{
handlerFile: 'src/handler1.js',
funcName: 'func1',
func: func1
},
{
handlerFile: 'src/handler2.js',
funcName: 'func2',
func: func2
},
];
beforeEach(() => {
// Setup sandbox and behavior for individual packaging
_.set(module, 'entryFunctions', entryFunctions);
_.set(serverless.service.package, 'individually', true);
});
it('should package', () => {
// Serverless behavior
sandbox.stub(serverless.config, 'servicePath').value('/my/Service/Path');
getVersionStub.returns('1.18.0');
getServiceObjectStub.returns({
name: 'test-service'
});
getAllFunctionsStub.returns(allFunctions);
getFunctionStub.withArgs('func1').returns(func1);
getFunctionStub.withArgs('func2').returns(func2);
// Mock behavior
globMock.sync.returns(files);
fsMock._streamMock.on.withArgs('open').yields();
fsMock._streamMock.on.withArgs('close').yields();
fsMock._statMock.isDirectory.returns(false);
module.compileStats = stats;
return expect(module.packageModules()).to.be.fulfilled
.then(() => BbPromise.all([
expect(func1).to.have.a.nested.property('package.artifact').that.equals(path.join('.serverless', 'func1.zip')),
expect(func2).to.have.a.nested.property('package.artifact').that.equals(path.join('.serverless', 'func2.zip')),
]));
});
});
});
});