npx skills add smithery/incubateur-ademe --skill create-e2e-test
mx-space/core · Archived
create-e2e-test
Create E2E test file for a specified module. Use when adding end-to-end tests for controllers or unit tests for services and repositories.
Installation
npx skills add mx-space/core --skill create-e2e-test
Stronger alternatives
This repository is archived — consider an actively maintained alternative.
Mix Space project Zod schema patterns. Apply when creating DTOs, validation schemas, or handlin…
44 installsMix Space API design conventions. Apply when writing controllers, API endpoints, or handling HT…
37 installsCreate a new NestJS module with repository, service, controller, schema, and Drizzle table defi…
3 installsRun tests. Supports running all tests, single file, or pattern-matched tests.
3 installsSimilar popular skills
Related neighbors and high-traction skills in the same topics — useful to compare before installing.
Browser automation CLI for AI agents. Use when the user needs to interact with websites, includ…
810.4K installsDebug Azure production issues on Azure using AppLens, Azure Monitor, resource health, and safe …
568.9K installsPre-deployment validation for Azure readiness. Run deep checks on configuration, infrastructure…
567.7K installsConfigure Azure API Management as an AI Gateway for AI models, MCP tools, and agents. WHEN: sem…
566.3K installsAzure VM/VMSS router. WHEN: create / provision / deploy / spin-up VM, recommend VM size, compar…
510K installsPostgres best practices maintained by Supabase, for Postgres running anywhere. Load this skill …
391.6K installsAlso in this package
Other skills from mx-space/core · top by installs.
npx skills add mx-space/core
More details
Agent compatibility
Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.
Also listed on
Alternate registries and mirrors of this skill.
Repository health
master
Package contents
Files included with this skill beyond the listing page.
-
skill md
SKILL.md9,451 B -
docs
SUMMARY.md161 B
History
- First seen on skills.sh
- First recorded snapshot · 3 installs
SKILL.md
Create Test
Create test file for a module. Module name: $ARGUMENTS
Test File Locations
- Controller/service tests:
apps/core/test/src/modules/<module-name>/<module-name>.controller.spec.ts - Repository tests (with real PG):
apps/core/test/src/modules/<module-name>/<module-name>.repository.spec.ts
Test Pattern 1: Unit Test with Mocked Dependencies
For testing controllers, services, or business logic without a real database:
import { Test } from '@nestjs/testing'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { <Name>Controller } from '~/modules/<name>/<name>.controller'
import { <Name>Service } from '~/modules/<name>/<name>.service'
describe('<Name>Controller', () => {
let controller: <Name>Controller
const mock<Name>Service = {
findById: vi.fn(),
create: vi.fn(),
update: vi.fn(),
deleteById: vi.fn(),
}
beforeEach(async () => {
vi.clearAllMocks()
const module = await Test.createTestingModule({
controllers: [<Name>Controller],
providers: [
{
provide: <Name>Service,
useValue: mock<Name>Service,
},
],
}).compile()
controller = module.get(<Name>Controller)
})
it('should be defined', () => {
expect(controller).toBeDefined()
})
it('calls service.findById with the correct id', async () => {
const mockRow = { id: '1234567890', name: 'Test', createdAt: new Date() }
mock<Name>Service.findById.mockResolvedValue(mockRow)
const result = await controller.getById({ id: '1234567890' })
expect(mock<Name>Service.findById).toHaveBeenCalledWith('1234567890')
expect(result).toEqual(mockRow)
})
})
Test Pattern 2: E2E Test with createE2EApp
For testing controllers through the full HTTP pipeline (with mocked DB):
import { describe, expect, it } from 'vitest'
import { <Name>Controller } from '~/modules/<name>/<name>.controller'
import { <Name>Service } from '~/modules/<name>/<name>.service'
import { <Name>Repository } from '~/modules/<name>/<name>.repository'
import { createE2EApp } from 'test/helper/create-e2e-app'
describe('<Name>Controller (e2e)', () => {
const proxy = createE2EApp({
controllers: [<Name>Controller],
providers: [<Name>Service, <Name>Repository],
})
it('GET /<name>s returns paginated list', async () => {
const res = await proxy.app.inject({
method: 'GET',
url: '/<name>s',
})
expect(res.statusCode).toBe(200)
const json = res.json()
// ResponseInterceptor wraps arrays as { data: [...] }
// Paginated responses include { data: [...], pagination: {...} }
})
it('GET /<name>s/:id returns single item', async () => {
const res = await proxy.app.inject({
method: 'GET',
url: '/<name>s/invalid-id',
})
// Invalid Snowflake IDs should return 400
expect(res.statusCode).toBe(400)
})
})
createE2EApp Behavior
The createE2EApp helper (from test/helper/create-e2e-app.ts):
- Sets up a NestJS testing module with your controllers and providers
- Overrides
AuthGuardwithAuthTestingGuard— pass header'test-token': 1for authenticated requests - Registers all standard interceptors (
ResponseInterceptor,JSONTransformInterceptor,DbQueryInterceptor,HttpCacheInterceptor) - Registers the global Zod validation pipe
- Creates a Fastify-based Nest application
- Returns
{ app }— useproxy.app.inject({ method, url, payload })for HTTP requests - Automatically closes the app in
afterAll
Auth in tests: All requests are treated as unauthenticated by default. To authenticate, pass the test header:
const res = await proxy.app.inject({
method: 'POST',
url: '/<name>s',
payload: { name: 'Test' },
headers: { 'test-token': 1 }, // <-- authenticates as mock admin
})
Test Pattern 3: Repository Test with Real PostgreSQL
For testing repository logic against a real database using testcontainers:
import path from 'node:path'
import { drizzle, type NodePgDatabase } from 'drizzle-orm/node-postgres'
import { migrate } from 'drizzle-orm/node-postgres/migrator'
import { Pool } from 'pg'
import { beforeAll, beforeEach, describe, expect, it, afterAll } from 'vitest'
import { <name>s } from '~/database/schema'
import { <Name>Repository } from '~/modules/<name>/<name>.repository'
import { SnowflakeService } from '~/shared/id/snowflake.service'
const verifyUrl = process.env.PG_VERIFY_URL
const describeIfPg = verifyUrl ? describe : describe.skip
describeIfPg('<Name>Repository', () => {
let pool: Pool
let db: NodePgDatabase<typeof import('~/database/schema')>
let repository: <Name>Repository
let snowflake: SnowflakeService
beforeAll(async () => {
pool = new Pool({ connectionString: verifyUrl })
db = drizzle(pool, { casing: 'snake_case' })
const migrationsFolder = path.resolve(
__dirname,
'../../../../src/database/migrations',
)
await migrate(db, { migrationsFolder })
snowflake = new SnowflakeService()
repository = new <Name>Repository(db as any, snowflake)
}, 60_000)
beforeEach(async () => {
// Truncate tables between tests (respect FK order)
await pool.query('truncate table <name>s cascade')
})
afterAll(async () => {
if (pool) await pool.end()
})
it('creates a row with a generated Snowflake id', async () => {
const created = await repository.create({
name: 'test',
})
expect(typeof created.id).toBe('string')
expect(created.id).toMatch(/^[1-9]\d+$/) // Snowflake format
expect(created.name).toBe('test')
})
it('findById returns null for missing id', async () => {
const result = await repository.findById('9999999999999999999')
expect(result).toBeNull()
})
it('update mutates only specified fields', async () => {
const created = await repository.create({ name: 'old' })
const updated = await repository.update(created.id, { name: 'new' })
expect(updated?.name).toBe('new')
})
it('deleteById removes the row', async () => {
const created = await repository.create({ name: 'to-delete' })
await repository.deleteById(created.id)
const found = await repository.findById(created.id)
expect(found).toBeNull()
})
})
Running with Testcontainers
To run repository tests that need PostgreSQL, start a container first:
# Set PG_VERIFY_URL to a running PostgreSQL instance
export PG_VERIFY_URL=postgres://mx:[email protected]:5432/mx_verify
# Or use docker:
docker run -d --name pg-test -e POSTGRES_USER=mx -e POSTGRES_PASSWORD=mx -e POSTGRES_DB=mx_verify -p 5433:5432 postgres:17-alpine
export PG_VERIFY_URL=postgres://mx:[email protected]:5433/mx_verify
Then run the test:
# Run a single test file
pnpm test -- test/src/modules/<name>/<name>.repository.spec.ts
# Run all tests
pnpm test
# Watch mode
pnpm -C apps/core run test:watch
Common Assertion Patterns
HTTP Response Assertions
// Status codes
expect(res.statusCode).toBe(200)
expect(res.statusCode).toBe(201) // Created
expect(res.statusCode).toBe(204) // No Content (deletes)
expect(res.statusCode).toBe(400) // Validation error
expect(res.statusCode).toBe(404) // Not found
// JSON body (auto snake_case via JSONTransformInterceptor)
const json = res.json()
expect(json).toMatchObject({ name: 'test' })
// Paginated response shape
expect(json).toMatchObject({
data: expect.any(Array),
pagination: expect.objectContaining({
total: expect.any(Number),
current_page: expect.any(Number),
total_page: expect.any(Number),
}),
})
Snowflake ID Assertions
// Valid Snowflake ID format
expect(created.id).toMatch(/^[1-9]\d+$/)
expect(typeof created.id).toBe('string')
// Invalid ID throws
await expect(repository.findById('not-an-id')).rejects.toThrow()
Direct DB Inserts for Test Setup
When testing with a real database, use Drizzle directly to set up test data:
await db.insert(<name>s).values([
{ id: snowflake.nextId(), name: 'Item 1' },
{ id: snowflake.nextId(), name: 'Item 2' },
])
Test Helpers Location
test/helper/create-e2e-app.ts— E2E app setup with mock auth and Redistest/helper/setup-e2e.ts— Low-level NestJS testing module setuptest/helper/pg-testcontainer.ts— PostgreSQL 17 testcontainers helpertest/helper/redis-mock.helper.ts— In-memory Redis mocktest/mock/guard/auth.guard.ts—AuthTestingGuard(bypasses auth withtest-tokenheader)test/mock/modules/— Module-level mocks
Notes
- The
createE2EApphelper uses mock Redis and bypasses auth. For real DB tests, use the repository test pattern. - Use
proxy.app.inject()to send HTTP requests through the full interceptor chain. - Responses go through
JSONTransformInterceptor— field names become snake_case. - Paginated responses include
dataandpaginationfields. - Empty delete responses return 204 status code.
- Repository tests with real PG are gated behind
process.env.PGVERIFYURL— usedescribeIfPg/describe.skippattern so they don't fail in CI without a database.