diff --git a/README.md b/README.md index 559e7dba..12cc1f60 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,7 @@ Logo -🖇️ A flexible and easy-to-use **Test Runner** for [**Node**][node-version-url], [**Bun**][bun-version-url] and [**Deno**][deno-version-url], which allows parallel or sequential runs and high isolation level. - -> **Poku** starts from the premise where tests come to help, not overcomplicate. +A flexible and easy-to-use **Test Runner** for [Node][node-version-url], [Bun][bun-version-url] and [Deno][deno-version-url] that allows you to run **parallel** and **sequential** tests, plus **high isolation level per test file**. [![Node.js Version][node-version-image]][node-version-url] [![Bun Version][bun-version-image]][bun-version-url] @@ -33,10 +31,10 @@ ## Why Poku? -Runs test files in an individual process, shows progress and exits 🪄 +> **Poku** starts from the premise where tests come to help, not overcomplicate: runs test files in an individual process per file, shows progress and exits 🧙🏻 -- **Poku** is designed to be highly intuitive - Supports **ESM** and **CJS** +- Designed to be highly intuitive - No need to compile **TypeScript** - Compatible with **Coverage** tools - Allows both **in-code** and **CLI** usage @@ -170,7 +168,9 @@ npx poku --include='./targetDirA,./targetDirB' ### `poku(string | string[], configs: Configs)` -#### `filter` +#### `filter: RexExp` + +By default, **Poku** searches for _`*.test.*`_ files, but you can customize it using the `filter` option. > Filter by path using **Regex** to match only the files that should be performed. @@ -207,6 +207,12 @@ poku(['...'], { npx poku --include='...' --filter='some-file' ``` +```bash +# Testing only a specific file + +npx poku --include='...' --filter='some-file|other-file' +``` + ```bash # Testing only paths that contains "unit" @@ -223,6 +229,12 @@ npx poku --include='...' --filter='unit' FILTER='some-file' npx poku --include='...' ``` +```bash +# Testing only a specific file + +FILTER='some-file|other-file' npx poku --include='...' +``` + ```bash # Testing only paths that contains "unit" @@ -231,9 +243,9 @@ FILTER='unit' npx poku --include='...' --- -#### `parallel` +#### `parallel: boolean` -Determines the mode of test execution across **parallelism** or **sequential** modes. +Determines the mode of test execution across **sequential** or **parallel** modes. ```ts /** @@ -259,6 +271,88 @@ poku(['...'], { --- +#### `exclude: RexExp | RexExp[]` + +> Exclude by path using Regex to match only the files that should be performed. + +- **in-code**: + +```ts +/** + * Excluding directories from tests + */ + +poku(['...'], { + exclude: /\/(helpers|tools)\//, +}); +``` + +```ts +/** + * Excluding directories from tests + */ + +poku(['...'], { + exclude: [/\/helpers\//, /\/tools\//], +}); +``` + +```ts +/** + * Excluding specific files from tests + */ + +poku(['...'], { + exclude: /(index|common).test.ts/, +}); +``` + +```ts +/** + * Excluding specific files from tests + */ + +poku(['...'], { + exclude: [/index.test.ts/, /common.test.ts/], +}); +``` + +```ts +/** + * Excluding directories and files from tests + */ + +poku(['...'], { + exclude: /\/(helpers|tools)\/|(index|common).test.ts/, +}); +``` + +```ts +/** + * Excluding directories and files from tests + */ + +poku(['...'], { + exclude: [/\/helpers\//, /\/tools\//, /index.test.ts/, /common.test.ts/], +}); +``` + +- **CLI** + +```bash +# Excluding directories and files from tests + +npx poku --include='...' --exclude='some-file-or-dir' +``` + +```bash +# Excluding directories and files from tests + +npx poku --include='...' --exclude='some-file-or-dir|other-file-or-dir' +``` + +--- + ## Documentation in Progress... > 🧑🏻‍🎓 Soon documenting all options and **Poku**'s usage variations. diff --git a/package.json b/package.json index 188e6339..500ac1bf 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "poku", "version": "1.1.1", - "description": "🐷 A flexible and easy-to-use Test Runner for Node, Bun and Deno, which allows parallel or sequential runs and high isolation level", + "description": "🐷 Poku is a flexible and easy-to-use Test Runner for Node, Bun and Deno that allows you to run parallel and sequential tests, plus high isolation level per test file", "main": "./lib/index.js", "scripts": { "test": "npx tsx --tsconfig ./tsconfig.test.json ./test/run.test.ts", @@ -43,7 +43,11 @@ "typescript", "filter", "queue", - "queuing" + "queuing", + "nodejs", + "node", + "bun", + "deno" ], "author": "https://github.com/wellwelwel", "bugs": { @@ -51,6 +55,7 @@ }, "engines": { "node": ">=6.0.0", + "bun": ">=0.5.3", "deno": ">=1.17.0" }, "files": [ diff --git a/src/@types/get-files.ts b/src/@types/get-files.ts new file mode 100644 index 00000000..70865b5d --- /dev/null +++ b/src/@types/get-files.ts @@ -0,0 +1,14 @@ +export type Configs = { + /** + * Filter by path to match only the files that should be performed. + * + * @default /\.test\./i + */ + filter?: RegExp; + /** + * Exclude by path to match only the files that should be performed. + * + * @default undefined + */ + exclude?: RegExp | RegExp[]; +}; diff --git a/src/@types/poku.ts b/src/@types/poku.ts index ceb8624a..422b77bd 100644 --- a/src/@types/poku.ts +++ b/src/@types/poku.ts @@ -1,3 +1,5 @@ +import type { Configs as GetFileOptions } from './get-files.ts'; + export type Configs = { /** * By setting `true`, **Poku** won't exit the process and will return the exit code (`0` or `1`). @@ -26,16 +28,10 @@ export type Configs = { * @default false */ quiet?: boolean; - /** - * Filter by path to match only the files that should be performed. - * - * @default /\.test\./i - */ - filter?: RegExp; /** * Determines the mode of test execution. * * @default false */ parallel?: boolean; -}; +} & GetFileOptions; diff --git a/src/bin/index.ts b/src/bin/index.ts index 066cb185..c63de402 100644 --- a/src/bin/index.ts +++ b/src/bin/index.ts @@ -1,14 +1,16 @@ #! /usr/bin/env node -import { escapeRegExp } from '../helpers/get-files.js'; +import { escapeRegExp } from '../modules/get-files.js'; import { getArg } from '../helpers/get-arg.js'; import { poku } from '../index.js'; const rawDirs = getArg('include'); const rawFilter = getArg('filter'); +const rawExclude = getArg('exclude'); const dirs = rawDirs?.split(',') || []; poku(dirs, { filter: rawFilter ? new RegExp(escapeRegExp(rawFilter)) : undefined, + exclude: rawExclude ? new RegExp(escapeRegExp(rawExclude)) : undefined, }); diff --git a/src/helpers/get-files.ts b/src/helpers/get-files.ts deleted file mode 100644 index faf6512b..00000000 --- a/src/helpers/get-files.ts +++ /dev/null @@ -1,33 +0,0 @@ -import process from 'node:process'; -import fs from 'node:fs'; -import path from 'node:path'; -import type { Configs } from '../@types/poku.ts'; - -export const escapeRegExp = (string: string) => - string.replace(/[.*+?^${}()[\]\\]/g, '\\$&'); - -export const envFilter = process.env.FILTER?.trim() - ? new RegExp(escapeRegExp(process.env.FILTER), 'i') - : null; - -export const getFiles = ( - dirPath: string, - files: string[] = [], - configs?: Configs -) => { - const currentFiles = fs.readdirSync(dirPath); - const filter: RegExp = - (envFilter ? envFilter : configs?.filter) || /\.test\./i; - - for (const file of currentFiles) { - const fullPath = path.join(dirPath, file); - - if (fs.statSync(fullPath).isDirectory()) { - getFiles(fullPath, files, configs); - } else if (filter.test(fullPath)) { - files.push(fullPath); - } - } - - return files; -}; diff --git a/src/modules/get-files.ts b/src/modules/get-files.ts new file mode 100644 index 00000000..b5e0f698 --- /dev/null +++ b/src/modules/get-files.ts @@ -0,0 +1,43 @@ +import process from 'node:process'; +import fs from 'node:fs'; +import path from 'node:path'; +import type { Configs } from '../@types/get-files.ts'; + +export const escapeRegExp = (string: string) => + string.replace(/[.*+?^${}()[\]\\]/g, '\\$&'); + +const envFilter = process.env.FILTER?.trim() + ? new RegExp(escapeRegExp(process.env.FILTER), 'i') + : null; + +export const getFiles = ( + dirPath: string, + files: string[] = [], + configs?: Configs +) => { + const currentFiles = fs.readdirSync(dirPath); + const defaultRegExp = /\.test\./i; + const filter: RegExp = + (envFilter + ? envFilter + : configs?.filter instanceof RegExp + ? configs.filter + : defaultRegExp) || defaultRegExp; + + const exclude: Configs['exclude'] = configs?.exclude + ? Array.isArray(configs.exclude) + ? configs.exclude + : [configs.exclude] + : undefined; + + for (const file of currentFiles) { + const fullPath = path.join(dirPath, file); + + if (exclude && exclude.some((regex) => regex.test(fullPath))) continue; + + if (fs.statSync(fullPath).isDirectory()) getFiles(fullPath, files, configs); + else if (filter.test(fullPath)) files.push(fullPath); + } + + return files; +}; diff --git a/src/modules/poku.ts b/src/modules/poku.ts index d5fd2f91..e8edc28c 100644 --- a/src/modules/poku.ts +++ b/src/modules/poku.ts @@ -1,7 +1,7 @@ import { Code } from '../@types/code.js'; import { Configs } from '../@types/poku.js'; import { forceArray } from '../helpers/force-array.js'; -import { runTests, runTestsParallel } from '../services/runTests.js'; +import { runTests, runTestsParallel } from '../services/run-tests.js'; import { exit } from './exit.js'; export async function poku( diff --git a/src/services/runTestFile.ts b/src/services/run-test-file.ts similarity index 100% rename from src/services/runTestFile.ts rename to src/services/run-test-file.ts diff --git a/src/services/runTests.ts b/src/services/run-tests.ts similarity index 96% rename from src/services/runTests.ts rename to src/services/run-tests.ts index 09063f80..9c409a6d 100644 --- a/src/services/runTests.ts +++ b/src/services/run-tests.ts @@ -3,10 +3,10 @@ import { EOL } from 'node:os'; import path from 'node:path'; import { runner } from '../helpers/runner.js'; import { indentation } from '../helpers/indentation.js'; -import { getFiles } from '../helpers/get-files.js'; +import { getFiles } from '../modules/get-files.js'; import { hr } from '../helpers/hr.js'; import { format } from '../helpers/format.js'; -import { runTestFile } from './runTestFile.js'; +import { runTestFile } from './run-test-file.js'; import { Configs } from '../@types/poku.js'; import { isQuiet } from '../helpers/logs.js'; @@ -80,5 +80,6 @@ export const runTestsParallel = async ( }); const results = await Promise.all(promises); + return results.every((result) => result); }; diff --git a/test/docker/bun/Dockerfile.0.5.3 b/test/docker/bun/0.5.3.Dockerfile similarity index 100% rename from test/docker/bun/Dockerfile.0.5.3 rename to test/docker/bun/0.5.3.Dockerfile diff --git a/test/docker/bun/Dockerfile.01 b/test/docker/bun/01.Dockerfile similarity index 100% rename from test/docker/bun/Dockerfile.01 rename to test/docker/bun/01.Dockerfile diff --git a/test/docker/bun/Dockerfile.canary b/test/docker/bun/canary.Dockerfile similarity index 100% rename from test/docker/bun/Dockerfile.canary rename to test/docker/bun/canary.Dockerfile diff --git a/test/docker/deno/Dockerfile.1.30.0 b/test/docker/deno/1.30.0.Dockerfile similarity index 100% rename from test/docker/deno/Dockerfile.1.30.0 rename to test/docker/deno/1.30.0.Dockerfile diff --git a/test/docker/deno/Dockerfile.latest b/test/docker/deno/latest.Dockerfile similarity index 100% rename from test/docker/deno/Dockerfile.latest rename to test/docker/deno/latest.Dockerfile diff --git a/test/docker/docker-compose.yml b/test/docker/docker-compose.yml index 28b30eaf..fd1faec7 100644 --- a/test/docker/docker-compose.yml +++ b/test/docker/docker-compose.yml @@ -5,7 +5,7 @@ services: container_name: 'bun.0.5.3' build: context: ../../ - dockerfile: ./test/docker/bun/Dockerfile.0.5.3 + dockerfile: ./test/docker/bun/0.5.3.Dockerfile environment: NODE_ENV: production @@ -13,7 +13,7 @@ services: container_name: 'bun-01' build: context: ../../ - dockerfile: ./test/docker/bun/Dockerfile.01 + dockerfile: ./test/docker/bun/01.Dockerfile environment: NODE_ENV: production @@ -21,7 +21,7 @@ services: container_name: 'bun-canary' build: context: ../../ - dockerfile: ./test/docker/bun/Dockerfile.canary + dockerfile: ./test/docker/bun/canary.Dockerfile environment: NODE_ENV: production @@ -30,7 +30,7 @@ services: platform: linux/amd64 build: context: ../../ - dockerfile: ./test/docker/deno/Dockerfile.1.30.0 + dockerfile: ./test/docker/deno/1.30.0.Dockerfile environment: NODE_ENV: production @@ -39,7 +39,7 @@ services: platform: linux/amd64 build: context: ../../ - dockerfile: ./test/docker/deno/Dockerfile.latest + dockerfile: ./test/docker/deno/latest.Dockerfile environment: NODE_ENV: production @@ -47,7 +47,7 @@ services: container_name: 'node-06' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.06 + dockerfile: ./test/docker/node/06.Dockerfile environment: NODE_ENV: production @@ -55,7 +55,7 @@ services: container_name: 'node-07' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.07 + dockerfile: ./test/docker/node/07.Dockerfile environment: NODE_ENV: production @@ -63,7 +63,7 @@ services: container_name: 'node-08' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.08 + dockerfile: ./test/docker/node/08.Dockerfile environment: NODE_ENV: production @@ -71,7 +71,7 @@ services: container_name: 'node-09' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.09 + dockerfile: ./test/docker/node/09.Dockerfile environment: NODE_ENV: production @@ -79,7 +79,7 @@ services: container_name: 'node-10' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.10 + dockerfile: ./test/docker/node/10.Dockerfile environment: NODE_ENV: production @@ -87,7 +87,7 @@ services: container_name: 'node-11' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.11 + dockerfile: ./test/docker/node/11.Dockerfile environment: NODE_ENV: production @@ -95,7 +95,7 @@ services: container_name: 'node-12' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.12 + dockerfile: ./test/docker/node/12.Dockerfile environment: NODE_ENV: production @@ -103,7 +103,7 @@ services: container_name: 'node-13' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.13 + dockerfile: ./test/docker/node/13.Dockerfile environment: NODE_ENV: production @@ -111,7 +111,7 @@ services: container_name: 'node-14' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.14 + dockerfile: ./test/docker/node/14.Dockerfile environment: NODE_ENV: production @@ -119,7 +119,7 @@ services: container_name: 'node-15' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.15 + dockerfile: ./test/docker/node/15.Dockerfile environment: NODE_ENV: production @@ -127,7 +127,7 @@ services: container_name: 'node-16' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.16 + dockerfile: ./test/docker/node/16.Dockerfile environment: NODE_ENV: production @@ -135,7 +135,7 @@ services: container_name: 'node-17' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.17 + dockerfile: ./test/docker/node/17.Dockerfile environment: NODE_ENV: production @@ -143,7 +143,7 @@ services: container_name: 'node-18' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.18 + dockerfile: ./test/docker/node/18.Dockerfile environment: NODE_ENV: production @@ -151,7 +151,7 @@ services: container_name: 'node-19' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.19 + dockerfile: ./test/docker/node/19.Dockerfile environment: NODE_ENV: production @@ -159,7 +159,7 @@ services: container_name: 'node-20' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.20 + dockerfile: ./test/docker/node/20.Dockerfile environment: NODE_ENV: production @@ -167,6 +167,6 @@ services: container_name: 'node-latest' build: context: ../../ - dockerfile: ./test/docker/node/Dockerfile.latest + dockerfile: ./test/docker/node/latest.Dockerfile environment: NODE_ENV: production diff --git a/test/docker/node/Dockerfile.06 b/test/docker/node/06.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.06 rename to test/docker/node/06.Dockerfile diff --git a/test/docker/node/Dockerfile.07 b/test/docker/node/07.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.07 rename to test/docker/node/07.Dockerfile diff --git a/test/docker/node/Dockerfile.08 b/test/docker/node/08.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.08 rename to test/docker/node/08.Dockerfile diff --git a/test/docker/node/Dockerfile.09 b/test/docker/node/09.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.09 rename to test/docker/node/09.Dockerfile diff --git a/test/docker/node/Dockerfile.10 b/test/docker/node/10.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.10 rename to test/docker/node/10.Dockerfile diff --git a/test/docker/node/Dockerfile.11 b/test/docker/node/11.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.11 rename to test/docker/node/11.Dockerfile diff --git a/test/docker/node/Dockerfile.12 b/test/docker/node/12.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.12 rename to test/docker/node/12.Dockerfile diff --git a/test/docker/node/Dockerfile.13 b/test/docker/node/13.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.13 rename to test/docker/node/13.Dockerfile diff --git a/test/docker/node/Dockerfile.14 b/test/docker/node/14.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.14 rename to test/docker/node/14.Dockerfile diff --git a/test/docker/node/Dockerfile.15 b/test/docker/node/15.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.15 rename to test/docker/node/15.Dockerfile diff --git a/test/docker/node/Dockerfile.16 b/test/docker/node/16.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.16 rename to test/docker/node/16.Dockerfile diff --git a/test/docker/node/Dockerfile.17 b/test/docker/node/17.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.17 rename to test/docker/node/17.Dockerfile diff --git a/test/docker/node/Dockerfile.18 b/test/docker/node/18.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.18 rename to test/docker/node/18.Dockerfile diff --git a/test/docker/node/Dockerfile.19 b/test/docker/node/19.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.19 rename to test/docker/node/19.Dockerfile diff --git a/test/docker/node/Dockerfile.20 b/test/docker/node/20.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.20 rename to test/docker/node/20.Dockerfile diff --git a/test/docker/node/Dockerfile.latest b/test/docker/node/latest.Dockerfile similarity index 100% rename from test/docker/node/Dockerfile.latest rename to test/docker/node/latest.Dockerfile diff --git a/test/unit/runTestFile.test.ts b/test/unit/runTestFile.test.ts index 5072cc2f..57755506 100644 --- a/test/unit/runTestFile.test.ts +++ b/test/unit/runTestFile.test.ts @@ -1,6 +1,6 @@ import process from 'node:process'; import assert from 'node:assert'; -import { runTestFile } from '../../src/services/runTestFile.js'; +import { runTestFile } from '../../src/services/run-test-file.js'; import { getRuntime } from '../../src/helpers/get-runtime.js'; const isProduction = process.env.NODE_ENV === 'production'; diff --git a/test/unit/runTests.test.ts b/test/unit/runTests.test.ts index 78eda1a9..3351e399 100644 --- a/test/unit/runTests.test.ts +++ b/test/unit/runTests.test.ts @@ -1,5 +1,5 @@ import assert from 'node:assert'; -import { runTests } from '../../src/services/runTests.js'; +import { runTests } from '../../src/services/run-tests.js'; (async () => { { diff --git a/tools/compatibility/deno.ts b/tools/compatibility/deno.ts index ceea7233..c0c96c43 100644 --- a/tools/compatibility/deno.ts +++ b/tools/compatibility/deno.ts @@ -1,5 +1,5 @@ import { promises as fs } from 'node:fs'; -import { getFiles } from '../../src/helpers/get-files.ts'; +import { getFiles } from '../../src/modules/get-files.ts'; const ensureDenoCompatibility = async (path: string) => { const files = getFiles(path, [], { @@ -12,8 +12,6 @@ const ensureDenoCompatibility = async (path: string) => { const raw = await fs.readFile(file, 'utf8'); const content = raw.replace(/((import|export).+)(\.js)/g, '$1.ts'); - if (/index\.ts/.test(file)) console.log(content); - await fs.writeFile(file, content); } }; diff --git a/tools/compatibility/node.ts b/tools/compatibility/node.ts index 1033a6b9..898b0c41 100644 --- a/tools/compatibility/node.ts +++ b/tools/compatibility/node.ts @@ -1,5 +1,5 @@ import { promises as fs } from 'node:fs'; -import { getFiles } from '../../src/helpers/get-files.js'; +import { getFiles } from '../../src/modules/get-files.js'; const ensureNodeCompatibility = async (path: string) => { const files = getFiles(path, [], {