cfsa-antigravity 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.mjs +324 -0
- package/package.json +34 -0
- package/template/.agent/instructions/commands.md +48 -0
- package/template/.agent/instructions/patterns.md +61 -0
- package/template/.agent/instructions/structure.md +29 -0
- package/template/.agent/instructions/tech-stack.md +43 -0
- package/template/.agent/instructions/workflow.md +41 -0
- package/template/.agent/kit-sync.md +15 -0
- package/template/.agent/rules/boundary-not-placeholder.md +146 -0
- package/template/.agent/rules/completion-checklist.md +48 -0
- package/template/.agent/rules/decision-classification.md +103 -0
- package/template/.agent/rules/extensibility.md +47 -0
- package/template/.agent/rules/question-vs-command.md +81 -0
- package/template/.agent/rules/security-first.md +43 -0
- package/template/.agent/rules/specificity-standards.md +54 -0
- package/template/.agent/rules/tdd-contract-first.md +57 -0
- package/template/.agent/rules/vertical-slices.md +42 -0
- package/template/.agent/skill-library/MANIFEST.md +480 -0
- package/template/.agent/skill-library/README.md +38 -0
- package/template/.agent/skill-library/meta/brand-guidelines/SKILL.md +73 -0
- package/template/.agent/skill-library/meta/claude-code/README.md +9 -0
- package/template/.agent/skill-library/meta/claude-code/agent-development/SKILL.md +415 -0
- package/template/.agent/skill-library/meta/claude-code/hook-development/SKILL.md +712 -0
- package/template/.agent/skill-library/meta/claude-code/plugin-structure/SKILL.md +476 -0
- package/template/.agent/skill-library/meta/git-advanced/SKILL.md +972 -0
- package/template/.agent/skill-library/meta/mcp-builder/SKILL.md +236 -0
- package/template/.agent/skill-library/meta/product-marketing-context/SKILL.md +241 -0
- package/template/.agent/skill-library/meta/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skill-library/meta/tmux-processes/SKILL.md +210 -0
- package/template/.agent/skill-library/meta/using-tmux-for-interactive-commands/SKILL.md +178 -0
- package/template/.agent/skill-library/stack/3d/threejs-pro/SKILL.md +300 -0
- package/template/.agent/skill-library/stack/ai/ai-sdk/SKILL.md +77 -0
- package/template/.agent/skill-library/stack/ai/langchain/SKILL.md +530 -0
- package/template/.agent/skill-library/stack/ai/ollama/SKILL.md +321 -0
- package/template/.agent/skill-library/stack/ai/openai-sdk/SKILL.md +549 -0
- package/template/.agent/skill-library/stack/analytics/google-analytics/SKILL.md +153 -0
- package/template/.agent/skill-library/stack/api/graphql/SKILL.md +1061 -0
- package/template/.agent/skill-library/stack/api/trpc/SKILL.md +576 -0
- package/template/.agent/skill-library/stack/auth/authjs/SKILL.md +569 -0
- package/template/.agent/skill-library/stack/auth/clerk/SKILL.md +590 -0
- package/template/.agent/skill-library/stack/auth/firebase-auth/SKILL.md +734 -0
- package/template/.agent/skill-library/stack/cms/payload-cms/SKILL.md +573 -0
- package/template/.agent/skill-library/stack/cms/shopify/SKILL.md +1193 -0
- package/template/.agent/skill-library/stack/cms/wordpress/SKILL.md +1104 -0
- package/template/.agent/skill-library/stack/css/sass-scss/SKILL.md +1121 -0
- package/template/.agent/skill-library/stack/css/tailwind-css-patterns/SKILL.md +863 -0
- package/template/.agent/skill-library/stack/css/tailwind-design-system/SKILL.md +490 -0
- package/template/.agent/skill-library/stack/css/vanilla-css/SKILL.md +1078 -0
- package/template/.agent/skill-library/stack/databases/clickhouse/SKILL.md +311 -0
- package/template/.agent/skill-library/stack/databases/influxdb/SKILL.md +280 -0
- package/template/.agent/skill-library/stack/databases/lancedb/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/databases/mongodb/SKILL.md +1169 -0
- package/template/.agent/skill-library/stack/databases/neo4j/SKILL.md +839 -0
- package/template/.agent/skill-library/stack/databases/pgvector/SKILL.md +241 -0
- package/template/.agent/skill-library/stack/databases/pinecone/SKILL.md +212 -0
- package/template/.agent/skill-library/stack/databases/postgresql/SKILL.md +658 -0
- package/template/.agent/skill-library/stack/databases/qdrant/SKILL.md +312 -0
- package/template/.agent/skill-library/stack/databases/redis/SKILL.md +1079 -0
- package/template/.agent/skill-library/stack/databases/spacetimedb/SKILL.md +532 -0
- package/template/.agent/skill-library/stack/databases/sqlite/SKILL.md +1132 -0
- package/template/.agent/skill-library/stack/databases/supabase/SKILL.md +640 -0
- package/template/.agent/skill-library/stack/databases/surrealdb-expert/SKILL.md +945 -0
- package/template/.agent/skill-library/stack/databases/timescaledb/SKILL.md +745 -0
- package/template/.agent/skill-library/stack/databases/weaviate/SKILL.md +218 -0
- package/template/.agent/skill-library/stack/devops/github-actions/SKILL.md +554 -0
- package/template/.agent/skill-library/stack/devops/kubernetes/SKILL.md +950 -0
- package/template/.agent/skill-library/stack/devops/nginx/SKILL.md +841 -0
- package/template/.agent/skill-library/stack/devops/terraform/SKILL.md +860 -0
- package/template/.agent/skill-library/stack/email/resend/SKILL.md +391 -0
- package/template/.agent/skill-library/stack/engines/godot/SKILL.md +488 -0
- package/template/.agent/skill-library/stack/extensions/chrome-extension/SKILL.md +375 -0
- package/template/.agent/skill-library/stack/extensions/vscode-extension/SKILL.md +453 -0
- package/template/.agent/skill-library/stack/frameworks/astro-framework/SKILL.md +162 -0
- package/template/.agent/skill-library/stack/frameworks/electron/SKILL.md +1286 -0
- package/template/.agent/skill-library/stack/frameworks/fastapi/SKILL.md +650 -0
- package/template/.agent/skill-library/stack/frameworks/hono/SKILL.md +90 -0
- package/template/.agent/skill-library/stack/frameworks/nestjs/SKILL.md +878 -0
- package/template/.agent/skill-library/stack/frameworks/nextjs/SKILL.md +635 -0
- package/template/.agent/skill-library/stack/frameworks/nuxt/SKILL.md +564 -0
- package/template/.agent/skill-library/stack/frameworks/sveltekit/SKILL.md +614 -0
- package/template/.agent/skill-library/stack/frameworks/tauri/SKILL.md +920 -0
- package/template/.agent/skill-library/stack/gamedev/godot/SKILL.md +1032 -0
- package/template/.agent/skill-library/stack/gamedev/unity/SKILL.md +1175 -0
- package/template/.agent/skill-library/stack/hosting/aws/SKILL.md +467 -0
- package/template/.agent/skill-library/stack/hosting/cloudflare/SKILL.md +201 -0
- package/template/.agent/skill-library/stack/hosting/docker-expert/SKILL.md +409 -0
- package/template/.agent/skill-library/stack/hosting/vercel/SKILL.md +484 -0
- package/template/.agent/skill-library/stack/languages/bash-scripting/SKILL.md +773 -0
- package/template/.agent/skill-library/stack/languages/c-cpp/SKILL.md +712 -0
- package/template/.agent/skill-library/stack/languages/gdscript/SKILL.md +789 -0
- package/template/.agent/skill-library/stack/languages/go/SKILL.md +664 -0
- package/template/.agent/skill-library/stack/languages/java/SKILL.md +778 -0
- package/template/.agent/skill-library/stack/languages/kotlin/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/languages/python/SKILL.md +678 -0
- package/template/.agent/skill-library/stack/languages/rust/SKILL.md +673 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/SKILL.md +141 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/advanced-generics.md +90 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/branded-types.md +57 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/builder-pattern.md +71 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/common-pitfalls.md +135 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/conditional-types.md +27 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/decorators.md +98 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/discriminated-unions.md +62 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/mapped-types.md +53 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/performance-best-practices.md +104 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/template-literal-types.md +49 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/testing-types.md +112 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-guards.md +70 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-inference.md +101 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/utility-types.md +98 -0
- package/template/.agent/skill-library/stack/languages/vanilla-javascript/SKILL.md +803 -0
- package/template/.agent/skill-library/stack/messaging/kafka/SKILL.md +235 -0
- package/template/.agent/skill-library/stack/mobile/expo-react-native/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/mobile/flutter/SKILL.md +316 -0
- package/template/.agent/skill-library/stack/mobile/react-native/SKILL.md +337 -0
- package/template/.agent/skill-library/stack/monitoring/posthog/SKILL.md +396 -0
- package/template/.agent/skill-library/stack/monitoring/sentry/SKILL.md +509 -0
- package/template/.agent/skill-library/stack/observability/datadog/SKILL.md +179 -0
- package/template/.agent/skill-library/stack/observability/distributed-tracing/SKILL.md +140 -0
- package/template/.agent/skill-library/stack/observability/logging-best-practices/SKILL.md +168 -0
- package/template/.agent/skill-library/stack/observability/opentelemetry/SKILL.md +164 -0
- package/template/.agent/skill-library/stack/observability/prometheus-grafana/SKILL.md +246 -0
- package/template/.agent/skill-library/stack/observability/python-observability/SKILL.md +158 -0
- package/template/.agent/skill-library/stack/orm/drizzle-orm/SKILL.md +613 -0
- package/template/.agent/skill-library/stack/orm/prisma/SKILL.md +744 -0
- package/template/.agent/skill-library/stack/payments/lemonsqueezy/SKILL.md +393 -0
- package/template/.agent/skill-library/stack/payments/stripe-integration/SKILL.md +457 -0
- package/template/.agent/skill-library/stack/queue/bullmq/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/queue/inngest/SKILL.md +438 -0
- package/template/.agent/skill-library/stack/realtime/socketio/SKILL.md +595 -0
- package/template/.agent/skill-library/stack/search/elasticsearch/SKILL.md +248 -0
- package/template/.agent/skill-library/stack/search/meilisearch/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/security/crypto-patterns/SKILL.md +437 -0
- package/template/.agent/skill-library/stack/security/csp-cors-headers/SKILL.md +588 -0
- package/template/.agent/skill-library/stack/security/dependency-auditing/SKILL.md +560 -0
- package/template/.agent/skill-library/stack/security/input-sanitization/SKILL.md +430 -0
- package/template/.agent/skill-library/stack/security/owasp-web-security/SKILL.md +421 -0
- package/template/.agent/skill-library/stack/state/tanstack-query/SKILL.md +637 -0
- package/template/.agent/skill-library/stack/state/zustand/SKILL.md +483 -0
- package/template/.agent/skill-library/stack/storage/aws-s3/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/testing/playwright/SKILL.md +641 -0
- package/template/.agent/skill-library/stack/testing/storybook/SKILL.md +923 -0
- package/template/.agent/skill-library/stack/testing/testing-library/SKILL.md +872 -0
- package/template/.agent/skill-library/stack/testing/vitest/SKILL.md +714 -0
- package/template/.agent/skill-library/stack/ui/react-best-practices/SKILL.md +877 -0
- package/template/.agent/skill-library/stack/ui/react-composition-patterns/SKILL.md +1107 -0
- package/template/.agent/skill-library/stack/ui/react-flow/SKILL.md +425 -0
- package/template/.agent/skill-library/stack/ui/shadcn-ui/SKILL.md +703 -0
- package/template/.agent/skill-library/surface/api/api-caching/SKILL.md +458 -0
- package/template/.agent/skill-library/surface/api/api-documentation-openapi/SKILL.md +697 -0
- package/template/.agent/skill-library/surface/api/api-error-handling/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/api-security-checklist/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/api-versioning/SKILL.md +420 -0
- package/template/.agent/skill-library/surface/api/email-best-practices/SKILL.md +59 -0
- package/template/.agent/skill-library/surface/api/rate-limiting-abuse-protection/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/webhook-design/SKILL.md +752 -0
- package/template/.agent/skill-library/surface/cli/cli-configuration-management/SKILL.md +445 -0
- package/template/.agent/skill-library/surface/cli/cli-error-diagnostics/SKILL.md +515 -0
- package/template/.agent/skill-library/surface/cli/cli-shell-integration/SKILL.md +479 -0
- package/template/.agent/skill-library/surface/cli/cli-ux-design/SKILL.md +477 -0
- package/template/.agent/skill-library/surface/desktop/desktop-app-distribution/SKILL.md +416 -0
- package/template/.agent/skill-library/surface/desktop/desktop-security-sandboxing/SKILL.md +407 -0
- package/template/.agent/skill-library/surface/desktop/desktop-ux-conventions/SKILL.md +361 -0
- package/template/.agent/skill-library/surface/desktop/native-os-integration/SKILL.md +563 -0
- package/template/.agent/skill-library/surface/extension/browser-extension-patterns/SKILL.md +482 -0
- package/template/.agent/skill-library/surface/extension/plugin-architecture-design/SKILL.md +632 -0
- package/template/.agent/skill-library/surface/extension/vscode-extension-development/SKILL.md +728 -0
- package/template/.agent/skill-library/surface/mobile/app-store-submission/SKILL.md +304 -0
- package/template/.agent/skill-library/surface/mobile/mobile-offline-sync/SKILL.md +443 -0
- package/template/.agent/skill-library/surface/mobile/mobile-responsive-patterns/SKILL.md +432 -0
- package/template/.agent/skill-library/surface/mobile/push-notifications/SKILL.md +495 -0
- package/template/.agent/skill-library/surface/web/accessibility-compliance/SKILL.md +827 -0
- package/template/.agent/skill-library/surface/web/ai-seo/SKILL.md +398 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/content-patterns.md +285 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/platform-ranking-factors.md +152 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/SKILL.md +309 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/event-library.md +260 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/ga4-implementation.md +300 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/gtm-implementation.md +390 -0
- package/template/.agent/skill-library/surface/web/authentication-ui-flows/SKILL.md +530 -0
- package/template/.agent/skill-library/surface/web/dark-mode-theming/SKILL.md +516 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/SKILL.md +105 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/charts.csv +26 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/colors.csv +97 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/landing.csv +31 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/styles.csv +59 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/typography.csv +58 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/ux-guidelines.csv +100 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/core.py +258 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/design_system.py +1067 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/search.py +106 -0
- package/template/.agent/skill-library/surface/web/form-handling-validation/SKILL.md +675 -0
- package/template/.agent/skill-library/surface/web/frontend-design/SKILL.md +1393 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/cppn-hero.tsx +299 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/wave-hero.tsx +875 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/SKILL.md +111 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/scripts/ux_audit.py +739 -0
- package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +154 -0
- package/template/.agent/skill-library/surface/web/offline-first-pwa/SKILL.md +657 -0
- package/template/.agent/skill-library/surface/web/page-cro/SKILL.md +182 -0
- package/template/.agent/skill-library/surface/web/page-cro/references/experiments.md +248 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/SKILL.md +238 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/references/playbooks.md +308 -0
- package/template/.agent/skill-library/surface/web/schema-markup/SKILL.md +179 -0
- package/template/.agent/skill-library/surface/web/schema-markup/references/schema-examples.md +398 -0
- package/template/.agent/skill-library/surface/web/seo-audit/SKILL.md +394 -0
- package/template/.agent/skill-library/surface/web/seo-audit/references/ai-writing-detection.md +200 -0
- package/template/.agent/skill-library/surface/web/web-performance-optimization/SKILL.md +646 -0
- package/template/.agent/skill-library/surface/web/web-scraping/SKILL.md +58 -0
- package/template/.agent/skills/accessibility/SKILL.md +522 -0
- package/template/.agent/skills/accessibility/references/WCAG.md +162 -0
- package/template/.agent/skills/adversarial-review/SKILL.md +90 -0
- package/template/.agent/skills/antigravity-workflows/SKILL.md +81 -0
- package/template/.agent/skills/antigravity-workflows/resources/implementation-playbook.md +36 -0
- package/template/.agent/skills/api-design-principles/SKILL.md +37 -0
- package/template/.agent/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/template/.agent/skills/api-design-principles/assets/rest-api-template.py +182 -0
- package/template/.agent/skills/api-design-principles/references/graphql-schema-design.md +583 -0
- package/template/.agent/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/template/.agent/skills/api-design-principles/resources/implementation-playbook.md +513 -0
- package/template/.agent/skills/api-versioning/SKILL.md +420 -0
- package/template/.agent/skills/architecture-mapping/SKILL.md +219 -0
- package/template/.agent/skills/bootstrap-agents/SKILL.md +259 -0
- package/template/.agent/skills/brainstorming/SKILL.md +236 -0
- package/template/.agent/skills/brand-guidelines/SKILL.md +44 -0
- package/template/.agent/skills/clean-code/SKILL.md +94 -0
- package/template/.agent/skills/code-review-pro/SKILL.md +152 -0
- package/template/.agent/skills/concise-planning/SKILL.md +68 -0
- package/template/.agent/skills/cross-layer-consistency/SKILL.md +117 -0
- package/template/.agent/skills/database-schema-design/SKILL.md +429 -0
- package/template/.agent/skills/deployment-procedures/SKILL.md +241 -0
- package/template/.agent/skills/design-anti-cliche/SKILL.md +159 -0
- package/template/.agent/skills/design-direction/SKILL.md +45 -0
- package/template/.agent/skills/error-handling-patterns/SKILL.md +721 -0
- package/template/.agent/skills/find-skills/SKILL.md +145 -0
- package/template/.agent/skills/git-advanced/SKILL.md +972 -0
- package/template/.agent/skills/git-workflow/SKILL.md +420 -0
- package/template/.agent/skills/idea-extraction/SKILL.md +271 -0
- package/template/.agent/skills/logging-best-practices/SKILL.md +851 -0
- package/template/.agent/skills/migration-management/SKILL.md +384 -0
- package/template/.agent/skills/minimalist-surgical-development/SKILL.md +69 -0
- package/template/.agent/skills/parallel-agents/SKILL.md +165 -0
- package/template/.agent/skills/parallel-debugging/SKILL.md +135 -0
- package/template/.agent/skills/parallel-feature-development/SKILL.md +166 -0
- package/template/.agent/skills/performance-budgeting/SKILL.md +144 -0
- package/template/.agent/skills/pipeline-rubrics/SKILL.md +51 -0
- package/template/.agent/skills/pipeline-rubrics/references/architecture-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/be-rubric.md +21 -0
- package/template/.agent/skills/pipeline-rubrics/references/fe-rubric.md +20 -0
- package/template/.agent/skills/pipeline-rubrics/references/ia-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/scoring.md +28 -0
- package/template/.agent/skills/pipeline-rubrics/references/vision-rubric.md +11 -0
- package/template/.agent/skills/prd-templates/SKILL.md +88 -0
- package/template/.agent/skills/prd-templates/references/architecture-design-template.md +88 -0
- package/template/.agent/skills/prd-templates/references/be-spec-template.md +101 -0
- package/template/.agent/skills/prd-templates/references/data-placement-template.md +74 -0
- package/template/.agent/skills/prd-templates/references/decomposition-templates.md +211 -0
- package/template/.agent/skills/prd-templates/references/design-system-decisions.md +198 -0
- package/template/.agent/skills/prd-templates/references/engineering-standards-template.md +124 -0
- package/template/.agent/skills/prd-templates/references/fe-classification-procedures.md +47 -0
- package/template/.agent/skills/prd-templates/references/fe-spec-template.md +84 -0
- package/template/.agent/skills/prd-templates/references/infrastructure-report-template.md +71 -0
- package/template/.agent/skills/prd-templates/references/operational-templates.md +116 -0
- package/template/.agent/skills/prd-templates/references/placeholder-guard-template.md +21 -0
- package/template/.agent/skills/prd-templates/references/surface-model.md +61 -0
- package/template/.agent/skills/prd-templates/references/vision-template.md +66 -0
- package/template/.agent/skills/prompt-engineer/README.md +659 -0
- package/template/.agent/skills/prompt-engineer/SKILL.md +249 -0
- package/template/.agent/skills/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skills/resolve-ambiguity/SKILL.md +278 -0
- package/template/.agent/skills/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skills/security-scanning-security-hardening/SKILL.md +231 -0
- package/template/.agent/skills/session-continuity/SKILL.md +730 -0
- package/template/.agent/skills/session-continuity/protocols/01-session-resumption.md +38 -0
- package/template/.agent/skills/session-continuity/protocols/02-progress-generation.md +85 -0
- package/template/.agent/skills/session-continuity/protocols/03-progress-update.md +70 -0
- package/template/.agent/skills/session-continuity/protocols/04-pattern-extraction.md +60 -0
- package/template/.agent/skills/session-continuity/protocols/05-session-close.md +37 -0
- package/template/.agent/skills/session-continuity/protocols/06-decision-analysis.md +84 -0
- package/template/.agent/skills/session-continuity/protocols/07-spec-pipeline-generation.md +48 -0
- package/template/.agent/skills/session-continuity/protocols/08-spec-pipeline-update.md +43 -0
- package/template/.agent/skills/session-continuity/protocols/09-parallel-claim.md +122 -0
- package/template/.agent/skills/session-continuity/protocols/10-placeholder-verification-gate.md +104 -0
- package/template/.agent/skills/session-continuity/protocols/ambiguity-gates.md +48 -0
- package/template/.agent/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.agent/skills/skill-creator/README.md +270 -0
- package/template/.agent/skills/skill-creator/SKILL.md +590 -0
- package/template/.agent/skills/skill-creator/references/output-patterns.md +82 -0
- package/template/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/template/.agent/skills/skill-creator/scripts/init_skill.py +303 -0
- package/template/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/template/.agent/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/template/.agent/skills/spec-writing/SKILL.md +110 -0
- package/template/.agent/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/template/.agent/skills/systematic-debugging/SKILL.md +297 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/template/.agent/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/template/.agent/skills/systematic-debugging/find-polluter.sh +63 -0
- package/template/.agent/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/template/.agent/skills/systematic-debugging/test-academic.md +14 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/template/.agent/skills/tdd-workflow/SKILL.md +409 -0
- package/template/.agent/skills/tech-stack-catalog/SKILL.md +49 -0
- package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +21 -0
- package/template/.agent/skills/tech-stack-catalog/references/dev-tooling-decisions.md +37 -0
- package/template/.agent/skills/tech-stack-catalog/references/surface-decision-tables.md +69 -0
- package/template/.agent/skills/technical-writer/SKILL.md +242 -0
- package/template/.agent/skills/testing-strategist/SKILL.md +932 -0
- package/template/.agent/skills/verification-before-completion/SKILL.md +145 -0
- package/template/.agent/skills/workflow-automation/SKILL.md +73 -0
- package/template/.agent/workflows/audit-ambiguity-execute.md +165 -0
- package/template/.agent/workflows/audit-ambiguity-rubrics.md +83 -0
- package/template/.agent/workflows/audit-ambiguity.md +64 -0
- package/template/.agent/workflows/bootstrap-agents-fill.md +201 -0
- package/template/.agent/workflows/bootstrap-agents-provision.md +197 -0
- package/template/.agent/workflows/bootstrap-agents.md +66 -0
- package/template/.agent/workflows/create-prd-architecture.md +119 -0
- package/template/.agent/workflows/create-prd-compile.md +138 -0
- package/template/.agent/workflows/create-prd-design-system.md +135 -0
- package/template/.agent/workflows/create-prd-security.md +113 -0
- package/template/.agent/workflows/create-prd-stack.md +91 -0
- package/template/.agent/workflows/create-prd.md +168 -0
- package/template/.agent/workflows/decompose-architecture-structure.md +82 -0
- package/template/.agent/workflows/decompose-architecture-validate.md +119 -0
- package/template/.agent/workflows/decompose-architecture.md +111 -0
- package/template/.agent/workflows/evolve-contract.md +98 -0
- package/template/.agent/workflows/evolve-feature-cascade.md +140 -0
- package/template/.agent/workflows/evolve-feature-classify.md +116 -0
- package/template/.agent/workflows/evolve-feature.md +56 -0
- package/template/.agent/workflows/ideate-discover.md +144 -0
- package/template/.agent/workflows/ideate-extract.md +129 -0
- package/template/.agent/workflows/ideate-validate.md +117 -0
- package/template/.agent/workflows/ideate.md +113 -0
- package/template/.agent/workflows/implement-slice-setup.md +113 -0
- package/template/.agent/workflows/implement-slice-tdd.md +198 -0
- package/template/.agent/workflows/implement-slice.md +50 -0
- package/template/.agent/workflows/plan-phase.md +202 -0
- package/template/.agent/workflows/propagate-decision-apply.md +135 -0
- package/template/.agent/workflows/propagate-decision-scan.md +147 -0
- package/template/.agent/workflows/propagate-decision.md +56 -0
- package/template/.agent/workflows/remediate-pipeline-assess.md +138 -0
- package/template/.agent/workflows/remediate-pipeline-execute.md +135 -0
- package/template/.agent/workflows/remediate-pipeline.md +55 -0
- package/template/.agent/workflows/resolve-ambiguity.md +82 -0
- package/template/.agent/workflows/sync-kit.md +209 -0
- package/template/.agent/workflows/update-architecture-map.md +74 -0
- package/template/.agent/workflows/validate-phase.md +219 -0
- package/template/.agent/workflows/verify-infrastructure.md +207 -0
- package/template/.agent/workflows/write-architecture-spec-deepen.md +139 -0
- package/template/.agent/workflows/write-architecture-spec-design.md +202 -0
- package/template/.agent/workflows/write-architecture-spec.md +63 -0
- package/template/.agent/workflows/write-be-spec-classify.md +165 -0
- package/template/.agent/workflows/write-be-spec-write.md +98 -0
- package/template/.agent/workflows/write-be-spec.md +76 -0
- package/template/.agent/workflows/write-fe-spec-classify.md +170 -0
- package/template/.agent/workflows/write-fe-spec-write.md +94 -0
- package/template/.agent/workflows/write-fe-spec.md +71 -0
- package/template/AGENTS.md +176 -0
- package/template/GEMINI.md +177 -0
- package/template/docs/README.md +187 -0
- package/template/docs/audits/.gitkeep +0 -0
- package/template/docs/audits/README.md +10 -0
- package/template/docs/plans/.gitkeep +0 -0
- package/template/docs/plans/README.md +21 -0
- package/template/docs/plans/be/.gitkeep +0 -0
- package/template/docs/plans/be/README.md +11 -0
- package/template/docs/plans/fe/.gitkeep +0 -0
- package/template/docs/plans/fe/README.md +11 -0
- package/template/docs/plans/ia/.gitkeep +0 -0
- package/template/docs/plans/ia/README.md +17 -0
- package/template/docs/plans/ia/deep-dives/.gitkeep +0 -0
- package/template/docs/plans/ia/deep-dives/README.md +5 -0
- package/template/docs/plans/phases/.gitkeep +0 -0
- package/template/docs/plans/phases/README.md +11 -0
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vitest
|
|
3
|
+
description: "Comprehensive Vitest unit testing guide covering configuration, assertions, mocking, snapshots, coverage, async testing, timer mocking, component testing, type testing, and benchmarking. Use when writing unit tests, configuring test environments, mocking modules, or setting up coverage."
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Vitest Unit Testing
|
|
8
|
+
|
|
9
|
+
## 1. Configuration
|
|
10
|
+
|
|
11
|
+
### vitest.config.ts
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { defineConfig } from 'vitest/config';
|
|
15
|
+
import react from '@vitejs/plugin-react';
|
|
16
|
+
import tsconfigPaths from 'vite-tsconfig-paths';
|
|
17
|
+
|
|
18
|
+
export default defineConfig({
|
|
19
|
+
plugins: [react(), tsconfigPaths()],
|
|
20
|
+
test: {
|
|
21
|
+
// Environment
|
|
22
|
+
environment: 'node', // 'node' | 'jsdom' | 'happy-dom'
|
|
23
|
+
globals: true, // Use describe/it/expect without imports
|
|
24
|
+
|
|
25
|
+
// File patterns
|
|
26
|
+
include: ['src/**/*.test.{ts,tsx}'],
|
|
27
|
+
exclude: ['node_modules', 'dist', 'tests/e2e'],
|
|
28
|
+
|
|
29
|
+
// Setup files (run before each test file)
|
|
30
|
+
setupFiles: ['./src/test/setup.ts'],
|
|
31
|
+
|
|
32
|
+
// Coverage
|
|
33
|
+
coverage: {
|
|
34
|
+
provider: 'v8', // 'v8' or 'istanbul'
|
|
35
|
+
reporter: ['text', 'html', 'lcov'],
|
|
36
|
+
include: ['src/**/*.{ts,tsx}'],
|
|
37
|
+
exclude: [
|
|
38
|
+
'src/**/*.test.{ts,tsx}',
|
|
39
|
+
'src/**/*.d.ts',
|
|
40
|
+
'src/test/**',
|
|
41
|
+
'src/**/index.ts', // barrel files
|
|
42
|
+
],
|
|
43
|
+
thresholds: {
|
|
44
|
+
statements: 80,
|
|
45
|
+
branches: 80,
|
|
46
|
+
functions: 80,
|
|
47
|
+
lines: 80,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
// Timeouts
|
|
52
|
+
testTimeout: 10_000,
|
|
53
|
+
hookTimeout: 10_000,
|
|
54
|
+
|
|
55
|
+
// Isolation
|
|
56
|
+
pool: 'forks', // 'threads' | 'forks' | 'vmThreads'
|
|
57
|
+
isolate: true, // Isolate test files
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Per-File Environment Override
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// @vitest-environment jsdom
|
|
66
|
+
// This comment at the top of a test file overrides the global environment
|
|
67
|
+
|
|
68
|
+
import { render, screen } from '@testing-library/react';
|
|
69
|
+
|
|
70
|
+
test('renders component', () => {
|
|
71
|
+
render(<Button>Click me</Button>);
|
|
72
|
+
expect(screen.getByRole('button')).toHaveTextContent('Click me');
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Workspaces (Monorepo)
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// vitest.workspace.ts
|
|
80
|
+
import { defineWorkspace } from 'vitest/config';
|
|
81
|
+
|
|
82
|
+
export default defineWorkspace([
|
|
83
|
+
{
|
|
84
|
+
extends: './vitest.config.ts',
|
|
85
|
+
test: {
|
|
86
|
+
name: 'unit',
|
|
87
|
+
include: ['src/**/*.test.ts'],
|
|
88
|
+
environment: 'node',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
extends: './vitest.config.ts',
|
|
93
|
+
test: {
|
|
94
|
+
name: 'components',
|
|
95
|
+
include: ['src/**/*.test.tsx'],
|
|
96
|
+
environment: 'jsdom',
|
|
97
|
+
setupFiles: ['./src/test/setup-dom.ts'],
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
]);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 2. Test Structure
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { describe, it, test, expect, beforeAll, beforeEach, afterEach, afterAll } from 'vitest';
|
|
109
|
+
|
|
110
|
+
describe('UserService', () => {
|
|
111
|
+
let service: UserService;
|
|
112
|
+
|
|
113
|
+
// Runs once before all tests in this describe block
|
|
114
|
+
beforeAll(async () => {
|
|
115
|
+
await setupDatabase();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Runs before each test
|
|
119
|
+
beforeEach(() => {
|
|
120
|
+
service = new UserService();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Runs after each test
|
|
124
|
+
afterEach(() => {
|
|
125
|
+
service.dispose();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Runs once after all tests
|
|
129
|
+
afterAll(async () => {
|
|
130
|
+
await teardownDatabase();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should create a user with valid data', async () => {
|
|
134
|
+
const user = await service.create({ email: 'test@example.com', name: 'Test' });
|
|
135
|
+
expect(user.id).toBeDefined();
|
|
136
|
+
expect(user.email).toBe('test@example.com');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should throw on duplicate email', async () => {
|
|
140
|
+
await service.create({ email: 'dup@example.com', name: 'First' });
|
|
141
|
+
await expect(service.create({ email: 'dup@example.com', name: 'Second' }))
|
|
142
|
+
.rejects.toThrow('Email already exists');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Nested describe for grouping
|
|
146
|
+
describe('findByEmail', () => {
|
|
147
|
+
it('should return null for unknown email', async () => {
|
|
148
|
+
const user = await service.findByEmail('unknown@example.com');
|
|
149
|
+
expect(user).toBeNull();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Test Filtering
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// Run only this test (use during development, never commit)
|
|
159
|
+
it.only('focused test', () => { /* ... */ });
|
|
160
|
+
|
|
161
|
+
// Skip this test
|
|
162
|
+
it.skip('skipped test', () => { /* ... */ });
|
|
163
|
+
|
|
164
|
+
// Mark as to-do (shows in output but does not fail)
|
|
165
|
+
it.todo('test to write later');
|
|
166
|
+
|
|
167
|
+
// Run tests concurrently within a describe block
|
|
168
|
+
describe.concurrent('parallel tests', () => {
|
|
169
|
+
it('test A', async () => { /* ... */ });
|
|
170
|
+
it('test B', async () => { /* ... */ });
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Repeat a test multiple times (useful for flakiness detection)
|
|
174
|
+
it.repeats(100)('should be stable', () => { /* ... */ });
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## 3. Assertions
|
|
180
|
+
|
|
181
|
+
### Core Matchers
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// Equality
|
|
185
|
+
expect(value).toBe(2); // strict === (primitives, references)
|
|
186
|
+
expect(obj).toEqual({ a: 1, b: 2 }); // deep equality
|
|
187
|
+
expect(obj).toStrictEqual({ a: 1, b: 2 }); // deep equality + checks undefined properties
|
|
188
|
+
|
|
189
|
+
// Partial matching
|
|
190
|
+
expect(user).toMatchObject({ email: 'test@example.com' }); // subset match
|
|
191
|
+
expect(user).toEqual(expect.objectContaining({ email: 'test@example.com' }));
|
|
192
|
+
|
|
193
|
+
// Truthiness
|
|
194
|
+
expect(value).toBeTruthy();
|
|
195
|
+
expect(value).toBeFalsy();
|
|
196
|
+
expect(value).toBeNull();
|
|
197
|
+
expect(value).toBeUndefined();
|
|
198
|
+
expect(value).toBeDefined();
|
|
199
|
+
|
|
200
|
+
// Numbers
|
|
201
|
+
expect(count).toBeGreaterThan(0);
|
|
202
|
+
expect(count).toBeGreaterThanOrEqual(1);
|
|
203
|
+
expect(count).toBeLessThan(100);
|
|
204
|
+
expect(0.1 + 0.2).toBeCloseTo(0.3, 5); // floating point comparison
|
|
205
|
+
|
|
206
|
+
// Strings
|
|
207
|
+
expect(message).toContain('error');
|
|
208
|
+
expect(message).toMatch(/^Error: .+/);
|
|
209
|
+
|
|
210
|
+
// Arrays
|
|
211
|
+
expect(list).toContain('item');
|
|
212
|
+
expect(list).toHaveLength(3);
|
|
213
|
+
expect(list).toEqual(expect.arrayContaining(['a', 'b']));
|
|
214
|
+
|
|
215
|
+
// Exceptions
|
|
216
|
+
expect(() => riskyFunction()).toThrow();
|
|
217
|
+
expect(() => riskyFunction()).toThrow('specific message');
|
|
218
|
+
expect(() => riskyFunction()).toThrow(ValidationError);
|
|
219
|
+
expect(() => riskyFunction()).toThrowErrorMatchingInlineSnapshot(`"specific message"`);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Async Assertions
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
// Resolved value
|
|
226
|
+
await expect(asyncFn()).resolves.toBe(42);
|
|
227
|
+
await expect(asyncFn()).resolves.toEqual({ status: 'ok' });
|
|
228
|
+
|
|
229
|
+
// Rejected value
|
|
230
|
+
await expect(asyncFn()).rejects.toThrow('Not found');
|
|
231
|
+
await expect(asyncFn()).rejects.toBeInstanceOf(NotFoundError);
|
|
232
|
+
|
|
233
|
+
// Multiple assertions on resolved value
|
|
234
|
+
const result = await asyncFn();
|
|
235
|
+
expect(result.status).toBe(200);
|
|
236
|
+
expect(result.data).toHaveLength(10);
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## 4. Mocking
|
|
242
|
+
|
|
243
|
+
### Function Mocks (vi.fn)
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import { vi } from 'vitest';
|
|
247
|
+
|
|
248
|
+
// Create a mock function
|
|
249
|
+
const mockFn = vi.fn();
|
|
250
|
+
mockFn('arg1', 'arg2');
|
|
251
|
+
|
|
252
|
+
expect(mockFn).toHaveBeenCalled();
|
|
253
|
+
expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2');
|
|
254
|
+
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
255
|
+
|
|
256
|
+
// Mock with return value
|
|
257
|
+
const getId = vi.fn().mockReturnValue('abc-123');
|
|
258
|
+
const getUser = vi.fn().mockResolvedValue({ id: '1', name: 'Alice' });
|
|
259
|
+
const failingFn = vi.fn().mockRejectedValue(new Error('Failed'));
|
|
260
|
+
|
|
261
|
+
// Mock implementation
|
|
262
|
+
const calculate = vi.fn().mockImplementation((a: number, b: number) => a + b);
|
|
263
|
+
|
|
264
|
+
// Different returns on successive calls
|
|
265
|
+
const counter = vi.fn()
|
|
266
|
+
.mockReturnValueOnce(1)
|
|
267
|
+
.mockReturnValueOnce(2)
|
|
268
|
+
.mockReturnValueOnce(3);
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Spy on Methods (vi.spyOn)
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
// Spy on an object method (original implementation runs by default)
|
|
275
|
+
const spy = vi.spyOn(console, 'error');
|
|
276
|
+
doSomethingThatLogs();
|
|
277
|
+
expect(spy).toHaveBeenCalledWith('Expected error message');
|
|
278
|
+
spy.mockRestore(); // Restore original implementation
|
|
279
|
+
|
|
280
|
+
// Spy and replace implementation
|
|
281
|
+
const dateSpy = vi.spyOn(Date, 'now').mockReturnValue(1700000000000);
|
|
282
|
+
expect(Date.now()).toBe(1700000000000);
|
|
283
|
+
dateSpy.mockRestore();
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Module Mocking (vi.mock)
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
// Mock an entire module
|
|
290
|
+
vi.mock('./database', () => ({
|
|
291
|
+
db: {
|
|
292
|
+
query: vi.fn().mockResolvedValue([{ id: '1', name: 'Test' }]),
|
|
293
|
+
insert: vi.fn().mockResolvedValue({ id: '1' }),
|
|
294
|
+
},
|
|
295
|
+
}));
|
|
296
|
+
|
|
297
|
+
// The mock is hoisted to the top of the file automatically
|
|
298
|
+
import { db } from './database'; // This gets the mocked version
|
|
299
|
+
|
|
300
|
+
test('uses mocked database', async () => {
|
|
301
|
+
const result = await db.query('SELECT * FROM users');
|
|
302
|
+
expect(result).toEqual([{ id: '1', name: 'Test' }]);
|
|
303
|
+
});
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Factory Pattern for Module Mocks
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
// Mock with factory that has access to vi
|
|
310
|
+
vi.mock('./config', () => {
|
|
311
|
+
return {
|
|
312
|
+
getConfig: vi.fn(() => ({
|
|
313
|
+
apiUrl: 'http://test-api.local',
|
|
314
|
+
timeout: 1000,
|
|
315
|
+
})),
|
|
316
|
+
};
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// Change mock behavior per test
|
|
320
|
+
import { getConfig } from './config';
|
|
321
|
+
|
|
322
|
+
test('handles missing config', () => {
|
|
323
|
+
vi.mocked(getConfig).mockReturnValueOnce({ apiUrl: '', timeout: 0 });
|
|
324
|
+
expect(() => initializeApp()).toThrow('API URL is required');
|
|
325
|
+
});
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Partial Module Mocking
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
// Mock only specific exports, keep the rest real
|
|
332
|
+
vi.mock('./utils', async (importOriginal) => {
|
|
333
|
+
const actual = await importOriginal<typeof import('./utils')>();
|
|
334
|
+
return {
|
|
335
|
+
...actual,
|
|
336
|
+
fetchData: vi.fn().mockResolvedValue({ data: 'mocked' }),
|
|
337
|
+
// All other exports remain real
|
|
338
|
+
};
|
|
339
|
+
});
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Global Mocking
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
// Mock global objects
|
|
346
|
+
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
|
|
347
|
+
ok: true,
|
|
348
|
+
json: () => Promise.resolve({ data: 'test' }),
|
|
349
|
+
}));
|
|
350
|
+
|
|
351
|
+
// Mock environment variables
|
|
352
|
+
vi.stubEnv('API_KEY', 'test-key-123');
|
|
353
|
+
|
|
354
|
+
// Clean up in afterEach
|
|
355
|
+
afterEach(() => {
|
|
356
|
+
vi.unstubAllGlobals();
|
|
357
|
+
vi.unstubAllEnvs();
|
|
358
|
+
});
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## 5. Timer Mocking
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
import { vi, beforeEach, afterEach } from 'vitest';
|
|
367
|
+
|
|
368
|
+
beforeEach(() => {
|
|
369
|
+
vi.useFakeTimers();
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
afterEach(() => {
|
|
373
|
+
vi.useRealTimers();
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
test('debounce waits before calling', () => {
|
|
377
|
+
const callback = vi.fn();
|
|
378
|
+
const debounced = debounce(callback, 300);
|
|
379
|
+
|
|
380
|
+
debounced();
|
|
381
|
+
expect(callback).not.toHaveBeenCalled();
|
|
382
|
+
|
|
383
|
+
vi.advanceTimersByTime(299);
|
|
384
|
+
expect(callback).not.toHaveBeenCalled();
|
|
385
|
+
|
|
386
|
+
vi.advanceTimersByTime(1);
|
|
387
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
test('setInterval fires repeatedly', () => {
|
|
391
|
+
const callback = vi.fn();
|
|
392
|
+
setInterval(callback, 1000);
|
|
393
|
+
|
|
394
|
+
vi.advanceTimersByTime(3500);
|
|
395
|
+
expect(callback).toHaveBeenCalledTimes(3);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
// Run all pending timers
|
|
399
|
+
test('run all timers', () => {
|
|
400
|
+
const callback = vi.fn();
|
|
401
|
+
setTimeout(callback, 5000);
|
|
402
|
+
|
|
403
|
+
vi.runAllTimers();
|
|
404
|
+
expect(callback).toHaveBeenCalled();
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// Set system time
|
|
408
|
+
test('date-dependent logic', () => {
|
|
409
|
+
vi.setSystemTime(new Date('2025-06-15T12:00:00Z'));
|
|
410
|
+
expect(isWeekend()).toBe(true);
|
|
411
|
+
});
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## 6. Snapshot Testing
|
|
417
|
+
|
|
418
|
+
```typescript
|
|
419
|
+
// Inline snapshot (stored in the test file itself)
|
|
420
|
+
test('serializes user correctly', () => {
|
|
421
|
+
const user = formatUser({ id: '1', email: 'test@example.com', name: 'Test User' });
|
|
422
|
+
|
|
423
|
+
expect(user).toMatchInlineSnapshot(`
|
|
424
|
+
{
|
|
425
|
+
"displayName": "Test User",
|
|
426
|
+
"email": "test@example.com",
|
|
427
|
+
"id": "1",
|
|
428
|
+
}
|
|
429
|
+
`);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
// File snapshot (stored in __snapshots__/ directory)
|
|
433
|
+
test('config output', () => {
|
|
434
|
+
const config = generateConfig({ env: 'production' });
|
|
435
|
+
expect(config).toMatchSnapshot();
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
// Update snapshots: vitest --update (or press 'u' in watch mode)
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
**When to use snapshots**: Use them for serializable output (JSON, HTML, config objects). Avoid them for assertions that should be explicit -- prefer `toEqual` for business logic.
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## 7. Testing React Components
|
|
446
|
+
|
|
447
|
+
### Setup
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
// src/test/setup.ts
|
|
451
|
+
import '@testing-library/jest-dom/vitest';
|
|
452
|
+
import { cleanup } from '@testing-library/react';
|
|
453
|
+
import { afterEach } from 'vitest';
|
|
454
|
+
|
|
455
|
+
// Cleanup after each test
|
|
456
|
+
afterEach(() => {
|
|
457
|
+
cleanup();
|
|
458
|
+
});
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Component Tests
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
465
|
+
import userEvent from '@testing-library/user-event';
|
|
466
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
467
|
+
import { LoginForm } from './LoginForm';
|
|
468
|
+
|
|
469
|
+
describe('LoginForm', () => {
|
|
470
|
+
it('should render email and password fields', () => {
|
|
471
|
+
render(<LoginForm onSubmit={vi.fn()} />);
|
|
472
|
+
|
|
473
|
+
expect(screen.getByLabelText('Email')).toBeInTheDocument();
|
|
474
|
+
expect(screen.getByLabelText('Password')).toBeInTheDocument();
|
|
475
|
+
expect(screen.getByRole('button', { name: 'Sign in' })).toBeInTheDocument();
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
it('should call onSubmit with form values', async () => {
|
|
479
|
+
const user = userEvent.setup();
|
|
480
|
+
const handleSubmit = vi.fn();
|
|
481
|
+
render(<LoginForm onSubmit={handleSubmit} />);
|
|
482
|
+
|
|
483
|
+
await user.type(screen.getByLabelText('Email'), 'test@example.com');
|
|
484
|
+
await user.type(screen.getByLabelText('Password'), 'password123');
|
|
485
|
+
await user.click(screen.getByRole('button', { name: 'Sign in' }));
|
|
486
|
+
|
|
487
|
+
expect(handleSubmit).toHaveBeenCalledWith({
|
|
488
|
+
email: 'test@example.com',
|
|
489
|
+
password: 'password123',
|
|
490
|
+
});
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
it('should show validation errors', async () => {
|
|
494
|
+
const user = userEvent.setup();
|
|
495
|
+
render(<LoginForm onSubmit={vi.fn()} />);
|
|
496
|
+
|
|
497
|
+
// Submit without filling fields
|
|
498
|
+
await user.click(screen.getByRole('button', { name: 'Sign in' }));
|
|
499
|
+
|
|
500
|
+
await waitFor(() => {
|
|
501
|
+
expect(screen.getByText('Email is required')).toBeInTheDocument();
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
it('should disable button while submitting', async () => {
|
|
506
|
+
const user = userEvent.setup();
|
|
507
|
+
const handleSubmit = vi.fn(() => new Promise((resolve) => setTimeout(resolve, 1000)));
|
|
508
|
+
render(<LoginForm onSubmit={handleSubmit} />);
|
|
509
|
+
|
|
510
|
+
await user.type(screen.getByLabelText('Email'), 'test@example.com');
|
|
511
|
+
await user.type(screen.getByLabelText('Password'), 'password123');
|
|
512
|
+
await user.click(screen.getByRole('button', { name: 'Sign in' }));
|
|
513
|
+
|
|
514
|
+
expect(screen.getByRole('button', { name: 'Signing in...' })).toBeDisabled();
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### Testing Custom Hooks
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
import { renderHook, act } from '@testing-library/react';
|
|
523
|
+
import { useCounter } from './useCounter';
|
|
524
|
+
|
|
525
|
+
test('useCounter increments and decrements', () => {
|
|
526
|
+
const { result } = renderHook(() => useCounter(0));
|
|
527
|
+
|
|
528
|
+
expect(result.current.count).toBe(0);
|
|
529
|
+
|
|
530
|
+
act(() => { result.current.increment(); });
|
|
531
|
+
expect(result.current.count).toBe(1);
|
|
532
|
+
|
|
533
|
+
act(() => { result.current.decrement(); });
|
|
534
|
+
expect(result.current.count).toBe(0);
|
|
535
|
+
});
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
---
|
|
539
|
+
|
|
540
|
+
## 8. Type Testing
|
|
541
|
+
|
|
542
|
+
```typescript
|
|
543
|
+
import { expectTypeOf, test } from 'vitest';
|
|
544
|
+
import { getUser, type User } from './user';
|
|
545
|
+
|
|
546
|
+
test('getUser returns a User', () => {
|
|
547
|
+
expectTypeOf(getUser).returns.toEqualTypeOf<Promise<User>>();
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
test('User has expected shape', () => {
|
|
551
|
+
expectTypeOf<User>().toHaveProperty('id').toBeString();
|
|
552
|
+
expectTypeOf<User>().toHaveProperty('email').toBeString();
|
|
553
|
+
expectTypeOf<User>().toHaveProperty('active').toBeBoolean();
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
test('function parameter types', () => {
|
|
557
|
+
expectTypeOf(getUser).parameter(0).toBeString(); // first param is string
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
test('schema inference produces correct type', () => {
|
|
561
|
+
type Inferred = z.infer<typeof userSchema>;
|
|
562
|
+
expectTypeOf<Inferred>().toEqualTypeOf<{ name: string; email: string; age: number }>();
|
|
563
|
+
});
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## 9. Performance Benchmarking
|
|
569
|
+
|
|
570
|
+
```typescript
|
|
571
|
+
import { bench, describe } from 'vitest';
|
|
572
|
+
|
|
573
|
+
describe('string concatenation', () => {
|
|
574
|
+
const items = Array.from({ length: 1000 }, (_, i) => `item-${i}`);
|
|
575
|
+
|
|
576
|
+
bench('Array.join', () => {
|
|
577
|
+
items.join(', ');
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
bench('template literal reduce', () => {
|
|
581
|
+
items.reduce((acc, item) => `${acc}, ${item}`);
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
bench('string concatenation', () => {
|
|
585
|
+
let result = '';
|
|
586
|
+
for (const item of items) {
|
|
587
|
+
result += result ? `, ${item}` : item;
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
// Run benchmarks: vitest bench
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
|
|
597
|
+
## 10. In-Source Testing
|
|
598
|
+
|
|
599
|
+
Write tests alongside the code in the same file. Tests are removed from production builds by Vite.
|
|
600
|
+
|
|
601
|
+
```typescript
|
|
602
|
+
// src/lib/math.ts
|
|
603
|
+
export function fibonacci(n: number): number {
|
|
604
|
+
if (n <= 1) return n;
|
|
605
|
+
return fibonacci(n - 1) + fibonacci(n - 2);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// In-source test block (stripped from production build)
|
|
609
|
+
if (import.meta.vitest) {
|
|
610
|
+
const { it, expect } = import.meta.vitest;
|
|
611
|
+
|
|
612
|
+
it('fibonacci(0) = 0', () => { expect(fibonacci(0)).toBe(0); });
|
|
613
|
+
it('fibonacci(1) = 1', () => { expect(fibonacci(1)).toBe(1); });
|
|
614
|
+
it('fibonacci(10) = 55', () => { expect(fibonacci(10)).toBe(55); });
|
|
615
|
+
}
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
Requires config:
|
|
619
|
+
```typescript
|
|
620
|
+
// vitest.config.ts
|
|
621
|
+
export default defineConfig({
|
|
622
|
+
test: { includeSource: ['src/**/*.ts'] },
|
|
623
|
+
define: { 'import.meta.vitest': 'undefined' }, // strip in production
|
|
624
|
+
});
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
---
|
|
628
|
+
|
|
629
|
+
## 11. Common Patterns
|
|
630
|
+
|
|
631
|
+
### Testing Zod Schemas
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
import { describe, it, expect } from 'vitest';
|
|
635
|
+
import { userSchema } from './user.schema';
|
|
636
|
+
|
|
637
|
+
describe('userSchema', () => {
|
|
638
|
+
it('should accept valid input', () => {
|
|
639
|
+
const result = userSchema.safeParse({
|
|
640
|
+
email: 'test@example.com',
|
|
641
|
+
name: 'Test User',
|
|
642
|
+
age: 25,
|
|
643
|
+
});
|
|
644
|
+
expect(result.success).toBe(true);
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
it('should reject invalid email', () => {
|
|
648
|
+
const result = userSchema.safeParse({
|
|
649
|
+
email: 'not-an-email',
|
|
650
|
+
name: 'Test',
|
|
651
|
+
age: 25,
|
|
652
|
+
});
|
|
653
|
+
expect(result.success).toBe(false);
|
|
654
|
+
if (!result.success) {
|
|
655
|
+
expect(result.error.issues[0].path).toEqual(['email']);
|
|
656
|
+
}
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
it('should reject missing required fields', () => {
|
|
660
|
+
const result = userSchema.safeParse({});
|
|
661
|
+
expect(result.success).toBe(false);
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
it('should apply defaults', () => {
|
|
665
|
+
const result = userSchema.parse({ email: 'a@b.com', name: 'A' });
|
|
666
|
+
expect(result.role).toBe('user'); // default value
|
|
667
|
+
});
|
|
668
|
+
});
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
### Testing Error Boundaries
|
|
672
|
+
|
|
673
|
+
```typescript
|
|
674
|
+
import { vi } from 'vitest';
|
|
675
|
+
|
|
676
|
+
// Suppress console.error for expected errors
|
|
677
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
678
|
+
|
|
679
|
+
afterEach(() => {
|
|
680
|
+
consoleSpy.mockRestore();
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
test('handles async errors', async () => {
|
|
684
|
+
const result = await safeAsync(() => { throw new Error('test'); });
|
|
685
|
+
expect(result.ok).toBe(false);
|
|
686
|
+
expect(result.error?.message).toBe('test');
|
|
687
|
+
});
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
---
|
|
691
|
+
|
|
692
|
+
## 12. Critical Reminders
|
|
693
|
+
|
|
694
|
+
### ALWAYS
|
|
695
|
+
|
|
696
|
+
- Clean up mocks with `vi.restoreAllMocks()` in `afterEach` (or use `mockReset: true` in config)
|
|
697
|
+
- Use `vi.mocked()` to get typed mock references
|
|
698
|
+
- Prefer `userEvent` over `fireEvent` for component interaction tests
|
|
699
|
+
- Use `vi.useFakeTimers()` and `vi.useRealTimers()` in matched pairs
|
|
700
|
+
- Test both success and error paths
|
|
701
|
+
- Use `waitFor` for async DOM updates, not `setTimeout`
|
|
702
|
+
- Run coverage to find untested code paths
|
|
703
|
+
- Match test file names to source files (`user.ts` -> `user.test.ts`)
|
|
704
|
+
|
|
705
|
+
### NEVER
|
|
706
|
+
|
|
707
|
+
- Leave `test.only` or `describe.only` in committed code
|
|
708
|
+
- Mock what you own -- test your code, mock external dependencies
|
|
709
|
+
- Use `any` in test code -- tests should be type-safe too
|
|
710
|
+
- Ignore flaky tests -- fix the root cause (usually missing `await` or `waitFor`)
|
|
711
|
+
- Write tests that depend on execution order
|
|
712
|
+
- Mock `Date.now()` without restoring it
|
|
713
|
+
- Skip cleanup of spies and mocks (causes test pollution)
|
|
714
|
+
- Use `toBe` for object comparison (use `toEqual` or `toStrictEqual`)
|