From 116d6b24d49219d88af82a13f92edc1626d8c7dc Mon Sep 17 00:00:00 2001 From: wellwelwel <46850407+wellwelwel@users.noreply.github.com> Date: Sat, 21 Dec 2024 04:46:49 -0300 Subject: [PATCH 1/9] feat: add `only` modifier to `describe`, `it` and `test` methods --- src/configs/poku.ts | 1 + src/modules/essentials/poku.ts | 1 - src/modules/helpers/describe.ts | 18 ++- src/modules/helpers/it/core.ts | 12 +- src/modules/helpers/modifiers.ts | 20 +++- src/parsers/callback.ts | 23 ++++ src/parsers/get-arg.ts | 8 +- src/services/run-tests.ts | 6 +- .../only/--describe-only/basic-logs.test.ts | 29 ----- .../e2e/only/--it-only/basic-logs.test.ts | 41 ------- .../e2e/only/--only/basic-logs.test.ts | 110 +++++++++++++----- .../e2e/only/--only/no-logs.test.ts | 2 +- test/e2e/only.test.ts | 78 ------------- 13 files changed, 151 insertions(+), 198 deletions(-) create mode 100644 src/parsers/callback.ts delete mode 100644 test/__fixtures__/e2e/only/--describe-only/basic-logs.test.ts delete mode 100644 test/__fixtures__/e2e/only/--it-only/basic-logs.test.ts diff --git a/src/configs/poku.ts b/src/configs/poku.ts index 8d4cf95c..a3da6f37 100644 --- a/src/configs/poku.ts +++ b/src/configs/poku.ts @@ -13,4 +13,5 @@ export const deepOptions: string[] = []; export const GLOBAL = { cwd: cwd(), + runAsOnly: false, }; diff --git a/src/modules/essentials/poku.ts b/src/modules/essentials/poku.ts index 6ca2bf32..b26cbf76 100644 --- a/src/modules/essentials/poku.ts +++ b/src/modules/essentials/poku.ts @@ -44,7 +44,6 @@ export async function poku( const concurrency = await Promise.all(promises); if (concurrency.some((result) => !result)) code = 1; - } catch { } finally { const end = process.hrtime(start); const total = (end[0] * 1e3 + end[1] / 1e6).toFixed(6); diff --git a/src/modules/helpers/describe.ts b/src/modules/helpers/describe.ts index 0c5b91f0..517dea84 100644 --- a/src/modules/helpers/describe.ts +++ b/src/modules/helpers/describe.ts @@ -4,7 +4,9 @@ import { format } from '../../services/format.js'; import { Write } from '../../services/write.js'; import { indentation } from '../../configs/indentation.js'; import { todo, skip, onlyDescribe } from './modifiers.js'; -import { hasDescribeOnly, hasOnly } from '../../parsers/get-arg.js'; +import { hasOnly } from '../../parsers/get-arg.js'; +import { checkOnly } from '../../parsers/callback.js'; +import { GLOBAL } from '../../configs/poku.js'; export async function describeBase( arg1: string | (() => unknown | Promise), @@ -56,6 +58,7 @@ export async function describeBase( const total = (end[0] * 1e3 + end[1] / 1e6).toFixed(6); + GLOBAL.runAsOnly = false; indentation.hasDescribe = false; Write.log( `${format(`● ${title}`).success().bold()} ${format(`› ${total}ms`).success().dim()}` @@ -77,7 +80,18 @@ async function describeCore( if (typeof messageOrCb === 'string' && typeof cbOrOptions !== 'function') return describeBase(messageOrCb, cbOrOptions); - if (hasOnly || hasDescribeOnly) return; + if (hasOnly) { + const hasItOnly = checkOnly( + typeof messageOrCb === 'function' ? messageOrCb : cbOrOptions + ); + + if (!hasItOnly) return; + + if (typeof messageOrCb === 'string' && typeof cbOrOptions === 'function') + return describeBase(messageOrCb, cbOrOptions); + + if (typeof messageOrCb === 'function') return describeBase(messageOrCb); + } if (typeof messageOrCb === 'string' && typeof cbOrOptions === 'function') return describeBase(messageOrCb, cbOrOptions); diff --git a/src/modules/helpers/it/core.ts b/src/modules/helpers/it/core.ts index 682973e1..b01fa022 100644 --- a/src/modules/helpers/it/core.ts +++ b/src/modules/helpers/it/core.ts @@ -4,7 +4,8 @@ import { indentation } from '../../../configs/indentation.js'; import { format } from '../../../services/format.js'; import { Write } from '../../../services/write.js'; import { todo, skip, onlyIt } from '../modifiers.js'; -import { hasItOnly, hasOnly } from '../../../parsers/get-arg.js'; +import { hasOnly } from '../../../parsers/get-arg.js'; +import { GLOBAL } from '../../../configs/poku.js'; export async function itBase( ...args: [ @@ -86,7 +87,14 @@ async function itCore( messageOrCb: string | (() => unknown) | (() => Promise), cb?: (() => unknown) | (() => Promise) ): Promise { - if (hasOnly || hasItOnly) return; + if (hasOnly) { + if (!GLOBAL.runAsOnly) return; + + if (typeof messageOrCb === 'string' && typeof cb === 'function') + return itBase(messageOrCb, cb); + + if (typeof messageOrCb === 'function') return itBase(messageOrCb); + } if (typeof messageOrCb === 'string' && cb) return itBase(messageOrCb, cb); if (typeof messageOrCb === 'function') return itBase(messageOrCb); diff --git a/src/modules/helpers/modifiers.ts b/src/modules/helpers/modifiers.ts index 061d05bf..5efe2f42 100644 --- a/src/modules/helpers/modifiers.ts +++ b/src/modules/helpers/modifiers.ts @@ -1,10 +1,12 @@ +import { env, exit } from 'node:process'; import { Write } from '../../services/write.js'; import { indentation } from '../../configs/indentation.js'; import { format } from '../../services/format.js'; import { itBase } from './it/core.js'; import { describeBase } from './describe.js'; -import { hasDescribeOnly, hasItOnly, hasOnly } from '../../parsers/get-arg.js'; -import { exit } from 'node:process'; +import { hasOnly } from '../../parsers/get-arg.js'; +import { CheckNoOnly } from '../../parsers/callback.js'; +import { GLOBAL } from '../../configs/poku.js'; export function todo(message: string): void; export async function todo( @@ -50,15 +52,21 @@ export async function onlyDescribe( messageOrCb: string | (() => unknown) | (() => Promise), cb?: (() => unknown) | (() => Promise) ): Promise { - if (!(hasOnly || hasDescribeOnly)) { + if (!hasOnly) { Write.log( format( - "Can't run `describe.only` tests without `--only` or `--only=describe` flags" + `Can't run \`describe.only\` tests without \`--only\` flag: ${env.POKU_FILE}` ).fail() ); exit(1); } + const noItOnly = CheckNoOnly( + typeof messageOrCb === 'function' ? messageOrCb : cb + ); + + if (noItOnly) GLOBAL.runAsOnly = true; + if (typeof messageOrCb === 'string' && cb) return describeBase(messageOrCb, cb); if (typeof messageOrCb === 'function') return describeBase(messageOrCb); @@ -75,10 +83,10 @@ export async function onlyIt( messageOrCb: string | (() => unknown) | (() => Promise), cb?: (() => unknown) | (() => Promise) ): Promise { - if (!(hasOnly || hasItOnly)) { + if (!hasOnly) { Write.log( format( - "Can't run `it.only` and `test.only` tests without `--only`, `--only=it` or `--only=test` flags" + `Can't run \`it.only\` and \`test.only\` tests without \`--only\` flag: ${env.POKU_FILE}` ).fail() ); exit(1); diff --git a/src/parsers/callback.ts b/src/parsers/callback.ts new file mode 100644 index 00000000..1716d18f --- /dev/null +++ b/src/parsers/callback.ts @@ -0,0 +1,23 @@ +export const checkOnly = (cb: unknown): boolean => { + if (typeof cb !== 'function') return false; + + const body = cb.toString(); + + return ( + body.includes('it.only') || + body.includes('test.only') || + body.includes('describe.only') + ); +}; + +export const CheckNoOnly = (cb: unknown): boolean => { + if (typeof cb !== 'function') return false; + + const body = cb.toString(); + + return ( + !body.includes('it.only') && + !body.includes('test.only') && + !body.includes('describe.only') + ); +}; diff --git a/src/parsers/get-arg.ts b/src/parsers/get-arg.ts index 8ff9fb9d..e299a79c 100644 --- a/src/parsers/get-arg.ts +++ b/src/parsers/get-arg.ts @@ -56,10 +56,4 @@ export const argToArray = ( .filter((a) => a); }; -const only = getArg('only'); - -export const hasOnly = hasArg('only') && !only; - -export const hasDescribeOnly = only === 'describe'; - -export const hasItOnly = only && ['it', 'test'].includes(only); +export const hasOnly = hasArg('only'); diff --git a/src/services/run-tests.ts b/src/services/run-tests.ts index fdde64bb..33a89801 100644 --- a/src/services/run-tests.ts +++ b/src/services/run-tests.ts @@ -8,14 +8,12 @@ import { runTestFile } from './run-test-file.js'; import { isQuiet } from '../parsers/output.js'; import { deepOptions, GLOBAL, results } from '../configs/poku.js'; import { availableParallelism } from '../polyfills/os.js'; -import { hasOnly, hasDescribeOnly, hasItOnly } from '../parsers/get-arg.js'; +import { hasOnly } from '../parsers/get-arg.js'; const { cwd } = GLOBAL; const failFastError = ` ${format('ℹ').fail()} ${format('failFast').bold()} is enabled`; -if (hasDescribeOnly) deepOptions.push('--only=describe'); -else if (hasItOnly) deepOptions.push('--only=it'); -else if (hasOnly) deepOptions.push('--only'); +if (hasOnly) deepOptions.push('--only'); export const runTests = async ( dir: string, diff --git a/test/__fixtures__/e2e/only/--describe-only/basic-logs.test.ts b/test/__fixtures__/e2e/only/--describe-only/basic-logs.test.ts deleted file mode 100644 index b65ed1f0..00000000 --- a/test/__fixtures__/e2e/only/--describe-only/basic-logs.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { assert } from '../../../../../src/modules/essentials/assert.js'; -import { describe } from '../../../../../src/modules/helpers/describe.js'; -import { it } from '../../../../../src/modules/helpers/it/core.js'; - -let counter = 0; - -it('Should skip', () => { - counter++; -}); - -describe.only('Should run', () => { - it('Should run', () => { - counter++; - }); -}); - -describe('Should skip', () => { - counter++; - - it('Should never be called', () => { - counter++; - }); - - it.only('Should never be called', () => { - counter++; - }); -}); - -assert.strictEqual(counter, 2); diff --git a/test/__fixtures__/e2e/only/--it-only/basic-logs.test.ts b/test/__fixtures__/e2e/only/--it-only/basic-logs.test.ts deleted file mode 100644 index c798af77..00000000 --- a/test/__fixtures__/e2e/only/--it-only/basic-logs.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { assert } from '../../../../../src/modules/essentials/assert.js'; -import { describe } from '../../../../../src/modules/helpers/describe.js'; -import { it } from '../../../../../src/modules/helpers/it/core.js'; - -let counter = 0; - -it('Should skip', () => { - counter++; -}); - -it.only('Should run', () => { - counter++; -}); - -describe('Should skip', () => { - it('Should skip', () => { - counter++; - }); - - it.only('Should run', () => { - counter++; - }); -}); - -describe('Should run', () => { - it('Should skip', () => { - counter++; - }); - - it.only('Should run', () => { - counter++; - }); -}); - -describe('Should run', () => { - it.only('Should run', () => { - counter++; - }); -}); - -assert.strictEqual(counter, 4); diff --git a/test/__fixtures__/e2e/only/--only/basic-logs.test.ts b/test/__fixtures__/e2e/only/--only/basic-logs.test.ts index 8e14d03a..10f1df69 100644 --- a/test/__fixtures__/e2e/only/--only/basic-logs.test.ts +++ b/test/__fixtures__/e2e/only/--only/basic-logs.test.ts @@ -2,44 +2,100 @@ import { assert } from '../../../../../src/modules/essentials/assert.js'; import { describe } from '../../../../../src/modules/helpers/describe.js'; import { it } from '../../../../../src/modules/helpers/it/core.js'; -let counter = 0; +(async () => { + describe('1', () => { + it('2', () => { + assert(true); + }); -it('Should skip', () => { - counter++; -}); + it.only('3', () => { + assert(true); + }); + }); -it.only('Should run', () => { - counter++; -}); + describe.only('4', () => { + assert(true); + }); -it('Should skip', () => { - counter++; -}); + it.only('5', () => { + assert(true); + }); -describe('Should skip', () => { - it('Should never be called', () => { - counter++; + describe('6', () => { + it('7', () => { + assert(true); + }); }); - it.only('Should never be called', () => { - counter++; + describe.only('8', () => { + it('9', () => { + assert(true); + }); + + it('10', () => { + assert(true); + }); + + it('11', () => { + assert(true); + }); }); -}); -describe.only('Should run', () => { - it('Should skip', () => { - counter++; + describe('12', () => { + it('13', () => { + assert(true); + }); + + it('14', () => { + assert(true); + }); }); - it.only('Should run', () => { - counter++; + describe.only('15', () => { + it('16', () => { + assert(true); + }); + + it.only('17', () => { + assert(true); + }); + + it('18', () => { + assert(true); + }); }); -}); -describe.only('Should run', () => { - it.only('Should run', () => { - counter++; + await describe.only('19', async () => { + await it('20', async () => { + await Promise.resolve(true); + assert(true); + }); + + await it('21', async () => { + await Promise.resolve(true); + assert(true); + }); + + await it('22', async () => { + await Promise.resolve(true); + assert(true); + }); }); -}); -assert.strictEqual(counter, 3); + await describe.only('23', async () => { + await it('24', async () => { + await Promise.resolve(true); + assert(true); + }); + + await it.only('25', async () => { + await Promise.resolve(true); + assert(true); + }); + + await it('26', async () => { + await Promise.resolve(true); + assert(true); + }); + }); +})(); diff --git a/test/__fixtures__/e2e/only/--only/no-logs.test.ts b/test/__fixtures__/e2e/only/--only/no-logs.test.ts index ba8f8ad7..4baca295 100644 --- a/test/__fixtures__/e2e/only/--only/no-logs.test.ts +++ b/test/__fixtures__/e2e/only/--only/no-logs.test.ts @@ -42,4 +42,4 @@ describe.only(() => { }); }); -assert.strictEqual(counter, 3); +assert.strictEqual(counter, 4); diff --git a/test/e2e/only.test.ts b/test/e2e/only.test.ts index 64eb7886..0a830017 100644 --- a/test/e2e/only.test.ts +++ b/test/e2e/only.test.ts @@ -20,71 +20,6 @@ describe('Only', async () => { assert.strictEqual(results.exitCode, 0, 'Passed'); }); - await it('--only=it', async () => { - const results = await inspectPoku('--only=it --debug', { - cwd: 'test/__fixtures__/e2e/only/--it-only', - }); - - if (results.exitCode !== 0) { - console.log(results.stdout); - console.log(results.stderr); - } - - assert.strictEqual(results.exitCode, 0, 'Passed'); - }); - - await it('--only=test', async () => { - const results = await inspectPoku('--only=test --debug', { - cwd: 'test/__fixtures__/e2e/only/--it-only', - }); - - if (results.exitCode !== 0) { - console.log(results.stdout); - console.log(results.stderr); - } - - assert.strictEqual(results.exitCode, 0, 'Passed'); - }); - - await it('Should fail without `--only` (it)', async () => { - const results = await inspectPoku('--debug', { - cwd: 'test/__fixtures__/e2e/only/--it-only', - }); - - if (results.exitCode !== 1) { - console.log(results.stdout); - console.log(results.stderr); - } - - assert.strictEqual(results.exitCode, 1, 'Failed'); - }); - - await it('--only=describe', async () => { - const results = await inspectPoku('--only=describe --debug', { - cwd: 'test/__fixtures__/e2e/only/--describe-only', - }); - - if (results.exitCode !== 0) { - console.log(results.stdout); - console.log(results.stderr); - } - - assert.strictEqual(results.exitCode, 0, 'Passed'); - }); - - await it('Should fail without `--only` (describe)', async () => { - const results = await inspectPoku('--debug', { - cwd: 'test/__fixtures__/e2e/only/--describe-only', - }); - - if (results.exitCode !== 1) { - console.log(results.stdout); - console.log(results.stderr); - } - - assert.strictEqual(results.exitCode, 1, 'Failed'); - }); - await it('No Poku Runner', async () => { const results = await inspectCLI( `${cmd} ./test/__fixtures__/e2e/only/--only/basic-logs.test.${ext} --only` @@ -123,17 +58,4 @@ describe('Only', async () => { assert.strictEqual(results.exitCode, 1, 'Failed'); }); - - await it('Ensure complex examples works', async () => { - const results = await inspectPoku('--only=it', { - cwd: 'test/__fixtures__/e2e/only/examples', - }); - - if (results.exitCode !== 0) { - console.log(results.stdout); - console.log(results.stderr); - } - - assert.strictEqual(results.exitCode, 0, 'Passed'); - }); }); From 2433e29b3daee49ab5d49eb1cc57a81c997375a4 Mon Sep 17 00:00:00 2001 From: wellwelwel <46850407+wellwelwel@users.noreply.github.com> Date: Sat, 21 Dec 2024 04:54:33 -0300 Subject: [PATCH 2/9] chore: fix lint --- src/parsers/callback.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/parsers/callback.ts b/src/parsers/callback.ts index 1716d18f..88e3ed35 100644 --- a/src/parsers/callback.ts +++ b/src/parsers/callback.ts @@ -15,9 +15,9 @@ export const CheckNoOnly = (cb: unknown): boolean => { const body = cb.toString(); - return ( - !body.includes('it.only') && - !body.includes('test.only') && - !body.includes('describe.only') + return !( + body.includes('it.only') || + body.includes('test.only') || + body.includes('describe.only') ); }; From aefc0fd810ae3438539aed5776c02a049f5ca55f Mon Sep 17 00:00:00 2001 From: wellwelwel <46850407+wellwelwel@users.noreply.github.com> Date: Sat, 21 Dec 2024 05:47:04 -0300 Subject: [PATCH 3/9] ci: add tests --- .../e2e/only/--only/no-logs.test.ts | 110 +++++++++++++----- test/__fixtures__/e2e/only/describe.test.ts | 6 + .../only-it.test.ts => hooks.test.ts} | 36 +++--- test/__fixtures__/e2e/only/it.test.ts | 6 + test/e2e/only.test.ts | 39 +++++++ 5 files changed, 149 insertions(+), 48 deletions(-) create mode 100644 test/__fixtures__/e2e/only/describe.test.ts rename test/__fixtures__/e2e/only/{examples/only-it.test.ts => hooks.test.ts} (52%) create mode 100644 test/__fixtures__/e2e/only/it.test.ts diff --git a/test/__fixtures__/e2e/only/--only/no-logs.test.ts b/test/__fixtures__/e2e/only/--only/no-logs.test.ts index 4baca295..d16590df 100644 --- a/test/__fixtures__/e2e/only/--only/no-logs.test.ts +++ b/test/__fixtures__/e2e/only/--only/no-logs.test.ts @@ -2,44 +2,100 @@ import { assert } from '../../../../../src/modules/essentials/assert.js'; import { describe } from '../../../../../src/modules/helpers/describe.js'; import { it } from '../../../../../src/modules/helpers/it/core.js'; -let counter = 0; +(async () => { + describe(() => { + it(() => { + assert(true); + }); -it(() => { - counter++; -}); + it.only(() => { + assert(true); + }); + }); -it.only(() => { - counter++; -}); + describe.only(() => { + assert(true); + }); -it(() => { - counter++; -}); + it.only(() => { + assert(true); + }); -describe(() => { - it(() => { - counter++; + describe(() => { + it(() => { + assert(true); + }); }); - it.only(() => { - counter++; + describe.only(() => { + it(() => { + assert(true); + }); + + it(() => { + assert(true); + }); + + it(() => { + assert(true); + }); }); -}); -describe.only(() => { - it(() => { - counter++; + describe(() => { + it(() => { + assert(true); + }); + + it(() => { + assert(true); + }); }); - it.only(() => { - counter++; + describe.only(() => { + it(() => { + assert(true); + }); + + it.only(() => { + assert(true); + }); + + it(() => { + assert(true); + }); }); -}); -describe.only(() => { - it.only(() => { - counter++; + await describe.only(async () => { + await it(async () => { + await Promise.resolve(true); + assert(true); + }); + + await it(async () => { + await Promise.resolve(true); + assert(true); + }); + + await it(async () => { + await Promise.resolve(true); + assert(true); + }); }); -}); -assert.strictEqual(counter, 4); + await describe.only(async () => { + await it(async () => { + await Promise.resolve(true); + assert(true); + }); + + await it.only(async () => { + await Promise.resolve(true); + assert(true); + }); + + await it(async () => { + await Promise.resolve(true); + assert(true); + }); + }); +})(); diff --git a/test/__fixtures__/e2e/only/describe.test.ts b/test/__fixtures__/e2e/only/describe.test.ts new file mode 100644 index 00000000..35559dbf --- /dev/null +++ b/test/__fixtures__/e2e/only/describe.test.ts @@ -0,0 +1,6 @@ +import { assert } from '../../../../src/modules/essentials/assert.js'; +import { describe } from '../../../../src/modules/helpers/describe.js'; + +describe.only('1', () => { + assert(true); +}); diff --git a/test/__fixtures__/e2e/only/examples/only-it.test.ts b/test/__fixtures__/e2e/only/hooks.test.ts similarity index 52% rename from test/__fixtures__/e2e/only/examples/only-it.test.ts rename to test/__fixtures__/e2e/only/hooks.test.ts index 05bc6fc8..ae75780e 100644 --- a/test/__fixtures__/e2e/only/examples/only-it.test.ts +++ b/test/__fixtures__/e2e/only/hooks.test.ts @@ -1,24 +1,21 @@ -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'; -import { - beforeEach, - afterEach, -} from '../../../../../src/modules/helpers/each.js'; -import { assert } from '../../../../../src/modules/essentials/assert.js'; +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'; +import { beforeEach, afterEach } from '../../../../src/modules/helpers/each.js'; +import { assert } from '../../../../src/modules/essentials/assert.js'; + +let counter = 0; +let beforeHookCounter = 0; +let afterHookCounter = 0; beforeEach(() => { - // It will run normally before all `it.only` and `test.only`. + beforeHookCounter++; }); afterEach(() => { - // It will run normally after all `it.only` and `test.only`. + afterHookCounter++; }); -let counter = 0; - -// ⬇️ `describe` scopes ⬇️ - describe('1', () => { counter++; // ✅ `describe` scope will be executed as it's in "native" JavaScript flow @@ -39,9 +36,8 @@ describe('1', () => { }); }); -// ⬇️ Top-level or non-`describe` scopes ⬇️ - counter++; // ✅ Will be executed as it's in "native" JavaScript flow +assert.strictEqual(counter, 4, 'Ensure JavaScript natural flow'); test('6', () => { counter++; // ⏭️ `test` will be skipped @@ -59,8 +55,6 @@ it.only('9', () => { counter++; // ✅ `it.only` will be executed }); -// describe.only('10', () => { -// counter++; // ❌ It would force a failure since `describe.only` is not enabled in `--only=it` -// }); - -assert.strictEqual(counter, 6); +assert.strictEqual(counter, 6, '1 describe + 2 it + 2 test + 1 "natural"'); +assert.strictEqual(beforeHookCounter, 4, '2 test + 2 it'); +assert.strictEqual(afterHookCounter, 4, '2 test + 2 it'); diff --git a/test/__fixtures__/e2e/only/it.test.ts b/test/__fixtures__/e2e/only/it.test.ts new file mode 100644 index 00000000..86f3138d --- /dev/null +++ b/test/__fixtures__/e2e/only/it.test.ts @@ -0,0 +1,6 @@ +import { assert } from '../../../../src/modules/essentials/assert.js'; +import { it } from '../../../../src/modules/helpers/it/core.js'; + +it.only('1', () => { + assert(true); +}); diff --git a/test/e2e/only.test.ts b/test/e2e/only.test.ts index 0a830017..343bf210 100644 --- a/test/e2e/only.test.ts +++ b/test/e2e/only.test.ts @@ -46,6 +46,32 @@ describe('Only', async () => { assert.strictEqual(results.exitCode, 1, 'Failed'); }); + await it('No Poku Runner should fail without `--only` (describe)', async () => { + const results = await inspectCLI( + `${cmd} ./test/__fixtures__/e2e/only/describe.test.${ext}` + ); + + if (results.exitCode !== 1) { + console.log(results.stdout); + console.log(results.stderr); + } + + assert.strictEqual(results.exitCode, 1, 'Failed'); + }); + + await it('No Poku Runner should fail without `--only` (it)', async () => { + const results = await inspectCLI( + `${cmd} ./test/__fixtures__/e2e/only/it.test.${ext}` + ); + + if (results.exitCode !== 1) { + console.log(results.stdout); + console.log(results.stderr); + } + + assert.strictEqual(results.exitCode, 1, 'Failed'); + }); + await it('No Poku Runner should fail without `--only`', async () => { const results = await inspectCLI( `${cmd} ./test/__fixtures__/e2e/only/--only/basic-logs.test.${ext}` @@ -58,4 +84,17 @@ describe('Only', async () => { assert.strictEqual(results.exitCode, 1, 'Failed'); }); + + await it('Check hooks when using .only modifier', async () => { + const results = await inspectCLI( + `${cmd} ./test/__fixtures__/e2e/only/hooks.test.${ext} --only` + ); + + if (results.exitCode !== 1) { + console.log(results.stdout); + console.log(results.stderr); + } + + assert.strictEqual(results.exitCode, 0, 'Passed'); + }); }); From 13ae6d32e320ebc84c646b03ef82089358612cd0 Mon Sep 17 00:00:00 2001 From: wellwelwel <46850407+wellwelwel@users.noreply.github.com> Date: Sat, 21 Dec 2024 06:26:48 -0300 Subject: [PATCH 4/9] ci: add tests --- src/configs/poku.ts | 4 +- src/modules/helpers/describe.ts | 7 +-- src/modules/helpers/it/core.ts | 10 +--- src/modules/helpers/skip.ts | 7 ++- src/services/assert.ts | 5 +- .../__fixtures__/e2e/skip/skip-helper.test.ts | 5 ++ .../e2e/skip/skip-modifier.test.ts | 28 ++++++++++ test/e2e/skip.test.ts | 51 +++++++++++++++++++ 8 files changed, 95 insertions(+), 22 deletions(-) create mode 100644 test/__fixtures__/e2e/skip/skip-helper.test.ts create mode 100644 test/__fixtures__/e2e/skip/skip-modifier.test.ts create mode 100644 test/e2e/skip.test.ts diff --git a/src/configs/poku.ts b/src/configs/poku.ts index a3da6f37..6672c2bf 100644 --- a/src/configs/poku.ts +++ b/src/configs/poku.ts @@ -1,4 +1,4 @@ -import { cwd } from 'node:process'; +import { env, cwd } from 'node:process'; export const results = { success: 0, @@ -14,4 +14,6 @@ export const deepOptions: string[] = []; export const GLOBAL = { cwd: cwd(), runAsOnly: false, + isPoku: typeof env?.POKU_FILE === 'string' && env?.POKU_FILE.length > 0, + FILE: env.POKU_FILE, }; diff --git a/src/modules/helpers/describe.ts b/src/modules/helpers/describe.ts index 517dea84..a81e0960 100644 --- a/src/modules/helpers/describe.ts +++ b/src/modules/helpers/describe.ts @@ -1,5 +1,5 @@ import type { DescribeOptions } from '../../@types/describe.js'; -import { hrtime, env } from 'node:process'; +import { hrtime } from 'node:process'; import { format } from '../../services/format.js'; import { Write } from '../../services/write.js'; import { indentation } from '../../configs/indentation.js'; @@ -16,9 +16,6 @@ export async function describeBase( let cb: (() => unknown | Promise) | undefined; let options: DescribeOptions | undefined; - const isPoku = typeof env?.FILE === 'string' && env?.FILE.length > 0; - const FILE = env.POKU_FILE; - if (typeof arg1 === 'string') { title = arg1; @@ -33,7 +30,7 @@ export async function describeBase( indentation.hasDescribe = true; const { background, icon } = options ?? {}; - const message = `${cb ? format('◌').dim() : (icon ?? '☰')} ${cb ? format(isPoku ? `${title} › ${format(`${FILE}`).italic().gray()}` : title).dim() : format(title).bold()}`; + const message = `${cb ? format('◌').dim() : (icon ?? '☰')} ${cb ? format(title).dim() : format(title).bold()}`; const noBackground = !background; if (noBackground) Write.log(format(message).bold()); diff --git a/src/modules/helpers/it/core.ts b/src/modules/helpers/it/core.ts index b01fa022..79a9bded 100644 --- a/src/modules/helpers/it/core.ts +++ b/src/modules/helpers/it/core.ts @@ -1,4 +1,4 @@ -import { hrtime, env } from 'node:process'; +import { hrtime } from 'node:process'; import { each } from '../../../configs/each.js'; import { indentation } from '../../../configs/indentation.js'; import { format } from '../../../services/format.js'; @@ -17,10 +17,6 @@ export async function itBase( let message: string | undefined; let cb: () => unknown | Promise; - const isPoku = - typeof env?.POKU_FILE === 'string' && env?.POKU_FILE.length > 0; - const FILE = env.POKU_FILE; - if (typeof args[0] === 'string') { message = args[0]; cb = args[1] as () => unknown | Promise; @@ -30,9 +26,7 @@ export async function itBase( indentation.hasItOrTest = true; Write.log( - isPoku - ? `${indentation.hasDescribe ? ' ' : ''}${format(`◌ ${message} › ${format(`${FILE}`).italic().gray()}`).dim()}` - : `${indentation.hasDescribe ? ' ' : ''}${format(`◌ ${message}`).dim()}` + `${indentation.hasDescribe ? ' ' : ''}${format(`◌ ${message}`).dim()}` ); } diff --git a/src/modules/helpers/skip.ts b/src/modules/helpers/skip.ts index 130def10..8c680a19 100644 --- a/src/modules/helpers/skip.ts +++ b/src/modules/helpers/skip.ts @@ -1,11 +1,10 @@ -import { exit, env } from 'node:process'; +import { exit } from 'node:process'; import { Write } from '../../services/write.js'; import { format } from '../../services/format.js'; +import { GLOBAL } from '../../configs/poku.js'; export const skip = (message = 'Skipping') => { - const isPoku = - typeof env?.POKU_FILE === 'string' && env?.POKU_FILE.length > 0; - const FILE = env.POKU_FILE; + const { isPoku, FILE } = GLOBAL; if (message) Write.log( diff --git a/src/services/assert.ts b/src/services/assert.ts index cf9271b8..102b685f 100644 --- a/src/services/assert.ts +++ b/src/services/assert.ts @@ -13,10 +13,7 @@ const { cwd } = GLOBAL; const regexFile = /file:(\/\/)?/; const assertProcessor = () => { - const isPoku = - typeof process.env?.POKU_FILE === 'string' && - process.env?.POKU_FILE.length > 0; - const FILE = process.env.POKU_FILE; + const { isPoku, FILE } = GLOBAL; let preIdentation = ''; diff --git a/test/__fixtures__/e2e/skip/skip-helper.test.ts b/test/__fixtures__/e2e/skip/skip-helper.test.ts new file mode 100644 index 00000000..a00137dd --- /dev/null +++ b/test/__fixtures__/e2e/skip/skip-helper.test.ts @@ -0,0 +1,5 @@ +import { exit } from 'node:process'; +import { skip } from '../../../../src/modules/helpers/skip.js'; + +skip('Testing'); +exit(1); diff --git a/test/__fixtures__/e2e/skip/skip-modifier.test.ts b/test/__fixtures__/e2e/skip/skip-modifier.test.ts new file mode 100644 index 00000000..ca98bd1c --- /dev/null +++ b/test/__fixtures__/e2e/skip/skip-modifier.test.ts @@ -0,0 +1,28 @@ +import { describe } from '../../../../src/modules/helpers/describe.js'; +import { test } from '../../../../src/modules/helpers/test.js'; +import { it } from '../../../../src/modules/helpers/it/core.js'; +import { exit } from 'node:process'; + +describe.skip('1', () => { + exit(1); +}); + +describe.skip(() => { + exit(1); +}); + +it.skip('2', () => { + exit(1); +}); + +it.skip(() => { + exit(1); +}); + +test.skip('3', () => { + exit(1); +}); + +test.skip(() => { + exit(1); +}); diff --git a/test/e2e/skip.test.ts b/test/e2e/skip.test.ts new file mode 100644 index 00000000..1e2c8e89 --- /dev/null +++ b/test/e2e/skip.test.ts @@ -0,0 +1,51 @@ +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 { ext, inspectPoku, inspectCLI } from '../__utils__/capture-cli.test.js'; +import { runner } from '../../src/parsers/get-runner.js'; + +describe('Skip', async () => { + const cmd = runner(`_.${ext}`).join(' '); + + await it('Using Poku', async () => { + const results = await inspectPoku('--debug', { + cwd: 'test/__fixtures__/e2e/skip', + }); + + if (results.exitCode !== 0) { + console.log(results.stdout); + console.log(results.stderr); + } + + assert.strictEqual(results.exitCode, 0, 'Passed'); + assert.match(results.stdout, /PASS › 2/, 'Passed 2'); + assert.match(results.stdout, /FAIL › 0/, 'Failed 0'); + assert.match(results.stdout, /SKIP › 7/, 'Skipped 7'); + }); + + await it('No Poku Runner (Modifier)', async () => { + const results = await inspectCLI( + `${cmd} ./test/__fixtures__/e2e/skip/skip-modifier.test.${ext}` + ); + + if (results.exitCode !== 0) { + console.log(results.stdout); + console.log(results.stderr); + } + + assert.strictEqual(results.exitCode, 0, 'Passed'); + }); + + await it('No Poku Runner (Helper)', async () => { + const results = await inspectCLI( + `${cmd} ./test/__fixtures__/e2e/skip/skip-helper.test.${ext}` + ); + + if (results.exitCode !== 0) { + console.log(results.stdout); + console.log(results.stderr); + } + + assert.strictEqual(results.exitCode, 0, 'Passed'); + }); +}); From 2bd02a1c1061a1e962cac7c82a1419e6e5f115be Mon Sep 17 00:00:00 2001 From: wellwelwel <46850407+wellwelwel@users.noreply.github.com> Date: Sat, 21 Dec 2024 06:48:29 -0300 Subject: [PATCH 5/9] ci: add tests --- .../__fixtures__/e2e/skip/skip-helper.test.ts | 4 + test/unit/parse-callbacks.test.ts | 293 ++++++++++++++++++ 2 files changed, 297 insertions(+) create mode 100644 test/unit/parse-callbacks.test.ts diff --git a/test/__fixtures__/e2e/skip/skip-helper.test.ts b/test/__fixtures__/e2e/skip/skip-helper.test.ts index a00137dd..0bdc0c66 100644 --- a/test/__fixtures__/e2e/skip/skip-helper.test.ts +++ b/test/__fixtures__/e2e/skip/skip-helper.test.ts @@ -1,5 +1,9 @@ import { exit } from 'node:process'; import { skip } from '../../../../src/modules/helpers/skip.js'; +import { GLOBAL } from '../../../../src/configs/poku.js'; + +// Mock +GLOBAL.isPoku = false; skip('Testing'); exit(1); diff --git a/test/unit/parse-callbacks.test.ts b/test/unit/parse-callbacks.test.ts new file mode 100644 index 00000000..25b9bfe4 --- /dev/null +++ b/test/unit/parse-callbacks.test.ts @@ -0,0 +1,293 @@ +import { describe } from '../../src/modules/helpers/describe.js'; +import { test } from '../../src/modules/helpers/test.js'; +import { it } from '../../src/modules/helpers/it/core.js'; +import { assert } from '../../src/modules/essentials/assert.js'; +import { checkOnly, CheckNoOnly } from '../../src/parsers/callback.js'; + +const cbWithOnly = { + function: function cb() { + describe.only(() => {}); + }, + function2: function cb() { + it.only(() => {}); + }, + function3: function cb() { + test.only(() => {}); + }, + anon: function () { + describe.only(() => {}); + }, + anon2: function () { + it.only(() => {}); + }, + anon3: function () { + test.only(() => {}); + }, + arrow: () => { + describe.only(() => {}); + }, + arrow2: () => { + it.only(() => {}); + }, + arrow3: () => { + test.only(() => {}); + }, +}; + +const cbWithoutOnly = { + function: function cb() { + describe(() => {}); + }, + function2: function cb() { + it(() => {}); + }, + function3: function cb() { + test(() => {}); + }, + anon: function () { + describe(() => {}); + }, + anon2: function () { + it(() => {}); + }, + anon3: function () { + test(() => {}); + }, + arrow: () => { + describe(() => {}); + }, + arrow2: () => { + it(() => {}); + }, + arrow3: () => { + test(() => {}); + }, +}; + +describe('Parse Callbacks: checkOnly — true', () => { + assert.strictEqual(checkOnly(undefined), false, 'No function'); + + assert.strictEqual( + checkOnly(cbWithOnly.function), + true, + 'Classic Function: describe.only' + ); + + assert.strictEqual( + checkOnly(cbWithOnly.function2), + true, + 'Classic Function: it.only' + ); + + assert.strictEqual( + checkOnly(cbWithOnly.function3), + true, + 'Classic Function: test.only' + ); + + assert.strictEqual( + checkOnly(cbWithOnly.anon), + true, + 'Anonymous Function: describe.only' + ); + + assert.strictEqual( + checkOnly(cbWithOnly.anon2), + true, + 'Anonymous Function: it.only' + ); + + assert.strictEqual( + checkOnly(cbWithOnly.anon3), + true, + 'Anonymous Function: test.only' + ); + + assert.strictEqual( + checkOnly(cbWithOnly.arrow), + true, + 'Arrow Function: describe.only' + ); + + assert.strictEqual( + checkOnly(cbWithOnly.arrow2), + true, + 'Arrow Function: it.only' + ); + + assert.strictEqual( + checkOnly(cbWithOnly.arrow3), + true, + 'Arrow Function: test.only' + ); +}); + +describe('Parse Callbacks: checkOnly — false', () => { + assert.strictEqual( + checkOnly(cbWithoutOnly.function), + false, + 'Classic Function: describe.only' + ); + + assert.strictEqual( + checkOnly(cbWithoutOnly.function2), + false, + 'Classic Function: it.only' + ); + + assert.strictEqual( + checkOnly(cbWithoutOnly.function3), + false, + 'Classic Function: test.only' + ); + + assert.strictEqual( + checkOnly(cbWithoutOnly.anon), + false, + 'Anonymous Function: describe.only' + ); + + assert.strictEqual( + checkOnly(cbWithoutOnly.anon2), + false, + 'Anonymous Function: it.only' + ); + + assert.strictEqual( + checkOnly(cbWithoutOnly.anon3), + false, + 'Anonymous Function: test.only' + ); + + assert.strictEqual( + checkOnly(cbWithoutOnly.arrow), + false, + 'Arrow Function: describe.only' + ); + + assert.strictEqual( + checkOnly(cbWithoutOnly.arrow2), + false, + 'Arrow Function: it.only' + ); + + assert.strictEqual( + checkOnly(cbWithoutOnly.arrow3), + false, + 'Arrow Function: test.only' + ); +}); + +describe('Parse Callbacks: CheckNoOnly — true', () => { + assert.strictEqual(CheckNoOnly(undefined), false, 'No function'); + + assert.strictEqual( + CheckNoOnly(cbWithoutOnly.function), + true, + 'Classic Function: describe.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithoutOnly.function2), + true, + 'Classic Function: it.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithoutOnly.function3), + true, + 'Classic Function: test.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithoutOnly.anon), + true, + 'Anonymous Function: describe.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithoutOnly.anon2), + true, + 'Anonymous Function: it.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithoutOnly.anon3), + true, + 'Anonymous Function: test.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithoutOnly.arrow), + true, + 'Arrow Function: describe.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithoutOnly.arrow2), + true, + 'Arrow Function: it.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithoutOnly.arrow3), + true, + 'Arrow Function: test.only' + ); +}); + +describe('Parse Callbacks: CheckNoOnly — false', () => { + assert.strictEqual( + CheckNoOnly(cbWithOnly.function), + false, + 'Classic Function: describe.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithOnly.function2), + false, + 'Classic Function: it.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithOnly.function3), + false, + 'Classic Function: test.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithOnly.anon), + false, + 'Anonymous Function: describe.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithOnly.anon2), + false, + 'Anonymous Function: it.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithOnly.anon3), + false, + 'Anonymous Function: test.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithOnly.arrow), + false, + 'Arrow Function: describe.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithOnly.arrow2), + false, + 'Arrow Function: it.only' + ); + + assert.strictEqual( + CheckNoOnly(cbWithOnly.arrow3), + false, + 'Arrow Function: test.only' + ); +}); From 681cb0a34e4cf8d3326c060c495d1dccc497955b Mon Sep 17 00:00:00 2001 From: wellwelwel <46850407+wellwelwel@users.noreply.github.com> Date: Sat, 21 Dec 2024 06:51:50 -0300 Subject: [PATCH 6/9] ci: remove old tests --- .../by-docker-compose/node-12.test.ts | 32 ------------------- 1 file changed, 32 deletions(-) delete mode 100644 test/compatibility/by-docker-compose/node-12.test.ts diff --git a/test/compatibility/by-docker-compose/node-12.test.ts b/test/compatibility/by-docker-compose/node-12.test.ts deleted file mode 100644 index 002dda0f..00000000 --- a/test/compatibility/by-docker-compose/node-12.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { test } from '../../../src/modules/helpers/test.js'; -import { assert } from '../../../src/modules/essentials/assert.js'; -import { docker } from '../../../src/modules/helpers/container.js'; - -const projectName = 'poku'; -const serviceName = 'node-12'; - -test(`Compatibility Tests: ${serviceName}`, async () => { - const dockerfile = docker.dockerfile({ - containerName: serviceName, - tagName: `${projectName}-${serviceName}`, - }); - - await dockerfile.remove(); - - const compose = docker.compose({ - build: true, - cwd: './test/__docker__', - detach: false, - serviceName, - projectName, - // verbose: true, - }); - - const result = await compose.up(); - - if (!result) { - assert.fail(`See the logs by running \`docker logs ${serviceName}\``); - } - - await dockerfile.remove(); -}); From 8e073234393f67e38ecf4f59bfa5ef4ce9554b3c Mon Sep 17 00:00:00 2001 From: wellwelwel <46850407+wellwelwel@users.noreply.github.com> Date: Sat, 21 Dec 2024 07:08:58 -0300 Subject: [PATCH 7/9] ci: add ordered tests --- test/e2e/only.test.ts | 44 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/test/e2e/only.test.ts b/test/e2e/only.test.ts index 343bf210..851f81d2 100644 --- a/test/e2e/only.test.ts +++ b/test/e2e/only.test.ts @@ -12,12 +12,54 @@ describe('Only', async () => { cwd: 'test/__fixtures__/e2e/only/--only', }); + const actual = results.stdout.split('\n'); + const offset = + actual.findIndex((line) => line.includes('Running Tests')) + 1; + if (results.exitCode !== 0) { console.log(results.stdout); console.log(results.stderr); } assert.strictEqual(results.exitCode, 0, 'Passed'); + + assert.match(actual[offset + 1], /1/); + assert.match(actual[offset + 2], /3/); + assert.match(actual[offset + 3], /3/); + assert.match(actual[offset + 4], /1/); + + assert.match(actual[offset + 5], /4/); + assert.match(actual[offset + 6], /4/); + assert.match(actual[offset + 7], /5/); + assert.match(actual[offset + 8], /5/); + + assert.match(actual[offset + 9], /8/); + assert.match(actual[offset + 10], /9/); + assert.match(actual[offset + 11], /9/); + assert.match(actual[offset + 12], /10/); + assert.match(actual[offset + 13], /10/); + assert.match(actual[offset + 14], /11/); + assert.match(actual[offset + 15], /11/); + assert.match(actual[offset + 16], /8/); + + assert.match(actual[offset + 17], /15/); + assert.match(actual[offset + 18], /17/); + assert.match(actual[offset + 19], /17/); + assert.match(actual[offset + 20], /15/); + + assert.match(actual[offset + 21], /19/); + assert.match(actual[offset + 22], /20/); + assert.match(actual[offset + 23], /20/); + assert.match(actual[offset + 24], /21/); + assert.match(actual[offset + 25], /21/); + assert.match(actual[offset + 26], /22/); + assert.match(actual[offset + 27], /22/); + assert.match(actual[offset + 28], /19/); + + assert.match(actual[offset + 29], /23/); + assert.match(actual[offset + 30], /25/); + assert.match(actual[offset + 31], /25/); + assert.match(actual[offset + 32], /23/); }); await it('No Poku Runner', async () => { @@ -90,7 +132,7 @@ describe('Only', async () => { `${cmd} ./test/__fixtures__/e2e/only/hooks.test.${ext} --only` ); - if (results.exitCode !== 1) { + if (results.exitCode !== 0) { console.log(results.stdout); console.log(results.stderr); } From 05e6e5117f0a9d944abf6459bb7061439d8cbbbc Mon Sep 17 00:00:00 2001 From: wellwelwel <46850407+wellwelwel@users.noreply.github.com> Date: Sat, 21 Dec 2024 07:47:25 -0300 Subject: [PATCH 8/9] docs: add `only` modifier to `describe`, `it` and `test` methods --- src/modules/helpers/modifiers.ts | 8 +- website/docs/documentation/helpers/only.mdx | 337 +++----------------- 2 files changed, 56 insertions(+), 289 deletions(-) diff --git a/src/modules/helpers/modifiers.ts b/src/modules/helpers/modifiers.ts index 5efe2f42..47edfd22 100644 --- a/src/modules/helpers/modifiers.ts +++ b/src/modules/helpers/modifiers.ts @@ -1,4 +1,4 @@ -import { env, exit } from 'node:process'; +import { exit } from 'node:process'; import { Write } from '../../services/write.js'; import { indentation } from '../../configs/indentation.js'; import { format } from '../../services/format.js'; @@ -54,9 +54,7 @@ export async function onlyDescribe( ): Promise { if (!hasOnly) { Write.log( - format( - `Can't run \`describe.only\` tests without \`--only\` flag: ${env.POKU_FILE}` - ).fail() + format("Can't run `describe.only` tests without `--only` flag").fail() ); exit(1); } @@ -86,7 +84,7 @@ export async function onlyIt( if (!hasOnly) { Write.log( format( - `Can't run \`it.only\` and \`test.only\` tests without \`--only\` flag: ${env.POKU_FILE}` + "Can't run `it.only` and `test.only` tests without `--only` flag" ).fail() ); exit(1); diff --git a/website/docs/documentation/helpers/only.mdx b/website/docs/documentation/helpers/only.mdx index 6f4f2a00..c7c4d615 100644 --- a/website/docs/documentation/helpers/only.mdx +++ b/website/docs/documentation/helpers/only.mdx @@ -8,19 +8,25 @@ import { Stability } from '@site/src/components/Stability'; # 🌌 only -The `.only` helper enables selective execution of tests, allowing you to focus on specific `describe`, `it`, and/or `test` blocks by running only those marked with `.only`. See the [usage](#usage) to understand the different conditions and behaviors. +The `.only` modifier enables selective execution of tests, allowing you to focus on specific `describe`, `it`, and/or `test` blocks by running only those marked with `.only`. See the [usage](#usage) to understand the different conditions and behaviors. + From{' '} + + 3.0.0-rc.1 + {' '} + onwards. + } /> Add only modifier to describe,{' '} @@ -28,257 +34,77 @@ The `.only` helper enables selective execution of tests, allowing you to focus o , ], }, + { + version: '2.7.0', + changes: [ + <> + Add only modifier to describe,{' '} + it and test methods (experimental). + , + ], + }, ]} /> ## Usage -To enable the `.only` helper, you must to pass one of the following flags to enable it selectively: - -### `--only` - -Enables the `.only` helper for `describe`, `it` and `test` methods. +To enable the `.only` modifier, you must to pass the `--only` flag. -
- -- ✅ `describe.only` -- ✅ `it.only` -- ✅ `test.only` -- ⏭️ `describe` _(it will be skipped)_ -- ⏭️ `it` _(it will be skipped)_ -- ⏭️ `test` _(it will be skipped)_ - -
- -```ts -import { describe, it, test } from 'poku'; - -describe.only(() => { - it.only(() => { - // ... - }); - - test.only(() => { - // ... - }); -}); +:::tip -test.only(() => { - // ... -}); -``` +You can pass the `--only` flag either using the test runner (**Poku**) or the runner you prefer, for example: -```bash +```sh npx poku --only +npx tsx test/my-test.test.ts --only +npm test -- --only +node test/my-test.test.js --only ``` -:::note - -- `describe`, `it` and `test` methods without `.only` will be skipped. - ::: -### `--only=describe` - -Enables the `.only` helper for `describe` method. - -
- -- ✅ `describe.only` -- ✅ `it` -- ✅ `test` -- ⏭️ `describe` _(it will be skipped)_ -- ❌ `it.only` _(it forces a failure since `it.only` is not enabled in `--only=describe`)_ -- ❌ `test.only` _(it forces a failure since `test.only` is not enabled in `--only=describe`)_ - -
+### Common Examples ```ts import { describe, it, test } from 'poku'; describe.only(() => { + // ✅ Will be executed + it(() => { - // ... + // ✅ Will be executed }); test(() => { - // ... + // ✅ Will be executed }); }); -test(() => { - // ... -}); -``` - -```bash -npx poku --only=describe -``` - -:::note - -- `describe` methods without `.only` will be skipped. -- `it` and `test` methods without `.only` will be executed normally, including outside the scope of `describe` (top-level). - -::: - -### `--only=it` - -> Alternative flag: `--only=test` - -Enables the `.only` helper for `it` and `test` methods. - -
- -- ✅ `it.only` -- ✅ `test.only` -- ✅ `describe` -- ⏭️ `it` _(it will be skipped)_ -- ⏭️ `test` _(it will be skipped)_ -- ❌ `describe.only` _(it forces a failure since `describe.only` is not enabled in `--only=it`)_ - -
- -```ts -import { describe, it, test } from 'poku'; - describe(() => { - it.only(() => { - // ... - }); + // ⏭️ Will be skipped - test.only(() => { - // ... + it(() => { + // ⏭️ Will be skipped }); -}); - -test.only(() => { - // ... -}); -``` - -```bash -npx poku --only=it -``` - -:::note - -- `it` and `test` methods without `.only` will be skipped. -- `describe` methods without `.only` will be executed normally. - -::: - ---- - -:::tip - -- The `.only` helper works exactly as its respective `describe`, `it` and `test` methods (e.g., by running `beforeEach` and `afterEach` for the `test.only` or `it.only`). -- It works for both sequential and parallel executions normally, including synchronous and asynchronous tests. - -::: - -:::danger Important -It's important to recall that **Poku** respects conventional **JavaScript** syntax in tests and doesn't change the order of the executions. See the [examples](#complex-examples) to clarify it. -::: - ---- - -## Common issues - -### `.only` vs. scope - -If a `.only` method is inside a skipped method, it won't be executed, for example: - -```ts -import { describe, it, test } from 'poku'; -describe.only(() => { - it.only(() => { - // ... ✅ + test(() => { + // ⏭️ Will be skipped }); - - // it(() => { - // // ... - // }); - - // test(() => { - // // ... - // }); }); -// describe(() => { -// it.only(() => { -// // ... ❌ -// }); -// -// test(() => { -// // ... -// }); -// }); -``` - -```bash -npx poku --only -``` - ---- - -## Migrating from other Test Runners - -In **Poku**, the `.only` helper works like a switch: - -- To enable the `.only` helper for both `describe`, `it` and `test` methods, you need to use the `--only` flag. -- To enable the `.only` helper for `describe` methods, you need to use the `--only=describe` flag. -- To enable the `.only` helper for `it` and `test` methods, you need to use the `--only=it` flag. - -An example running a `it.only` inside a `describe` method without `.only`: +describe(() => { + // ✅ Will be executed -```ts -import { describe, it } from 'poku'; + it(() => { + // ⏭️ Will be skipped + }); -describe(() => { it.only(() => { - // ... ✅ + // ✅ Will be executed }); - // it(() => { - // // ... - // }); -}); -``` - -```bash -npx poku --only=it -``` - -This way, you enable `.only` only for `it` and `test` methods, keeping `describe` methods with their default behavior. It means that `describe` methods will run even without `.only` due to `--only=it`, while `it` and `test` methods will only run if you use the `.only` helper. - -It's also important to note that the `--only` flag applies to all files to be tested and you can use the flag with or without `poku` command, for example: - -```bash -npx poku test/my-test.test.js --only -``` - -```bash -node test/my-test.test.js --only -``` - -```bash -npx tsx test/my-test.test.ts --only -``` - ---- - -## Mapped vs. non-mapped tests _(advanced concept)_ - -**Poku** doesn't map the tests to determine which ones will be run or not from appending `.only` tests, instead, it toggles which methods (`describe`, `it` and `test`) will be run according to the flags `--only`, `--only=describe` or `--only=it`. - -Why isn't `it.only` executed in the following example? - -```ts -describe(() => { - it.only(() => { - // ... ❌ + test(() => { + // ⏭️ Will be skipped }); }); ``` @@ -287,76 +113,19 @@ describe(() => { npx poku --only ``` -As the `describe` method isn't using the `.only` helper, it will be skipped, including everything within its scope, which includes the `it.only` in this example. - --- -## Complex examples - -### `--only=it` - -```ts -import { describe, it, test, assert, beforeEach, afterEach } from 'poku'; - -beforeEach(() => { - // It will run normally before all `it.only` and `test.only`. -}); - -afterEach(() => { - // It will run normally after all `it.only` and `test.only`. -}); - -let counter = 0; - -// ⬇️ `describe` scopes ⬇️ - -describe('1', () => { - counter++; // ✅ `describe` scope will be executed as it's in "native" JavaScript flow - - it.only('2', () => { - counter++; // ✅ `it.only` will be executed - }); - - it('3', () => { - counter++; // ⏭️ `it` will be skipped - }); - - test.only('4', () => { - counter++; // ✅ `test.only` will be executed - }); - - test('5', () => { - counter++; // ⏭️ `test` will be skipped - }); -}); - -// ⬇️ Top-level or non-`describe` scopes ⬇️ - -counter++; // ✅ Will be executed as it's in "native" JavaScript flow - -test('6', () => { - counter++; // ⏭️ `test` will be skipped -}); - -test.only('7', () => { - counter++; // ✅ `test.only` will be executed -}); +:::tip -it('8', () => { - counter++; // ⏭️ `it` will be skipped -}); +- The `.only` modifier works exactly as its respective `describe`, `it` and `test` methods (e.g., by running `beforeEach` and `afterEach` for the `test.only` or `it.only`). +- It's not possible to run `.only` modifiers without `--only` flag. -it.only('9', () => { - counter++; // ✅ `it.only` will be executed -}); +::: -// describe.only('10', () => { -// counter++; // ❌ It would force a failure since `describe.only` is not enabled in `--only=it` -// }); +:::note +It's important to recall that **Poku** respects conventional **JavaScript** syntax in tests and doesn't change the order of the executions. +::: -assert.strictEqual(counter, 6); -``` +--- -```bash -npx poku --only=it -``` +### Examples From 7c90894b403d8f92363a17d461ed1cd9f6fccd79 Mon Sep 17 00:00:00 2001 From: wellwelwel <46850407+wellwelwel@users.noreply.github.com> Date: Sat, 21 Dec 2024 07:48:39 -0300 Subject: [PATCH 9/9] docs: improve only documentation --- website/docs/documentation/helpers/only.mdx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/website/docs/documentation/helpers/only.mdx b/website/docs/documentation/helpers/only.mdx index c7c4d615..d3b43776 100644 --- a/website/docs/documentation/helpers/only.mdx +++ b/website/docs/documentation/helpers/only.mdx @@ -125,7 +125,3 @@ npx poku --only :::note It's important to recall that **Poku** respects conventional **JavaScript** syntax in tests and doesn't change the order of the executions. ::: - ---- - -### Examples