@applicaster/zapplicaster-cli
Version:
CLI Tool for the zapp app and Quick Brick project
264 lines (215 loc) • 6.16 kB
JavaScript
const { taskRunner } = require("../index");
const logger = require("../../logger");
const welcomeSpy = jest.spyOn(logger, "welcome");
const logSpy = jest.spyOn(logger, "log").mockImplementation(jest.fn());
const errorSpy = jest.spyOn(logger, "error").mockImplementation(jest.fn());
jest.spyOn(console, "log").mockImplementation(jest.fn());
jest.mock("ramda", () => ({
...jest.requireActual("ramda"),
T: jest.fn(),
}));
const R = require("ramda");
const mock_PREREQUISITES_CHECKER_ERROR = new Error(
"error in prerequisites checker"
);
const mock_CONFIGURATOR_ERROR = new Error("error in configurator");
const name = "task_name";
const startMessage = "start_message";
const prerequisitesChecker = jest.fn(() => Promise.resolve(true));
const FAIL_prerequisitesChecker = jest.fn(() => Promise.resolve(false));
const THROW_prerequisitesChecker = jest.fn(() => {
throw mock_PREREQUISITES_CHECKER_ERROR;
});
const configurator = jest.fn();
const FAIL_configurator = jest.fn(() => {
throw mock_CONFIGURATOR_ERROR;
});
const step1Sstart = "step1_start";
const step1Action = jest.fn();
const step1Error = "step1_error";
const step1Completion = "step1_completion";
const step2Start = "step2_start";
const step2Action = jest.fn();
const step2Error = "step2_error";
const step2Completion = "step2_completion";
const cleanUp = jest.fn();
const steps = [
{
start: step1Sstart,
run: step1Action,
error: step1Error,
completion: step1Completion,
},
{
start: step2Start,
run: step2Action,
error: step2Error,
completion: step2Completion,
},
];
const FAILING_STEP_ERROR = new Error("FAILING_STEP");
const failing_step_with_no_error = {
start: "failing step",
run: () => {
throw FAILING_STEP_ERROR;
},
completion: "done",
};
const failing_step = {
...failing_step_with_no_error,
error: "failing_step_error",
};
const task = {
name,
startMessage,
prerequisitesChecker,
configurator,
steps,
cleanUp,
};
describe("taskRunner", () => {
afterEach(() => {
logSpy.mockClear();
errorSpy.mockClear();
});
describe("when all goes well", () => {
beforeAll(async () => {
await taskRunner(task)({});
});
it("returns a function", () => {
expect(taskRunner(task)).toBeFunction();
});
it("invokes the logger's welcome message", () => {
expect(welcomeSpy).toHaveBeenCalledWith(name, startMessage);
});
it("invokes the prerequisite checker if provided", () => {
expect(prerequisitesChecker).toHaveBeenCalled();
});
it("invokes the configurator if provided", () => {
expect(configurator).toHaveBeenCalled();
});
it("runs each step", () => {
expect(step1Action).toHaveBeenCalled();
expect(step2Action).toHaveBeenCalled();
});
it("it invokes the cleanup function if provided", () => {
expect(cleanUp).toHaveBeenCalled();
});
});
describe("when prerequisitesChecker fails", () => {
beforeAll(async () => {
await taskRunner({
...task,
prerequisitesChecker: FAIL_prerequisitesChecker,
})({});
});
afterEach(() => {
errorSpy.mockClear();
});
it("invokes the logger error", () => {
expect(errorSpy).toHaveBeenCalledWith(
"Prerequisites are not satisfied",
expect.any(Error)
);
});
});
describe("when prerequisitesChecker throws", () => {
beforeAll(async () => {
await taskRunner({
...task,
prerequisitesChecker: THROW_prerequisitesChecker,
})({});
});
afterEach(() => {
errorSpy.mockClear();
});
it("invokes the logger error", () => {
expect(errorSpy).toHaveBeenCalledWith(
"error in prerequisites checker",
mock_PREREQUISITES_CHECKER_ERROR
);
});
});
describe("when no prerequisites checker is invoked", () => {
beforeAll(async () => {
await taskRunner({ ...task, prerequisitesChecker: undefined })({});
});
it("uses Ramda's True function", () => {
expect(R.T).toHaveBeenCalled();
});
});
describe("when the configurator fails", () => {
beforeAll(async () => {
await taskRunner({ ...task, configurator: FAIL_configurator })({});
});
afterEach(() => {
logSpy.mockClear();
errorSpy.mockClear();
});
it("invokes the logger error", () => {
expect(errorSpy).toHaveBeenCalledWith(
"error in configurator",
mock_CONFIGURATOR_ERROR
);
});
});
describe("when using the verbose option", () => {
beforeAll(async () => {
await taskRunner(task)("", {
verbose: true,
});
});
afterEach(() => {
logSpy.mockClear();
errorSpy.mockClear();
});
it("prints verbose output", () => {
expect(logSpy).toHaveBeenCalled();
});
});
describe("when no configurator is provided", () => {
beforeAll(async () => {
await taskRunner({ ...task, configurator: undefined })({});
});
it("uses the default function ", () => {});
});
describe("when no cleanup is provided", () => {
beforeAll(async () => {
await taskRunner({ ...task, cleanUp: undefined })({});
});
afterEach(() => {
logSpy.mockClear();
});
it("skips the cleanup step", () => {
expect(logSpy).not.toHaveBeenCalledWith("cleaning up...");
});
});
describe("when a step fails", () => {
beforeAll(async () => {
await taskRunner({ ...task, steps: [failing_step] })({});
});
afterEach(() => {
errorSpy.mockClear();
});
it("catches the error", () => {
expect(errorSpy).toHaveBeenCalledWith(
failing_step.error,
FAILING_STEP_ERROR
);
});
});
describe("when a step fails and has no default error message", () => {
beforeAll(async () => {
await taskRunner({ ...task, steps: [failing_step_with_no_error] })({});
});
afterEach(() => {
errorSpy.mockClear();
});
it("catches the error", () => {
expect(errorSpy).toHaveBeenCalledWith(
FAILING_STEP_ERROR.message,
FAILING_STEP_ERROR
);
});
});
});