serverless-build-client
Version:
A Serverless Framework plugin used to build front end applications
545 lines (498 loc) • 15.8 kB
JavaScript
const childProcess = require("cross-spawn");
const ServerlessClientBuildPlugin = require("../index");
const constants = require("../constants");
jest.mock("cross-spawn", () => ({
spawn: jest.fn(() => ({
stdout: {
on: jest.fn()
},
stderr: {
on: jest.fn()
},
on: jest.fn()
}))
}));
describe("ServerlessClientBuildPlugin tests", () => {
const env = process.env;
const options = {
packager: "yarn",
command: "build",
verbose: true
};
beforeEach(() => {
jest.clearAllMocks();
process.env = JSON.parse(JSON.stringify(env));
});
it("should create the object", () => {
const serverless = {
cli: {
log: jest.fn()
}
};
const plugin = new ServerlessClientBuildPlugin(serverless, options);
expect(plugin.serverless).toEqual(serverless);
expect(plugin.options).toEqual(options);
expect(plugin.commands).toEqual({
client: {
usage: "A plugin used to build front end applications",
lifecycleEvents: ["build"],
commands: {
build: {
usage: "Build the client",
lifecycleEvents: ["build"],
options: {
packager: {
usage: "The packager that will be used to build the client",
shortcut: "p"
},
command: {
usage: "The command that will be used to build the client",
shortcut: "c"
},
cwd: {
usage: "The directory that will be used to run the packager",
shortcut: "d"
},
verbose: {
usage:
"Setting this command prints the environment variables in the console",
shortcut: "v"
}
}
}
}
}
});
expect(plugin.hooks).toEqual({
"before:client:build:build": expect.any(Function),
"client:build:build": expect.any(Function),
"after:client:build:build": expect.any(Function)
});
});
it("should log message after build is completed", () => {
const serverless = {
cli: {
log: jest.fn()
}
};
const plugin = new ServerlessClientBuildPlugin(serverless, options);
plugin.afterClientBuild();
expect(plugin.serverless.cli.log("Successfully built the client"));
});
describe("beforeClientBuild tests", () => {
it("should skip processing environment variables", () => {
const serverless = {
cli: {
log: jest.fn()
},
service: {
provider: {},
custom: {
buildClient: {}
}
}
};
const plugin = new ServerlessClientBuildPlugin(serverless, options);
plugin.beforeClientBuild();
expect(plugin.serverless.cli.log).toHaveBeenCalledWith(
"No environment variables detected. Skipping step..."
);
expect(process.env).toEqual(env);
});
it("should skip an empty list of environment variables", () => {
const serverless = {
cli: {
log: jest.fn()
},
service: {
provider: {
environment: {}
},
custom: {
buildClient: {
environment: {}
}
}
}
};
const plugin = new ServerlessClientBuildPlugin(serverless, options);
plugin.beforeClientBuild();
expect(plugin.serverless.cli.log).toHaveBeenCalledWith(
"No environment variables detected. Skipping step..."
);
expect(process.env).toEqual(env);
});
const tests = [
[
"should process a provider environment variable",
{
HELLO_WORLD: "hello world"
},
{},
{
HELLO_WORLD: "hello world"
}
],
[
"should process a custom environment variable",
{},
{
HELLO_WORLD: "hello world"
},
{
HELLO_WORLD: "hello world"
}
],
[
"should process multiple environment variables",
{
HELLO_WORLD: "hello world"
},
{
FOO_BAR: "foo bar"
},
{
HELLO_WORLD: "hello world",
FOO_BAR: "foo bar"
}
],
[
"should override provider environment variables",
{
HELLO_WORLD: "hello world"
},
{
HELLO_WORLD: "foo bar"
},
{
HELLO_WORLD: "foo bar"
}
]
];
it.each(tests)(
"%s",
(message, providerEnvironment, customEnvironment, expectedResult) => {
const serverless = {
cli: {
log: jest.fn()
},
service: {
provider: {
environment: providerEnvironment
},
custom: {
buildClient: {
environment: customEnvironment
}
}
}
};
const plugin = new ServerlessClientBuildPlugin(serverless, options);
plugin.beforeClientBuild();
const environment = Object.assign(
{},
providerEnvironment,
customEnvironment
);
expect(plugin.serverless.cli.log.mock.calls).toEqual(
[["Setting the environment variables"]].concat(
Object.keys(environment).map(variable => [
`Setting ${variable} to ${environment[variable]}`
])
)
);
expect(process.env).toEqual(expect.objectContaining(expectedResult));
}
);
it("should not log the environment variables", () => {
const environment = {
HELLO_WORLD: "hello world"
};
const serverless = {
cli: {
log: jest.fn()
},
service: {
provider: {
environment
},
custom: {
buildClient: {
environment: {}
}
}
}
};
const plugin = new ServerlessClientBuildPlugin(
serverless,
Object.assign({}, options, { verbose: false })
);
plugin.beforeClientBuild();
expect(plugin.serverless.cli.log.mock.calls).toEqual([
["Setting the environment variables"]
]);
});
});
describe("clientBuild tests", () => {
const resolve = jest.fn();
const reject = jest.fn();
const stdout = jest.fn((event, f) => f("some stdout"));
const stderr = jest.fn((event, f) => f("some stderr"));
const error = "error";
const serverless = {
cli: {
log: jest.fn()
},
classes: {
Error: jest.fn(err => new Error(err))
}
};
beforeEach(() => {
jest.clearAllMocks();
});
it("should start to build the client", () => {
const plugin = new ServerlessClientBuildPlugin(serverless, options);
plugin.clientBuild();
expect(plugin.serverless.cli.log).toHaveBeenCalledWith(
"Building the client"
);
});
it("should throw if packager is invalid", () => {
const on = jest.fn((event, f) => f(0));
childProcess.spawn.mockImplementation(() => ({
stdout: {
on: stdout
},
stderr: {
on: stderr
},
on
}));
const plugin = new ServerlessClientBuildPlugin(serverless, {
packager: "hello",
command: "build"
});
plugin._onStdout = jest.fn();
plugin._onStderr = jest.fn();
plugin._onError = jest.fn();
plugin._clientBuild(resolve, reject);
expect(childProcess.spawn).not.toHaveBeenCalled();
expect(stdout).not.toHaveBeenCalled();
expect(stderr).not.toHaveBeenCalled();
expect(on).not.toHaveBeenCalled();
expect(resolve).not.toHaveBeenCalled();
expect(reject).toHaveBeenCalledWith(
new Error(
`Invalid packager hello. Expected one of ${Object.keys(
constants.packagers
)}`
)
);
});
it("should build with cwd option", () => {
const on = jest.fn((event, f) => f(0));
childProcess.spawn.mockImplementation(() => ({
stdout: {
on: stdout
},
stderr: {
on: stderr
},
on
}));
const plugin = new ServerlessClientBuildPlugin(serverless, {
packager: "yarn",
command: "build",
cwd: "client"
});
plugin._onStdout = jest.fn();
plugin._onStderr = jest.fn();
plugin._onError = jest.fn();
plugin._clientBuild(resolve, reject);
expect(childProcess.spawn).toHaveBeenCalledWith("yarn", ["build"], {
cwd: "client"
});
expect(stdout).toHaveBeenCalledWith("data", expect.any(Function));
expect(stderr).toHaveBeenCalledWith("data", expect.any(Function));
expect(on.mock.calls).toEqual([
["error", expect.any(Function)],
["close", expect.any(Function)]
]);
expect(resolve).toHaveBeenCalled();
expect(reject).not.toHaveBeenCalled();
});
it("should build with default packager and default command", () => {
const on = jest.fn((event, f) => f(0));
childProcess.spawn.mockImplementation(() => ({
stdout: {
on: stdout
},
stderr: {
on: stderr
},
on
}));
const plugin = new ServerlessClientBuildPlugin(serverless, {});
plugin._onStdout = jest.fn();
plugin._onStderr = jest.fn();
plugin._onError = jest.fn();
plugin._clientBuild(resolve, reject);
expect(childProcess.spawn).toHaveBeenCalledWith("yarn", ["build"], {
cwd: undefined
});
expect(stdout).toHaveBeenCalledWith("data", expect.any(Function));
expect(stderr).toHaveBeenCalledWith("data", expect.any(Function));
expect(on.mock.calls).toEqual([
["error", expect.any(Function)],
["close", expect.any(Function)]
]);
expect(resolve).toHaveBeenCalled();
expect(reject).not.toHaveBeenCalled();
});
it.each(Object.keys(constants.packagers))(
"should build with %s packager and custom command",
packager => {
const on = jest.fn((event, f) => f(0));
childProcess.spawn.mockImplementation(() => ({
stdout: {
on: stdout
},
stderr: {
on: stderr
},
on
}));
const plugin = new ServerlessClientBuildPlugin(serverless, {
packager,
command: "build"
});
plugin._onStdout = jest.fn();
plugin._onStderr = jest.fn();
plugin._onError = jest.fn();
plugin._clientBuild(resolve, reject);
expect(childProcess.spawn).toHaveBeenCalledWith(
constants.packagers[packager],
["build"],
{
cwd: undefined
}
);
expect(stdout).toHaveBeenCalledWith("data", expect.any(Function));
expect(stderr).toHaveBeenCalledWith("data", expect.any(Function));
expect(on.mock.calls).toEqual([
["error", expect.any(Function)],
["close", expect.any(Function)]
]);
expect(resolve).toHaveBeenCalled();
expect(reject).not.toHaveBeenCalled();
}
);
it.each(Object.keys(constants.packagers))(
"should build with %s packager and default command",
packager => {
const on = jest.fn((event, f) => f(0));
childProcess.spawn.mockImplementation(() => ({
stdout: {
on: stdout
},
stderr: {
on: stderr
},
on
}));
const plugin = new ServerlessClientBuildPlugin(serverless, {
packager
});
plugin._onStdout = jest.fn();
plugin._onStderr = jest.fn();
plugin._onError = jest.fn();
plugin._clientBuild(resolve, reject);
expect(childProcess.spawn).toHaveBeenCalledWith(
constants.packagers[packager],
constants.defaults.command[packager].split(" "),
{ cwd: undefined }
);
expect(stdout).toHaveBeenCalledWith("data", expect.any(Function));
expect(stderr).toHaveBeenCalledWith("data", expect.any(Function));
expect(on.mock.calls).toEqual([
["error", expect.any(Function)],
["close", expect.any(Function)]
]);
expect(resolve).toHaveBeenCalled();
expect(reject).not.toHaveBeenCalled();
}
);
it("should resolve with exit code 0", () => {
const on = jest.fn((event, f) => f(0));
childProcess.spawn.mockImplementation(() => ({
stdout: {
on: stdout
},
stderr: {
on: stderr
},
on
}));
const plugin = new ServerlessClientBuildPlugin(serverless, options);
plugin._onStdout = jest.fn();
plugin._onStderr = jest.fn();
plugin._onError = jest.fn();
plugin._clientBuild(resolve, reject);
expect(childProcess.spawn).toHaveBeenCalledWith("yarn", ["build"], {
cwd: undefined
});
expect(stdout).toHaveBeenCalledWith("data", expect.any(Function));
expect(stderr).toHaveBeenCalledWith("data", expect.any(Function));
expect(on.mock.calls).toEqual([
["error", expect.any(Function)],
["close", expect.any(Function)]
]);
expect(resolve).toHaveBeenCalled();
expect(reject).not.toHaveBeenCalled();
});
it("should resolve with exit code 1", () => {
const on = jest.fn((event, f) => f(1));
childProcess.spawn.mockImplementation(() => ({
stdout: {
on: stdout
},
stderr: {
on: stderr
},
on
}));
const plugin = new ServerlessClientBuildPlugin(serverless, options);
plugin._onStdout = jest.fn();
plugin._onStderr = jest.fn();
plugin._onError = jest.fn();
plugin._clientBuild(resolve, reject);
expect(childProcess.spawn).toHaveBeenCalledWith("yarn", ["build"], {
cwd: undefined
});
expect(stdout).toHaveBeenCalledWith("data", expect.any(Function));
expect(stderr).toHaveBeenCalledWith("data", expect.any(Function));
expect(on.mock.calls).toEqual([
["error", expect.any(Function)],
["close", expect.any(Function)]
]);
expect(resolve).not.toHaveBeenCalled();
expect(reject).toHaveBeenCalled();
});
it("should log the stdout", () => {
const plugin = new ServerlessClientBuildPlugin(serverless, options);
plugin._onStdout(new Buffer(" hello "));
expect(serverless.cli.log).toHaveBeenCalledWith("hello");
});
it("should log the stderr", () => {
const plugin = new ServerlessClientBuildPlugin(serverless, options);
plugin._onStderr(new Buffer(` ${error} `));
expect(plugin.error).toEqual(new Error(error));
expect(serverless.cli.log).toHaveBeenCalledWith(error);
});
it("should set the error", () => {
const plugin = new ServerlessClientBuildPlugin(serverless, options);
plugin._onError(error);
expect(plugin.error).toEqual(new Error(error));
});
});
});