diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 32296767..cbbdbd31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,7 @@ jobs: node-version: ${{ matrix.node }} - name: Test - run: pnpm exec vitest --coverage + run: pnpm test:all --coverage - name: Submit coverage uses: coverallsapp/github-action@master diff --git a/bin/read-package-json.ts b/bin/read-package-json.ts index ea597d78..0bcad863 100644 --- a/bin/read-package-json.ts +++ b/bin/read-package-json.ts @@ -1,17 +1,13 @@ import { readFileSync } from 'node:fs'; import { createRequire } from 'node:module'; +const require = createRequire(import.meta.url); + /** * Read the package.json file of `concurrently` */ export function readPackageJson(): Record { - let resolver; - try { - resolver = require.resolve; - } catch { - resolver = createRequire(import.meta.url).resolve; - } - const path = resolver('concurrently/package.json'); + const path = require.resolve('concurrently/package.json'); const content = readFileSync(path, 'utf8'); return JSON.parse(content); } diff --git a/package.json b/package.json index d474b816..08cd7a7a 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,8 @@ "lint": "eslint", "prepublishOnly": "safe-publish-latest && pnpm run build", "test": "vitest --project unit", + "test:all": "vitest run", + "test:e2e": "vitest run --project e2e", "test:smoke": "vitest run --project smoke", "prepare": "husky" }, diff --git a/bin/__fixtures__/read-echo.js b/tests/e2e/__fixtures__/read-echo.js similarity index 100% rename from bin/__fixtures__/read-echo.js rename to tests/e2e/__fixtures__/read-echo.js diff --git a/bin/__fixtures__/sleep.js b/tests/e2e/__fixtures__/sleep.js similarity index 100% rename from bin/__fixtures__/sleep.js rename to tests/e2e/__fixtures__/sleep.js diff --git a/bin/index.spec.ts b/tests/e2e/index.spec.ts similarity index 94% rename from bin/index.spec.ts rename to tests/e2e/index.spec.ts index 4536a9d1..adb4f80d 100644 --- a/bin/index.spec.ts +++ b/tests/e2e/index.spec.ts @@ -1,18 +1,16 @@ import { spawn } from 'node:child_process'; import fs from 'node:fs'; -import os from 'node:os'; import path from 'node:path'; import readline from 'node:readline'; import { subscribeSpyTo } from '@hirez_io/observer-spy'; import { sendCtrlC, spawnWithWrapper } from 'ctrlc-wrapper'; -import { build } from 'esbuild'; import Rx from 'rxjs'; import { map } from 'rxjs/operators'; import stringArgv from 'string-argv'; -import { afterAll, beforeAll, describe, expect, it } from 'vitest'; +import { describe, expect, it } from 'vitest'; -import { escapeRegExp } from '../lib/utils.js'; +import { escapeRegExp } from '../../lib/utils.js'; const isWindows = process.platform === 'win32'; const createKillMessage = (prefix: string, signal: 'SIGTERM' | 'SIGINT' | string) => { @@ -24,37 +22,13 @@ const createKillMessage = (prefix: string, signal: 'SIGTERM' | 'SIGINT' | string return new RegExp(`${escapeRegExp(prefix)} exited with code ${map[signal] ?? signal}`); }; -let tmpDir: string; - -beforeAll(async () => { - // Build 'concurrently' and store it in a temporary directory - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'concurrently-')); - await build({ - entryPoints: [path.join(__dirname, 'index.ts')], - platform: 'node', - bundle: true, - // it doesn't seem like esbuild is able to change a CJS module to ESM, so target CJS instead. - // https://github.com/evanw/esbuild/issues/1921 - format: 'cjs', - outfile: path.join(tmpDir, 'concurrently.cjs'), - }); - fs.copyFileSync(path.join(__dirname, '..', 'package.json'), path.join(tmpDir, 'package.json')); -}, 8000); - -afterAll(() => { - // Remove the temporary directory where 'concurrently' was stored - if (tmpDir) { - fs.rmSync(tmpDir, { recursive: true }); - } -}); - /** * Creates a child process running 'concurrently' with the given args. * Returns observables for its combined stdout + stderr output, close events, pid, and stdin stream. */ const run = (args: string, ctrlcWrapper?: boolean) => { const spawnFn = ctrlcWrapper ? spawnWithWrapper : spawn; - const child = spawnFn('node', [path.join(tmpDir, 'concurrently.cjs'), ...stringArgv(args)], { + const child = spawnFn('node', ['../../dist/bin/index.js', ...stringArgv(args)], { cwd: __dirname, env: { ...process.env, @@ -126,7 +100,7 @@ it('prints help when no arguments are passed', async () => { }); describe('has version command', () => { - const pkg = fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'); + const pkg = fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'), 'utf-8'); const { version } = JSON.parse(pkg); it.each(['--version', '-V', '-v'])('%s', async (arg) => { diff --git a/tests/package.json b/tests/package.json index f803ee8d..66d310b9 100644 --- a/tests/package.json +++ b/tests/package.json @@ -1,8 +1,6 @@ { + "type": "module", "dependencies": { "concurrently": "workspace:*" - }, - "scripts": { - "test": "pnpm --workspace-root test:smoke" } } diff --git a/tests/setup.ts b/tests/setup.ts new file mode 100644 index 00000000..31c9ef82 --- /dev/null +++ b/tests/setup.ts @@ -0,0 +1,36 @@ +import { exec as originalExec } from 'node:child_process'; +import util from 'node:util'; + +import type { TestProject, TestSpecification } from 'vitest/node'; + +const exec = util.promisify(originalExec); + +function buildProject() { + return exec('pnpm run build'); +} + +function isBuildRequired(testFiles: TestSpecification[]) { + for (const file of testFiles) { + if (file.project.name === 'e2e' || file.project.name === 'smoke') { + return true; + } + } + return false; +} + +export default async function setup(project: TestProject) { + // @ts-expect-error not typed + const pattern: string[] | undefined = project.vitest.filenamePattern; + + const testFiles = await project.vitest.getRelevantTestSpecifications(pattern); + + if (isBuildRequired(testFiles)) { + await buildProject(); + } + + project.onTestsRerun(async (testFiles) => { + if (isBuildRequired(testFiles)) { + await buildProject(); + } + }); +} diff --git a/tests/cjs-import/package.json b/tests/smoke/cjs-import/package.json similarity index 100% rename from tests/cjs-import/package.json rename to tests/smoke/cjs-import/package.json diff --git a/tests/cjs-import/smoke-test.ts b/tests/smoke/cjs-import/smoke-test.ts similarity index 100% rename from tests/cjs-import/smoke-test.ts rename to tests/smoke/cjs-import/smoke-test.ts diff --git a/tests/cjs-import/tsconfig.json b/tests/smoke/cjs-import/tsconfig.json similarity index 100% rename from tests/cjs-import/tsconfig.json rename to tests/smoke/cjs-import/tsconfig.json diff --git a/tests/cjs-require/package.json b/tests/smoke/cjs-require/package.json similarity index 100% rename from tests/cjs-require/package.json rename to tests/smoke/cjs-require/package.json diff --git a/tests/cjs-require/smoke-test.ts b/tests/smoke/cjs-require/smoke-test.ts similarity index 100% rename from tests/cjs-require/smoke-test.ts rename to tests/smoke/cjs-require/smoke-test.ts diff --git a/tests/cjs-require/tsconfig.json b/tests/smoke/cjs-require/tsconfig.json similarity index 100% rename from tests/cjs-require/tsconfig.json rename to tests/smoke/cjs-require/tsconfig.json diff --git a/tests/esm/package.json b/tests/smoke/esm/package.json similarity index 100% rename from tests/esm/package.json rename to tests/smoke/esm/package.json diff --git a/tests/esm/smoke-test.ts b/tests/smoke/esm/smoke-test.ts similarity index 100% rename from tests/esm/smoke-test.ts rename to tests/smoke/esm/smoke-test.ts diff --git a/tests/esm/tsconfig.json b/tests/smoke/esm/tsconfig.json similarity index 100% rename from tests/esm/tsconfig.json rename to tests/smoke/esm/tsconfig.json diff --git a/tests/smoke-tests.spec.ts b/tests/smoke/index.spec.ts similarity index 69% rename from tests/smoke-tests.spec.ts rename to tests/smoke/index.spec.ts index 6035a951..cfc9d7a1 100644 --- a/tests/smoke-tests.spec.ts +++ b/tests/smoke/index.spec.ts @@ -1,18 +1,10 @@ import { exec as originalExec } from 'node:child_process'; import util from 'node:util'; -import { beforeAll, expect, it } from 'vitest'; +import { expect, it } from 'vitest'; const exec = util.promisify(originalExec); -beforeAll(async () => { - await exec('pnpm run build'); -}, 20_000); - -it('spawns binary', async () => { - await expect(exec('node dist/bin/index.js "echo test"')).resolves.toBeDefined(); -}); - it.each(['cjs-import', 'cjs-require', 'esm'])('loads library in %s context', async (project) => { // Use as separate execs as tsc outputs to stdout, instead of stderr, and so its text isn't shown await exec(`tsc -p ${project}`, { cwd: __dirname }).catch((err) => Promise.reject(err.stdout)); diff --git a/vitest.config.ts b/vitest.config.ts index 3f50728e..47ef6a72 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -7,19 +7,24 @@ export default defineConfig({ // lcov is used for coveralls reporter: ['text', 'html', 'lcov'], }, + globalSetup: 'tests/setup.ts', projects: [ { - extends: true, test: { name: 'unit', - include: ['{bin,lib}/**/*.spec.ts'], + include: ['lib/**/*.spec.ts'], + }, + }, + { + test: { + name: 'e2e', + include: ['tests/e2e/*.spec.ts'], }, }, { - extends: true, test: { name: 'smoke', - include: ['tests/**/*.spec.ts'], + include: ['tests/smoke/*.spec.ts'], }, }, ],