diff --git a/lib/classes/Service.js b/lib/classes/Service.js index 6fdbbd4c3..748266aa1 100644 --- a/lib/classes/Service.js +++ b/lib/classes/Service.js @@ -69,8 +69,10 @@ class Service { return BbPromise.try(() => { // use require to load serverless.js file // eslint-disable-next-line global-require - const config = require(serviceFilePath); - + const configExport = require(serviceFilePath); + // In case of a promise result, first resolve it. + return configExport; + }).then(config => { if (!_.isPlainObject(config)) { throw new Error('serverless.js must export plain object'); } diff --git a/lib/classes/Service.test.js b/lib/classes/Service.test.js index 96bf7529f..41441c6ec 100644 --- a/lib/classes/Service.test.js +++ b/lib/classes/Service.test.js @@ -342,6 +342,61 @@ describe('Service', () => { }); }); + it('should load serverless.js from filesystem', () => { + const SUtils = new Utils(); + const serverlessJSON = { + service: 'new-service', + provider: { + name: 'aws', + stage: 'dev', + region: 'us-east-1', + variableSyntax: '\\${{([ ~:a-zA-Z0-9._\'",\\-\\/\\(\\)]+?)}}', + }, + plugins: ['testPlugin'], + functions: { + functionA: {}, + }, + resources: { + aws: { + resourcesProp: 'value', + }, + azure: {}, + google: {}, + }, + package: { + exclude: ['exclude-me'], + include: ['include-me'], + artifact: 'some/path/foo.zip', + }, + }; + + SUtils.writeFileSync(path.join(tmpDirPath, 'serverless.js'), + `module.exports = new Promise(resolve => { resolve(${JSON.stringify(serverlessJSON)}) });`); + + const serverless = new Serverless(); + serverless.config.update({ servicePath: tmpDirPath }); + serviceInstance = new Service(serverless); + + return expect(serviceInstance.load()).to.eventually.be.fulfilled + .then(() => { + expect(serviceInstance.service).to.be.equal('new-service'); + expect(serviceInstance.provider.name).to.deep.equal('aws'); + expect(serviceInstance.provider.variableSyntax).to.equal( + '\\${{([ ~:a-zA-Z0-9._\'",\\-\\/\\(\\)]+?)}}' + ); + expect(serviceInstance.plugins).to.deep.equal(['testPlugin']); + expect(serviceInstance.resources.aws).to.deep.equal({ resourcesProp: 'value' }); + expect(serviceInstance.resources.azure).to.deep.equal({}); + expect(serviceInstance.resources.google).to.deep.equal({}); + expect(serviceInstance.package.exclude.length).to.equal(1); + expect(serviceInstance.package.exclude[0]).to.equal('exclude-me'); + expect(serviceInstance.package.include.length).to.equal(1); + expect(serviceInstance.package.include[0]).to.equal('include-me'); + expect(serviceInstance.package.artifact).to.equal('some/path/foo.zip'); + expect(serviceInstance.package.excludeDevDependencies).to.equal(undefined); + }); + }); + it('should throw error if serverless.js exports invalid config', () => { const SUtils = new Utils(); diff --git a/lib/utils/getServerlessConfigFile.js b/lib/utils/getServerlessConfigFile.js index a85a1b67b..559fbc884 100644 --- a/lib/utils/getServerlessConfigFile.js +++ b/lib/utils/getServerlessConfigFile.js @@ -28,8 +28,10 @@ const getServerlessConfigFile = _.memoize((servicePath) => { return BbPromise.try(() => { // use require to load serverless.js // eslint-disable-next-line global-require - const config = require(jsPath); - + const configExport = require(jsPath); + // In case of a promise result, first resolve it. + return configExport; + }).then(config => { if (_.isPlainObject(config)) { return config; } diff --git a/lib/utils/getServerlessConfigFile.test.js b/lib/utils/getServerlessConfigFile.test.js index 2d6c0fa48..e5ac960c0 100644 --- a/lib/utils/getServerlessConfigFile.test.js +++ b/lib/utils/getServerlessConfigFile.test.js @@ -63,6 +63,20 @@ describe('#getServerlessConfigFile()', () => { ); }); + it('should return the resolved value if a promise-using serverless.js file found', () => { + const serverlessFilePath = path.join(tmpDirPath, 'serverless.js'); + writeFileSync( + serverlessFilePath, + 'module.exports = new Promise(resolve => { resolve({"service": "my-json-service"}); });' + ); + + return expect(getServerlessConfigFile(tmpDirPath)).to.be.fulfilled.then( + (result) => { + expect(result).to.deep.equal({ service: 'my-json-service' }); + } + ); + }); + it('should throw an error, if serverless.js export not a plain object', () => { const serverlessFilePath = path.join(tmpDirPath, 'serverless.js'); writeFileSync(