From 526112c26fa028895487004101dc66f0fd72837e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Weslley=20Ara=C3=BAjo?= <46850407+wellwelwel@users.noreply.github.com> Date: Thu, 1 Aug 2024 02:58:03 -0300 Subject: [PATCH] feat: add `.todo` helper for `describe`, `it`, and `test` (#633) * ci: add `todo` tdd * refactor: adjusts unreached lines * chore: adjust ignored paths * feat: add `.todo` helper for `describe`, `it`, and `test` * ci: add failure tests * ci: improve Windows timeout * ci: improve coverage * ci: improve coverage * docs: improve documentation * chore: adjust table size * docs: improve docs guides * docs: add `.todo` documentation and examples --- .github/workflows/ci_coverage-windows.yml | 2 +- CONTRIBUTING.md | 10 +++ README.md | 29 ++++++++- .../final-results/skip-and-todo/skip.test.ts | 3 + .../final-results/skip-and-todo/todo.test.ts | 3 + .../skip-todo-and-failure/failure.test.ts | 3 + .../skip-todo-and-failure/skip.test.ts | 3 + .../skip-todo-and-failure/todo.test.ts | 3 + fixtures/final-results/skip/skip.test.ts | 3 + fixtures/final-results/todo/todo.test.ts | 3 + fixtures/schemas/options.json | 2 +- src/bin/index.ts | 12 +++- src/configs/poku.ts | 3 +- src/modules/essentials/poku.ts | 8 +-- src/modules/helpers/describe.ts | 17 ++++-- src/modules/helpers/exit.ts | 33 ++++++++-- src/modules/helpers/it/core.ts | 5 +- src/modules/helpers/it/todo.ts | 9 +++ src/modules/helpers/list-files.ts | 2 +- src/modules/helpers/skip.ts | 6 +- src/parsers/output.ts | 11 +++- src/services/format.ts | 5 ++ src/services/watch.ts | 18 +++--- test/c8.test.ts | 18 +++--- test/e2e/final-results.test.ts | 53 ++++++++++++++++ test/e2e/ignored-paths.test.ts | 42 +++++++++++++ test/integration/describe/todo.test.ts | 9 +++ test/integration/it/it.test.ts | 2 +- test/integration/it/todo.test.ts | 10 +++ test/integration/test/test.test.ts | 2 +- test/integration/test/todo.test.ts | 10 +++ test/unit/wait-for/wait-for-trhows.test.ts | 50 +++++++++++++++ website/README.md | 2 +- .../documentation/helpers/startScript.mdx | 2 +- .../documentation/helpers/startService.mdx | 2 +- website/docs/documentation/helpers/todo.mdx | 61 +++++++++++++++++++ .../docs/documentation/poku/config-files.mdx | 6 +- .../docs/documentation/poku/include-files.mdx | 12 ++-- website/docs/examples/local-server.mdx | 1 + website/docs/philosophy.mdx | 12 ++-- website/docs/tutorials/beginner.mdx | 4 +- website/docs/tutorials/cross-platform.mdx | 6 +- website/docs/tutorials/good-practices.mdx | 4 +- website/sidebars.ts | 12 ++-- 44 files changed, 433 insertions(+), 80 deletions(-) create mode 100644 fixtures/final-results/skip-and-todo/skip.test.ts create mode 100644 fixtures/final-results/skip-and-todo/todo.test.ts create mode 100644 fixtures/final-results/skip-todo-and-failure/failure.test.ts create mode 100644 fixtures/final-results/skip-todo-and-failure/skip.test.ts create mode 100644 fixtures/final-results/skip-todo-and-failure/todo.test.ts create mode 100644 fixtures/final-results/skip/skip.test.ts create mode 100644 fixtures/final-results/todo/todo.test.ts create mode 100644 src/modules/helpers/it/todo.ts create mode 100644 test/e2e/final-results.test.ts create mode 100644 test/e2e/ignored-paths.test.ts create mode 100644 test/integration/describe/todo.test.ts create mode 100644 test/integration/it/todo.test.ts create mode 100644 test/integration/test/todo.test.ts create mode 100644 test/unit/wait-for/wait-for-trhows.test.ts create mode 100644 website/docs/documentation/helpers/todo.mdx diff --git a/.github/workflows/ci_coverage-windows.yml b/.github/workflows/ci_coverage-windows.yml index 0b8a0cc3..76347148 100644 --- a/.github/workflows/ci_coverage-windows.yml +++ b/.github/workflows/ci_coverage-windows.yml @@ -10,7 +10,7 @@ on: jobs: windows: runs-on: windows-latest - timeout-minutes: 5 + timeout-minutes: 10 strategy: fail-fast: false name: Windows diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b8d8fa3b..77ee0b71 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,13 +48,23 @@ It's better to discuss an **API** before actually start implementing it. You can Check if there is an existing section or feel free to create a new one. You can find the wesite source code at [./website](https://github.com/wellwelwel/poku/tree/main/website). +- Feel free to open PRs fixing typos or adding support for other languages 🤝 +
Before commiting, consider to run: ```sh cd website + +# Installing dependencies +npm ci + +# Fixing lint rules npm run lint:fix + +# Testing +npm run test ```
diff --git a/README.md b/README.md index b56b34a8..eb963fcb 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Enjoying **Poku**? Give him a star to show your support 🌟 check Run **CommonJS** files directly with [**Deno**][deno-version-url]
check Auto detect **ESM**, **CJS**, and **TypeScript** files
check Run the **same test suite** for [**Node.js**][node-version-url], [**Bun**][bun-version-url], and [**Deno**][deno-version-url]
-check Easily handle **servers**, **processes**, **ports**, and **containers** ✨ +check Easily handle **servers**, **processes**, **ports**, and even **containers** ✨ --- @@ -37,20 +37,43 @@ Enjoying **Poku**? Give him a star to show your support 🌟 ### check Install + + + + + + + +
+ ```bash # Node.js npm i -D poku +``` + + +```bash # TypeScript (Node.js) npm i -D poku tsx +``` + + +```bash # Bun bun add -d poku +``` + + -# Deno +```bash +# Deno (optional) deno add npm:poku ``` +
+ --- ### check Test @@ -220,8 +243,8 @@ To see the detailed documentation, please visit the [**Documentation**](https:// - [Avoiding conflicts in environments with multiple platforms installed](https://poku.io/docs/tutorials/cross-platform#recommendations). - [Properly running asynchronous tests on the same file](https://poku.io/docs/examples/promises). -- [Migrating from version **1.x** to version **2.x**](https://github.com/wellwelwel/poku/issues/533). - [Using **Poku** without installing on **Deno** and alternatives to **JSR**](https://github.com/wellwelwel/poku/discussions/565). +- [Migrating from version **1.x** to version **2.x**](https://github.com/wellwelwel/poku/issues/533). --- diff --git a/fixtures/final-results/skip-and-todo/skip.test.ts b/fixtures/final-results/skip-and-todo/skip.test.ts new file mode 100644 index 00000000..9b9526ac --- /dev/null +++ b/fixtures/final-results/skip-and-todo/skip.test.ts @@ -0,0 +1,3 @@ +import { skip } from '../../../src/modules/helpers/skip.js'; + +skip('Some skip'); diff --git a/fixtures/final-results/skip-and-todo/todo.test.ts b/fixtures/final-results/skip-and-todo/todo.test.ts new file mode 100644 index 00000000..e3db8c9f --- /dev/null +++ b/fixtures/final-results/skip-and-todo/todo.test.ts @@ -0,0 +1,3 @@ +import { test } from '../../../src/modules/helpers/test.js'; + +test.todo('Some todo'); diff --git a/fixtures/final-results/skip-todo-and-failure/failure.test.ts b/fixtures/final-results/skip-todo-and-failure/failure.test.ts new file mode 100644 index 00000000..40f3bbc8 --- /dev/null +++ b/fixtures/final-results/skip-todo-and-failure/failure.test.ts @@ -0,0 +1,3 @@ +import { exit } from 'node:process'; + +exit(1); diff --git a/fixtures/final-results/skip-todo-and-failure/skip.test.ts b/fixtures/final-results/skip-todo-and-failure/skip.test.ts new file mode 100644 index 00000000..9b9526ac --- /dev/null +++ b/fixtures/final-results/skip-todo-and-failure/skip.test.ts @@ -0,0 +1,3 @@ +import { skip } from '../../../src/modules/helpers/skip.js'; + +skip('Some skip'); diff --git a/fixtures/final-results/skip-todo-and-failure/todo.test.ts b/fixtures/final-results/skip-todo-and-failure/todo.test.ts new file mode 100644 index 00000000..e3db8c9f --- /dev/null +++ b/fixtures/final-results/skip-todo-and-failure/todo.test.ts @@ -0,0 +1,3 @@ +import { test } from '../../../src/modules/helpers/test.js'; + +test.todo('Some todo'); diff --git a/fixtures/final-results/skip/skip.test.ts b/fixtures/final-results/skip/skip.test.ts new file mode 100644 index 00000000..9b9526ac --- /dev/null +++ b/fixtures/final-results/skip/skip.test.ts @@ -0,0 +1,3 @@ +import { skip } from '../../../src/modules/helpers/skip.js'; + +skip('Some skip'); diff --git a/fixtures/final-results/todo/todo.test.ts b/fixtures/final-results/todo/todo.test.ts new file mode 100644 index 00000000..e3db8c9f --- /dev/null +++ b/fixtures/final-results/todo/todo.test.ts @@ -0,0 +1,3 @@ +import { test } from '../../../src/modules/helpers/test.js'; + +test.todo('Some todo'); diff --git a/fixtures/schemas/options.json b/fixtures/schemas/options.json index c4a345d4..c67e8ec4 100644 --- a/fixtures/schemas/options.json +++ b/fixtures/schemas/options.json @@ -13,7 +13,7 @@ "items": { "type": "string" }, - "description": "Specify the path(s) to include in the configuration.\nhttps://poku.io/docs/documentation/poku/include-files", + "description": "Specify the path(s) to include in the configuration. Doesn't support glob patterns.\nhttps://poku.io/docs/documentation/poku/include-files", "default": "." }, "parallel": { diff --git a/src/bin/index.ts b/src/bin/index.ts index f9c64f00..566a90eb 100644 --- a/src/bin/index.ts +++ b/src/bin/index.ts @@ -20,7 +20,8 @@ import { getConfigs } from '../parsers/options.js'; const defaultConfigs = await getConfigs(configFile); const dirs: string[] = (() => { - const includeArg = getArg('include'); // deprecated + /* c8 ignore next 4 */ // Deprecated + const includeArg = getArg('include'); if (includeArg !== undefined) { return includeArg.split(','); } @@ -38,6 +39,7 @@ import { getConfigs } from '../parsers/options.js'; const killPort = getArg('kill-port'); const killRange = getArg('kill-range'); const killPID = getArg('kill-pid'); + /* c8 ignore start */ // Deno const denoAllow = argToArray('deno-allow') ?? defaultConfigs?.deno?.allow; const denoDeny = argToArray('deno-deny') ?? defaultConfigs?.deno?.deny; const denoCJS = @@ -47,6 +49,7 @@ import { getConfigs } from '../parsers/options.js'; .filter((a) => a) || hasArg('deno-cjs') || defaultConfigs?.deno?.cjs; + /* c8 ignore stop */ const parallel = hasArg('parallel') || hasArg('p', '-') || defaultConfigs?.parallel; const quiet = hasArg('quiet') || hasArg('q', '-') || defaultConfigs?.quiet; @@ -70,6 +73,7 @@ import { getConfigs } from '../parsers/options.js'; const tasks: Promise[] = []; + /* c8 ignore start */ // Process-based if (killPort || defaultConfigs?.kill?.port) { const ports = killPort?.split(',').map(Number) || defaultConfigs?.kill?.port || []; @@ -96,6 +100,7 @@ import { getConfigs } from '../parsers/options.js'; tasks.push(kill.pid(PIDs)); } + /* c8 ignore stop */ if (hasEnvFile || defaultConfigs?.envFile) { const envFilePath = getArg('env-file') ?? defaultConfigs?.envFile; @@ -104,6 +109,7 @@ import { getConfigs } from '../parsers/options.js'; } const options: Configs = { + /* c8 ignore next 11 */ // Varies Platform platform: platformIsValid(platform) ? platform : hasArg('node') @@ -152,6 +158,7 @@ import { getConfigs } from '../parsers/options.js'; let isRunning = false; + /* c8 ignore start */ // Process-based const listenStdin = (input: Buffer | string) => { if (isRunning || executing.size > 0) { return; @@ -167,6 +174,7 @@ import { getConfigs } from '../parsers/options.js'; startTests(); } }; + /* c8 ignore stop */ const resultsClear = () => { fileResults.success.clear(); @@ -184,6 +192,7 @@ import { getConfigs } from '../parsers/options.js'; poku(dirs, options) .then(() => { if (watchMode) { + /* c8 ignore next 2 */ // Process-based process.stdin.removeListener('data', listenStdin); process.removeListener('SIGINT', onSigint); resultsClear(); @@ -245,6 +254,7 @@ import { getConfigs } from '../parsers/options.js'; `${format('Watching:').bold()} ${format(dirs.join(', ')).underline()}` ); + /* c8 ignore next 2 */ // Process-based process.stdin.setEncoding('utf-8'); process.stdin.on('data', listenStdin); } diff --git a/src/configs/poku.ts b/src/configs/poku.ts index eb53deb2..8960d5c8 100644 --- a/src/configs/poku.ts +++ b/src/configs/poku.ts @@ -1,5 +1,6 @@ export const results = { success: 0, fail: 0, - skipped: 0, + skip: 0, + todo: 0, }; diff --git a/src/modules/essentials/poku.ts b/src/modules/essentials/poku.ts index 710fba72..90d163c4 100644 --- a/src/modules/essentials/poku.ts +++ b/src/modules/essentials/poku.ts @@ -8,13 +8,13 @@ import { format, showTestResults } from '../../services/format.js'; import { isQuiet } from '../../parsers/output.js'; import { finalResults } from '../../configs/files.js'; -/* c8 ignore next 3 */ // Process-based +/* c8 ignore start */ // Process-based export const onSigint = () => { process.stdout.write('\u001B[?25h'); }; -/* c8 ignore next */ // Process-based process.once('SIGINT', onSigint); +/* c8 ignore stop */ export async function poku( targetPaths: string | string[], @@ -33,8 +33,7 @@ export async function poku( finalResults.started = new Date(); const start = process.hrtime(); - const prepareDirs = Array.prototype.concat(targetPaths); - const dirs = prepareDirs.length > 0 ? prepareDirs : ['.']; + const dirs = Array.prototype.concat(targetPaths); const showLogs = !isQuiet(configs); // Sequential @@ -62,7 +61,6 @@ export async function poku( showLogs && showTestResults(); exit(code, configs?.quiet); - return; } // Parallel diff --git a/src/modules/helpers/describe.ts b/src/modules/helpers/describe.ts index 43f359c3..01764515 100644 --- a/src/modules/helpers/describe.ts +++ b/src/modules/helpers/describe.ts @@ -3,16 +3,17 @@ import { hrtime, env } from 'node:process'; import { format } from '../../services/format.js'; import { Write } from '../../services/write.js'; import { indentation } from '../../configs/indentation.js'; +import { todo } from './it/todo.js'; -export async function describe( +async function describeCore( title: string, cb: () => Promise ): Promise; -export function describe(title: string, cb: () => unknown): void; -export async function describe(cb: () => Promise): Promise; -export function describe(cb: () => unknown): unknown; -export function describe(title: string, options?: DescribeOptions): void; -export async function describe( +function describeCore(title: string, cb: () => unknown): void; +async function describeCore(cb: () => Promise): Promise; +function describeCore(cb: () => unknown): unknown; +function describeCore(title: string, options?: DescribeOptions): void; +async function describeCore( arg1: string | (() => unknown | Promise), arg2?: (() => unknown | Promise) | DescribeOptions ): Promise { @@ -76,3 +77,7 @@ export async function describe( ); } } + +export const describe = Object.assign(describeCore, { + todo, +}); diff --git a/src/modules/helpers/exit.ts b/src/modules/helpers/exit.ts index 3f58fe30..16acfafc 100644 --- a/src/modules/helpers/exit.ts +++ b/src/modules/helpers/exit.ts @@ -6,8 +6,35 @@ import { Write } from '../../services/write.js'; import { fileResults, finalResults } from '../../configs/files.js'; import { parseTime, parseTimeToSecs } from '../../parsers/time.js'; -export const exit = (code: Code, quiet?: boolean) => { +export const exit = (code: Code, quiet?: boolean): never => { const isPoku = results.success > 0 || results.fail > 0; + const success = ` PASS › ${results.success - results.skip || 0} `; + const failure = ` FAIL › ${results.fail} `; + const skips = ` SKIP › ${results.skip} `; + const plans = ` TODO › ${results.todo} `; + const inline = results.skip === 0 || results.todo === 0; + + let message = ''; + + if (inline) { + message += `${format(success).bg('green')} ${format(failure).bg(results.fail === 0 ? 'grey' : 'brightRed')}`; + + if (results.skip) { + message += ` ${format(skips).bg('brightBlue')}`; + } + + if (results.todo) { + message += ` ${format(plans).bg('brightBlue')}`; + } + } else { + message += `${format(success).success().bold()}\n`; + message += + results.fail === 0 + ? format(`${failure}\n`).bold() + : `${format(failure).fail().bold()}\n`; + message += `${format(skips).info().bold()}\n`; + message += `${format(plans).info().bold()}`; + } !quiet && process.on('exit', (code) => { @@ -23,9 +50,7 @@ export const exit = (code: Code, quiet?: boolean) => { ` ${format(`Test Files › ${format(String(fileResults.success.size + fileResults.fail.size)).bold()}`).dim()}` ); Write.hr(); - Write.log( - `${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.log(message); Write.hr(); } diff --git a/src/modules/helpers/it/core.ts b/src/modules/helpers/it/core.ts index 7c133b75..584a85e5 100644 --- a/src/modules/helpers/it/core.ts +++ b/src/modules/helpers/it/core.ts @@ -3,6 +3,7 @@ import { each } from '../../../configs/each.js'; import { indentation } from '../../../configs/indentation.js'; import { format } from '../../../services/format.js'; import { Write } from '../../../services/write.js'; +import { todo } from './todo.js'; async function itCore( message: string, @@ -89,4 +90,6 @@ async function itCore( } } -export const it = Object.assign(itCore, {}); +export const it = Object.assign(itCore, { + todo, +}); diff --git a/src/modules/helpers/it/todo.ts b/src/modules/helpers/it/todo.ts new file mode 100644 index 00000000..0c4d0100 --- /dev/null +++ b/src/modules/helpers/it/todo.ts @@ -0,0 +1,9 @@ +import { Write } from '../../../services/write.js'; +import { indentation } from '../../../configs/indentation.js'; +import { format } from '../../../services/format.js'; + +export const todo = (message: string, _cb?: () => unknown) => { + Write.log( + `${indentation.hasDescribe ? ' ' : ''}${format(`● ${message}`).cyan().bold()}` + ); +}; diff --git a/src/modules/helpers/list-files.ts b/src/modules/helpers/list-files.ts index 0b9c2334..a0eca8c9 100644 --- a/src/modules/helpers/list-files.ts +++ b/src/modules/helpers/list-files.ts @@ -70,7 +70,7 @@ export const getAllFiles = async ( if ( fullPath.indexOf('node_modules') !== -1 || - fullPath.indexOf('.git') === 0 + fullPath.indexOf('.git/') !== -1 ) { return; } diff --git a/src/modules/helpers/skip.ts b/src/modules/helpers/skip.ts index eb0ee404..bff5356e 100644 --- a/src/modules/helpers/skip.ts +++ b/src/modules/helpers/skip.ts @@ -2,7 +2,7 @@ import { exit, env } from 'node:process'; import { Write } from '../../services/write.js'; import { format } from '../../services/format.js'; -export const skip = (message?: string) => { +export const skip = (message = 'Skipping') => { const isPoku = typeof env?.FILE === 'string' && env?.FILE.length > 0; const FILE = env.FILE; @@ -10,8 +10,8 @@ export const skip = (message?: string) => { Write.log( format( isPoku - ? `ℹ ${message} ${format('›').dim()} ${format(`${FILE}`).italic().gray().dim()}` - : `ℹ ${message}` + ? `◯ ${message} ${format('›').dim()} ${format(`${FILE}`).italic().gray().dim()}` + : `◯ ${message}` ) .info() .bold() diff --git a/src/parsers/output.ts b/src/parsers/output.ts index 8fe9897d..b814f479 100644 --- a/src/parsers/output.ts +++ b/src/parsers/output.ts @@ -4,7 +4,8 @@ import { results } from '../configs/poku.js'; const regex = { newLine: /\n/, ansi: /u001b\[0m|\n/i, - skipped: /^"\\u001b\[94m\\u001b\[1mℹ/i, + skip: /\\u001b\[94m\\u001b\[1m◯/i, + todo: /\\u001b\[96m\\u001b\[1m●/i, } as const; export const isQuiet = (configs?: Configs): boolean => @@ -20,8 +21,12 @@ export const parserOutput = (options: { const { output, result, configs } = options; const normalizedOutput = JSON.stringify(output); - if (regex.skipped.test(normalizedOutput)) { - ++results.skipped; + if (regex.skip.test(normalizedOutput)) { + ++results.skip; + } + + if (regex.todo.test(normalizedOutput)) { + ++results.todo; } const debug = isDebug(configs); diff --git a/src/services/format.ts b/src/services/format.ts index c13cc479..35b826e7 100644 --- a/src/services/format.ts +++ b/src/services/format.ts @@ -79,6 +79,11 @@ export class Formatter { return this; } + cyan() { + this.parts += '\x1b[96m'; + return this; + } + bg(color: keyof typeof backgroundColor) { this.parts += `\x1b[${backgroundColor[color]}m\x1b[1m`; return this; diff --git a/src/services/watch.ts b/src/services/watch.ts index 2938ee4d..0548efcb 100644 --- a/src/services/watch.ts +++ b/src/services/watch.ts @@ -77,18 +77,16 @@ export class Watcher { } public async start() { - try { - const stats = await stat(this.rootDir); + const stats = await stat(this.rootDir); - if (stats.isDirectory()) { - this.files = await listFiles(this.rootDir); + if (stats.isDirectory()) { + this.files = await listFiles(this.rootDir); - this.watchFiles(this.files); - await this.watchDirectory(this.rootDir); - } else { - this.watchFile(this.rootDir); - } - } catch {} + this.watchFiles(this.files); + await this.watchDirectory(this.rootDir); + } else { + this.watchFile(this.rootDir); + } } public stop() { diff --git a/test/c8.test.ts b/test/c8.test.ts index 75122097..45372c4d 100644 --- a/test/c8.test.ts +++ b/test/c8.test.ts @@ -21,7 +21,7 @@ test(async () => { await describe('CLI', async () => { await it('Sequential (Just Touch)', async () => { const results = await inspectCLI( - 'npx tsx src/bin/index.ts --platform=node --include=test/integration/import.test.ts' + 'npx tsx src/bin/index.ts --platform=node test/integration/import.test.ts' ); console.log(results.stdout); @@ -32,7 +32,7 @@ test(async () => { await it('Parallel (Just Touch)', async () => { const results = await inspectCLI( - 'npx tsx src/bin/index.ts --platform=node --parallel --include=test/integration/import.test.ts' + 'npx tsx src/bin/index.ts --platform=node --parallel test/integration/import.test.ts' ); console.log(results.stdout); @@ -43,7 +43,7 @@ test(async () => { await it('Parallel (FILTER Env)', async () => { const results = await inspectCLI( - 'npx tsx src/bin/index.ts --platform=node --parallel --include=test/integration', + 'npx tsx src/bin/index.ts --platform=node --parallel test/integration', { env: { ...process.env, FILTER: 'import' }, } @@ -58,8 +58,8 @@ test(async () => { await it('Sequential + Options (Just Touch)', async () => { const results = await inspectCLI( isWindows - ? 'npx tsx src/bin/index.ts --concurrency=4 --platform=node --fast-fail --debug --exclude=".bak" --kill-port=4000 --kill-range="4000-4001" --include=test/integration/import.test.ts --filter=".test.|.spec."' - : 'npx tsx src/bin/index.ts --concurrency=4 --platform=node --fast-fail --debug --exclude=.bak --kill-port=4000 --kill-range=4000-4001 --include=test/integration/import.test.ts --filter=.test.|.spec.' + ? 'npx tsx src/bin/index.ts --concurrency=4 --platform=node --fast-fail --debug --exclude=".bak" --kill-port=4000 --kill-range="4000-4001" test/integration/import.test.ts --filter=".test.|.spec."' + : 'npx tsx src/bin/index.ts --concurrency=4 --platform=node --fast-fail --debug --exclude=.bak --kill-port=4000 --kill-range=4000-4001 test/integration/import.test.ts --filter=.test.|.spec.' ); console.log(results.stdout); @@ -71,8 +71,8 @@ test(async () => { await it('Parallel + Options (Just Touch)', async () => { const results = await inspectCLI( isWindows - ? 'npx tsx src/bin/index.ts --parallel --concurrency=4 --platform=node --fast-fail --debug --exclude=".bak" --kill-port=4000 --kill-range="4000-4001" --include=test/integration/import.test.ts --filter=".test.|.spec."' - : 'npx tsx src/bin/index.ts --parallel --concurrency=4 --platform=node --fast-fail --debug --exclude=.bak --kill-port=4000 --kill-range=4000-4001 --include=test/integration/import.test.ts --filter=.test.|.spec.' + ? 'npx tsx src/bin/index.ts --parallel --concurrency=4 --platform=node --fast-fail --debug --exclude=".bak" --kill-port=4000 --kill-range="4000-4001" test/integration/import.test.ts --filter=".test.|.spec."' + : 'npx tsx src/bin/index.ts --parallel --concurrency=4 --platform=node --fast-fail --debug --exclude=.bak --kill-port=4000 --kill-range=4000-4001 test/integration/import.test.ts --filter=.test.|.spec.' ); console.log(results.stdout); @@ -84,8 +84,8 @@ test(async () => { await it('Parallel + Options (CLI Env Variables Propagation)', async () => { const results = await inspectCLI( isWindows - ? 'npx tsx src/bin/index.ts --include=test/integration/env --env-file="fixtures/.env.test"' - : 'npx tsx src/bin/index.ts --include=test/integration/env --env-file=fixtures/.env.test', + ? 'npx tsx src/bin/index.ts test/integration/env --env-file="fixtures/.env.test"' + : 'npx tsx src/bin/index.ts test/integration/env --env-file=fixtures/.env.test', { env: { ...env, diff --git a/test/e2e/final-results.test.ts b/test/e2e/final-results.test.ts new file mode 100644 index 00000000..b96d2496 --- /dev/null +++ b/test/e2e/final-results.test.ts @@ -0,0 +1,53 @@ +import { describe } from '../../src/modules/helpers/describe.js'; +import { it } from '../../src/modules/helpers/it/core.js'; +import { assert } from '../../src/modules/essentials/assert.js'; +import { inspectCLI, isProduction } from '../helpers/capture-cli.test.js'; +import { skip } from '../../src/modules/helpers/skip.js'; + +if (isProduction) { + skip(); +} + +describe('Final Results', async () => { + await it('Skip', async () => { + const results = await inspectCLI('npx tsx ../../../src/bin/index.ts', { + cwd: './fixtures/final-results/skip', + }); + + assert.match(results.stdout, /PASS › 0/, 'Needs to pass 0'); + assert.match(results.stdout, /FAIL › 0/, 'Needs to fail 0'); + assert.match(results.stdout, /SKIP › 1/, 'Needs to skip 1'); + }); + + await it('Todo', async () => { + const results = await inspectCLI('npx tsx ../../../src/bin/index.ts', { + cwd: './fixtures/final-results/todo', + }); + + assert.match(results.stdout, /PASS › 1/, 'Needs to pass 1'); + assert.match(results.stdout, /FAIL › 0/, 'Needs to fail 0'); + assert.match(results.stdout, /TODO › 1/, 'Needs to todo 1'); + }); + + await it('Skip + Todo', async () => { + const results = await inspectCLI('npx tsx ../../../src/bin/index.ts', { + cwd: './fixtures/final-results/skip-and-todo', + }); + + assert.match(results.stdout, /PASS › 1/, 'Needs to pass 1'); + assert.match(results.stdout, /FAIL › 0/, 'Needs to fail 0'); + assert.match(results.stdout, /SKIP › 1/, 'Needs to todo 1'); + assert.match(results.stdout, /TODO › 1/, 'Needs to todo 1'); + }); + + await it('Skip + Todo + Failure', async () => { + const results = await inspectCLI('npx tsx ../../../src/bin/index.ts', { + cwd: './fixtures/final-results/skip-todo-and-failure', + }); + + assert.match(results.stdout, /PASS › 1/, 'Needs to pass 1'); + assert.match(results.stdout, /FAIL › 1/, 'Needs to fail 1'); + assert.match(results.stdout, /SKIP › 1/, 'Needs to todo 1'); + assert.match(results.stdout, /TODO › 1/, 'Needs to todo 1'); + }); +}); diff --git a/test/e2e/ignored-paths.test.ts b/test/e2e/ignored-paths.test.ts new file mode 100644 index 00000000..bae8a6c1 --- /dev/null +++ b/test/e2e/ignored-paths.test.ts @@ -0,0 +1,42 @@ +import { join } from 'node:path'; +import { describe } from '../../src/modules/helpers/describe.js'; +import { it } from '../../src/modules/helpers/it/core.js'; +import { assert } from '../../src/modules/essentials/assert.js'; +import { inspectCLI, isProduction } from '../helpers/capture-cli.test.js'; +import { skip } from '../../src/modules/helpers/skip.js'; +import { accessSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'; + +if (isProduction) { + skip(); +} + +const createTestFile = (dirName: string) => { + try { + const baseDir = join('./fixtures/list-files', dirName); + const filePath = join(baseDir, 'a.test.js'); + + mkdirSync(baseDir, { recursive: true }); + + try { + accessSync(filePath); + } catch { + writeFileSync(filePath, ''); + } + } catch {} +}; + +describe('List Files: node_modules and .git', async () => { + createTestFile('.git'); + createTestFile('node_modules'); + + await it('Sequential', async () => { + const results = await inspectCLI('npx tsx ../../src/bin/index.ts', { + cwd: './fixtures/list-files', + }); + + assert.doesNotMatch(results.stdout, /PASS ›/, 'Needs to pass 0'); + assert.doesNotMatch(results.stdout, /FAIL ›/, 'Needs to fail 0'); + }); + + rmSync('./fixtures/list-files', { force: true, recursive: true }); +}); diff --git a/test/integration/describe/todo.test.ts b/test/integration/describe/todo.test.ts new file mode 100644 index 00000000..44659e8e --- /dev/null +++ b/test/integration/describe/todo.test.ts @@ -0,0 +1,9 @@ +import { describe } from '../../../src/modules/helpers/describe.js'; + +describe('Testing "describe.todo" overloads', () => { + describe.todo('Basic todo'); + describe.todo( + 'Ignore callback', + async () => await new Promise((_, reject) => reject(undefined)) + ); +}); diff --git a/test/integration/it/it.test.ts b/test/integration/it/it.test.ts index a650804a..1bca9dd3 100644 --- a/test/integration/it/it.test.ts +++ b/test/integration/it/it.test.ts @@ -2,7 +2,7 @@ import { test } from '../../../src/modules/helpers/test.js'; import { describe } from '../../../src/modules/helpers/describe.js'; import { it } from '../../../src/modules/helpers/it/core.js'; -test('Testing "it" method', () => { +test('Testing "it" overloads', () => { describe(async () => { it(() => {}); it(() => true); diff --git a/test/integration/it/todo.test.ts b/test/integration/it/todo.test.ts new file mode 100644 index 00000000..a9edae7e --- /dev/null +++ b/test/integration/it/todo.test.ts @@ -0,0 +1,10 @@ +import { describe } from '../../../src/modules/helpers/describe.js'; +import { it } from '../../../src/modules/helpers/it/core.js'; + +describe('Testing "it.todo" overloads', () => { + it.todo('Basic todo'); + it.todo( + 'Ignore callback', + async () => await new Promise((_, reject) => reject(undefined)) + ); +}); diff --git a/test/integration/test/test.test.ts b/test/integration/test/test.test.ts index 7d0b175a..87af8389 100644 --- a/test/integration/test/test.test.ts +++ b/test/integration/test/test.test.ts @@ -1,6 +1,6 @@ import { test } from '../../../src/modules/helpers/test.js'; -test('Testing "test" method', async () => { +test('Testing "test" overloads', async () => { test(() => {}); test(() => true); test(() => false); diff --git a/test/integration/test/todo.test.ts b/test/integration/test/todo.test.ts new file mode 100644 index 00000000..3daae7ac --- /dev/null +++ b/test/integration/test/todo.test.ts @@ -0,0 +1,10 @@ +import { describe } from '../../../src/modules/helpers/describe.js'; +import { test } from '../../../src/modules/helpers/test.js'; + +describe('Testing "test.todo" overloads', () => { + test.todo('Basic todo'); + test.todo( + 'Ignore callback', + async () => await new Promise((_, reject) => reject(undefined)) + ); +}); diff --git a/test/unit/wait-for/wait-for-trhows.test.ts b/test/unit/wait-for/wait-for-trhows.test.ts new file mode 100644 index 00000000..c70b4c63 --- /dev/null +++ b/test/unit/wait-for/wait-for-trhows.test.ts @@ -0,0 +1,50 @@ +import { test } from '../../../src/modules/helpers/test.js'; +import { assert } from '../../../src/modules/essentials/assert.js'; +import { + sleep, + waitForExpectedResult, + waitForPort, +} from '../../../src/modules/helpers/wait-for.js'; + +test('Wait For Expected Result: Throws', async () => { + await assert.rejects( + // @ts-expect-error + async () => await sleep(undefined), + 'Invalid milliseconds' + ); + await assert.rejects( + // @ts-expect-error + async () => await waitForExpectedResult(undefined, true), + 'Invalid callback' + ); + await assert.rejects( + async () => + await waitForExpectedResult(() => true, true, { + // @ts-expect-error + interval: true, + }), + 'Invalid interval' + ); + await assert.rejects( + async () => + await waitForExpectedResult(() => true, true, { + // @ts-expect-error + timeout: true, + }), + 'Invalid timeout' + ); + await assert.rejects( + async () => + await waitForExpectedResult(() => true, true, { + // @ts-expect-error + delay: true, + }), + 'Invalid delay' + ); + await assert.rejects( + async () => + // @ts-expect-error + await waitForPort(undefined), + 'Invalid port' + ); +}); diff --git a/website/README.md b/website/README.md index 2b18280d..9ae49351 100644 --- a/website/README.md +++ b/website/README.md @@ -1,3 +1,3 @@ # Website -This [website](https://poku.io) is built using [Docusaurus 3](https://docusaurus.io/), a modern static website generator and [SVPS](https://github.com/wellwelwel/svps) to deploy it. +This [website](https://poku.io) is built using [**Docusaurus 3**](https://docusaurus.io/), a modern static website generator and [**SVPS**](https://github.com/wellwelwel/svps) to deploy it. diff --git a/website/docs/documentation/helpers/startScript.mdx b/website/docs/documentation/helpers/startScript.mdx index 676c6085..9191b9cd 100644 --- a/website/docs/documentation/helpers/startScript.mdx +++ b/website/docs/documentation/helpers/startScript.mdx @@ -1,6 +1,6 @@ --- sidebar_position: 7 -tags: [background, server, service, package.json, scripts] +tags: [background, server, service, package.json, scripts, supertest] --- import Tabs from '@theme/Tabs'; diff --git a/website/docs/documentation/helpers/startService.mdx b/website/docs/documentation/helpers/startService.mdx index 2d1dbd24..996b745f 100644 --- a/website/docs/documentation/helpers/startService.mdx +++ b/website/docs/documentation/helpers/startService.mdx @@ -1,6 +1,6 @@ --- sidebar_position: 8 -tags: [background, server, service] +tags: [background, server, service, supertest] --- import Tabs from '@theme/Tabs'; diff --git a/website/docs/documentation/helpers/todo.mdx b/website/docs/documentation/helpers/todo.mdx new file mode 100644 index 00000000..aa0e03f5 --- /dev/null +++ b/website/docs/documentation/helpers/todo.mdx @@ -0,0 +1,61 @@ +--- +sidebar_position: 10 +tags: [boilerplate] +--- + +# 📋 todo + +`.todo` is an extended helper for `describe`, `it`, and `test` to assist you plan future tests. + +## Basic Usage + +### Simple message + +```ts +import { describe, it, test } from 'poku'; + +describe.todo('todo: Upcoming test'); + +it.todo('todo: Upcoming test'); + +test.todo('todo: Upcoming test'); +``` + +- There is no difference between the features. + +Also in internal contexts: + +```ts +import { describe, it } from 'poku'; + +describe(() => { + it.todo('todo: Upcoming test'); + + it('Real test', () => { + /* ... */ + }); +}); +``` + +### Ignoring a callback + +This can be useful when you already have an idea or prototype of what you want to test, but you don't want the test to actually run.
+It can also be useful for tests that have unexpectedly stopped working due to some external event, requiring further attention. + +```ts +import { describe, it } from 'poku'; + +describe.todo('todo: Upcoming test', () => { + it(async () => { + process.exit(1); + }); +}); +``` + +- The method received by `todo` and everything inside it will be completely ignored. + +
+ +:::note +When using `beforeEach` or `afterEach`, they will not be triggered by tests with `.todo`. +::: diff --git a/website/docs/documentation/poku/config-files.mdx b/website/docs/documentation/poku/config-files.mdx index 37d7c7f6..54cc136d 100644 --- a/website/docs/documentation/poku/config-files.mdx +++ b/website/docs/documentation/poku/config-files.mdx @@ -43,7 +43,7 @@ By default, **Poku** comes with the most common usage pre-set, but you can confi Pros: Supports functions and regex.
- Cons: Needs to be an CommonJS file. + Cons: Needs to be a CommonJS file.
} @@ -55,7 +55,7 @@ Create a `poku.config.js` (or `poku.config.cjs` when using `"type": "module"` in const { defineConfig } = require('poku'); module.exports = defineConfig({ - include: ['.'], + include: ['.'], // Doesn't support glob patterns parallel: false, debug: false, filter: /\.(test.|.spec)\./, @@ -107,7 +107,7 @@ Create a `.pokurc.json` (or `.pokurc.jsonc`) in your project's root directory, f ```js { "$schema": "https://poku.io/schemas/configs.json", - "include": ["."], + "include": ["."], // Doesn't support glob patterns "parallel": false, "debug": false, "filter": ".test.|.spec.", // regex as string diff --git a/website/docs/documentation/poku/include-files.mdx b/website/docs/documentation/poku/include-files.mdx index 4034190c..c316fa1c 100644 --- a/website/docs/documentation/poku/include-files.mdx +++ b/website/docs/documentation/poku/include-files.mdx @@ -45,6 +45,12 @@ npx poku --parallel - Run all tests in parallel. +```bash +npx poku ./test +``` + +- Run all tests in `./test` directory. + :::tip You can pass both directories and files. ::: @@ -55,11 +61,7 @@ It's not possible to run tests in the `.git` and `node_modules` directories.
-### By setting the directories as the last argument - -```bash -npx poku targetPath -``` +### By setting multiple paths ```bash npx poku targetPathA targetPathB diff --git a/website/docs/examples/local-server.mdx b/website/docs/examples/local-server.mdx index ab2683f7..e613bf7a 100644 --- a/website/docs/examples/local-server.mdx +++ b/website/docs/examples/local-server.mdx @@ -1,5 +1,6 @@ --- sidebar_position: 1 +tags: [background, server, service, package.json, scripts, supertest] --- import Tabs from '@theme/Tabs'; diff --git a/website/docs/philosophy.mdx b/website/docs/philosophy.mdx index f9d6b13d..17ff4b45 100644 --- a/website/docs/philosophy.mdx +++ b/website/docs/philosophy.mdx @@ -3,7 +3,7 @@ import TabItem from '@theme/TabItem'; # Philosophy -**Poku**'s philosophy focuses on simplicity and efficiency, removing complexities and boilerplate to make testing accessible for the simplest to the most complex projects. +**Poku**'s philosophy consists of simplicity and efficiency, removing complexities and boilerplate requirements to make testing accessible for the simplest to the most complex projects.
@@ -291,9 +291,11 @@ Although not a priority, there are plans to integrate the following features int They aren't considered breaking changes: -- Formatting and style changes to outputs. -- New functionalities that depend from a specific platform version. -- If a feature is no longer useful due to a new approach. +- Formatting and style changes to outputs _(including reporters — soon)_. +- New functionalities that depend from a specific platform version: + - As long as it doesn't affect basic usability. + - E.g., when using **Node.js** previous to `v15.x.x`, the `strict` method isn't available. +- If a feature is no longer useful due to a new approach _(as long as it doesn't affect the end user)_. - _JSON_ intellisense schema changes _(config files)_.
@@ -306,5 +308,5 @@ They aren't considered breaking changes: - Although these points are taken into consideration, the main aim is to maintain a balance between good practices. :::danger -Note that **Poku** has a different way of being used, inspired entirely by the essence of native JavaScript, which can be both an advantage and a disadvantage for those who are used to the traditional _hooks_ of other test runners. +Note that **Poku** has a different way of being used, inspired entirely by the essence of native **JavaScript**, which can be both an advantage and a disadvantage for those who are used to the traditional _hooks_ of other test runners. ::: diff --git a/website/docs/tutorials/beginner.mdx b/website/docs/tutorials/beginner.mdx index 6e8dbc05..c78a3d36 100644 --- a/website/docs/tutorials/beginner.mdx +++ b/website/docs/tutorials/beginner.mdx @@ -1,5 +1,5 @@ --- -title: Beginner +title: 🐣 Beginner description: From a basic assertion test to its execution. tags: [assert, assertion, tutorial, beginner, roadmap] sidebar_position: 0 @@ -10,7 +10,7 @@ import Junior from '@site/static/img/junior.svg';