UNPKG

typescript-assistant

Version:

Combines and integrates professional Typescript tools into your project

167 lines (156 loc) 4.52 kB
import { Bus, EventType } from "../bus"; import { Git } from "../git"; import { Logger } from "../logger"; import { Task, TaskRunner } from "../taskrunner"; export interface NYC { start( triggers: EventType[], withCoverage: boolean, config?: string, testsGlob?: string ): void; stop(): void; run( withCoverage?: boolean, config?: string, testsGlob?: string ): Promise<boolean>; } function delay(ms: number): Promise<void> { return new Promise((resolve) => setTimeout(resolve, ms)); } export function createNyc(dependencies: { taskRunner: TaskRunner; logger: Logger; bus: Bus; git: Git; }): NYC { const { taskRunner, logger, bus, git } = dependencies; let runningTask: Task | undefined; let coolingDown: Promise<void> | undefined; async function startNyc( withCoverage = true, config?: string, testsGlob = "test/**/*-tests.ts*" ): Promise<boolean> { let hasFailingTest = false; let myCoolingDown = delay(100); coolingDown = myCoolingDown; await myCoolingDown; if (coolingDown !== myCoolingDown) { return false; } if (runningTask) { logger.log("nyc", "Aborting previous nyc run"); runningTask.kill(); runningTask = undefined; } else { bus.report({ tool: "test", status: "busy" }); bus.report({ tool: "coverage", status: "busy" }); } let lastLineWasNotOk = false; function handleOutput(line: string) { if (task === runningTask) { let notOk = /^not ok \d+ (.*)/.exec(line); let ok = /^ok \d+ (.*)/.exec(line); if (notOk) { lastLineWasNotOk = true; logger.log("nyc", `FAILED: ${notOk[1]}`); hasFailingTest = true; } else if (ok) { lastLineWasNotOk = false; } else if (lastLineWasNotOk) { logger.log("nyc", line); } } return true; } function handleError(line: string) { if (task === runningTask && !line.startsWith("ERROR: Coverage for")) { logger.error("nyc", line); } return true; } if (withCoverage) { runningTask = taskRunner.runTask( "./node_modules/.bin/nyc", [ config ? `--nycrc-path ${config}` : "", "--check-coverage", "-- mocha --require ts-node/register/transpile-only --exit --reporter tap", `"${testsGlob}"`, ] .join(" ") .trim() .split(" "), { name: "nyc", logger, handleOutput, handleError, } ); } else { logger.log("nyc", "running tests without coverage"); runningTask = taskRunner.runTask( "./node_modules/.bin/mocha", [ "--require ts-node/register/transpile-only --exit --reporter tap", `"${testsGlob}"`, ] .join(" ") .split(" "), { name: "nyc", logger, handleOutput, handleError, } ); } let task = runningTask; return runningTask.result .then(() => { if (task === runningTask) { runningTask = undefined; logger.log("nyc", withCoverage ? "code coverage OK" : "tests ok"); bus.report({ tool: "test", status: "ready", errors: 0 }); bus.report({ tool: "coverage", status: "ready", errors: 0 }); } return true; }) .catch(async () => { if (task === runningTask) { runningTask = undefined; logger.log("nyc", "code coverage FAILED"); bus.report({ tool: "test", status: "ready", errors: hasFailingTest ? 1 : 0, }); bus.report({ tool: "coverage", status: "ready", errors: 1 }); } let isOnMasterOrRelease = await git.isOnMasterOrReleaseBranch(); return !isOnMasterOrRelease && !hasFailingTest; }); } let callback: (() => Promise<boolean>) | undefined; return { run(withCoverage?: boolean, config?: string, testsGlob?: string) { return startNyc(withCoverage, config, testsGlob).catch(() => false); }, start( triggers: EventType[], withCoverage, config?: string, testsGlob?: string ) { callback = () => startNyc(withCoverage, config, testsGlob); bus.registerAll(triggers, callback as () => void); callback().catch(() => false); }, stop() { bus.unregister(callback as () => void); }, }; }