diff --git a/.nycrc b/.nycrc index c3b935e2..293cf726 100644 --- a/.nycrc +++ b/.nycrc @@ -13,6 +13,7 @@ "src/modules/helpers/list-files-sync.ts", "src/modules/helpers/kill.ts", "src/modules/helpers/log.ts", + "src/modules/helpers/skip.ts", "src/services/pid.ts", "src/services/container.ts", "src/parsers/get-runner.ts", diff --git a/.vscode/settings.json b/.vscode/settings.json index 77c58be8..d4944655 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,5 +15,8 @@ }, "[yaml]": { "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[mdx]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" } } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 48473437..df64e99f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -92,12 +92,16 @@ npm run test:deno:parallel # Test with the locally installed Deno version ### Coverage -Methods that vary according to **Node.js** version, platform or OS aren't tested against the coverage rate. +The coverage target is **95%**. ```sh npm run test:c8:sequential ``` +> [!tip] +> +> Don't be intimidated by high coverage, methods that vary according to platform, platform versions, _OS_ and processes _(`process.exit`, `process.once`, etc.)_ aren't tested against the coverage rate 🙋🏻‍♂️ + ### Compatibility Per Platform (Docker) > ⚠️ Testing using **Docker** can require a considerable local storage. diff --git a/biome.json b/biome.json index 1427375a..aab7a4d6 100644 --- a/biome.json +++ b/biome.json @@ -41,7 +41,8 @@ "all": true, "useImportRestrictions": "off", "noConsole": "off", - "noMisplacedAssertion": "off" + "noMisplacedAssertion": "off", + "useImportExtensions": "error" }, "performance": { "all": true diff --git a/fixtures/before-after-each/integration.test.cjs b/fixtures/before-after-each/integration.test.cjs index 1c54f033..63797510 100644 --- a/fixtures/before-after-each/integration.test.cjs +++ b/fixtures/before-after-each/integration.test.cjs @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ - const fs = require('node:fs'); const path = require('node:path'); diff --git a/fixtures/deno/require.cjs b/fixtures/deno/require.cjs index 827720a0..d17bc0df 100644 --- a/fixtures/deno/require.cjs +++ b/fixtures/deno/require.cjs @@ -1,6 +1,4 @@ -// eslint-disable-next-line @typescript-eslint/no-var-requires const asModule = require('./module.cjs'); -// eslint-disable-next-line @typescript-eslint/no-var-requires const { message: asExports } = require('./exports.cjs'); console.log(asModule); diff --git a/fixtures/docker/src/docker-compose-server.js b/fixtures/docker/src/docker-compose-server.js index 46993056..704693e6 100644 --- a/fixtures/docker/src/docker-compose-server.js +++ b/fixtures/docker/src/docker-compose-server.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line @typescript-eslint/no-var-requires const http = require('node:http'); const server = http.createServer((_, res) => { diff --git a/fixtures/docker/src/dockerfile-server.js b/fixtures/docker/src/dockerfile-server.js index 26c6e194..12c4d24a 100644 --- a/fixtures/docker/src/dockerfile-server.js +++ b/fixtures/docker/src/dockerfile-server.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line @typescript-eslint/no-var-requires const http = require('node:http'); const server = http.createServer((_, res) => { diff --git a/fixtures/sintax/big-int.ts b/fixtures/sintax/big-int.ts index 6ad353d7..176958bf 100644 --- a/fixtures/sintax/big-int.ts +++ b/fixtures/sintax/big-int.ts @@ -1,3 +1,2 @@ -// eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: BigInt literals are not available when targeting lower than ES2020 export const bigIntValue = 987456321456987456321n; diff --git a/src/configs/poku.ts b/src/configs/poku.ts index b9f5c894..eb53deb2 100644 --- a/src/configs/poku.ts +++ b/src/configs/poku.ts @@ -1,4 +1,5 @@ export const results = { success: 0, fail: 0, + skipped: 0, }; diff --git a/src/modules/essentials/assert.ts b/src/modules/essentials/assert.ts index 8c78f7b2..21b651ee 100644 --- a/src/modules/essentials/assert.ts +++ b/src/modules/essentials/assert.ts @@ -111,7 +111,7 @@ const ifError = ( }; /* c8 ignore start */ -const fail = (message?: ProcessAssertionOptions['message']): void => { +const fail = (message?: ProcessAssertionOptions['message']): never => { processAssert( () => { nodeAssert.fail(message); @@ -122,6 +122,8 @@ const fail = (message?: ProcessAssertionOptions['message']): void => { hideDiff: true, } ); + + process.exit(1); }; /* c8 ignore stop */ diff --git a/src/modules/helpers/assert-promise.ts b/src/modules/helpers/assert-promise.ts index 47c03aa1..ecbe548c 100644 --- a/src/modules/helpers/assert-promise.ts +++ b/src/modules/helpers/assert-promise.ts @@ -119,7 +119,7 @@ const ifError = async ( /* c8 ignore start */ const fail = async ( message?: ProcessAssertionOptions['message'] -): Promise => { +): Promise => { await processAssert( () => { nodeAssert.fail(message); @@ -130,6 +130,8 @@ const fail = async ( hideDiff: true, } ); + + process.exit(1); }; /* c8 ignore stop */ diff --git a/src/modules/helpers/exit.ts b/src/modules/helpers/exit.ts index 56999ed8..69c7fc2b 100644 --- a/src/modules/helpers/exit.ts +++ b/src/modules/helpers/exit.ts @@ -24,7 +24,7 @@ export const exit = (code: Code, quiet?: boolean) => { ); Write.hr(); Write.log( - `${format(` PASS › ${results.success} `).bg('green')} ${format(` FAIL › ${results.fail} `).bg(results.fail === 0 ? 'grey' : 'red')}` + `${format(` PASS › ${results.success - results.skipped} `).bg('green')} ${format(` FAIL › ${results.fail} `).bg(results.fail === 0 ? 'grey' : 'red')} ${results.skipped > 0 ? format(` SKIPPED › ${results.skipped} `).bg(results.skipped === 0 ? 'grey' : 'blue') : ''}` ); Write.hr(); } diff --git a/src/modules/helpers/skip.ts b/src/modules/helpers/skip.ts new file mode 100644 index 00000000..eb0ee404 --- /dev/null +++ b/src/modules/helpers/skip.ts @@ -0,0 +1,22 @@ +import { exit, env } from 'node:process'; +import { Write } from '../../services/write.js'; +import { format } from '../../services/format.js'; + +export const skip = (message?: string) => { + const isPoku = typeof env?.FILE === 'string' && env?.FILE.length > 0; + const FILE = env.FILE; + + if (message) { + Write.log( + format( + isPoku + ? `ℹ ${message} ${format('›').dim()} ${format(`${FILE}`).italic().gray().dim()}` + : `ℹ ${message}` + ) + .info() + .bold() + ); + } + + exit(0); +}; diff --git a/src/modules/helpers/wait-for.ts b/src/modules/helpers/wait-for.ts index c40e88bd..3ded5051 100644 --- a/src/modules/helpers/wait-for.ts +++ b/src/modules/helpers/wait-for.ts @@ -62,7 +62,6 @@ export const waitForExpectedResult = async ( const startTime = Date.now(); - // eslint-disable-next-line no-constant-condition while (true) { const result = await callback(); diff --git a/src/modules/index.ts b/src/modules/index.ts index 84830146..31b7e70d 100755 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -3,6 +3,7 @@ export { assert } from './essentials/assert.js'; export { test } from './helpers/test.js'; export { describe } from './helpers/describe.js'; export { it } from './helpers/it.js'; +export { skip } from './helpers/skip.js'; export { beforeEach, afterEach } from './helpers/each.js'; export { docker } from './helpers/container.js'; export { startScript, startService } from './helpers/create-service.js'; diff --git a/src/parsers/output.ts b/src/parsers/output.ts index fba4c867..e7281f29 100644 --- a/src/parsers/output.ts +++ b/src/parsers/output.ts @@ -1,9 +1,11 @@ /* c8 ignore next */ // Types import type { Configs } from '../@types/poku.js'; +import { results } from '../configs/poku.js'; const regex = { newLine: /\n/, ansi: /u001b\[0m|\n/i, + skipped: /^"\\u001b\[94m\\u001b\[1mℹ/i, } as const; export const isQuiet = (configs?: Configs): boolean => @@ -19,6 +21,11 @@ export const parserOutput = (options: { configs?: Configs; }) => { const { output, result, configs } = options; + const normalizedOutput = JSON.stringify(output); + + if (regex.skipped.test(normalizedOutput)) { + ++results.skipped; + } const debug = isDebug(configs); const pad = configs?.parallel ? ' ' : ' '; diff --git a/test/e2e/cli.test.ts b/test/e2e/cli.test.ts index c40dbfcb..c8b9b018 100644 --- a/test/e2e/cli.test.ts +++ b/test/e2e/cli.test.ts @@ -2,11 +2,12 @@ import { test } from '../../src/modules/helpers/test.js'; import { assert } from '../../src/modules/essentials/assert.js'; import { executeCLI, ext, isProduction } from '../helpers/capture-cli.test.js'; import { getRuntime } from '../../src/parsers/get-runtime.js'; +import { skip } from '../../src/modules/helpers/skip.js'; const runtime = getRuntime(); if (runtime === 'deno' && !isProduction) { - process.exit(0); + skip(); } test('Poku Test Runner: CLI', async () => { diff --git a/test/e2e/runners.test.ts b/test/e2e/runners.test.ts index 4be2c0e9..c18f19cf 100644 --- a/test/e2e/runners.test.ts +++ b/test/e2e/runners.test.ts @@ -1,12 +1,12 @@ -import process from 'node:process'; import { execSync } from 'node:child_process'; import { describe } from '../../src/modules/helpers/describe.js'; import { it } from '../../src/modules/helpers/it.js'; import { assert } from '../../src/modules/essentials/assert.js'; import { isProduction, inspectCLI } from '../helpers/capture-cli.test.js'; +import { skip } from '../../src/modules/helpers/skip.js'; if (isProduction) { - process.exit(0); + skip(); } const hasNode = (() => { diff --git a/test/integration/before-and-after-each/external-file-update.test.ts b/test/integration/before-and-after-each/external-file-update.test.ts index 878b2da7..c92942c4 100644 --- a/test/integration/before-and-after-each/external-file-update.test.ts +++ b/test/integration/before-and-after-each/external-file-update.test.ts @@ -1,8 +1,8 @@ -import process from 'node:process'; import { nodeVersion, getRuntime } from '../../../src/parsers/get-runtime.js'; +import { skip } from '../../../src/modules/helpers/skip.js'; if (nodeVersion && nodeVersion < 16) { - process.exit(0); + skip(); } import fs from 'node:fs'; @@ -14,7 +14,7 @@ import { assert } from '../../../src/modules/essentials/assert.js'; const runtime = getRuntime(); if (runtime === 'deno') { - process.exit(0); + skip(); } const jsonFilePath = path.resolve('./test-before-and-after-each.json'); diff --git a/test/integration/containers/test-docker-compose.test.ts b/test/integration/containers/test-docker-compose.test.ts index b676790e..2ef2b786 100644 --- a/test/integration/containers/test-docker-compose.test.ts +++ b/test/integration/containers/test-docker-compose.test.ts @@ -2,16 +2,14 @@ import { execSync } from 'node:child_process'; import { describe } from '../../../src/modules/helpers/describe.js'; import { it } from '../../../src/modules/helpers/it.js'; import { assert } from '../../../src/modules/essentials/assert.js'; -import { Write } from '../../../src/services/write.js'; -import { format } from '../../../src/services/format.js'; import { docker } from '../../../src/modules/helpers/container.js'; import { legacyFetch } from '../../helpers/legacy-fetch.test.js'; import { isWindows } from '../../../src/parsers/get-runner.js'; import { waitForPort } from '../../../src/modules/helpers/wait-for.js'; +import { skip } from '../../../src/modules/helpers/skip.js'; -// External error: no matching manifest for windows/amd64 if (isWindows) { - process.exit(0); + skip('External error: no matching manifest for windows/amd64'); } const hasDockerCompose = (() => { @@ -25,10 +23,7 @@ const hasDockerCompose = (() => { describe('Docker Compose Service', async () => { if (!hasDockerCompose) { - Write.log( - format(' ℹ Skipping: Docker Compose not found').success().bold() - ); - return; + skip('Docker Compose not found'); } await it('Using all configs', async () => { diff --git a/test/integration/containers/test-dockerfile.test.ts b/test/integration/containers/test-dockerfile.test.ts index be9c6511..1c31ee3b 100644 --- a/test/integration/containers/test-dockerfile.test.ts +++ b/test/integration/containers/test-dockerfile.test.ts @@ -2,16 +2,14 @@ import { execSync } from 'node:child_process'; import { describe } from '../../../src/modules/helpers/describe.js'; import { it } from '../../../src/modules/helpers/it.js'; import { assert } from '../../../src/modules/essentials/assert.js'; -import { Write } from '../../../src/services/write.js'; -import { format } from '../../../src/services/format.js'; import { docker } from '../../../src/modules/helpers/container.js'; import { waitForPort } from '../../../src/modules/helpers/wait-for.js'; import { legacyFetch } from '../../helpers/legacy-fetch.test.js'; import { isWindows } from '../../../src/parsers/get-runner.js'; +import { skip } from '../../../src/modules/helpers/skip.js'; -// External error: no matching manifest for windows/amd64 if (isWindows) { - process.exit(0); + skip('External error: no matching manifest for windows/amd64'); } const hasDocker = (() => { @@ -25,8 +23,7 @@ const hasDocker = (() => { describe('Docker Service', async () => { if (!hasDocker) { - Write.log(format(' ℹ Skipping: Docker not found').success().bold()); - return; + skip('Docker not found'); } await it('Using custom configs', async () => { diff --git a/test/integration/import.test.ts b/test/integration/import.test.ts index 16829044..dd240ec8 100644 --- a/test/integration/import.test.ts +++ b/test/integration/import.test.ts @@ -15,6 +15,7 @@ index.test('Import Suite', () => { index.assert.ok(index.afterEach, 'Importing afterEach helper'); index.assert.ok(index.log, 'Importing log helper'); index.assert.ok(index.test, 'Importing test helper'); + index.assert.ok(index.skip, 'Importing skip helper'); index.assert.ok(index.sleep, 'Importing sleep helper'); index.assert.ok( index.waitForExpectedResult, diff --git a/test/unit/deno/cjs.test.ts b/test/unit/deno/cjs.test.ts index e7af7f99..6a292c0a 100644 --- a/test/unit/deno/cjs.test.ts +++ b/test/unit/deno/cjs.test.ts @@ -2,12 +2,13 @@ import process from 'node:process'; import { spawn } from 'node:child_process'; import { test } from '../../../src/modules/helpers/test.js'; import { assert } from '../../../src/modules/essentials/assert.js'; +import { skip } from '../../../src/modules/helpers/skip.js'; import { getRuntime } from '../../../src/parsers/get-runtime.js'; const runtime = getRuntime(); if (runtime !== 'deno') { - process.exit(0); + skip('Skipping for non-Deno platforms'); } test('Deno Compatibility', async () => { diff --git a/test/unit/map-tests.test.ts b/test/unit/map-tests.test.ts index 55503dd5..d55cee78 100644 --- a/test/unit/map-tests.test.ts +++ b/test/unit/map-tests.test.ts @@ -1,8 +1,8 @@ -import process from 'node:process'; import { nodeVersion } from '../../src/parsers/get-runtime.js'; +import { skip } from '../../src/modules/helpers/skip.js'; if (nodeVersion && nodeVersion < 14) { - process.exit(0); + skip(); } import { join } from 'node:path'; diff --git a/test/unit/watch.test.ts b/test/unit/watch.test.ts index f2cbd113..384313ce 100644 --- a/test/unit/watch.test.ts +++ b/test/unit/watch.test.ts @@ -1,4 +1,3 @@ -import process from 'node:process'; import fs from 'node:fs'; import path from 'node:path'; import { it } from '../../src/modules/helpers/it.js'; @@ -8,10 +7,11 @@ import { assert } from '../../src/modules/essentials/assert.js'; import { getRuntime, nodeVersion } from '../../src/parsers/get-runtime.js'; import { watch } from '../../src/services/watch.js'; import { sleep } from '../../src/modules/helpers/wait-for.js'; +import { skip } from '../../src/modules/helpers/skip.js'; import type { WatchCallback } from '../../src/@types/watch.js'; if (nodeVersion && nodeVersion < 10) { - process.exit(0); + skip('rmSync is available from Node.js 10 onwards'); } const runtime = getRuntime(); diff --git a/website/docs/documentation/helpers/before-after-each/_category_.json b/website/docs/documentation/helpers/before-after-each/_category_.json index f5df1e30..8e1609a9 100644 --- a/website/docs/documentation/helpers/before-after-each/_category_.json +++ b/website/docs/documentation/helpers/before-after-each/_category_.json @@ -4,5 +4,5 @@ "link": { "type": "generated-index" }, - "position": 4 + "position": 5 } diff --git a/website/docs/documentation/helpers/containers.mdx b/website/docs/documentation/helpers/containers.mdx index f1d7a7f5..5764ef3f 100644 --- a/website/docs/documentation/helpers/containers.mdx +++ b/website/docs/documentation/helpers/containers.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 5 +sidebar_position: 6 tags: [containers] --- diff --git a/website/docs/documentation/helpers/processes/_category_.json b/website/docs/documentation/helpers/processes/_category_.json index bffd446f..d731d606 100644 --- a/website/docs/documentation/helpers/processes/_category_.json +++ b/website/docs/documentation/helpers/processes/_category_.json @@ -4,5 +4,5 @@ "link": { "type": "generated-index" }, - "position": 8 + "position": 9 } diff --git a/website/docs/documentation/helpers/skip.mdx b/website/docs/documentation/helpers/skip.mdx new file mode 100644 index 00000000..f3b24fc5 --- /dev/null +++ b/website/docs/documentation/helpers/skip.mdx @@ -0,0 +1,53 @@ +--- +sidebar_position: 4 +--- + +# ⏭️ skip + +You can skip tests when necessary: + +```ts +import { skip } from 'poku'; + +skip(); +``` + +You can also pass an optional message to `skip` method: + +```ts +import { skip } from 'poku'; + +skip('Skipping for some reason'); +``` + +:::important +This will skip the entire file and it's recommended to be used at the top of the test file. +::: + +--- + +## Examples + +Imagine that a specific test doesn't work on a specific _OS_: + +```ts +import { test, skip } from 'poku'; +// highlight-start +import { platform } from 'node:process'; + +const isWindows = platform === 'win32'; + +// highlight-end +if (isWindows) skip('Skipping due to incompatibility with Windows'); + +// Runs tests normally on other operating systems +// highlight-start +test(() => { + // ... +}); +// highlight-end +``` + +:::note +Skipped tests are considered successful tests. +::: diff --git a/website/docs/documentation/helpers/startScript.mdx b/website/docs/documentation/helpers/startScript.mdx index 20491edf..6498d9e8 100644 --- a/website/docs/documentation/helpers/startScript.mdx +++ b/website/docs/documentation/helpers/startScript.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 6 +sidebar_position: 7 tags: [background, server, service, package.json, scripts] --- diff --git a/website/docs/documentation/helpers/startService.mdx b/website/docs/documentation/helpers/startService.mdx index 8ecda9dc..0e1d6075 100644 --- a/website/docs/documentation/helpers/startService.mdx +++ b/website/docs/documentation/helpers/startService.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 7 +sidebar_position: 8 tags: [background, server, service] ---