serverless/lib/plugins/print/print.test.js
Erik Erikson dc3a4aa6af Fix print, clean pre-population, fix cyclic bug
Fix `print`
The print command is highly linked to the `Variables` and `Service` codebases, keep those in sync and leave reminders about the link.  Made these explicit and separately implemented to avoid complexity.
Additionally, the print command re-populates an object with the *very similar* content as the previously pre-populated service (just not augmented as just mentioned).  This can lead to cross contamination between the two.  As such, all caches must be cleared per unique invocation of service/object/property population.
Add tests for some expected but previously unverified behaviors.

Clean pre-population
The previous implementation worked okay but was unnecessary and would have been a maintenance problem.  Instead, just knock out the population of variables depending on those config dependent services and use the standard means of resolution.

Fix cyclic bug (resulting from running print against a self-referencing serverless.yml)
The caching of values could lead to a cyclic object remaining in the caches for variable population.  This causes crashes and pain.  Solved by the cache cleaning logic.
2018-02-22 16:30:04 -08:00

211 lines
5.5 KiB
JavaScript

'use strict';
const expect = require('chai').expect;
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const Serverless = require('../../Serverless');
const CLI = require('../../classes/CLI');
const YAML = require('js-yaml');
describe('Print', () => {
let print;
let serverless;
let getServerlessConfigFileStub;
beforeEach(() => {
getServerlessConfigFileStub = sinon.stub();
const PrintPlugin = proxyquire('./print.js', {
'../../utils/getServerlessConfigFile': getServerlessConfigFileStub,
});
serverless = new Serverless();
serverless.variables.options = {
stage: 'dev',
region: 'us-east-1',
};
serverless.cli = new CLI(serverless);
print = new PrintPlugin(serverless);
print.serverless.cli = {
consoleLog: sinon.spy(),
};
});
afterEach(() => {
serverless.service.provider.variableSyntax = '\\${([ ~:a-zA-Z0-9._\'",\\-\\/\\(\\)]+?)}';
});
it('should print standard config', () => {
const conf = {
service: 'my-service',
provider: {
name: 'aws',
},
};
getServerlessConfigFileStub.resolves(conf);
return print.print().then(() => {
const message = print.serverless.cli.consoleLog.args.join();
expect(getServerlessConfigFileStub.calledOnce).to.equal(true);
expect(print.serverless.cli.consoleLog.called).to.be.equal(true);
expect(YAML.load(message)).to.eql(conf);
});
});
it('should print special service object and provider string configs', () => {
const conf = {
service: {
name: 'my-service',
},
provider: 'aws',
};
getServerlessConfigFileStub.resolves(conf);
return print.print().then(() => {
const message = print.serverless.cli.consoleLog.args.join();
expect(getServerlessConfigFileStub.calledOnce).to.equal(true);
expect(print.serverless.cli.consoleLog.called).to.be.equal(true);
expect(YAML.load(message)).to.eql(conf);
});
});
it('should resolve command line variables', () => {
const conf = {
service: 'my-service',
provider: {
name: 'aws',
stage: '${opt:stage}',
},
};
getServerlessConfigFileStub.resolves(conf);
serverless.processedInput = {
commands: ['print'],
options: { stage: 'dev', region: undefined },
};
const expected = {
service: 'my-service',
provider: {
name: 'aws',
stage: 'dev',
},
};
return print.print().then(() => {
const message = print.serverless.cli.consoleLog.args.join();
expect(getServerlessConfigFileStub.calledOnce).to.equal(true);
expect(print.serverless.cli.consoleLog.called).to.be.equal(true);
expect(YAML.load(message)).to.eql(expected);
});
});
it('should resolve using custom variable syntax', () => {
const conf = {
service: 'my-service',
provider: {
name: 'aws',
stage: '${{opt:stage}}',
variableSyntax: "\\${{([ ~:a-zA-Z0-9._\\'\",\\-\\/\\(\\)]+?)}}",
},
};
serverless.service.provider.variableSyntax = "\\${{([ ~:a-zA-Z0-9._\\'\",\\-\\/\\(\\)]+?)}}";
getServerlessConfigFileStub.resolves(conf);
serverless.processedInput = {
commands: ['print'],
options: { stage: 'dev', region: undefined },
};
const expected = {
service: 'my-service',
provider: {
name: 'aws',
stage: 'dev',
variableSyntax: "\\${{([ ~:a-zA-Z0-9._\\'\",\\-\\/\\(\\)]+?)}}",
},
};
return print.print().then(() => {
const message = print.serverless.cli.consoleLog.args.join();
expect(getServerlessConfigFileStub.calledOnce).to.equal(true);
expect(print.serverless.cli.consoleLog.called).to.be.equal(true);
expect(YAML.load(message)).to.eql(expected);
});
});
it('should resolve custom variables', () => {
const conf = {
service: 'my-service',
custom: { region: 'us-east-1' },
provider: {
name: 'aws',
stage: '${opt:stage}',
region: '${self:custom.region}',
},
};
getServerlessConfigFileStub.resolves(conf);
serverless.processedInput = {
commands: ['print'],
options: { stage: 'dev', region: undefined },
};
serverless.service.custom = { region: 'us-east-1' };
const expected = {
service: 'my-service',
custom: {
region: 'us-east-1',
},
provider: {
name: 'aws',
stage: 'dev',
region: 'us-east-1',
},
};
return print.print().then(() => {
const message = print.serverless.cli.consoleLog.args.join();
expect(getServerlessConfigFileStub.calledOnce).to.equal(true);
expect(print.serverless.cli.consoleLog.called).to.be.equal(true);
expect(YAML.load(message)).to.eql(expected);
});
});
it('should resolve self references', () => {
const conf = {
custom: {
me: '${self:}',
},
provider: {},
};
getServerlessConfigFileStub.resolves(conf);
serverless.processedInput = {
commands: ['print'],
options: {},
};
const expected = {
custom: {
me: {
$ref: '$',
},
},
provider: {},
};
return print.print().then(() => {
const message = print.serverless.cli.consoleLog.args.join();
expect(getServerlessConfigFileStub.calledOnce).to.equal(true);
expect(print.serverless.cli.consoleLog.called).to.be.equal(true);
expect(YAML.load(message)).to.eql(expected);
});
});
});