بنقرة واحدة
migrate-e2e-playwright-to-jest
Helps users migrate an e2e test for API layer using playwright into Jest
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Helps users migrate an e2e test for API layer using playwright into Jest
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | migrate-e2e-playwright-to-jest |
| description | Helps users migrate an e2e test for API layer using playwright into Jest |
Use this skill when asked to migrate Playwright-based API tests from e2e/specs/neutron/ to
Jest/Supertest tests following the patterns in apps/neutron/test/.
Playwright E2E tests under e2e/specs/neutron/ test the Neutron API over a live HTTP server.
The equivalent Jest tests live under apps/neutron/test/<domain>/ and use supertest against a
NestJS testing module, backed by either pg-mem (fast, in-process) or Testcontainers
(real Postgres, for complex scenarios).
Reference implementation: apps/neutron/test/observation/
For each domain being migrated, create files mirroring the observation reference:
apps/neutron/test/<domain>/
<domain>.controller.spec.ts # HTTP routing, auth, validation, response shape
<domain>.service.spec.ts # Business logic, edge cases (only when needed — see below)
<domain>.helpers.ts # createXxxModule() helper that wires up NovaTest
NovaTest — module builder (apps/neutron/test/helpers/nest.ts)import { NovaTest } from '../helpers/nest';
export function createMyModule(dataSource: DataSource): NovaTest {
return new NovaTest()
.withProviders(MyService, MyRepository /* ...deps */)
.withAuthGuard(dataSource) // required for controllers with guards
.withControllers(MyController)
.withDataSource(dataSource);
}
Useful NovaTest methods:
| Method | Purpose |
|---|---|
.withProviders(...providers) | Add services, repositories, or { provide, useValue } objects |
.withDataSource(dataSource) | Inject a TypeORM DataSource (and its EntityManager) |
.withAuthGuard(dataSource) | Wire GlobalAuthGuard, MinimumRoleGuard, GlobalRolesGuard + JWT strategy |
.withControllers(...controllers) | Register NestJS controllers |
.withModules(...) / .withImports(...) | Add NestJS modules or dynamic modules |
.withCommonProviders() | Shortcut for ConfigService, OrgService, UserService, WarehouseRepository, etc. |
.withCustomFormsProviders() | Shortcut for all custom-forms repositories |
.withMockedService(ServiceClass, { method: jest.fn() }) | Inject a shallow mock of a service |
.withFeatureFlagService(mock) | Override FeatureFlagService |
.compile() | Build and return the TestingModule |
apps/neutron/test/helpers/fixtures/)import { useDataSourceFixture } from '../helpers/fixtures';
const getDataSource = useDataSourceFixture();
beforeAll(async () => {
const { dataSource } = getDataSource()!;
// ...
});
useDataSourceFixture sets up beforeAll / afterAll / beforeEach (with snapshot restore).
import { useTestContainerFixture } from '../helpers/fixtures';
// or directly:
import { setupTestContainers, CONTAINER_HOOK_TIMEOUT_MS } from '../helpers/datasource';
const getTestContainer = useTestContainerFixture();
beforeAll(async () => {
const { dataSource } = getTestContainer();
// ...
}, CONTAINER_HOOK_TIMEOUT_MS);
Choose pg-mem for controller/service tests that do not rely on transactions, triggers, custom constraints, or other Postgres-specific behavior.
Choose Testcontainers when:
QueryRunner, nested transactions)On macOS with Colima, prefix Testcontainers runs with:
TESTCONTAINERS_RYUK_DISABLED=true npx jest <spec> --runInBand
apps/neutron/test/factories/)import { makeFactories } from '../factories';
const factories = makeFactories(dataSource);
// Build (in-memory, no DB write):
const user = factories.userFactory.build({ role: UserRole.ADMIN });
// Create (persisted):
const user = await factories.userFactory.create({ role: UserRole.INTERNAL });
apps/neutron/test/helpers/utils.ts)import { getAuthHeader } from '../helpers/utils';
const user = await factories.userFactory.create({ role: UserRole.ADMIN });
request(app.getHttpServer()).get('/my-endpoint').set('Authorization', getAuthHeader(user));
For internal "login-as" impersonation tests use getLoginAsAuthHeader(impersonated, internal).
import 'dotenv/config';
import request from 'supertest';
import { HttpStatus, INestApplication } from '@nestjs/common';
import { makeFactories } from '../factories';
import { useDataSourceFixture } from '../helpers/fixtures';
import { createMyModule } from './my.helpers';
import { UserRole } from '@nova/core';
import { getAuthHeader } from '../helpers/utils';
describe('MyController', () => {
let app: INestApplication;
let factories: ReturnType<typeof makeFactories>;
const getDataSource = useDataSourceFixture();
beforeAll(async () => {
const { dataSource } = getDataSource()!;
factories = makeFactories(dataSource);
const moduleRef = await createMyModule(dataSource).compile();
app = moduleRef.createNestApplication();
await app.init();
});
afterAll(async () => {
await app.close();
});
describe('GET /my-resource', () => {
it('requires authentication', async () => {
const res = await request(app.getHttpServer()).get('/my-resource');
expect(res.status).toBe(HttpStatus.UNAUTHORIZED);
});
it('returns 200 for authenticated user', async () => {
const user = await factories.userFactory.create({ role: UserRole.ADMIN });
const res = await request(app.getHttpServer()).get('/my-resource').set('Authorization', getAuthHeader(user));
expect(res.status).toBe(HttpStatus.OK);
});
});
});
UNAUTHORIZED, FORBIDDEN)BAD_REQUEST)toMatchObject, toEqual)Service methods are typically mocked with jest.spyOn(service, 'method').mockResolvedValue(...).
This keeps controller tests focused on HTTP concerns.
Add a service spec when any of:
import 'dotenv/config';
import { useDataSourceFixture } from '../helpers/fixtures';
import { makeFactories } from '../factories';
import { NovaTest } from '../helpers/nest';
import { MyService } from '@nova/neutron/app/my/my.service';
import { MyRepository } from '@nova/neutron/app/my/my.repository';
describe('MyService', () => {
let service: MyService;
let factories: ReturnType<typeof makeFactories>;
const getDataSource = useDataSourceFixture();
beforeAll(async () => {
const { dataSource } = getDataSource()!;
factories = makeFactories(dataSource);
const moduleRef = await new NovaTest()
.withDataSource(dataSource)
.withCommonProviders()
.withProviders(MyRepository, MyService)
.compile();
service = moduleRef.get(MyService);
});
it('does the right thing', async () => {
// ...
});
});
Services that call external HTTP APIs, S3, SQS, etc. should be mocked at the module level in the
helpers file, not individually per test. See observation.helpers.ts for examples:
// In <domain>.helpers.ts
const mockHttpService = {
get: jest.fn(),
post: jest.fn(),
// ...
};
export function createMyModule(dataSource: DataSource): NovaTest {
return new NovaTest().withProviders(
{ provide: HttpService, useValue: mockHttpService },
{ provide: S3Client, useValue: s3client },
// ...
);
// ...
}
For FeatureFlagService:
import { useFeatureFlagFixture } from '../helpers/fixtures';
const getFeatureFlag = useFeatureFlagFixture(true); // true = all flags on
const { service: mockFeatureFlagService } = getFeatureFlag();
e2e/specs/neutron/<domain>/.apps/neutron/test/<domain>/<domain>.helpers.ts with createXxxModule().
.withCommonProviders() then add domain-specific providers.apps/neutron/test/<domain>/<domain>.controller.spec.ts.
jest.spyOn where possible.apps/neutron/test/<domain>/<domain>.service.spec.ts only if warranted (see criteria above).useDataSourceFixture() (pg-mem).useTestContainerFixture() / setupTestContainers when the domain uses transactions or complex SQL.npm run neutron:lint
npx jest apps/neutron/test/<domain> --runInBand
# Run a specific Jest test file
npx jest apps/neutron/test/my-domain --runInBand
# Run with Testcontainers on macOS/Colima
TESTCONTAINERS_RYUK_DISABLED=true npx jest apps/neutron/test/my-domain --runInBand
# Lint check
npm run neutron:lint