From 56e643d8fc7458f65274a25b83c2c12b336b3302 Mon Sep 17 00:00:00 2001 From: RolandSall Date: Fri, 11 Sep 2026 16:06:10 +0300 Subject: [PATCH 1/2] Rename npm package to @integration-testing/data-isolation --- CHANGELOG.md | 2 +- README.md | 44 +++++++++---------- bun.lock | 12 ++--- docs/releasing.md | 22 ++++++---- examples/nestjs-inventory/README.md | 2 +- examples/nestjs-inventory/jest.config.cjs | 2 +- examples/nestjs-inventory/package.json | 2 +- examples/nestjs-inventory/test/context.ts | 8 ++-- .../nestjs-inventory/test/failure.test.ts | 2 +- .../test/inventory.integration.test.ts | 2 +- examples/nestjs-inventory/test/jest.setup.ts | 2 +- .../test/parallel.integration.test.ts | 2 +- .../nestjs-inventory/test/vitest.setup.ts | 2 +- examples/with-testcontainers/README.md | 4 +- examples/with-testcontainers/package.json | 2 +- .../with-testcontainers/test/data.setup.ts | 4 +- .../test/notes.container.integration.test.ts | 2 +- .../test/second.container.integration.test.ts | 2 +- examples/without-testcontainers/README.md | 2 +- examples/without-testcontainers/package.json | 2 +- .../without-testcontainers/test/data.setup.ts | 4 +- .../test/notes.integration.test.ts | 2 +- package.json | 5 ++- packages/data/README.md | 44 +++++++++---------- packages/data/package.json | 2 +- packages/data/src/jest/index.ts | 2 +- scripts/verify-demo.ts | 34 +++++++++----- scripts/verify-package.ts | 40 ++++++++--------- scripts/verify-release.ts | 2 +- scripts/verify-runner-minimum.ts | 2 +- scripts/verify-runners.ts | 8 ++-- 31 files changed, 143 insertions(+), 124 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9a9695..3b5167e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - Add the TypeORM adapter and preserve errors across rollback and resource release. - Verify nested fixtures, retries, timeouts, expected failures, and declaration isolation in child processes. - Include a repository-only NestJS consumer verified outside the workspace against the packed package, covering the real database matrix and handwritten baselines. -- Extract the database test annotation and lifecycle manager into `@integration-testing/data`. +- Extract the database test annotation and lifecycle manager into `@integration-testing/data-isolation`. - Include optional Prisma and node-postgres rollback adapters. - Provide independent examples with the published Testcontainers package and without containers. - Preserve original setup failures when cleanup also fails. diff --git a/README.md b/README.md index eee81e8..4e07c04 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# @integration-testing/data +# @integration-testing/data-isolation **Write isolated database integration tests with a consistent API across supported test runners and database clients.** @@ -21,7 +21,7 @@ Configure your database and test runner once. Then declare each transactional te the shared context: ```ts -import { declareDataIntegrationTest } from '@integration-testing/data'; +import { declareDataIntegrationTest } from '@integration-testing/data-isolation'; import { dataContext } from './data-context.js'; declareDataIntegrationTest(); @@ -44,7 +44,7 @@ class has the same effect as `declareDataIntegrationTest()`; use one form per fi Use **[@integration-testing/testcontainers](https://www.npmjs.com/package/@integration-testing/testcontainers)** to start a disposable PostgreSQL instance and provide its connection URL. Apply your application's -real migrations once, then use **@integration-testing/data** to roll back each test's writes. +real migrations once, then use **@integration-testing/data-isolation** to roll back each test's writes. Testcontainers Integration stops the infrastructure after the run; Data Integration manages the test transactions and its configured clients. @@ -94,7 +94,7 @@ not establish SQL Server transaction support. **Release target: `0.1.0`.** Once this version is available on npm, install it with: ```sh -npm install --save-dev @integration-testing/data@0.1.0 +npm install --save-dev @integration-testing/data-isolation@0.1.0 ``` Before publication, use a local package archive instead. Build and pack this repository: @@ -109,7 +109,7 @@ npm pack ./packages/data --pack-destination . Copy the resulting archive to your application's `vendor` directory and install it: ```sh -npm install --save-dev ./vendor/integration-testing-data-0.1.0.tgz +npm install --save-dev ./vendor/integration-testing-data-isolation-0.1.0.tgz ``` For the pg quick start, install the driver and TypeScript tooling: @@ -149,8 +149,8 @@ exist, merge the relevant options into them. ```ts // test/data-context.ts import { Pool } from 'pg'; -import { createDataIntegrationTestContext } from '@integration-testing/data'; -import { PgTransactionAdapter } from '@integration-testing/data/pg'; +import { createDataIntegrationTestContext } from '@integration-testing/data-isolation'; +import { PgTransactionAdapter } from '@integration-testing/data-isolation/pg'; export function databaseUrl(): string { const url = process.env.DATABASE_URL; @@ -180,7 +180,7 @@ Export it once and import that same instance from your test files. ```ts // test/vitest.setup.ts -import { installVitestDataIntegrationTestSupport } from '@integration-testing/data/vitest'; +import { installVitestDataIntegrationTestSupport } from '@integration-testing/data-isolation/vitest'; import { dataContext } from './data-context.js'; installVitestDataIntegrationTestSupport(dataContext); @@ -241,7 +241,7 @@ runs unchanged under Jest: ```ts // test/products.integration.test.ts -import { declareDataIntegrationTest } from '@integration-testing/data'; +import { declareDataIntegrationTest } from '@integration-testing/data-isolation'; import { dataContext } from './data-context.js'; declareDataIntegrationTest(); @@ -283,7 +283,7 @@ a test-class instance or register test methods. Continue using your runner's ord If you prefer annotations, replace the `declareDataIntegrationTest` import and call with: ```ts -import { DataIntegrationTest } from '@integration-testing/data'; +import { DataIntegrationTest } from '@integration-testing/data-isolation'; @DataIntegrationTest export class ProductRepositoryTest {} @@ -336,7 +336,7 @@ start; select Jest types as described below. ```ts // test/jest.setup.ts -import { installJestDataIntegrationTestSupport } from '@integration-testing/data/jest'; +import { installJestDataIntegrationTestSupport } from '@integration-testing/data-isolation/jest'; import { dataContext } from './data-context.js'; installJestDataIntegrationTestSupport(dataContext); @@ -345,7 +345,7 @@ installJestDataIntegrationTestSupport(dataContext); ```js // jest.integration.config.cjs module.exports = { - testEnvironment: '@integration-testing/data/jest/environment', + testEnvironment: '@integration-testing/data-isolation/jest/environment', setupFilesAfterEnv: ['/test/jest.setup.ts'], testMatch: ['**/test/**/*.integration.test.ts'], maxWorkers: 2, @@ -539,7 +539,7 @@ Replace `test/vitest.setup.ts` with: import { Container, ContainerResources } from '@integration-testing/testcontainers'; import { CONTAINER_RESOURCES_CONTEXT_KEY } from '@integration-testing/testcontainers/vitest'; import { inject } from 'vitest'; -import { installVitestDataIntegrationTestSupport } from '@integration-testing/data/vitest'; +import { installVitestDataIntegrationTestSupport } from '@integration-testing/data-isolation/vitest'; import { dataContext } from './data-context.js'; const resources = ContainerResources.fromSerializable(inject(CONTAINER_RESOURCES_CONTEXT_KEY)); @@ -611,7 +611,7 @@ import { readFileSync } from 'node:fs'; import { Container, ContainerResources } from '@integration-testing/testcontainers'; import type { SerializableContainerResources } from '@integration-testing/testcontainers'; import { JEST_CONTAINER_RESOURCES_PATH_ENV } from '@integration-testing/testcontainers/jest'; -import { installJestDataIntegrationTestSupport } from '@integration-testing/data/jest'; +import { installJestDataIntegrationTestSupport } from '@integration-testing/data-isolation/jest'; import { dataContext } from './data-context.js'; const resourcePath = process.env[JEST_CONTAINER_RESOURCES_PATH_ENV]; @@ -668,8 +668,8 @@ npx prisma generate ```ts // test/data-context.ts import { PrismaClient, type Prisma } from '@prisma/client'; -import { createDataIntegrationTestContext } from '@integration-testing/data'; -import { PrismaTransactionAdapter } from '@integration-testing/data/prisma'; +import { createDataIntegrationTestContext } from '@integration-testing/data-isolation'; +import { PrismaTransactionAdapter } from '@integration-testing/data-isolation/prisma'; export const dataContext = createDataIntegrationTestContext({ getResources: () => { @@ -718,8 +718,8 @@ npm install typeorm@~0.3.28 pg@8 reflect-metadata // test/data-context.ts import 'reflect-metadata'; import { DataSource } from 'typeorm'; -import { createDataIntegrationTestContext } from '@integration-testing/data'; -import { TypeOrmTransactionAdapter } from '@integration-testing/data/typeorm'; +import { createDataIntegrationTestContext } from '@integration-testing/data-isolation'; +import { TypeOrmTransactionAdapter } from '@integration-testing/data-isolation/typeorm'; import { ProductEntity, ReservationEntity } from '../src/entities.js'; export const dataContext = createDataIntegrationTestContext({ @@ -795,7 +795,7 @@ are for applications whose SQLite migrations are maintained by Prisma. The testing library does not patch production clients. Override the database provider in a NestJS `TestingModule` with the scoped client. Application services and repositories should not import -`@integration-testing/data`. +`@integration-testing/data-isolation`. For an application exposing `DATABASE_CLIENT`, `InventoryRepository`, and `InventoryService`, the pg implementation can be tested like this: @@ -803,7 +803,7 @@ the pg implementation can be tested like this: ```ts import 'reflect-metadata'; import { Test, type TestingModule } from '@nestjs/testing'; -import { DataIntegrationTest } from '@integration-testing/data'; +import { DataIntegrationTest } from '@integration-testing/data-isolation'; import { dataContext } from './data-context.js'; import { DATABASE_CLIENT, InventoryRepository, InventoryService } from '../src/inventory.js'; import { PgInventoryRepository } from '../src/pg-repository.js'; @@ -892,7 +892,7 @@ Testcontainers as a dependency. | --- | --- | | Shared `ContainerRuntime` launcher | Verified with PostgreSQL + pg, Prisma 6.19, and TypeORM 0.3 under Jest and Vitest, using an installed data package archive | | Shared native `createVitestContainerGlobalSetup` | Verified with pg, global migrations, and transaction-scoped tests | -| Shared native `createJestContainerGlobalSetup` | Verified with pg while retaining `@integration-testing/data/jest/environment` | +| Shared native `createJestContainerGlobalSetup` | Verified with pg while retaining `@integration-testing/data-isolation/jest/environment` | | Named `@RequiredContainer` with `isolation: 'shared'` and manual global setup | Demonstrated by the small Vitest example; both files select the same named database | | Generated annotation/project file setup, including `isolation: 'dedicated'` | Not a supported drop-in pairing in this release; file lifecycle coordination is still needed | | RabbitMQ, MongoDB, or SQL Server containers | Available infrastructure in Testcontainers Integration; this does not add transactional adapter coverage to Data Integration | @@ -902,7 +902,7 @@ Testcontainers as a dependency. ```ts import { Container, RequiredContainer } from '@integration-testing/testcontainers'; -import { DataIntegrationTest } from '@integration-testing/data'; +import { DataIntegrationTest } from '@integration-testing/data-isolation'; @RequiredContainer({ database: { kind: Container.PostgreSql, isolation: 'shared' }, diff --git a/bun.lock b/bun.lock index d2b8deb..cf9d9c4 100644 --- a/bun.lock +++ b/bun.lock @@ -6,7 +6,7 @@ "name": "data-integration-testing-workspace", "devDependencies": { "@eslint/js": "^9.35.0", - "@integration-testing/data": "workspace:*", + "@integration-testing/data-isolation": "workspace:*", "@jest/types": "^30.0.0", "@types/jest": "^30.0.0", "@types/node": "^22.18.0", @@ -36,7 +36,7 @@ "typeorm": "~0.3.28", }, "devDependencies": { - "@integration-testing/data": "workspace:*", + "@integration-testing/data-isolation": "workspace:*", "@integration-testing/testcontainers": "0.1.0", "@nestjs/testing": "^11.1.0", "@types/jest": "^30.0.0", @@ -54,7 +54,7 @@ "name": "example-with-testcontainers", "version": "0.0.0", "dependencies": { - "@integration-testing/data": "workspace:*", + "@integration-testing/data-isolation": "workspace:*", "@integration-testing/testcontainers": "0.1.0", "pg": "^8.16.3", "vitest": "~4.1.11", @@ -64,7 +64,7 @@ "name": "example-without-testcontainers", "version": "0.0.0", "dependencies": { - "@integration-testing/data": "workspace:*", + "@integration-testing/data-isolation": "workspace:*", "@prisma/client": "6.19.3", "vitest": "~4.1.11", }, @@ -73,7 +73,7 @@ }, }, "packages/data": { - "name": "@integration-testing/data", + "name": "@integration-testing/data-isolation", "version": "0.1.0-beta.0", "peerDependencies": { "jest": ">=30.1 <31", @@ -260,7 +260,7 @@ "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], - "@integration-testing/data": ["@integration-testing/data@workspace:packages/data"], + "@integration-testing/data-isolation": ["@integration-testing/data-isolation@workspace:packages/data"], "@integration-testing/testcontainers": ["@integration-testing/testcontainers@0.1.0", "", { "dependencies": { "@testcontainers/mongodb": "12.1.0", "@testcontainers/mssqlserver": "12.1.0", "@testcontainers/postgresql": "12.1.0", "@testcontainers/rabbitmq": "12.1.0", "testcontainers": "12.1.0", "typescript": ">=5.5 <7" }, "peerDependencies": { "jest": ">=30 <31", "vitest": ">=4 <5" }, "optionalPeers": ["jest", "vitest"] }, "sha512-e7+/e4gzEQb4hzXzG7ORZ+Y4QEZIgS6zkGcL/836PPbrGLI8KxH9AuCwQUIdgY+m9zWYziFpTefMIeEp6YWgBw=="], diff --git a/docs/releasing.md b/docs/releasing.md index 8a72c97..032420e 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -1,4 +1,4 @@ -# Publishing @integration-testing/data +# Publishing @integration-testing/data-isolation The first release target is **0.1.0**, published with npm's **latest** tag. Preparing the version, passing CI, and opening a release PR do not publish the package. @@ -42,7 +42,7 @@ publishing. The package does not inherit authentication or trusted-publisher set 4. When ready to publish, run: ```sh - npm publish ./.artifacts/integration-testing-data-0.1.0.tgz --access public --tag latest + npm publish ./.artifacts/integration-testing-data-isolation-0.1.0.tgz --access public --tag latest ``` This publishes the archive produced by the package checks. The publication is permanent for @@ -50,14 +50,20 @@ publishing. The package does not inherit authentication or trusted-publisher set 5. Check the registry rather than relying only on the command's exit status: ```sh - npm view @integration-testing/data@0.1.0 version dist.integrity repository --json - npm view @integration-testing/data dist-tags --json + npm view @integration-testing/data-isolation@0.1.0 version dist.integrity repository --json + npm view @integration-testing/data-isolation dist-tags --json ``` -6. In a clean directory outside this repository, install `@integration-testing/data@0.1.0` from - npm and run the documented setup against a migrated test database. Confirm that `latest` - resolves to `0.1.0` before announcing availability. A locally packed consumer does not prove - registry installation. +6. Run the registry consumer check from the repository root: + + ```sh + bun run test:consumer:published + ``` + + It copies the application outside the workspace, installs the manifest's exact package version + from npm (without a local tarball or source alias), and runs the same database matrix. Confirm + that `latest` resolves to `0.1.0` before announcing availability. A locally packed consumer + does not prove registry installation. ## Configure trusted publishing for subsequent releases diff --git a/examples/nestjs-inventory/README.md b/examples/nestjs-inventory/README.md index 5a3877c..7868d2a 100644 --- a/examples/nestjs-inventory/README.md +++ b/examples/nestjs-inventory/README.md @@ -1,6 +1,6 @@ # Transactional inventory integration tests -A small NestJS inventory application exercising `@integration-testing/data` from this repository. The same repositories, transaction configuration, and test scenarios run under +A small NestJS inventory application exercising `@integration-testing/data-isolation` from this repository. The same repositories, transaction configuration, and test scenarios run under Jest 30 and Vitest 4.1. The example is excluded from the published npm package. ## Run diff --git a/examples/nestjs-inventory/jest.config.cjs b/examples/nestjs-inventory/jest.config.cjs index e587ab8..28bf955 100644 --- a/examples/nestjs-inventory/jest.config.cjs +++ b/examples/nestjs-inventory/jest.config.cjs @@ -1,6 +1,6 @@ module.exports = { testMatch: [process.env.FAILURE_MODE ? '**/test/failure.test.ts' : process.env.BASELINE ? '**/test/baseline.test.ts' : '**/test/*.integration.test.ts'], - testEnvironment: process.env.BASELINE ? 'node' : '@integration-testing/data/jest/environment', + testEnvironment: process.env.BASELINE ? 'node' : '@integration-testing/data-isolation/jest/environment', setupFilesAfterEnv: process.env.BASELINE ? [] : ['/test/jest.setup.ts'], maxWorkers: process.env.DATA_CLIENT === 'sqlite' ? 1 : 2, testTimeout: 30000, diff --git a/examples/nestjs-inventory/package.json b/examples/nestjs-inventory/package.json index 1418177..e5efcf4 100644 --- a/examples/nestjs-inventory/package.json +++ b/examples/nestjs-inventory/package.json @@ -28,7 +28,7 @@ "typeorm": "~0.3.28" }, "devDependencies": { - "@integration-testing/data": "workspace:*", + "@integration-testing/data-isolation": "workspace:*", "@integration-testing/testcontainers": "0.1.0", "@nestjs/testing": "^11.1.0", "@types/node": "^22.18.0", diff --git a/examples/nestjs-inventory/test/context.ts b/examples/nestjs-inventory/test/context.ts index 9697bcd..be118bd 100644 --- a/examples/nestjs-inventory/test/context.ts +++ b/examples/nestjs-inventory/test/context.ts @@ -3,10 +3,10 @@ import { migrateSqlite } from '../src/migrate.js'; import { DataSource } from 'typeorm'; import { PrismaClient as PgPrisma, type Prisma } from '../generated/postgresql/index.js'; import { PrismaClient as SqlitePrisma, type Prisma as SqlitePrismaTypes } from '../generated/sqlite/index.js'; -import { createDataIntegrationTestContext } from '@integration-testing/data'; -import { PgTransactionAdapter } from '@integration-testing/data/pg'; -import { PrismaTransactionAdapter } from '@integration-testing/data/prisma'; -import { TypeOrmTransactionAdapter } from '@integration-testing/data/typeorm'; +import { createDataIntegrationTestContext } from '@integration-testing/data-isolation'; +import { PgTransactionAdapter } from '@integration-testing/data-isolation/pg'; +import { PrismaTransactionAdapter } from '@integration-testing/data-isolation/prisma'; +import { TypeOrmTransactionAdapter } from '@integration-testing/data-isolation/typeorm'; import { ProductEntity, ReservationEntity } from '../src/typeorm-repository.js'; import { createDatabase, dropDatabase, poolFor, migratePostgres, assertPostgresEmpty } from './database.js'; diff --git a/examples/nestjs-inventory/test/failure.test.ts b/examples/nestjs-inventory/test/failure.test.ts index a4e3dc9..a89c25e 100644 --- a/examples/nestjs-inventory/test/failure.test.ts +++ b/examples/nestjs-inventory/test/failure.test.ts @@ -1,4 +1,4 @@ -import { declareDataIntegrationTest } from '@integration-testing/data'; +import { declareDataIntegrationTest } from '@integration-testing/data-isolation'; import type { TestingModule } from '@nestjs/testing'; import { InventoryRepository, InventoryService } from '../src/inventory.js'; import { applicationFor } from './application.js'; diff --git a/examples/nestjs-inventory/test/inventory.integration.test.ts b/examples/nestjs-inventory/test/inventory.integration.test.ts index fc2e5f3..afe5628 100644 --- a/examples/nestjs-inventory/test/inventory.integration.test.ts +++ b/examples/nestjs-inventory/test/inventory.integration.test.ts @@ -1,4 +1,4 @@ -import { DataIntegrationTest } from '@integration-testing/data'; +import { DataIntegrationTest } from '@integration-testing/data-isolation'; import { currentClient, clientKind } from './context.js'; import { inventoryScenarios } from './scenarios.js'; @DataIntegrationTest diff --git a/examples/nestjs-inventory/test/jest.setup.ts b/examples/nestjs-inventory/test/jest.setup.ts index 84e0b4b..8b76105 100644 --- a/examples/nestjs-inventory/test/jest.setup.ts +++ b/examples/nestjs-inventory/test/jest.setup.ts @@ -1,4 +1,4 @@ -import { installJestDataIntegrationTestSupport as install } from '@integration-testing/data/jest'; +import { installJestDataIntegrationTestSupport as install } from '@integration-testing/data-isolation/jest'; import { clientKind, pgContext, prismaContext, sqliteContext, typeormContext } from './context.js'; switch (clientKind) { case 'prisma': install(prismaContext); break; diff --git a/examples/nestjs-inventory/test/parallel.integration.test.ts b/examples/nestjs-inventory/test/parallel.integration.test.ts index a718b3b..4d80b7a 100644 --- a/examples/nestjs-inventory/test/parallel.integration.test.ts +++ b/examples/nestjs-inventory/test/parallel.integration.test.ts @@ -1,4 +1,4 @@ -import { declareDataIntegrationTest } from '@integration-testing/data'; +import { declareDataIntegrationTest } from '@integration-testing/data-isolation'; import { currentClient, clientKind } from './context.js'; import { inventoryScenarios } from './scenarios.js'; declareDataIntegrationTest(); diff --git a/examples/nestjs-inventory/test/vitest.setup.ts b/examples/nestjs-inventory/test/vitest.setup.ts index 32075db..e461473 100644 --- a/examples/nestjs-inventory/test/vitest.setup.ts +++ b/examples/nestjs-inventory/test/vitest.setup.ts @@ -1,4 +1,4 @@ -import { installVitestDataIntegrationTestSupport as install } from '@integration-testing/data/vitest'; +import { installVitestDataIntegrationTestSupport as install } from '@integration-testing/data-isolation/vitest'; import { clientKind, pgContext, prismaContext, sqliteContext, typeormContext } from './context.js'; switch (clientKind) { case 'prisma': install(prismaContext); break; diff --git a/examples/with-testcontainers/README.md b/examples/with-testcontainers/README.md index d7d62d8..217d47d 100644 --- a/examples/with-testcontainers/README.md +++ b/examples/with-testcontainers/README.md @@ -1,6 +1,6 @@ # Data annotations with Testcontainers -This project uses `@integration-testing/data` and the published npm version +This project uses `@integration-testing/data-isolation` and the published npm version `@integration-testing/testcontainers@0.1.0`. It uses `pg`, not Prisma. From the repository root: @@ -25,5 +25,5 @@ This example therefore uses manual global setup without the generated container The container package stops the database after the run. No ports or credentials are hardcoded. To copy this project outside the workspace after publication, replace `workspace:*` with -`0.1.0` in its `@integration-testing/data` dependency, then run `bun install` +`0.1.0` in its `@integration-testing/data-isolation` dependency, then run `bun install` and `bun run test`. The TypeScript configuration is self-contained. diff --git a/examples/with-testcontainers/package.json b/examples/with-testcontainers/package.json index 83a943b..3931d29 100644 --- a/examples/with-testcontainers/package.json +++ b/examples/with-testcontainers/package.json @@ -7,7 +7,7 @@ "test": "vitest run" }, "dependencies": { - "@integration-testing/data": "workspace:*", + "@integration-testing/data-isolation": "workspace:*", "vitest": "~4.1.11", "@integration-testing/testcontainers": "0.1.0", "pg": "^8.16.3" diff --git a/examples/with-testcontainers/test/data.setup.ts b/examples/with-testcontainers/test/data.setup.ts index 24b89b4..044fb9c 100644 --- a/examples/with-testcontainers/test/data.setup.ts +++ b/examples/with-testcontainers/test/data.setup.ts @@ -2,8 +2,8 @@ import { Pool } from 'pg'; import { Container, ContainerResources } from '@integration-testing/testcontainers'; import { inject } from 'vitest'; import { CONTAINER_RESOURCES_CONTEXT_KEY } from '@integration-testing/testcontainers/vitest'; -import { PgTransactionAdapter } from '@integration-testing/data/pg'; -import { installVitestDataIntegrationTestSupport } from '@integration-testing/data/vitest'; +import { PgTransactionAdapter } from '@integration-testing/data-isolation/pg'; +import { installVitestDataIntegrationTestSupport } from '@integration-testing/data-isolation/vitest'; export const dataContext = installVitestDataIntegrationTestSupport({ getResources: () => ContainerResources.fromSerializable(inject(CONTAINER_RESOURCES_CONTEXT_KEY)) diff --git a/examples/with-testcontainers/test/notes.container.integration.test.ts b/examples/with-testcontainers/test/notes.container.integration.test.ts index 8862c2b..e821aca 100644 --- a/examples/with-testcontainers/test/notes.container.integration.test.ts +++ b/examples/with-testcontainers/test/notes.container.integration.test.ts @@ -1,4 +1,4 @@ -import { DataIntegrationTest } from '@integration-testing/data'; +import { DataIntegrationTest } from '@integration-testing/data-isolation'; import { Container, RequiredContainer } from '@integration-testing/testcontainers'; import { beforeEach, expect, test } from 'vitest'; import { dataContext } from './data.setup.js'; diff --git a/examples/with-testcontainers/test/second.container.integration.test.ts b/examples/with-testcontainers/test/second.container.integration.test.ts index 5ff568d..23669cf 100644 --- a/examples/with-testcontainers/test/second.container.integration.test.ts +++ b/examples/with-testcontainers/test/second.container.integration.test.ts @@ -1,4 +1,4 @@ -import { DataIntegrationTest } from '@integration-testing/data'; +import { DataIntegrationTest } from '@integration-testing/data-isolation'; import { Container, RequiredContainer } from '@integration-testing/testcontainers'; import { expect, test } from 'vitest'; import { dataContext } from './data.setup.js'; diff --git a/examples/without-testcontainers/README.md b/examples/without-testcontainers/README.md index 8bb757d..cebd067 100644 --- a/examples/without-testcontainers/README.md +++ b/examples/without-testcontainers/README.md @@ -1,6 +1,6 @@ # Data annotations without Testcontainers -This project uses `@integration-testing/data` with a real generated Prisma client and a +This project uses `@integration-testing/data-isolation` with a real generated Prisma client and a SQLite database in a fresh temporary directory. It has no Testcontainers dependency and needs no Docker or database server. diff --git a/examples/without-testcontainers/package.json b/examples/without-testcontainers/package.json index 2fb7ada..ff55303 100644 --- a/examples/without-testcontainers/package.json +++ b/examples/without-testcontainers/package.json @@ -8,7 +8,7 @@ "generate": "prisma generate" }, "dependencies": { - "@integration-testing/data": "workspace:*", + "@integration-testing/data-isolation": "workspace:*", "vitest": "~4.1.11", "@prisma/client": "6.19.3" }, diff --git a/examples/without-testcontainers/test/data.setup.ts b/examples/without-testcontainers/test/data.setup.ts index dd5a136..c48aae1 100644 --- a/examples/without-testcontainers/test/data.setup.ts +++ b/examples/without-testcontainers/test/data.setup.ts @@ -2,8 +2,8 @@ import { mkdtemp, rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { PrismaClient, type Prisma } from '../generated/client/index.js'; -import { PrismaTransactionAdapter } from '@integration-testing/data/prisma'; -import { installVitestDataIntegrationTestSupport } from '@integration-testing/data/vitest'; +import { PrismaTransactionAdapter } from '@integration-testing/data-isolation/prisma'; +import { installVitestDataIntegrationTestSupport } from '@integration-testing/data-isolation/vitest'; export const dataContext = installVitestDataIntegrationTestSupport({ getResources: () => tmpdir(), diff --git a/examples/without-testcontainers/test/notes.integration.test.ts b/examples/without-testcontainers/test/notes.integration.test.ts index 6fbf53c..934118e 100644 --- a/examples/without-testcontainers/test/notes.integration.test.ts +++ b/examples/without-testcontainers/test/notes.integration.test.ts @@ -1,4 +1,4 @@ -import { DataIntegrationTest } from '@integration-testing/data'; +import { DataIntegrationTest } from '@integration-testing/data-isolation'; import { beforeEach, expect, test } from 'vitest'; import { dataContext } from './data.setup.js'; diff --git a/package.json b/package.json index ea2a951..eb0fd5b 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "test:runners": "bun scripts/verify-runners.ts", "test:runners:minimum": "bun scripts/verify-runner-minimum.ts", "test:consumer": "bun scripts/verify-demo.ts", - "test:consumer:sqlite": "bun scripts/verify-demo.ts --sqlite" + "test:consumer:sqlite": "bun scripts/verify-demo.ts --sqlite", + "test:consumer:published": "bun scripts/verify-demo.ts --published" }, "devDependencies": { "@eslint/js": "^9.35.0", @@ -43,7 +44,7 @@ "ts-jest": "^29.4.1", "typeorm": "~0.3.28", "pg": "^8.16.3", - "@integration-testing/data": "workspace:*" + "@integration-testing/data-isolation": "workspace:*" }, "overrides": { "esbuild": "0.28.1", diff --git a/packages/data/README.md b/packages/data/README.md index eee81e8..4e07c04 100644 --- a/packages/data/README.md +++ b/packages/data/README.md @@ -1,4 +1,4 @@ -# @integration-testing/data +# @integration-testing/data-isolation **Write isolated database integration tests with a consistent API across supported test runners and database clients.** @@ -21,7 +21,7 @@ Configure your database and test runner once. Then declare each transactional te the shared context: ```ts -import { declareDataIntegrationTest } from '@integration-testing/data'; +import { declareDataIntegrationTest } from '@integration-testing/data-isolation'; import { dataContext } from './data-context.js'; declareDataIntegrationTest(); @@ -44,7 +44,7 @@ class has the same effect as `declareDataIntegrationTest()`; use one form per fi Use **[@integration-testing/testcontainers](https://www.npmjs.com/package/@integration-testing/testcontainers)** to start a disposable PostgreSQL instance and provide its connection URL. Apply your application's -real migrations once, then use **@integration-testing/data** to roll back each test's writes. +real migrations once, then use **@integration-testing/data-isolation** to roll back each test's writes. Testcontainers Integration stops the infrastructure after the run; Data Integration manages the test transactions and its configured clients. @@ -94,7 +94,7 @@ not establish SQL Server transaction support. **Release target: `0.1.0`.** Once this version is available on npm, install it with: ```sh -npm install --save-dev @integration-testing/data@0.1.0 +npm install --save-dev @integration-testing/data-isolation@0.1.0 ``` Before publication, use a local package archive instead. Build and pack this repository: @@ -109,7 +109,7 @@ npm pack ./packages/data --pack-destination . Copy the resulting archive to your application's `vendor` directory and install it: ```sh -npm install --save-dev ./vendor/integration-testing-data-0.1.0.tgz +npm install --save-dev ./vendor/integration-testing-data-isolation-0.1.0.tgz ``` For the pg quick start, install the driver and TypeScript tooling: @@ -149,8 +149,8 @@ exist, merge the relevant options into them. ```ts // test/data-context.ts import { Pool } from 'pg'; -import { createDataIntegrationTestContext } from '@integration-testing/data'; -import { PgTransactionAdapter } from '@integration-testing/data/pg'; +import { createDataIntegrationTestContext } from '@integration-testing/data-isolation'; +import { PgTransactionAdapter } from '@integration-testing/data-isolation/pg'; export function databaseUrl(): string { const url = process.env.DATABASE_URL; @@ -180,7 +180,7 @@ Export it once and import that same instance from your test files. ```ts // test/vitest.setup.ts -import { installVitestDataIntegrationTestSupport } from '@integration-testing/data/vitest'; +import { installVitestDataIntegrationTestSupport } from '@integration-testing/data-isolation/vitest'; import { dataContext } from './data-context.js'; installVitestDataIntegrationTestSupport(dataContext); @@ -241,7 +241,7 @@ runs unchanged under Jest: ```ts // test/products.integration.test.ts -import { declareDataIntegrationTest } from '@integration-testing/data'; +import { declareDataIntegrationTest } from '@integration-testing/data-isolation'; import { dataContext } from './data-context.js'; declareDataIntegrationTest(); @@ -283,7 +283,7 @@ a test-class instance or register test methods. Continue using your runner's ord If you prefer annotations, replace the `declareDataIntegrationTest` import and call with: ```ts -import { DataIntegrationTest } from '@integration-testing/data'; +import { DataIntegrationTest } from '@integration-testing/data-isolation'; @DataIntegrationTest export class ProductRepositoryTest {} @@ -336,7 +336,7 @@ start; select Jest types as described below. ```ts // test/jest.setup.ts -import { installJestDataIntegrationTestSupport } from '@integration-testing/data/jest'; +import { installJestDataIntegrationTestSupport } from '@integration-testing/data-isolation/jest'; import { dataContext } from './data-context.js'; installJestDataIntegrationTestSupport(dataContext); @@ -345,7 +345,7 @@ installJestDataIntegrationTestSupport(dataContext); ```js // jest.integration.config.cjs module.exports = { - testEnvironment: '@integration-testing/data/jest/environment', + testEnvironment: '@integration-testing/data-isolation/jest/environment', setupFilesAfterEnv: ['/test/jest.setup.ts'], testMatch: ['**/test/**/*.integration.test.ts'], maxWorkers: 2, @@ -539,7 +539,7 @@ Replace `test/vitest.setup.ts` with: import { Container, ContainerResources } from '@integration-testing/testcontainers'; import { CONTAINER_RESOURCES_CONTEXT_KEY } from '@integration-testing/testcontainers/vitest'; import { inject } from 'vitest'; -import { installVitestDataIntegrationTestSupport } from '@integration-testing/data/vitest'; +import { installVitestDataIntegrationTestSupport } from '@integration-testing/data-isolation/vitest'; import { dataContext } from './data-context.js'; const resources = ContainerResources.fromSerializable(inject(CONTAINER_RESOURCES_CONTEXT_KEY)); @@ -611,7 +611,7 @@ import { readFileSync } from 'node:fs'; import { Container, ContainerResources } from '@integration-testing/testcontainers'; import type { SerializableContainerResources } from '@integration-testing/testcontainers'; import { JEST_CONTAINER_RESOURCES_PATH_ENV } from '@integration-testing/testcontainers/jest'; -import { installJestDataIntegrationTestSupport } from '@integration-testing/data/jest'; +import { installJestDataIntegrationTestSupport } from '@integration-testing/data-isolation/jest'; import { dataContext } from './data-context.js'; const resourcePath = process.env[JEST_CONTAINER_RESOURCES_PATH_ENV]; @@ -668,8 +668,8 @@ npx prisma generate ```ts // test/data-context.ts import { PrismaClient, type Prisma } from '@prisma/client'; -import { createDataIntegrationTestContext } from '@integration-testing/data'; -import { PrismaTransactionAdapter } from '@integration-testing/data/prisma'; +import { createDataIntegrationTestContext } from '@integration-testing/data-isolation'; +import { PrismaTransactionAdapter } from '@integration-testing/data-isolation/prisma'; export const dataContext = createDataIntegrationTestContext({ getResources: () => { @@ -718,8 +718,8 @@ npm install typeorm@~0.3.28 pg@8 reflect-metadata // test/data-context.ts import 'reflect-metadata'; import { DataSource } from 'typeorm'; -import { createDataIntegrationTestContext } from '@integration-testing/data'; -import { TypeOrmTransactionAdapter } from '@integration-testing/data/typeorm'; +import { createDataIntegrationTestContext } from '@integration-testing/data-isolation'; +import { TypeOrmTransactionAdapter } from '@integration-testing/data-isolation/typeorm'; import { ProductEntity, ReservationEntity } from '../src/entities.js'; export const dataContext = createDataIntegrationTestContext({ @@ -795,7 +795,7 @@ are for applications whose SQLite migrations are maintained by Prisma. The testing library does not patch production clients. Override the database provider in a NestJS `TestingModule` with the scoped client. Application services and repositories should not import -`@integration-testing/data`. +`@integration-testing/data-isolation`. For an application exposing `DATABASE_CLIENT`, `InventoryRepository`, and `InventoryService`, the pg implementation can be tested like this: @@ -803,7 +803,7 @@ the pg implementation can be tested like this: ```ts import 'reflect-metadata'; import { Test, type TestingModule } from '@nestjs/testing'; -import { DataIntegrationTest } from '@integration-testing/data'; +import { DataIntegrationTest } from '@integration-testing/data-isolation'; import { dataContext } from './data-context.js'; import { DATABASE_CLIENT, InventoryRepository, InventoryService } from '../src/inventory.js'; import { PgInventoryRepository } from '../src/pg-repository.js'; @@ -892,7 +892,7 @@ Testcontainers as a dependency. | --- | --- | | Shared `ContainerRuntime` launcher | Verified with PostgreSQL + pg, Prisma 6.19, and TypeORM 0.3 under Jest and Vitest, using an installed data package archive | | Shared native `createVitestContainerGlobalSetup` | Verified with pg, global migrations, and transaction-scoped tests | -| Shared native `createJestContainerGlobalSetup` | Verified with pg while retaining `@integration-testing/data/jest/environment` | +| Shared native `createJestContainerGlobalSetup` | Verified with pg while retaining `@integration-testing/data-isolation/jest/environment` | | Named `@RequiredContainer` with `isolation: 'shared'` and manual global setup | Demonstrated by the small Vitest example; both files select the same named database | | Generated annotation/project file setup, including `isolation: 'dedicated'` | Not a supported drop-in pairing in this release; file lifecycle coordination is still needed | | RabbitMQ, MongoDB, or SQL Server containers | Available infrastructure in Testcontainers Integration; this does not add transactional adapter coverage to Data Integration | @@ -902,7 +902,7 @@ Testcontainers as a dependency. ```ts import { Container, RequiredContainer } from '@integration-testing/testcontainers'; -import { DataIntegrationTest } from '@integration-testing/data'; +import { DataIntegrationTest } from '@integration-testing/data-isolation'; @RequiredContainer({ database: { kind: Container.PostgreSql, isolation: 'shared' }, diff --git a/packages/data/package.json b/packages/data/package.json index c1b0427..877ba18 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -1,5 +1,5 @@ { - "name": "@integration-testing/data", + "name": "@integration-testing/data-isolation", "version": "0.1.0", "description": "Transactional database integration tests for Jest and Vitest with Prisma, pg, and TypeORM", "author": "Roland Salloum", diff --git a/packages/data/src/jest/index.ts b/packages/data/src/jest/index.ts index e5dcb7f..efb5208 100644 --- a/packages/data/src/jest/index.ts +++ b/packages/data/src/jest/index.ts @@ -14,7 +14,7 @@ export function installJestDataIntegrationTestSupport( ): DataIntegrationTestContextManager { const sandbox = globalThis as typeof globalThis & JestDataGlobal; if (!sandbox.__integration_testing_data_environment__) { - throw new Error('Configure testEnvironment: "@integration-testing/data/jest/environment" before installing data support'); + throw new Error('Configure testEnvironment: "@integration-testing/data-isolation/jest/environment" before installing data support'); } if (sandbox[BRIDGE_KEY]) throw new Error('Install data integration support only once per test file'); const timeout = options.transactionLifecycleTimeoutMs ?? 10_000; diff --git a/scripts/verify-demo.ts b/scripts/verify-demo.ts index a8c9eb1..da62004 100644 --- a/scripts/verify-demo.ts +++ b/scripts/verify-demo.ts @@ -8,6 +8,7 @@ const root = process.cwd(); const directory = await mkdtemp(join(tmpdir(), 'data-independent-consumer-')); const checkout = join(directory, 'nestjs-inventory'); const sqliteOnly = process.argv.includes('--sqlite'); +const published = process.argv.includes('--published'); async function run(command: string, args: string[], cwd = checkout): Promise { await new Promise((resolveRun, reject) => { const child = spawn(command, args, { cwd, stdio: 'inherit' }); @@ -16,23 +17,32 @@ async function run(command: string, args: string[], cwd = checkout): Promise !['node_modules', 'generated', '.artifacts', 'dist'].includes(path.split('/').at(-1) ?? ''), }); - await mkdir(join(checkout, 'vendor')); - const filename = `current-candidate-${digest}.tgz`; - await copyFile(archive, join(checkout, 'vendor', filename)); + let packageSpecifier = metadata.version; + if (archive !== undefined) { + await mkdir(join(checkout, 'vendor')); + const filename = `current-candidate-${digest}.tgz`; + await copyFile(archive, join(checkout, 'vendor', filename)); + packageSpecifier = `file:vendor/${filename}`; + } const manifestPath = join(checkout, 'package.json'); const manifest = JSON.parse(await readFile(manifestPath, 'utf8')) as { devDependencies: Record }; - manifest.devDependencies['@integration-testing/data'] = `file:vendor/${filename}`; + manifest.devDependencies[metadata.name] = packageSpecifier; await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n'); - await run('bun', ['install', '--network-concurrency', '8']); + if (published) await run('npm', ['install', '--registry=https://registry.npmjs.org', '--no-audit', '--no-fund']); + else await run('bun', ['install', '--network-concurrency', '8']); await run('bun', ['run', 'generate']); await run('bun', ['run', 'typecheck']); if (sqliteOnly) await run('bun', ['run', 'test:sqlite']); @@ -40,5 +50,7 @@ try { await run('bun', ['run', 'test', '--exercise-external']); await run('bun', ['run', 'test:per-file']); } - console.log(`Repository example passed outside the workspace with archive SHA-256 ${digest}`); + console.log(published + ? `Repository example passed outside the workspace with ${metadata.name}@${metadata.version} installed from npm` + : `Repository example passed outside the workspace with archive SHA-256 ${digest}`); } finally { await rm(directory, { recursive: true, force: true }); } diff --git a/scripts/verify-package.ts b/scripts/verify-package.ts index 2345374..2f29b03 100644 --- a/scripts/verify-package.ts +++ b/scripts/verify-package.ts @@ -46,12 +46,12 @@ try { const smoke = ` import assert from 'node:assert/strict'; import { createRequire } from 'node:module'; - import { DataIntegrationTest, isDataIntegrationTest, AsyncTransactionContext } from '@integration-testing/data'; - import { PrismaTransactionAdapter } from '@integration-testing/data/prisma'; - import { TypeOrmTransactionAdapter } from '@integration-testing/data/typeorm'; - import { installJestDataIntegrationTestSupport } from '@integration-testing/data/jest'; - import { prismaSqlServerUrlFor } from '@integration-testing/data/prisma/sql-server'; - import { PgTransactionAdapter } from '@integration-testing/data/pg'; + import { DataIntegrationTest, isDataIntegrationTest, AsyncTransactionContext } from '@integration-testing/data-isolation'; + import { PrismaTransactionAdapter } from '@integration-testing/data-isolation/prisma'; + import { TypeOrmTransactionAdapter } from '@integration-testing/data-isolation/typeorm'; + import { installJestDataIntegrationTestSupport } from '@integration-testing/data-isolation/jest'; + import { prismaSqlServerUrlFor } from '@integration-testing/data-isolation/prisma/sql-server'; + import { PgTransactionAdapter } from '@integration-testing/data-isolation/pg'; const require = createRequire(import.meta.url); class Suite {} DataIntegrationTest(Suite); @@ -63,13 +63,13 @@ try { assert.equal(typeof PgTransactionAdapter, 'function'); assert.equal(typeof TypeOrmTransactionAdapter, 'function'); assert.equal(typeof installJestDataIntegrationTestSupport, 'function'); - assert.equal(typeof require('@integration-testing/data/typeorm').TypeOrmTransactionAdapter, 'function'); - assert.equal(typeof require('@integration-testing/data/jest').installJestDataIntegrationTestSupport, 'function'); + assert.equal(typeof require('@integration-testing/data-isolation/typeorm').TypeOrmTransactionAdapter, 'function'); + assert.equal(typeof require('@integration-testing/data-isolation/jest').installJestDataIntegrationTestSupport, 'function'); assert.equal(typeof prismaSqlServerUrlFor, 'function'); - assert.equal(typeof require('@integration-testing/data/prisma/sql-server').prismaSqlServerUrlFor, 'function'); - assert.equal(typeof require('@integration-testing/data').DataIntegrationTestContextManager, 'function'); - assert.equal(typeof require('@integration-testing/data/prisma').PrismaTransactionAdapter, 'function'); - assert.equal(typeof require('@integration-testing/data/pg').PgTransactionAdapter, 'function'); + assert.equal(typeof require('@integration-testing/data-isolation/prisma/sql-server').prismaSqlServerUrlFor, 'function'); + assert.equal(typeof require('@integration-testing/data-isolation').DataIntegrationTestContextManager, 'function'); + assert.equal(typeof require('@integration-testing/data-isolation/prisma').PrismaTransactionAdapter, 'function'); + assert.equal(typeof require('@integration-testing/data-isolation/pg').PgTransactionAdapter, 'function'); for (const peer of ['vitest', 'pg', '@prisma/client', '@integration-testing/testcontainers', 'typeorm', 'jest', 'jest-environment-node', '@nestjs/common', '@nestjs/core', '@nestjs/testing']) { assert.throws(() => require.resolve(peer), { code: 'MODULE_NOT_FOUND' }); } @@ -77,14 +77,14 @@ try { await writeFile(join(core, 'smoke.mjs'), smoke); await run('node', ['smoke.mjs'], core); await run('npm', ['install', '--ignore-scripts', '--no-audit', '--no-fund', 'typescript@5.9.3', '@types/node@22', '@types/pg@8', 'typeorm@0.3.31', 'jest-environment-node@30.4.1'], core); - const consumer = `import { DataIntegrationTestContextManager, type TransactionAdapter } from '@integration-testing/data'; -import { PrismaTransactionAdapter } from '@integration-testing/data/prisma'; -import { PgTransactionAdapter } from '@integration-testing/data/pg'; -import { TypeOrmTransactionAdapter } from '@integration-testing/data/typeorm'; -import { installJestDataIntegrationTestSupport } from '@integration-testing/data/jest'; -import Environment from '@integration-testing/data/jest/environment'; + const consumer = `import { DataIntegrationTestContextManager, type TransactionAdapter } from '@integration-testing/data-isolation'; +import { PrismaTransactionAdapter } from '@integration-testing/data-isolation/prisma'; +import { PgTransactionAdapter } from '@integration-testing/data-isolation/pg'; +import { TypeOrmTransactionAdapter } from '@integration-testing/data-isolation/typeorm'; +import { installJestDataIntegrationTestSupport } from '@integration-testing/data-isolation/jest'; +import Environment from '@integration-testing/data-isolation/jest/environment'; void [TypeOrmTransactionAdapter, installJestDataIntegrationTestSupport, Environment]; -import { prismaSqlServerUrlFor } from '@integration-testing/data/prisma/sql-server'; +import { prismaSqlServerUrlFor } from '@integration-testing/data-isolation/prisma/sql-server'; void prismaSqlServerUrlFor; const adapter: TransactionAdapter = { rollbackOnly: async (_client, work) => work(1) }; void [DataIntegrationTestContextManager, PrismaTransactionAdapter, PgTransactionAdapter, adapter]; @@ -104,7 +104,7 @@ void [DataIntegrationTestContextManager, PrismaTransactionAdapter, PgTransaction }); const manifestPath = join(directory, 'package.json'); const manifest = JSON.parse(await readFile(manifestPath, 'utf8')) as { dependencies: Record }; - manifest.dependencies['@integration-testing/data'] = tarball; + manifest.dependencies['@integration-testing/data-isolation'] = tarball; await writeFile(manifestPath, JSON.stringify(manifest, undefined, 2)); await run('bun', ['install', '--network-concurrency', '8'], directory); if (example === 'without-testcontainers') await run('bun', ['run', 'generate'], directory); diff --git a/scripts/verify-release.ts b/scripts/verify-release.ts index 41fae1b..b85daae 100644 --- a/scripts/verify-release.ts +++ b/scripts/verify-release.ts @@ -1,6 +1,6 @@ import { readFile } from 'node:fs/promises'; const manifest = JSON.parse(await readFile('packages/data/package.json', 'utf8')) as { name: string; version: string; private?: boolean }; -if (manifest.private || manifest.name !== '@integration-testing/data') throw new Error('Unexpected release package'); +if (manifest.private || manifest.name !== '@integration-testing/data-isolation') throw new Error('Unexpected release package'); const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(manifest.name)}/${encodeURIComponent(manifest.version)}`); if (response.status !== 404) { throw new Error(response.ok ? 'Package version is already published' : `Registry check failed: ${response.status}`); diff --git a/scripts/verify-runner-minimum.ts b/scripts/verify-runner-minimum.ts index 70744a0..993f959 100644 --- a/scripts/verify-runner-minimum.ts +++ b/scripts/verify-runner-minimum.ts @@ -15,7 +15,7 @@ async function run(command: string, args: string[], env = process.env): Promise< try { const metadata = JSON.parse(await readFile(resolve('packages/data/package.json'), 'utf8')) as { version: string }; await writeFile(join(directory, 'package.json'), JSON.stringify({ private: true, type: 'module', dependencies: { - '@integration-testing/data': `file:${resolve(`.artifacts/integration-testing-data-${metadata.version}.tgz`)}`, + '@integration-testing/data-isolation': `file:${resolve(`.artifacts/integration-testing-data-isolation-${metadata.version}.tgz`)}`, jest: '30.1.0', 'jest-environment-node': '30.1.0', 'ts-jest': '^29.4.1', typescript: '^5.9.2', vitest: '~4.1.11', } })); await run('npm', ['install', '--legacy-peer-deps', '--no-audit', '--no-fund']); diff --git a/scripts/verify-runners.ts b/scripts/verify-runners.ts index 6a6aad9..bb525d6 100644 --- a/scripts/verify-runners.ts +++ b/scripts/verify-runners.ts @@ -10,7 +10,7 @@ await mkdir(directory, { recursive: true }); await writeFile(join(directory, 'tsconfig.json'), JSON.stringify({ compilerOptions: { target: 'ES2023', experimentalDecorators: true, esModuleInterop: true } })); const context = ` import { appendFileSync } from 'node:fs'; -import { createDataIntegrationTestContext } from '@integration-testing/data'; +import { createDataIntegrationTestContext } from '@integration-testing/data-isolation'; export const record = (event) => appendFileSync(process.env.CASE_TRACE, event + '\\n'); const scenario = process.env.CASE_NAME; let rollbackAttempts = 0; @@ -40,7 +40,7 @@ export const dataContext = createDataIntegrationTestContext({ await writeFile(join(directory, 'context.ts'), context); const common = ` import assert from 'node:assert/strict'; -import { DataIntegrationTest, declareDataIntegrationTest } from '@integration-testing/data'; +import { DataIntegrationTest, declareDataIntegrationTest } from '@integration-testing/data-isolation'; import { dataContext, record } from './context'; `; const fixtures = ` @@ -74,8 +74,8 @@ const cases = [ ]; for (const runner of ['jest', 'vitest'] as const) { - await writeFile(join(directory, 'setup.ts'), `import { dataContext } from './context';\nimport { install${runner === 'jest' ? 'Jest' : 'Vitest'}DataIntegrationTestSupport } from '@integration-testing/data/${runner}';\ninstall${runner === 'jest' ? 'Jest' : 'Vitest'}DataIntegrationTestSupport(dataContext, { transactionLifecycleTimeoutMs: 100 });\n`); - await writeFile(join(directory, 'jest.config.cjs'), `module.exports = { rootDir: __dirname, testMatch: ['**/*.test.ts'], testEnvironment: '@integration-testing/data/jest/environment', setupFilesAfterEnv: ['/setup.ts'], transform: { '^.+\\\\.ts$': ['ts-jest', { diagnostics: false, tsconfig: { module: 'CommonJS', target: 'ES2023', experimentalDecorators: true, esModuleInterop: true, isolatedModules: true } }] } };`); + await writeFile(join(directory, 'setup.ts'), `import { dataContext } from './context';\nimport { install${runner === 'jest' ? 'Jest' : 'Vitest'}DataIntegrationTestSupport } from '@integration-testing/data-isolation/${runner}';\ninstall${runner === 'jest' ? 'Jest' : 'Vitest'}DataIntegrationTestSupport(dataContext, { transactionLifecycleTimeoutMs: 100 });\n`); + await writeFile(join(directory, 'jest.config.cjs'), `module.exports = { rootDir: __dirname, testMatch: ['**/*.test.ts'], testEnvironment: '@integration-testing/data-isolation/jest/environment', setupFilesAfterEnv: ['/setup.ts'], transform: { '^.+\\\\.ts$': ['ts-jest', { diagnostics: false, tsconfig: { module: 'CommonJS', target: 'ES2023', experimentalDecorators: true, esModuleInterop: true, isolatedModules: true } }] } };`); await writeFile(join(directory, 'vitest.config.mts'), `import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { root: ${JSON.stringify(directory)}, include: ['**/*.test.ts'], allowOnly: true, globals: true, setupFiles: ['./setup.ts'], maxWorkers: 1 } });`); for (const scenario of cases) { // Jest has concurrent tests but no describe.concurrent; inheritance is exercised in Vitest. From 7fe1814c7d473d4b1faf423007df555659a10c4e Mon Sep 17 00:00:00 2001 From: RolandSall Date: Fri, 11 Sep 2026 16:06:56 +0300 Subject: [PATCH 2/2] Use Data Isolation branding in the README --- README.md | 20 ++++++++++---------- packages/data/README.md | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 4e07c04..65f3103 100644 --- a/README.md +++ b/README.md @@ -38,14 +38,14 @@ This is the test-file API after setup, using pg and runner globals. The quick st the context and runner configuration. Prefer annotations? `@DataIntegrationTest` on one marker class has the same effect as `declareDataIntegrationTest()`; use one form per file. -## Recommended pairing: Testcontainers Integration + Data Integration +## Recommended pairing: Testcontainers Integration + Data Isolation **Real infrastructure, isolated test data: two tools that work hand in hand.** Use **[@integration-testing/testcontainers](https://www.npmjs.com/package/@integration-testing/testcontainers)** to start a disposable PostgreSQL instance and provide its connection URL. Apply your application's real migrations once, then use **@integration-testing/data-isolation** to roll back each test's writes. -Testcontainers Integration stops the infrastructure after the run; Data Integration manages the +Testcontainers Integration stops the infrastructure after the run; Data Isolation manages the test transactions and its configured clients. The [Testcontainers Integration repository](https://github.com/RolandSall/testcontainers-integration) @@ -328,7 +328,7 @@ that client, for example through constructor injection; see [NestJS wiring](#inj ## Configure Jest once -Jest needs **both** the installer and the Data Integration Node environment. The installer +Jest needs **both** the installer and the Data Isolation Node environment. The installer registers the context inside Jest's test sandbox; the environment connects it to test execution. The annotation by itself cannot activate this behavior. Keep quick start steps 1 and 3, and use this section in place of its Vitest setup. The root TypeScript options are shown in the quick @@ -597,7 +597,7 @@ module.exports = require('./containers.lifecycle.cjs').setup; module.exports = require('./containers.lifecycle.cjs').teardown; ``` -Add these entries to `jest.integration.config.cjs`, retaining the Data Integration test environment: +Add these entries to `jest.integration.config.cjs`, retaining the Data Isolation test environment: ```js globalSetup: '/test/containers.global-setup.cjs', @@ -884,18 +884,18 @@ default setup and not permission for tests to invent tables that differ from pro The examples pin **`@integration-testing/testcontainers@0.1.0`**. The connection URL is the boundary between the libraries: Testcontainers Integration supplies a real database endpoint; -Data Integration creates the configured driver and controls transactions through its adapter. -Neither library needs to import the other's source, and Data Integration does not require +Data Isolation creates the configured driver and controls transactions through its adapter. +Neither library needs to import the other's source, and Data Isolation does not require Testcontainers as a dependency. -| Setup with Testcontainers Integration 0.1.0 | Data Integration compatibility | +| Setup with Testcontainers Integration 0.1.0 | Data Isolation compatibility | | --- | --- | | Shared `ContainerRuntime` launcher | Verified with PostgreSQL + pg, Prisma 6.19, and TypeORM 0.3 under Jest and Vitest, using an installed data package archive | | Shared native `createVitestContainerGlobalSetup` | Verified with pg, global migrations, and transaction-scoped tests | | Shared native `createJestContainerGlobalSetup` | Verified with pg while retaining `@integration-testing/data-isolation/jest/environment` | | Named `@RequiredContainer` with `isolation: 'shared'` and manual global setup | Demonstrated by the small Vitest example; both files select the same named database | | Generated annotation/project file setup, including `isolation: 'dedicated'` | Not a supported drop-in pairing in this release; file lifecycle coordination is still needed | -| RabbitMQ, MongoDB, or SQL Server containers | Available infrastructure in Testcontainers Integration; this does not add transactional adapter coverage to Data Integration | +| RabbitMQ, MongoDB, or SQL Server containers | Available infrastructure in Testcontainers Integration; this does not add transactional adapter coverage to Data Isolation | **Upgrading from the older Testcontainers beta:** replace the positional `@RequiredContainer(Container.PostgreSql)` declaration with its named form: @@ -921,12 +921,12 @@ the data declaration. `@ApplicationIntegrationTest` belongs to Testcontainers In application lifecycle and is not required for these direct database/repository setups. **Resource handoff in 0.1.0:** `injectedContainerResources()` now reads the active file lifecycle, -so it cannot supply resources during Data Integration's earlier initialization. The manual +so it cannot supply resources during Data Isolation's earlier initialization. The manual global-setup examples below restore the shared resources through the exported Vitest context key or Jest resource-file environment key. They do not install Testcontainers' generated file setup. **Why dedicated containers need more work:** Testcontainers Integration's generated file setup -starts them in `beforeAll`. Data Integration initializes its file context earlier, in Vitest's +starts them in `beforeAll`. Data Isolation initializes its file context earlier, in Vitest's `aroundAll` or Jest's `run_start`, so the dedicated resource is not yet available at that point. Simply stacking annotations or generated setup files does not establish the necessary startup and teardown ordering. Use the shared launcher or manual global setup documented here. diff --git a/packages/data/README.md b/packages/data/README.md index 4e07c04..65f3103 100644 --- a/packages/data/README.md +++ b/packages/data/README.md @@ -38,14 +38,14 @@ This is the test-file API after setup, using pg and runner globals. The quick st the context and runner configuration. Prefer annotations? `@DataIntegrationTest` on one marker class has the same effect as `declareDataIntegrationTest()`; use one form per file. -## Recommended pairing: Testcontainers Integration + Data Integration +## Recommended pairing: Testcontainers Integration + Data Isolation **Real infrastructure, isolated test data: two tools that work hand in hand.** Use **[@integration-testing/testcontainers](https://www.npmjs.com/package/@integration-testing/testcontainers)** to start a disposable PostgreSQL instance and provide its connection URL. Apply your application's real migrations once, then use **@integration-testing/data-isolation** to roll back each test's writes. -Testcontainers Integration stops the infrastructure after the run; Data Integration manages the +Testcontainers Integration stops the infrastructure after the run; Data Isolation manages the test transactions and its configured clients. The [Testcontainers Integration repository](https://github.com/RolandSall/testcontainers-integration) @@ -328,7 +328,7 @@ that client, for example through constructor injection; see [NestJS wiring](#inj ## Configure Jest once -Jest needs **both** the installer and the Data Integration Node environment. The installer +Jest needs **both** the installer and the Data Isolation Node environment. The installer registers the context inside Jest's test sandbox; the environment connects it to test execution. The annotation by itself cannot activate this behavior. Keep quick start steps 1 and 3, and use this section in place of its Vitest setup. The root TypeScript options are shown in the quick @@ -597,7 +597,7 @@ module.exports = require('./containers.lifecycle.cjs').setup; module.exports = require('./containers.lifecycle.cjs').teardown; ``` -Add these entries to `jest.integration.config.cjs`, retaining the Data Integration test environment: +Add these entries to `jest.integration.config.cjs`, retaining the Data Isolation test environment: ```js globalSetup: '/test/containers.global-setup.cjs', @@ -884,18 +884,18 @@ default setup and not permission for tests to invent tables that differ from pro The examples pin **`@integration-testing/testcontainers@0.1.0`**. The connection URL is the boundary between the libraries: Testcontainers Integration supplies a real database endpoint; -Data Integration creates the configured driver and controls transactions through its adapter. -Neither library needs to import the other's source, and Data Integration does not require +Data Isolation creates the configured driver and controls transactions through its adapter. +Neither library needs to import the other's source, and Data Isolation does not require Testcontainers as a dependency. -| Setup with Testcontainers Integration 0.1.0 | Data Integration compatibility | +| Setup with Testcontainers Integration 0.1.0 | Data Isolation compatibility | | --- | --- | | Shared `ContainerRuntime` launcher | Verified with PostgreSQL + pg, Prisma 6.19, and TypeORM 0.3 under Jest and Vitest, using an installed data package archive | | Shared native `createVitestContainerGlobalSetup` | Verified with pg, global migrations, and transaction-scoped tests | | Shared native `createJestContainerGlobalSetup` | Verified with pg while retaining `@integration-testing/data-isolation/jest/environment` | | Named `@RequiredContainer` with `isolation: 'shared'` and manual global setup | Demonstrated by the small Vitest example; both files select the same named database | | Generated annotation/project file setup, including `isolation: 'dedicated'` | Not a supported drop-in pairing in this release; file lifecycle coordination is still needed | -| RabbitMQ, MongoDB, or SQL Server containers | Available infrastructure in Testcontainers Integration; this does not add transactional adapter coverage to Data Integration | +| RabbitMQ, MongoDB, or SQL Server containers | Available infrastructure in Testcontainers Integration; this does not add transactional adapter coverage to Data Isolation | **Upgrading from the older Testcontainers beta:** replace the positional `@RequiredContainer(Container.PostgreSql)` declaration with its named form: @@ -921,12 +921,12 @@ the data declaration. `@ApplicationIntegrationTest` belongs to Testcontainers In application lifecycle and is not required for these direct database/repository setups. **Resource handoff in 0.1.0:** `injectedContainerResources()` now reads the active file lifecycle, -so it cannot supply resources during Data Integration's earlier initialization. The manual +so it cannot supply resources during Data Isolation's earlier initialization. The manual global-setup examples below restore the shared resources through the exported Vitest context key or Jest resource-file environment key. They do not install Testcontainers' generated file setup. **Why dedicated containers need more work:** Testcontainers Integration's generated file setup -starts them in `beforeAll`. Data Integration initializes its file context earlier, in Vitest's +starts them in `beforeAll`. Data Isolation initializes its file context earlier, in Vitest's `aroundAll` or Jest's `run_start`, so the dedicated resource is not yet available at that point. Simply stacking annotations or generated setup files does not establish the necessary startup and teardown ordering. Use the shared launcher or manual global setup documented here.