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,641 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: playwright
|
|
3
|
+
description: "Comprehensive Playwright E2E testing guide covering configuration, test patterns, locator strategies, network mocking, authentication, visual regression, debugging, and CI/CD integration. Use when writing end-to-end tests, setting up Playwright projects, or debugging test failures."
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Playwright E2E Testing
|
|
8
|
+
|
|
9
|
+
## 1. Configuration
|
|
10
|
+
|
|
11
|
+
### playwright.config.ts
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
15
|
+
|
|
16
|
+
export default defineConfig({
|
|
17
|
+
testDir: './tests/e2e',
|
|
18
|
+
outputDir: './test-results',
|
|
19
|
+
|
|
20
|
+
// Run all tests in parallel
|
|
21
|
+
fullyParallel: true,
|
|
22
|
+
|
|
23
|
+
// Fail the build on CI if you accidentally left test.only in the source code
|
|
24
|
+
forbidOnly: !!process.env.CI,
|
|
25
|
+
|
|
26
|
+
// Retry failed tests (more retries on CI)
|
|
27
|
+
retries: process.env.CI ? 2 : 0,
|
|
28
|
+
|
|
29
|
+
// Limit parallel workers on CI to avoid resource contention
|
|
30
|
+
workers: process.env.CI ? 1 : undefined,
|
|
31
|
+
|
|
32
|
+
// Reporter configuration
|
|
33
|
+
reporter: process.env.CI
|
|
34
|
+
? [['html', { open: 'never' }], ['github']]
|
|
35
|
+
: [['html', { open: 'on-failure' }]],
|
|
36
|
+
|
|
37
|
+
// Shared settings for all projects
|
|
38
|
+
use: {
|
|
39
|
+
baseURL: process.env.BASE_URL ?? 'http://localhost:3000',
|
|
40
|
+
trace: 'on-first-retry', // Capture trace on retry
|
|
41
|
+
screenshot: 'only-on-failure', // Screenshot on failure
|
|
42
|
+
video: 'retain-on-failure', // Video on failure
|
|
43
|
+
actionTimeout: 10_000, // Timeout for each action (click, fill, etc.)
|
|
44
|
+
navigationTimeout: 30_000, // Timeout for page.goto
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// Test projects (browsers and devices)
|
|
48
|
+
projects: [
|
|
49
|
+
// Desktop browsers
|
|
50
|
+
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
|
|
51
|
+
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
|
|
52
|
+
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
|
|
53
|
+
|
|
54
|
+
// Mobile viewports
|
|
55
|
+
{ name: 'mobile-chrome', use: { ...devices['Pixel 5'] } },
|
|
56
|
+
{ name: 'mobile-safari', use: { ...devices['iPhone 13'] } },
|
|
57
|
+
|
|
58
|
+
// Authenticated tests (uses stored auth state)
|
|
59
|
+
{
|
|
60
|
+
name: 'authenticated',
|
|
61
|
+
use: {
|
|
62
|
+
...devices['Desktop Chrome'],
|
|
63
|
+
storageState: './tests/e2e/.auth/user.json',
|
|
64
|
+
},
|
|
65
|
+
dependencies: ['setup'],
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
|
|
69
|
+
// Dev server (start before tests if not running)
|
|
70
|
+
webServer: {
|
|
71
|
+
command: 'pnpm dev',
|
|
72
|
+
url: 'http://localhost:3000',
|
|
73
|
+
reuseExistingServer: !process.env.CI,
|
|
74
|
+
timeout: 120_000,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 2. Test Structure and Patterns
|
|
82
|
+
|
|
83
|
+
### Basic Test
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { test, expect } from '@playwright/test';
|
|
87
|
+
|
|
88
|
+
test.describe('User Registration', () => {
|
|
89
|
+
test('should create a new account with valid data', async ({ page }) => {
|
|
90
|
+
await page.goto('/register');
|
|
91
|
+
|
|
92
|
+
await page.getByLabel('Email').fill('test@example.com');
|
|
93
|
+
await page.getByLabel('Password').fill('SecureP@ss123');
|
|
94
|
+
await page.getByLabel('Confirm password').fill('SecureP@ss123');
|
|
95
|
+
await page.getByRole('button', { name: 'Create account' }).click();
|
|
96
|
+
|
|
97
|
+
await expect(page).toHaveURL('/dashboard');
|
|
98
|
+
await expect(page.getByRole('heading', { name: 'Welcome' })).toBeVisible();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('should show validation errors for invalid email', async ({ page }) => {
|
|
102
|
+
await page.goto('/register');
|
|
103
|
+
|
|
104
|
+
await page.getByLabel('Email').fill('not-an-email');
|
|
105
|
+
await page.getByLabel('Password').fill('SecureP@ss123');
|
|
106
|
+
await page.getByRole('button', { name: 'Create account' }).click();
|
|
107
|
+
|
|
108
|
+
await expect(page.getByText('Invalid email address')).toBeVisible();
|
|
109
|
+
await expect(page).toHaveURL('/register'); // stays on the same page
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Page Object Model
|
|
115
|
+
|
|
116
|
+
Encapsulate page interactions for reuse and maintainability.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
// tests/e2e/pages/login-page.ts
|
|
120
|
+
import { type Page, type Locator, expect } from '@playwright/test';
|
|
121
|
+
|
|
122
|
+
export class LoginPage {
|
|
123
|
+
readonly page: Page;
|
|
124
|
+
readonly emailInput: Locator;
|
|
125
|
+
readonly passwordInput: Locator;
|
|
126
|
+
readonly submitButton: Locator;
|
|
127
|
+
readonly errorMessage: Locator;
|
|
128
|
+
|
|
129
|
+
constructor(page: Page) {
|
|
130
|
+
this.page = page;
|
|
131
|
+
this.emailInput = page.getByLabel('Email');
|
|
132
|
+
this.passwordInput = page.getByLabel('Password');
|
|
133
|
+
this.submitButton = page.getByRole('button', { name: 'Sign in' });
|
|
134
|
+
this.errorMessage = page.getByRole('alert');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async goto() {
|
|
138
|
+
await this.page.goto('/login');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async login(email: string, password: string) {
|
|
142
|
+
await this.emailInput.fill(email);
|
|
143
|
+
await this.passwordInput.fill(password);
|
|
144
|
+
await this.submitButton.click();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async expectError(message: string) {
|
|
148
|
+
await expect(this.errorMessage).toContainText(message);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async expectRedirectToDashboard() {
|
|
152
|
+
await expect(this.page).toHaveURL('/dashboard');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Usage in tests
|
|
157
|
+
import { LoginPage } from './pages/login-page';
|
|
158
|
+
|
|
159
|
+
test('should login with valid credentials', async ({ page }) => {
|
|
160
|
+
const loginPage = new LoginPage(page);
|
|
161
|
+
await loginPage.goto();
|
|
162
|
+
await loginPage.login('user@example.com', 'password123');
|
|
163
|
+
await loginPage.expectRedirectToDashboard();
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Fixtures
|
|
168
|
+
|
|
169
|
+
Custom fixtures provide reusable setup for multiple tests.
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// tests/e2e/fixtures.ts
|
|
173
|
+
import { test as base, expect } from '@playwright/test';
|
|
174
|
+
import { LoginPage } from './pages/login-page';
|
|
175
|
+
import { DashboardPage } from './pages/dashboard-page';
|
|
176
|
+
|
|
177
|
+
type AppFixtures = {
|
|
178
|
+
loginPage: LoginPage;
|
|
179
|
+
dashboardPage: DashboardPage;
|
|
180
|
+
authenticatedPage: DashboardPage;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export const test = base.extend<AppFixtures>({
|
|
184
|
+
loginPage: async ({ page }, use) => {
|
|
185
|
+
const loginPage = new LoginPage(page);
|
|
186
|
+
await loginPage.goto();
|
|
187
|
+
await use(loginPage);
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
dashboardPage: async ({ page }, use) => {
|
|
191
|
+
await use(new DashboardPage(page));
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
authenticatedPage: async ({ page }, use) => {
|
|
195
|
+
// Login before providing the fixture
|
|
196
|
+
const loginPage = new LoginPage(page);
|
|
197
|
+
await loginPage.goto();
|
|
198
|
+
await loginPage.login('user@example.com', 'password123');
|
|
199
|
+
const dashboard = new DashboardPage(page);
|
|
200
|
+
await use(dashboard);
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
export { expect };
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Parameterized Tests
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
const testCases = [
|
|
211
|
+
{ role: 'admin', expectNav: ['Dashboard', 'Users', 'Settings'] },
|
|
212
|
+
{ role: 'user', expectNav: ['Dashboard', 'Profile'] },
|
|
213
|
+
{ role: 'viewer', expectNav: ['Dashboard'] },
|
|
214
|
+
];
|
|
215
|
+
|
|
216
|
+
for (const { role, expectNav } of testCases) {
|
|
217
|
+
test(`${role} should see correct navigation items`, async ({ page }) => {
|
|
218
|
+
await loginAs(page, role);
|
|
219
|
+
for (const item of expectNav) {
|
|
220
|
+
await expect(page.getByRole('link', { name: item })).toBeVisible();
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## 3. Locator Strategies
|
|
229
|
+
|
|
230
|
+
### Priority Order (Most to Least Preferred)
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
// 1. Role-based (best: semantic, resilient, accessible)
|
|
234
|
+
page.getByRole('button', { name: 'Submit' });
|
|
235
|
+
page.getByRole('heading', { name: 'Dashboard', level: 1 });
|
|
236
|
+
page.getByRole('link', { name: 'Settings' });
|
|
237
|
+
page.getByRole('textbox', { name: 'Email' });
|
|
238
|
+
page.getByRole('checkbox', { name: 'Accept terms' });
|
|
239
|
+
page.getByRole('combobox', { name: 'Country' });
|
|
240
|
+
page.getByRole('navigation');
|
|
241
|
+
page.getByRole('dialog');
|
|
242
|
+
|
|
243
|
+
// 2. Label-based (great for form fields)
|
|
244
|
+
page.getByLabel('Email address');
|
|
245
|
+
page.getByLabel('Password');
|
|
246
|
+
|
|
247
|
+
// 3. Placeholder-based (acceptable for inputs without labels)
|
|
248
|
+
page.getByPlaceholder('Search...');
|
|
249
|
+
|
|
250
|
+
// 4. Text-based (good for static content)
|
|
251
|
+
page.getByText('Welcome back');
|
|
252
|
+
page.getByText(/total: \$[\d.]+/i); // regex for dynamic content
|
|
253
|
+
|
|
254
|
+
// 5. Test ID (fallback when semantic locators are impossible)
|
|
255
|
+
page.getByTestId('user-avatar');
|
|
256
|
+
page.getByTestId('chart-container');
|
|
257
|
+
|
|
258
|
+
// 6. CSS selector (last resort)
|
|
259
|
+
page.locator('.custom-widget >> .inner-element');
|
|
260
|
+
|
|
261
|
+
// AVOID: fragile selectors
|
|
262
|
+
page.locator('#app > div:nth-child(3) > button'); // Breaks on any DOM change
|
|
263
|
+
page.locator('.btn-primary'); // Class names change
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Filtering and Chaining
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// Filter within a section
|
|
270
|
+
const productCard = page.getByRole('article').filter({ hasText: 'Widget Pro' });
|
|
271
|
+
await productCard.getByRole('button', { name: 'Add to cart' }).click();
|
|
272
|
+
|
|
273
|
+
// Find nth match
|
|
274
|
+
await page.getByRole('listitem').nth(2).click();
|
|
275
|
+
|
|
276
|
+
// Filter by child element
|
|
277
|
+
const row = page.getByRole('row').filter({
|
|
278
|
+
has: page.getByRole('cell', { name: 'alice@example.com' }),
|
|
279
|
+
});
|
|
280
|
+
await row.getByRole('button', { name: 'Edit' }).click();
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## 4. Assertions
|
|
286
|
+
|
|
287
|
+
### Common Assertions
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
// Visibility
|
|
291
|
+
await expect(page.getByText('Success')).toBeVisible();
|
|
292
|
+
await expect(page.getByText('Error')).not.toBeVisible();
|
|
293
|
+
await expect(page.getByRole('dialog')).toBeHidden();
|
|
294
|
+
|
|
295
|
+
// Text content
|
|
296
|
+
await expect(page.getByRole('heading')).toHaveText('Dashboard');
|
|
297
|
+
await expect(page.getByRole('heading')).toContainText('Dash');
|
|
298
|
+
|
|
299
|
+
// URL
|
|
300
|
+
await expect(page).toHaveURL('/dashboard');
|
|
301
|
+
await expect(page).toHaveURL(/\/dashboard\?.*/);
|
|
302
|
+
|
|
303
|
+
// Input values
|
|
304
|
+
await expect(page.getByLabel('Email')).toHaveValue('user@example.com');
|
|
305
|
+
await expect(page.getByLabel('Email')).toBeEmpty();
|
|
306
|
+
|
|
307
|
+
// Attributes
|
|
308
|
+
await expect(page.getByRole('button')).toBeEnabled();
|
|
309
|
+
await expect(page.getByRole('button')).toBeDisabled();
|
|
310
|
+
await expect(page.getByRole('checkbox')).toBeChecked();
|
|
311
|
+
await expect(page.getByRole('link')).toHaveAttribute('href', '/settings');
|
|
312
|
+
|
|
313
|
+
// Count
|
|
314
|
+
await expect(page.getByRole('listitem')).toHaveCount(5);
|
|
315
|
+
|
|
316
|
+
// CSS
|
|
317
|
+
await expect(page.getByTestId('status')).toHaveCSS('color', 'rgb(255, 0, 0)');
|
|
318
|
+
|
|
319
|
+
// Page title
|
|
320
|
+
await expect(page).toHaveTitle('Dashboard | My App');
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Soft Assertions
|
|
324
|
+
|
|
325
|
+
Soft assertions do not stop the test on failure. All failures are reported at the end.
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
test('dashboard displays all widgets', async ({ page }) => {
|
|
329
|
+
await page.goto('/dashboard');
|
|
330
|
+
|
|
331
|
+
// Continue checking even if one fails
|
|
332
|
+
await expect.soft(page.getByTestId('revenue-widget')).toBeVisible();
|
|
333
|
+
await expect.soft(page.getByTestId('users-widget')).toBeVisible();
|
|
334
|
+
await expect.soft(page.getByTestId('orders-widget')).toBeVisible();
|
|
335
|
+
await expect.soft(page.getByTestId('chart-widget')).toBeVisible();
|
|
336
|
+
});
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## 5. Auto-Waiting
|
|
342
|
+
|
|
343
|
+
Playwright automatically waits for elements to be actionable before performing actions. You rarely need explicit waits.
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
// Playwright auto-waits for:
|
|
347
|
+
// - Element to be attached to DOM
|
|
348
|
+
// - Element to be visible
|
|
349
|
+
// - Element to be stable (no animations)
|
|
350
|
+
// - Element to be enabled
|
|
351
|
+
// - Element to receive events
|
|
352
|
+
await page.getByRole('button', { name: 'Submit' }).click(); // waits automatically
|
|
353
|
+
|
|
354
|
+
// Wait for navigation
|
|
355
|
+
await page.goto('/dashboard'); // waits for load event
|
|
356
|
+
|
|
357
|
+
// Wait for a specific condition
|
|
358
|
+
await page.waitForURL('/dashboard');
|
|
359
|
+
await page.waitForResponse(resp => resp.url().includes('/api/data') && resp.status() === 200);
|
|
360
|
+
|
|
361
|
+
// Wait for element state
|
|
362
|
+
await page.getByRole('dialog').waitFor({ state: 'hidden' });
|
|
363
|
+
|
|
364
|
+
// ANTI-PATTERN: Hard waits -- never use these
|
|
365
|
+
await page.waitForTimeout(3000); // BAD: arbitrary delay, flaky, slow
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## 6. Network Mocking
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
// Mock an API response
|
|
374
|
+
test('displays products from API', async ({ page }) => {
|
|
375
|
+
await page.route('**/api/products', async (route) => {
|
|
376
|
+
await route.fulfill({
|
|
377
|
+
status: 200,
|
|
378
|
+
contentType: 'application/json',
|
|
379
|
+
body: JSON.stringify([
|
|
380
|
+
{ id: '1', name: 'Widget', price: 29.99 },
|
|
381
|
+
{ id: '2', name: 'Gadget', price: 49.99 },
|
|
382
|
+
]),
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
await page.goto('/products');
|
|
387
|
+
await expect(page.getByText('Widget')).toBeVisible();
|
|
388
|
+
await expect(page.getByText('$29.99')).toBeVisible();
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
// Mock an error response
|
|
392
|
+
test('shows error state on API failure', async ({ page }) => {
|
|
393
|
+
await page.route('**/api/products', (route) =>
|
|
394
|
+
route.fulfill({ status: 500, body: JSON.stringify({ error: 'Internal error' }) })
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
await page.goto('/products');
|
|
398
|
+
await expect(page.getByText('Failed to load products')).toBeVisible();
|
|
399
|
+
await expect(page.getByRole('button', { name: 'Retry' })).toBeVisible();
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// Abort requests (e.g., block analytics)
|
|
403
|
+
test('page loads without analytics', async ({ page }) => {
|
|
404
|
+
await page.route('**/analytics/**', (route) => route.abort());
|
|
405
|
+
await page.goto('/dashboard');
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// Modify a real response
|
|
409
|
+
test('inject extra data into API response', async ({ page }) => {
|
|
410
|
+
await page.route('**/api/user', async (route) => {
|
|
411
|
+
const response = await route.fetch();
|
|
412
|
+
const json = await response.json();
|
|
413
|
+
json.featureFlags = { newDashboard: true };
|
|
414
|
+
await route.fulfill({ response, body: JSON.stringify(json) });
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
await page.goto('/dashboard');
|
|
418
|
+
});
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## 7. Authentication Setup
|
|
424
|
+
|
|
425
|
+
### Global Setup with Storage State
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
// tests/e2e/auth.setup.ts
|
|
429
|
+
import { test as setup, expect } from '@playwright/test';
|
|
430
|
+
|
|
431
|
+
const authFile = 'tests/e2e/.auth/user.json';
|
|
432
|
+
|
|
433
|
+
setup('authenticate', async ({ page }) => {
|
|
434
|
+
await page.goto('/login');
|
|
435
|
+
await page.getByLabel('Email').fill('e2e-user@example.com');
|
|
436
|
+
await page.getByLabel('Password').fill(process.env.E2E_PASSWORD!);
|
|
437
|
+
await page.getByRole('button', { name: 'Sign in' }).click();
|
|
438
|
+
|
|
439
|
+
// Wait for the redirect after login
|
|
440
|
+
await page.waitForURL('/dashboard');
|
|
441
|
+
|
|
442
|
+
// Save the authentication state (cookies, localStorage)
|
|
443
|
+
await page.context().storageState({ path: authFile });
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
// In playwright.config.ts:
|
|
447
|
+
// projects: [
|
|
448
|
+
// { name: 'setup', testMatch: /.*\.setup\.ts/ },
|
|
449
|
+
// {
|
|
450
|
+
// name: 'authenticated',
|
|
451
|
+
// use: { storageState: authFile },
|
|
452
|
+
// dependencies: ['setup'],
|
|
453
|
+
// },
|
|
454
|
+
// ]
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### Multiple Auth Roles
|
|
458
|
+
|
|
459
|
+
```typescript
|
|
460
|
+
// auth.setup.ts
|
|
461
|
+
import { test as setup } from '@playwright/test';
|
|
462
|
+
|
|
463
|
+
setup('auth as admin', async ({ page }) => {
|
|
464
|
+
await page.goto('/login');
|
|
465
|
+
await page.getByLabel('Email').fill('admin@example.com');
|
|
466
|
+
await page.getByLabel('Password').fill(process.env.ADMIN_PASSWORD!);
|
|
467
|
+
await page.getByRole('button', { name: 'Sign in' }).click();
|
|
468
|
+
await page.waitForURL('/admin');
|
|
469
|
+
await page.context().storageState({ path: 'tests/e2e/.auth/admin.json' });
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
setup('auth as user', async ({ page }) => {
|
|
473
|
+
await page.goto('/login');
|
|
474
|
+
await page.getByLabel('Email').fill('user@example.com');
|
|
475
|
+
await page.getByLabel('Password').fill(process.env.USER_PASSWORD!);
|
|
476
|
+
await page.getByRole('button', { name: 'Sign in' }).click();
|
|
477
|
+
await page.waitForURL('/dashboard');
|
|
478
|
+
await page.context().storageState({ path: 'tests/e2e/.auth/user.json' });
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
// In config: separate projects for admin vs user tests
|
|
482
|
+
// projects: [
|
|
483
|
+
// { name: 'admin tests', use: { storageState: 'tests/e2e/.auth/admin.json' }, dependencies: ['setup'] },
|
|
484
|
+
// { name: 'user tests', use: { storageState: 'tests/e2e/.auth/user.json' }, dependencies: ['setup'] },
|
|
485
|
+
// ]
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## 8. Visual Regression Testing
|
|
491
|
+
|
|
492
|
+
```typescript
|
|
493
|
+
test('homepage matches snapshot', async ({ page }) => {
|
|
494
|
+
await page.goto('/');
|
|
495
|
+
|
|
496
|
+
// Full page screenshot comparison
|
|
497
|
+
await expect(page).toHaveScreenshot('homepage.png', {
|
|
498
|
+
fullPage: true,
|
|
499
|
+
maxDiffPixelRatio: 0.01, // Allow 1% pixel difference
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
// Component-level screenshot
|
|
503
|
+
const hero = page.getByTestId('hero-section');
|
|
504
|
+
await expect(hero).toHaveScreenshot('hero-section.png');
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
// Update snapshots: npx playwright test --update-snapshots
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
**Best practices**:
|
|
511
|
+
- Mask dynamic content (timestamps, avatars) with `mask: [page.getByTestId('timestamp')]`
|
|
512
|
+
- Use `maxDiffPixelRatio` to handle anti-aliasing differences across OS
|
|
513
|
+
- Run visual tests on a single OS/browser in CI for consistency
|
|
514
|
+
- Store snapshots in version control
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
## 9. Debugging
|
|
519
|
+
|
|
520
|
+
### Trace Viewer
|
|
521
|
+
|
|
522
|
+
```bash
|
|
523
|
+
# Run with trace recording
|
|
524
|
+
npx playwright test --trace on
|
|
525
|
+
|
|
526
|
+
# View trace after test failure
|
|
527
|
+
npx playwright show-trace test-results/test-name/trace.zip
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### UI Mode (Interactive Debugging)
|
|
531
|
+
|
|
532
|
+
```bash
|
|
533
|
+
# Run in UI mode -- visual test runner with time travel
|
|
534
|
+
npx playwright test --ui
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### Debug Mode
|
|
538
|
+
|
|
539
|
+
```bash
|
|
540
|
+
# Run with browser visible and Playwright Inspector
|
|
541
|
+
npx playwright test --debug
|
|
542
|
+
|
|
543
|
+
# Debug a specific test
|
|
544
|
+
npx playwright test tests/e2e/login.spec.ts --debug
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### In-Test Debugging
|
|
548
|
+
|
|
549
|
+
```typescript
|
|
550
|
+
test('debug example', async ({ page }) => {
|
|
551
|
+
await page.goto('/dashboard');
|
|
552
|
+
|
|
553
|
+
// Pause execution and open inspector
|
|
554
|
+
await page.pause();
|
|
555
|
+
|
|
556
|
+
// Console output
|
|
557
|
+
page.on('console', (msg) => console.log(`BROWSER: ${msg.text()}`));
|
|
558
|
+
});
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
---
|
|
562
|
+
|
|
563
|
+
## 10. CI/CD Integration
|
|
564
|
+
|
|
565
|
+
### GitHub Actions
|
|
566
|
+
|
|
567
|
+
```yaml
|
|
568
|
+
# .github/workflows/e2e.yml
|
|
569
|
+
name: E2E Tests
|
|
570
|
+
on: [push, pull_request]
|
|
571
|
+
|
|
572
|
+
jobs:
|
|
573
|
+
e2e:
|
|
574
|
+
runs-on: ubuntu-latest
|
|
575
|
+
steps:
|
|
576
|
+
- uses: actions/checkout@v4
|
|
577
|
+
- uses: actions/setup-node@v4
|
|
578
|
+
with:
|
|
579
|
+
node-version: 20
|
|
580
|
+
- run: corepack enable pnpm && pnpm install
|
|
581
|
+
- run: pnpm exec playwright install --with-deps
|
|
582
|
+
- run: pnpm exec playwright test
|
|
583
|
+
- uses: actions/upload-artifact@v4
|
|
584
|
+
if: ${{ !cancelled() }}
|
|
585
|
+
with:
|
|
586
|
+
name: playwright-report
|
|
587
|
+
path: playwright-report/
|
|
588
|
+
retention-days: 14
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
### Parallel Execution and Sharding
|
|
592
|
+
|
|
593
|
+
```bash
|
|
594
|
+
# Shard tests across CI machines
|
|
595
|
+
# Machine 1:
|
|
596
|
+
npx playwright test --shard=1/4
|
|
597
|
+
# Machine 2:
|
|
598
|
+
npx playwright test --shard=2/4
|
|
599
|
+
# Machine 3:
|
|
600
|
+
npx playwright test --shard=3/4
|
|
601
|
+
# Machine 4:
|
|
602
|
+
npx playwright test --shard=4/4
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## 11. Common Anti-Patterns
|
|
608
|
+
|
|
609
|
+
| Anti-Pattern | Why It's Wrong | Correct Approach |
|
|
610
|
+
|-------------|---------------|-----------------|
|
|
611
|
+
| `page.waitForTimeout(3000)` | Arbitrary delay, flaky, slow | Use auto-waiting or `waitForURL`, `waitForResponse` |
|
|
612
|
+
| `page.locator('#root > div > div:nth-child(2) > button')` | Breaks on any DOM change | Use `getByRole`, `getByLabel`, `getByText` |
|
|
613
|
+
| Testing implementation details | Coupled to internal structure | Test user-visible behavior |
|
|
614
|
+
| Sharing state between tests | Order-dependent, flaky | Each test should set up its own state |
|
|
615
|
+
| Not cleaning up test data | Tests interfere with each other | Use API calls in `beforeEach`/`afterEach` to reset |
|
|
616
|
+
| Asserting too much in one test | Hard to debug failures | One logical assertion per test |
|
|
617
|
+
| Not using `expect` (just clicking and hoping) | Silent failures | Always assert expected outcomes |
|
|
618
|
+
| Mocking everything | Not testing real integration | Mock external services only, test your own stack |
|
|
619
|
+
|
|
620
|
+
---
|
|
621
|
+
|
|
622
|
+
## 12. Critical Reminders
|
|
623
|
+
|
|
624
|
+
### ALWAYS
|
|
625
|
+
|
|
626
|
+
- Use semantic locators (`getByRole`, `getByLabel`, `getByText`) as first choice
|
|
627
|
+
- Let Playwright auto-wait instead of adding explicit waits
|
|
628
|
+
- Use `storageState` for authentication (login once, reuse across tests)
|
|
629
|
+
- Run tests in CI on every PR
|
|
630
|
+
- Save traces, screenshots, and videos on failure
|
|
631
|
+
- Use `test.describe` to group related tests
|
|
632
|
+
- Add `--forbid-only` in CI to prevent `test.only` from being committed
|
|
633
|
+
|
|
634
|
+
### NEVER
|
|
635
|
+
|
|
636
|
+
- Use `page.waitForTimeout()` (hard waits cause flakiness)
|
|
637
|
+
- Use CSS class selectors as primary locators (they change with styling)
|
|
638
|
+
- Share mutable state between test files
|
|
639
|
+
- Skip error state testing (always test what happens when things fail)
|
|
640
|
+
- Run visual regression tests across different operating systems without masking
|
|
641
|
+
- Commit `.auth/` storage state files (add to `.gitignore`)
|