diff --git a/package-lock.json b/package-lock.json index b86f62a..da68867 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "@pokujs/scope-hooks", - "version": "1.0.1-rc.0", + "version": "1.0.0-rc.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pokujs/scope-hooks", - "version": "1.0.1-rc.0", + "version": "1.0.0-rc.1", "license": "MIT", "devDependencies": { "@ianvs/prettier-plugin-sort-imports": "^4.7.0", "@types/node": "^25.5.0", - "poku": "file:../poku", + "poku": "^4.3.0", "prettier": "^3.6.2", "rimraf": "^6.0.1", "tsx": "^4.21.0", @@ -24,40 +24,7 @@ "typescript": ">=6.x.x" }, "peerDependencies": { - "poku": ">=4.2.0" - } - }, - "../poku": { - "name": "poku", - "version": "4.2.0", - "dev": true, - "license": "MIT", - "bin": { - "poku": "lib/bin/index.js" - }, - "devDependencies": { - "@biomejs/biome": "^2.4.10", - "@ianvs/prettier-plugin-sort-imports": "^4.7.1", - "@pokujs/c8": "^1.0.2", - "@pokujs/docker": "^1.0.0", - "@types/node": "^25.5.0", - "concurrently": "^9.2.1", - "jsonc.min": "^1.1.2", - "monocart-coverage-reports": "^2.12.9", - "packages-update": "^2.0.0", - "prettier": "^3.8.1", - "tsx": "^4.21.0", - "typescript": "^6.0.2" - }, - "engines": { - "bun": ">=1.x.x", - "deno": ">=2.x.x", - "node": ">=16.x.x", - "typescript": ">=5.x.x" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wellwelwel" + "poku": ">=4.3.0" } }, "node_modules/@babel/code-frame": { @@ -703,13 +670,13 @@ } }, "node_modules/@types/node": { - "version": "25.5.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", - "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": "~7.19.0" } }, "node_modules/balanced-match": { @@ -811,9 +778,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.13.7", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", - "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", "dev": true, "license": "MIT", "dependencies": { @@ -862,9 +829,9 @@ } }, "node_modules/lru-cache": { - "version": "11.3.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.2.tgz", - "integrity": "sha512-wgWa6FWQ3QRRJbIjbsldRJZxdxYngT/dO0I5Ynmlnin8qy7tC6xYzbcJjtN4wHLXtkbVwHzk0C+OejVw1XM+DQ==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -936,13 +903,29 @@ "license": "ISC" }, "node_modules/poku": { - "resolved": "../poku", - "link": true + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/poku/-/poku-4.3.0.tgz", + "integrity": "sha512-s6xHA93lzirvScBuW5UxUAbx4Cw6C/5MEMTe/27jTtLkDmIsWNpUH2CiMbSOKMxLGj7C3JoM2zfacu3kCrlk3Q==", + "dev": true, + "license": "MIT", + "bin": { + "poku": "lib/bin/index.js" + }, + "engines": { + "bun": ">=1.x.x", + "deno": ">=2.x.x", + "node": ">=16.x.x", + "typescript": ">=5.x.x" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wellwelwel" + } }, "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, "license": "MIT", "bin": { @@ -1019,9 +1002,9 @@ } }, "node_modules/typescript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", - "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -1033,9 +1016,9 @@ } }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "dev": true, "license": "MIT" } diff --git a/package.json b/package.json index d7808cd..bb3939e 100644 --- a/package.json +++ b/package.json @@ -57,12 +57,12 @@ "provenance": true }, "peerDependencies": { - "poku": ">=4.2.0" + "poku": ">=4.3.0" }, "devDependencies": { "@ianvs/prettier-plugin-sort-imports": "^4.7.0", "@types/node": "^25.5.0", - "poku": "file:../poku", + "poku": "^4.3.0", "prettier": "^3.6.2", "rimraf": "^6.0.1", "tsx": "^4.21.0", diff --git a/src/index.ts b/src/index.ts index f9c62e9..b6cb2c7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import { SCOPE_HOOKS_KEY } from 'poku/plugins'; +const SCOPE_HOOKS_KEY = Symbol.for('@pokujs/poku.test-scope-hooks'); export type ScopeHookHolder = { scope: unknown }; diff --git a/tests/__fixtures__/integration/scope-hooks/integration.fixture.ts b/tests/__fixtures__/integration/scope-hooks/integration.fixture.ts new file mode 100644 index 0000000..772320c --- /dev/null +++ b/tests/__fixtures__/integration/scope-hooks/integration.fixture.ts @@ -0,0 +1,79 @@ +import { AsyncLocalStorage } from 'node:async_hooks'; +import { assert, describe, it } from 'poku'; +import { composeScopeHooks } from '../../../../src/index.ts'; + +const als = new AsyncLocalStorage(); +const events: string[] = []; +const seenIds: number[] = []; +let idSeed = 0; + +composeScopeHooks({ + name: '@pokujs/scope-hooks.integration-fixture', + createHolder: () => ({ scope: undefined }), + runScoped: async (holder, fn) => { + const id = ++idSeed; + holder.scope = { id }; + events.push(`before:${id}`); + + await als.run(id, async () => { + const result = fn(); + if (result instanceof Promise) await result; + }); + + events.push(`after:${id}`); + }, +}); + +await describe('scope hooks integration fixture', async () => { + const runs = [ + it('first test executes inside the composed scope', async () => { + const id = als.getStore(); + assert.ok(typeof id === 'number', 'ALS store exists for the first test'); + seenIds.push(id as number); + + await Promise.resolve(); + + assert.strictEqual( + als.getStore(), + id, + 'ALS store remains stable for the first test' + ); + + events.push(`test:${id}`); + }), + + it('second test executes inside the composed scope', async () => { + const id = als.getStore(); + assert.ok(typeof id === 'number', 'ALS store exists for the second test'); + seenIds.push(id as number); + + await Promise.resolve(); + + assert.strictEqual( + als.getStore(), + id, + 'ALS store remains stable for the second test' + ); + + events.push(`test:${id}`); + }), + ]; + + await Promise.all(runs); +}); + +assert.strictEqual(seenIds.length, 2, 'Both poku it callbacks executed'); +assert.ok( + seenIds[0] !== seenIds[1], + 'Each poku it callback received an isolated scope id' +); + +for (const id of seenIds) { + const beforeIndex = events.indexOf(`before:${id}`); + const testIndex = events.indexOf(`test:${id}`); + const afterIndex = events.indexOf(`after:${id}`); + + assert.ok(beforeIndex >= 0, `before hook ran for scope ${id}`); + assert.ok(testIndex > beforeIndex, `test body ran after before hook for scope ${id}`); + assert.ok(afterIndex > testIndex, `after hook ran after test body for scope ${id}`); +} \ No newline at end of file diff --git a/tests/poku-integration.test.ts b/tests/poku-integration.test.ts index 1de0162..5484c54 100644 --- a/tests/poku-integration.test.ts +++ b/tests/poku-integration.test.ts @@ -1,110 +1,14 @@ -import { mkdtemp, rm, writeFile } from 'node:fs/promises'; -import { join, relative } from 'node:path'; import process from 'node:process'; -import { afterEach, assert, test } from 'poku'; +import { assert, test } from 'poku'; test('scope hooks integrate with poku it execution', async () => { const repoDir = process.cwd(); - const tempDir = await mkdtemp(join(repoDir, '.poku-scope-hooks-')); - const fixturePath = join(tempDir, 'scope-hooks-it.fixture.ts'); - const fixtureRelativePath = relative(repoDir, fixturePath).replaceAll( - '\\', - '/' - ); - const scopeHooksModuleUrl = new URL('../src/index.ts', import.meta.url).href; - - const fixtureSource = ` -import { AsyncLocalStorage } from 'node:async_hooks'; -import { assert, describe, it } from 'poku'; -import { composeScopeHooks } from '${scopeHooksModuleUrl}'; - -const als = new AsyncLocalStorage(); -const events: string[] = []; -const seenIds: number[] = []; -let idSeed = 0; - -composeScopeHooks({ - name: '@pokujs/scope-hooks.integration-fixture', - createHolder: () => ({ scope: undefined }), - runScoped: async (holder, fn) => { - const id = ++idSeed; - holder.scope = { id }; - events.push(\`before:\${id}\`); - - await als.run(id, async () => { - const result = fn(); - if (result instanceof Promise) await result; - }); - - events.push(\`after:\${id}\`); - }, -}); - -await describe('scope hooks integration fixture', async () => { - const runs = [ - it('first test executes inside the composed scope', async () => { - const id = als.getStore(); - assert.ok(typeof id === 'number', 'ALS store exists for the first test'); - seenIds.push(id as number); - - await Promise.resolve(); - - assert.strictEqual( - als.getStore(), - id, - 'ALS store remains stable for the first test' - ); - - events.push(\`test:\${id}\`); - }), - - it('second test executes inside the composed scope', async () => { - const id = als.getStore(); - assert.ok(typeof id === 'number', 'ALS store exists for the second test'); - seenIds.push(id as number); - - await Promise.resolve(); - - assert.strictEqual( - als.getStore(), - id, - 'ALS store remains stable for the second test' - ); - - events.push(\`test:\${id}\`); - }), - ]; - - await Promise.all(runs); -}); - -assert.strictEqual(seenIds.length, 2, 'Both poku it callbacks executed'); -assert.ok( - seenIds[0] !== seenIds[1], - 'Each poku it callback received an isolated scope id' -); - -for (const id of seenIds) { - const beforeIndex = events.indexOf(\`before:\${id}\`); - const testIndex = events.indexOf(\`test:\${id}\`); - const afterIndex = events.indexOf(\`after:\${id}\`); - - assert.ok(beforeIndex >= 0, \`before hook ran for scope \${id}\`); - assert.ok(testIndex > beforeIndex, \`test body ran after before hook for scope \${id}\`); - assert.ok(afterIndex > testIndex, \`after hook ran after test body for scope \${id}\`); -} -`; - - afterEach(async () => { - await rm(tempDir, { recursive: true, force: true }); - }); - - await writeFile(fixturePath, fixtureSource, 'utf8'); + const fixturePath = 'tests/__fixtures__/integration/scope-hooks/integration.fixture.ts'; const { inspectPoku } = await import('poku/plugins'); const result = await inspectPoku({ - command: `./${fixtureRelativePath} --showLogs`, + command: `${fixturePath} --showLogs`, spawnOptions: { cwd: repoDir }, }); @@ -125,4 +29,4 @@ for (const id of seenIds) { result.stdout.includes('second test executes inside the composed scope'), 'Second test executed through poku' ); -}); +}); \ No newline at end of file diff --git a/tests/scope-hooks.test.ts b/tests/scope-hooks.test.ts index c9bb253..35852ec 100644 --- a/tests/scope-hooks.test.ts +++ b/tests/scope-hooks.test.ts @@ -1,7 +1,8 @@ import { afterEach, assert, beforeEach, test } from 'poku'; -import { SCOPE_HOOKS_KEY } from 'poku/plugins'; import { composeScopeHooks, getScopeHooks } from '../src/index.ts'; +const SCOPE_HOOKS_KEY = Symbol.for('@pokujs/poku.test-scope-hooks'); + const g = globalThis as Record; let originalHooks: unknown;