원클릭으로
vitest-testing-guidelines
Use when adding or changing tests in this Vitest-based monorepo.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Use when adding or changing tests in this Vitest-based monorepo.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use when adding, changing, extracting, or reusing client components, including Storybook stories and controls.
Use when adding or changing forms in apps/client.
Use when changing GitHub OAuth, session cookies, SessionGuard, logout, or authenticated API request identity.
Use when adding or changing routes in apps/client.
Use when adding or changing client state, React Query data flow, immutable context values, or Zustand stores.
Use when styling apps/client with Tailwind CSS v4.
| name | vitest-testing-guidelines |
| description | Use when adding or changing tests in this Vitest-based monorepo. |
Generated from ai/registry.json. Do not edit manually.
Canonical skill: ../../../ai/skills/vitest-testing-guidelines.md.
Referenced context:
../../../ai/rules/testing-rules.md../../../ai/architecture/monorepo.md../../../ai/architecture/client-app.md../../../ai/examples/good-evaluator-test.md../../../ai/examples/good-public-config-service.mdThis file is compiled from canonical AI knowledge files. Edit canonical files under ai, then run npm run ai:sync.
ai/skills/vitest-testing-guidelines.mdUse this skill when adding or changing tests in this Vitest-based monorepo.
Add focused tests that protect observable behavior and domain invariants without coupling to implementation details.
ai/rules/testing-rules.mdai/architecture/monorepo.mdai/architecture/client-app.mdai/examples/good-evaluator-test.mdai/examples/good-public-config-service.mdapps/client, place tests in the owning __tests__/ folder described by the client architecture and use existing Testing Library/React Query test helpers.apps/client API operations and hooks, test both successful mocked responses and mocked API error responses.__tests__/ folder layout instead of loose sibling *.test.ts(x) files..only remains.npm --workspace @capture-flag/client run test:coverage after changing client coverage configuration or broad client tests.ai/rules/testing-rules.mdTesting rules for this Vitest-based monorepo.
describe, it, expect, vi.fn, and vi.spyOn.__tests__/ folders next to the source area they cover, matching the Storybook stories/ grouping convention.apps/client/src/api request and hook tests in src/api/__tests__, using the existing fetch, React Query, and render helpers from src/test.apps/client/src/core tests under src/core/<category>/__tests__/<name>.test.ts.src/components/__tests__ and shared member component tests under src/components/members/__tests__.src/pages/<PageName>/__tests__ or src/pages/<PageName>/<section>/__tests__ for colocated page internals.src/__tests__ only for source files owned directly by apps/client/src, such as permissions.ts.apps/client code that calls the API, cover both successful responses and API error responses with mocked fetch/response behavior.apps/client coverage at 90% or higher for configured client coverage targets; aim for 100% on pure helpers and request functions.vi.fn() methods.jest.mock patterns..only in tests.apps/client tests beside source files as loose *.test.ts(x) files when a nearby __tests__/ folder is available.src/test/render.tsx, src/test/api.ts, or src/test/pageApi.ts already cover the setup.npm --workspace @capture-flag/api run test.npm --workspace @capture-flag/client run test.npm --workspace @capture-flag/client run test:coverage.npm --workspace @capture-flag/shared run test.npm --workspace @capture-flag/evaluator run test.npm --workspace @capture-flag/sdk-js run test.npm run test.ai/architecture/monorepo.mdCapture Flag is a TypeScript npm workspaces monorepo.
apps/api: NestJS API, Prisma access, authentication, tenant services, public SDK config endpoint.apps/client: Vite React app for platform UI.packages/shared: shared package boundary for reusable cross-workspace code.packages/evaluator: pure local evaluation engine.packages/sdk-js: JavaScript SDK that fetches public config and evaluates locally.packages/react: React provider and hook around the JavaScript SDK.npm run build.npm run test.npm run lint.npm run ai:sync.npm run ai:check.apps/api.apps/client.packages/* only when there is a real cross-workspace consumer.docs/* are part of the source of truth for behavior.ai/architecture/client-app.mdapps/client is a Vite React application for the Capture Flag platform UI.
src/main.tsx owns top-level providers.src/router.tsx owns React Router route definitions.lazyRoute() helper and should expose named exports.src/layouts contains route layout wrappers that render shared shells, navigation, headers, and nested <Outlet /> regions.src/pages contains route-level screens. Multi-file route screens use folder modules with index.ts named exports; simple one-file screens may stay as direct page files.src/components contains shared UI used by multiple pages or sections.src/core contains context-independent client utilities and reusable hooks organized by category.src/api contains client request functions, React Query hooks, operation barrels, domain barrels, and domain query keys.src/routing contains route path and route context helpers shared by pages and layouts.src/stories contains shared Storybook fixtures and API mocks, not component stories.src/test contains shared Vitest and Testing Library helpers.PlatformLayout owns the authenticated shell, navigation frame, sidebar/header state, logout flow, and nested route outlet.useRouteContext, not stored in a mutable layout context./: redirects to /organizations./login: GitHub login screen./account: authenticated user account details and display name editing./organizations and /organizations/:organizationId: organization selection and organization members./organizations/:organizationId/projects and /organizations/:organizationId/projects/:projectId: project selection and project members./organizations/:organizationId/projects/:projectId/environments: environments for the selected project./organizations/:organizationId/projects/:projectId/configs and /organizations/:organizationId/projects/:projectId/configs/:configId: configs and public Config JSON preview./organizations/:organizationId/projects/:projectId/configs/:configId/flags: feature flags and remote config values./organizations/:organizationId/projects/:projectId/configs/:configId/segments: reusable targeting segments./organizations/:organizationId/projects/:projectId/sdk-keys: SDK key lifecycle for project configs/environments, with selected config/environment in ?configId= and ?environmentId= when needed./organizations/:organizationId/audit-logs: organization/project audit log timeline, with selected project in ?projectId= when needed.*: redirects to /.src/api/<domain>/<operation>.useQuery or useInfiniteQuery according to the API shape.useRouteContext for selected resources and redirect-safe navigation paths.src/layouts/<LayoutName> until reused by another layout or page.src/components and are imported directly through aliases such as @components/Button.components/members primitives with page-specific role options.stories/ child folder beside the source area they cover.src/pages/stories.src/stories and are reused by stories and page tests.src/core/<category>/<name>.ts.date, json, strings, validation, and hooks.src/core/date/toDate.index.ts barrels under src/core; multiple helpers require multiple explicit imports.src/core/<category>/__tests__/<name>.test.ts next to the category they cover.__tests__/ child folders beside the source area they cover, mirroring Storybook stories/ folders.src/test and provide Testing Library render helpers, React Query providers, and fetch response mocks.npm --workspace @capture-flag/client run test:coverage and should stay at 90% or higher for configured client targets.src/api/__tests__ and cover operation behavior through mocked fetch responses.src/components/__tests__; member component tests live in src/components/members/__tests__.src/pages/<PageName>/__tests__ when they cover one page folder.src/pages/<PageName>/<section>/__tests__ when they cover colocated page internals such as feature flags or segments.src/__tests__ only for source files owned directly by src, such as permissions.ts.src/components/stories; member component stories live in src/components/members/stories.src/layouts/<LayoutName>/stories.stories/ child folder.src/pages/stories and use route parameters plus shared mock data to render realistic page states.src/stories; that folder is reserved for shared Storybook data, routes, and API mocks.ai/examples/good-evaluator-test.mdSource: packages/evaluator/test/index.spec.ts (sha256: 40f396c39736d1e39ecc8575adc4f3566a656b3665b3513c10b64d3d49018e81)
Why this is canonical:
Canonical evaluator test pattern from packages/evaluator/test/index.spec.ts.
function createFlag(overrides: Partial<CaptureFlagConfigFlag> = {}): CaptureFlagConfigFlag {
return {
defaultValue: false,
percentageAttribute: "identifier",
percentageOptions: [],
rules: [],
type: "boolean",
...overrides,
};
}
function createConfig(flag: CaptureFlagConfigFlag = createFlag()): CaptureFlagConfig {
return {
configKey: "default",
environment: "production",
flags: {
newCheckout: flag,
},
generatedAt: "2026-05-12T00:00:00.000Z",
projectKey: "ecommerce",
revision: 1,
schemaVersion: 1,
};
}
Tests build small config fixtures and assert behavior through the public evaluate function.
ai/examples/good-public-config-service.mdSource: apps/api/src/public-sdk/public-sdk.service.ts (sha256: 85e49bab9d48419a9c4333b902d45cd724ae62a4b946eea88831bc3a4d42007c)
Why this is canonical:
Canonical public config pattern from apps/api/src/public-sdk/public-sdk.service.ts.
const transactionResult = await this.prisma.$transaction(
async (tx) => {
const sdkKey = await this.sdkKeyAuth.findActiveSdkKey(tx, rawSdkKey);
const state = await tx.configEnvironmentState.findUnique({
where: {
configId_environmentId: {
configId: sdkKey.configId,
environmentId: sdkKey.environmentId,
},
},
});
},
{ isolationLevel: Prisma.TransactionIsolationLevel.RepeatableRead },
);
The public endpoint authenticates by hashed SDK key and reads config state in the same transaction as flag values.
if (this.cache.matchesIfNoneMatch(ifNoneMatch, state.etag)) {
return {
result: {
etag: state.etag,
cacheControl,
notModified: true,
},
sdkKeyId: sdkKey.id,
};
}
Not-modified responses still count as valid SDK config access for lastUsedAt.
const cacheControl = this.cache.cacheControlHeader();
await this.sdkKeyUsage.recordUse(transactionResult.sdkKeyId);
The public endpoint defaults away from shared caching because the raw SDK key is in the URL path, and usage telemetry is best-effort after a valid config read.