diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b2745c14..255f4922 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -55,9 +55,13 @@ jobs: - name: Install dependencies run: pnpm install && pnpm add --global concurrently - - name: Build & Test + - name: Build & Unit Test run: concurrently --prefix none --group "pnpm:build" "pnpm:test" + - name: Smoke Test + # Don't collect coverage here as it overrides the unit test's coverage + run: pnpm test:smoke --coverage=false + - name: Submit coverage uses: coverallsapp/github-action@master continue-on-error: true diff --git a/.gitignore b/.gitignore index aae9bcb8..18b9873d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Outputs -/dist +dist # Logs *.log diff --git a/jest.config.js b/jest.config.js index 1b259a68..7ca2110f 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,11 +1,30 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -const config = { +// Need to extend from a base config because projects don't inherit configurations as documented +// https://github.com/jestjs/jest/issues/11411 +/** @type {import('@jest/types').Config.InitialProjectOptions} */ +const baseConfig = { transform: { - '^.+\\.(t|j)sx?$': ['@swc/jest'], + '.*': ['@swc/jest'], }, - collectCoverage: true, - collectCoverageFrom: ['src/**/*.ts', '!src/index.ts'], testPathIgnorePatterns: ['/node_modules/', '/dist'], }; +/** @type {import('@jest/types').Config.InitialOptions} */ +const config = { + collectCoverage: true, + projects: [ + { + ...baseConfig, + displayName: 'unit', + collectCoverageFrom: ['src/**/*.ts', '!src/index.ts'], + // (src|bin) doesn't seem to work on Windows + testMatch: ['src', 'bin'].map((dir) => `/${dir}/**/*.spec.ts`), + }, + { + ...baseConfig, + displayName: 'smoke', + testMatch: ['/tests/**/*.spec.ts'], + }, + ], +}; + module.exports = config; diff --git a/package.json b/package.json index 95b8b39b..44a43093 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,8 @@ "lint:fix": "pnpm run lint --fix", "prepublishOnly": "safe-publish-latest && pnpm run build", "report-coverage": "cat coverage/lcov.info | coveralls", - "test": "jest", + "test": "jest --selectProjects unit", + "test:smoke": "jest --selectProjects smoke", "prepare": "husky install" }, "repository": { diff --git a/tests/cjs-import/package.json b/tests/cjs-import/package.json new file mode 100644 index 00000000..5bbefffb --- /dev/null +++ b/tests/cjs-import/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/tests/cjs-import/smoke-test.ts b/tests/cjs-import/smoke-test.ts new file mode 100644 index 00000000..9c12b0a5 --- /dev/null +++ b/tests/cjs-import/smoke-test.ts @@ -0,0 +1,15 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import type { ConcurrentlyResult } from 'concurrently'; +import concurrently, { concurrently as concurrently2, createConcurrently } from 'concurrently'; + +const result: ConcurrentlyResult = concurrently(['ls'], { + raw: true, +}); + +const result2: ConcurrentlyResult = concurrently2(['ls'], { + killOthers: ['failure'], +}); + +const result3: ConcurrentlyResult = createConcurrently(['ls'], { + successCondition: 'all', +}); diff --git a/tests/cjs-import/tsconfig.json b/tests/cjs-import/tsconfig.json new file mode 100644 index 00000000..9b586f29 --- /dev/null +++ b/tests/cjs-import/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "outDir": "dist", + "module": "CommonJS", + "moduleResolution": "Node", + "skipLibCheck": true + } +} diff --git a/tests/cjs-require/package.json b/tests/cjs-require/package.json new file mode 100644 index 00000000..5bbefffb --- /dev/null +++ b/tests/cjs-require/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/tests/cjs-require/smoke-test.ts b/tests/cjs-require/smoke-test.ts new file mode 100644 index 00000000..1d59ad12 --- /dev/null +++ b/tests/cjs-require/smoke-test.ts @@ -0,0 +1,17 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ + +import concurrently = require('concurrently'); + +const { concurrently: concurrently2, createConcurrently } = concurrently; + +const result: concurrently.ConcurrentlyResult = concurrently(['ls'], { + raw: true, +}); + +const result2: concurrently.ConcurrentlyResult = concurrently2(['ls'], { + killOthers: ['failure'], +}); + +const result3: concurrently.ConcurrentlyResult = createConcurrently(['ls'], { + successCondition: 'all', +}); diff --git a/tests/cjs-require/tsconfig.json b/tests/cjs-require/tsconfig.json new file mode 100644 index 00000000..9b586f29 --- /dev/null +++ b/tests/cjs-require/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "outDir": "dist", + "module": "CommonJS", + "moduleResolution": "Node", + "skipLibCheck": true + } +} diff --git a/tests/esm/package.json b/tests/esm/package.json new file mode 100644 index 00000000..3dbc1ca5 --- /dev/null +++ b/tests/esm/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/tests/esm/smoke-test.ts b/tests/esm/smoke-test.ts new file mode 100644 index 00000000..9c12b0a5 --- /dev/null +++ b/tests/esm/smoke-test.ts @@ -0,0 +1,15 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import type { ConcurrentlyResult } from 'concurrently'; +import concurrently, { concurrently as concurrently2, createConcurrently } from 'concurrently'; + +const result: ConcurrentlyResult = concurrently(['ls'], { + raw: true, +}); + +const result2: ConcurrentlyResult = concurrently2(['ls'], { + killOthers: ['failure'], +}); + +const result3: ConcurrentlyResult = createConcurrently(['ls'], { + successCondition: 'all', +}); diff --git a/tests/esm/tsconfig.json b/tests/esm/tsconfig.json new file mode 100644 index 00000000..24f1712c --- /dev/null +++ b/tests/esm/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "outDir": "dist", + "module": "Node16", + "moduleResolution": "Node16" + } +} diff --git a/tests/package.json b/tests/package.json new file mode 100644 index 00000000..a22bca31 --- /dev/null +++ b/tests/package.json @@ -0,0 +1,8 @@ +{ + "dependencies": { + "concurrently": "file:.." + }, + "scripts": { + "test": "pnpm --prefix .. test -- --selectProjects smoke" + } +} diff --git a/tests/pnpm-lock.yaml b/tests/pnpm-lock.yaml new file mode 100644 index 00000000..762bb5d3 --- /dev/null +++ b/tests/pnpm-lock.yaml @@ -0,0 +1,206 @@ +lockfileVersion: '6.1' + +settings: + autoInstallPeers: false + excludeLinksFromLockfile: false + +dependencies: + concurrently: + specifier: file:.. + version: file:.. + +packages: + + /@babel/runtime@7.23.7: + resolution: {integrity: sha512-w06OXVOFso7LcbzMiDGt+3X7Rh7Ho8MmgPoWU3rarH+8upf+wSU/grlGbWzQyr3DkdN6ZeuMFjpdwW0Q+HxobA==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + dev: false + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: false + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: false + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: false + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: false + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: false + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: false + + /date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + dependencies: + '@babel/runtime': 7.23.7 + dev: false + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: false + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: false + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: false + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: false + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: false + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false + + /regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + dev: false + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: false + + /rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + dependencies: + tslib: 2.6.2 + dev: false + + /shell-quote@1.8.1: + resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} + dev: false + + /spawn-command@0.0.2: + resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} + dev: false + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: false + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: false + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: false + + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + dev: false + + /tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + dev: false + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: false + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: false + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: false + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: false + + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: false + + file:..: + resolution: {directory: .., type: directory} + name: concurrently + version: 8.2.2 + engines: {node: '>=16'} + hasBin: true + dependencies: + chalk: 4.1.2 + date-fns: 2.30.0 + lodash: 4.17.21 + rxjs: 7.8.1 + shell-quote: 1.8.1 + spawn-command: 0.0.2 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + dev: false diff --git a/tests/smoke-tests.spec.ts b/tests/smoke-tests.spec.ts new file mode 100644 index 00000000..732bd581 --- /dev/null +++ b/tests/smoke-tests.spec.ts @@ -0,0 +1,21 @@ +import { exec as originalExec } from 'child_process'; +import * as util from 'util'; + +const exec = util.promisify(originalExec); + +beforeAll(async () => { + await exec('pnpm build', { cwd: `${__dirname}/..` }); + await exec('pnpm install', { cwd: __dirname }); +}, 10000); + +it.each(['cjs-import', 'cjs-require', 'esm'])( + '%s', + 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), + ); + await exec(`node ${project}/dist/smoke-test.js`, { cwd: __dirname }); + }, + 10000, +);