@etus/bhono-app 0.1.1
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/dist/cli.d.ts +13 -0
- package/dist/cli.js +46 -0
- package/dist/cli.js.map +1 -0
- package/dist/cli.test.d.ts +1 -0
- package/dist/cli.test.js +26 -0
- package/dist/cli.test.js.map +1 -0
- package/dist/generator.d.ts +14 -0
- package/dist/generator.js +142 -0
- package/dist/generator.js.map +1 -0
- package/dist/generator.test.d.ts +1 -0
- package/dist/generator.test.js +127 -0
- package/dist/generator.test.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +97 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts.d.ts +25 -0
- package/dist/prompts.js +83 -0
- package/dist/prompts.js.map +1 -0
- package/dist/prompts.test.d.ts +1 -0
- package/dist/prompts.test.js +24 -0
- package/dist/prompts.test.js.map +1 -0
- package/dist/providers/cloudflare.d.ts +37 -0
- package/dist/providers/cloudflare.js +61 -0
- package/dist/providers/cloudflare.js.map +1 -0
- package/dist/providers/cloudflare.test.d.ts +1 -0
- package/dist/providers/cloudflare.test.js +29 -0
- package/dist/providers/cloudflare.test.js.map +1 -0
- package/dist/providers/github.d.ts +16 -0
- package/dist/providers/github.js +57 -0
- package/dist/providers/github.js.map +1 -0
- package/dist/providers/github.test.d.ts +1 -0
- package/dist/providers/github.test.js +16 -0
- package/dist/providers/github.test.js.map +1 -0
- package/dist/templates.d.ts +8 -0
- package/dist/templates.js +88 -0
- package/dist/templates.js.map +1 -0
- package/dist/templates.test.d.ts +1 -0
- package/dist/templates.test.js +26 -0
- package/dist/templates.test.js.map +1 -0
- package/package.json +36 -0
- package/templates/base/.claude/agents/architect-review.md +160 -0
- package/templates/base/.claude/agents/backend-architect.md +308 -0
- package/templates/base/.claude/agents/code-reviewer.md +170 -0
- package/templates/base/.claude/agents/performance-engineer.md +166 -0
- package/templates/base/.claude/agents/test-automator.md +219 -0
- package/templates/base/.claude/commands/check-skill-rules.md +53 -0
- package/templates/base/.claude/commands/claude-md.md +250 -0
- package/templates/base/.claude/commands/code-prompt.md +212 -0
- package/templates/base/.claude/commands/explain-code.md +194 -0
- package/templates/base/.claude/commands/init-projec.md +89 -0
- package/templates/base/.claude/commands/linear/README.md +297 -0
- package/templates/base/.claude/commands/linear/create-issue.md +190 -0
- package/templates/base/.claude/commands/linear/implement-issue.md +248 -0
- package/templates/base/.claude/commands/linear/process-triage.md +399 -0
- package/templates/base/.claude/commands/linear/setup.md +180 -0
- package/templates/base/.claude/commands/prime.md +9 -0
- package/templates/base/.claude/commands/review-gap.md +10 -0
- package/templates/base/.claude/commands/setup-aa.md +311 -0
- package/templates/base/.claude/commands/ship.md +262 -0
- package/templates/base/.claude/commands/tools.md +3 -0
- package/templates/base/.claude/docs/claude-progress.txt +107 -0
- package/templates/base/.claude/hooks/package-lock.json +556 -0
- package/templates/base/.claude/hooks/package.json +16 -0
- package/templates/base/.claude/hooks/skill-activation-prompt.sh +7 -0
- package/templates/base/.claude/hooks/skill-activation-prompt.ts +142 -0
- package/templates/base/.claude/hooks/tsconfig.json +19 -0
- package/templates/base/.claude/scripts/check-updates.sh +85 -0
- package/templates/base/.claude/scripts/install_pkgs.sh +66 -0
- package/templates/base/.claude/scripts/setup-project.sh +177 -0
- package/templates/base/.claude/scripts/validate-skill-rules.sh +94 -0
- package/templates/base/.claude/settings.json +113 -0
- package/templates/base/.claude/settings.local.json +11 -0
- package/templates/base/.claude/skills/architecture-analyzer/SKILL.md +531 -0
- package/templates/base/.claude/skills/architecture-analyzer/assets/report-template.md +215 -0
- package/templates/base/.claude/skills/architecture-analyzer/references/c4-templates.md +234 -0
- package/templates/base/.claude/skills/architecture-analyzer/references/confidence-levels.md +203 -0
- package/templates/base/.claude/skills/architecture-analyzer/scripts/analyze_structure.py +266 -0
- package/templates/base/.claude/skills/architecture-analyzer/scripts/analyze_tech_debt.py +776 -0
- package/templates/base/.claude/skills/architecture-analyzer/scripts/extract_apis.py +338 -0
- package/templates/base/.claude/skills/architecture-analyzer/scripts/generate_c4.py +283 -0
- package/templates/base/.claude/skills/architecture-analyzer/scripts/generate_erd.py +935 -0
- package/templates/base/.claude/skills/architecture-analyzer/scripts/map_dependencies.py +555 -0
- package/templates/base/.claude/skills/dev-browser/SKILL.md +318 -0
- package/templates/base/.claude/skills/dev-browser/bun.lock +443 -0
- package/templates/base/.claude/skills/dev-browser/package-lock.json +2927 -0
- package/templates/base/.claude/skills/dev-browser/package.json +27 -0
- package/templates/base/.claude/skills/dev-browser/scripts/start-server.ts +117 -0
- package/templates/base/.claude/skills/dev-browser/server.sh +24 -0
- package/templates/base/.claude/skills/dev-browser/src/client.ts +403 -0
- package/templates/base/.claude/skills/dev-browser/src/index.ts +281 -0
- package/templates/base/.claude/skills/dev-browser/src/snapshot/__tests__/snapshot.test.ts +223 -0
- package/templates/base/.claude/skills/dev-browser/src/snapshot/browser-script.ts +877 -0
- package/templates/base/.claude/skills/dev-browser/src/snapshot/index.ts +14 -0
- package/templates/base/.claude/skills/dev-browser/src/snapshot/inject.ts +13 -0
- package/templates/base/.claude/skills/dev-browser/src/types.ts +27 -0
- package/templates/base/.claude/skills/dev-browser/tsconfig.json +36 -0
- package/templates/base/.claude/skills/dev-browser/vitest.config.ts +12 -0
- package/templates/base/.claude/skills/linear/SKILL.md +440 -0
- package/templates/base/.claude/skills/linear/examples.md +262 -0
- package/templates/base/.claude/skills/linear/lib/client.ts +51 -0
- package/templates/base/.claude/skills/linear/lib/config.ts +106 -0
- package/templates/base/.claude/skills/linear/lib/output.ts +34 -0
- package/templates/base/.claude/skills/linear/package-lock.json +698 -0
- package/templates/base/.claude/skills/linear/package.json +27 -0
- package/templates/base/.claude/skills/linear/reference.md +263 -0
- package/templates/base/.claude/skills/linear/scripts/comments/create.ts +47 -0
- package/templates/base/.claude/skills/linear/scripts/comments/list.ts +47 -0
- package/templates/base/.claude/skills/linear/scripts/issues/archive.ts +30 -0
- package/templates/base/.claude/skills/linear/scripts/issues/create.ts +279 -0
- package/templates/base/.claude/skills/linear/scripts/issues/get.ts +68 -0
- package/templates/base/.claude/skills/linear/scripts/issues/list.ts +67 -0
- package/templates/base/.claude/skills/linear/scripts/issues/update.ts +281 -0
- package/templates/base/.claude/skills/linear/scripts/labels/add-to-issue.ts +63 -0
- package/templates/base/.claude/skills/linear/scripts/labels/create.ts +45 -0
- package/templates/base/.claude/skills/linear/scripts/labels/list.ts +30 -0
- package/templates/base/.claude/skills/linear/scripts/list-teams.ts +52 -0
- package/templates/base/.claude/skills/linear/scripts/setup/setup-credentials.ts +96 -0
- package/templates/base/.claude/skills/linear/scripts/status/list.ts +31 -0
- package/templates/base/.claude/skills/linear/scripts/status/set-by-name.ts +78 -0
- package/templates/base/.claude/skills/linear/scripts/status/update.ts +44 -0
- package/templates/base/.claude/skills/linear/scripts/users/list.ts +59 -0
- package/templates/base/.claude/skills/linear/scripts/users/me.ts +20 -0
- package/templates/base/.claude/skills/linear/templates/README.md +203 -0
- package/templates/base/.claude/skills/linear/templates/api-reference.md +258 -0
- package/templates/base/.claude/skills/linear/templates/bug-report.md +99 -0
- package/templates/base/.claude/skills/linear/templates/feature-request.md +118 -0
- package/templates/base/.claude/skills/linear/templates/security-issue.md +162 -0
- package/templates/base/.claude/skills/linear/templates/sprint-task.md +175 -0
- package/templates/base/.claude/skills/linear/templates/tech-debt.md +137 -0
- package/templates/base/.claude/skills/linear/tsconfig.json +17 -0
- package/templates/base/.claude/skills/linear/workflows/issue-lifecycle.md +317 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/SKILL.md +113 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/assets/global-setup.template.js +97 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/assets/playwright.config.template.js +171 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/assets/test-template.spec.js +163 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/examples/README.md +26 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/examples/ads.email-deeplink.spec.ts +12 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/examples/mobile.realism.spec.ts +16 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/examples/smoke.home.spec.ts +6 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/references/architecture.md +578 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/references/best-practices.md +260 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/references/ci-reporting.md +86 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/references/debugging.md +629 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/references/mobile-realism.md +50 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/references/optimization.md +488 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/references/patterns.md +513 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/references/resources.md +44 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/references/visual-a11y.md +66 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/scripts/auth-setup.js +202 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/scripts/performance-analyzer.js +240 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/scripts/trace-url.js +132 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/templates/ci/github-actions.playwright.yml +78 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/templates/fixtures.ts +44 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/templates/global-setup.template.js +97 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/templates/global.setup.ts +35 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/templates/helpers/ad-gpt-observer.ts +80 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/templates/helpers/chromium-mobile-profile.ts +93 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/templates/playwright.config.template.js +171 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/templates/playwright.config.ts +126 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/templates/test-template.spec.js +163 -0
- package/templates/base/.claude/skills/playwright-e2e-testing/templates/tests/email-deeplink.ads.spec.ts +44 -0
- package/templates/base/.claude/skills/skill-rules.json +184 -0
- package/templates/base/.claude/skills/wrangler/SKILL.md +209 -0
- package/templates/base/.claude/skills/wrangler/resources/api.md +494 -0
- package/templates/base/.claude/skills/wrangler/resources/bundling.md +83 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/cert.md +64 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/check.md +66 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/containers.md +157 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/d1.md +843 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/delete.md +27 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/deploy.md +139 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/deployments.md +56 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/dev.md +157 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/dispatch-namespace.md +69 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/docs.md +61 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/how-to-run.md +62 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/hyperdrive.md +425 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/init.md +31 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/kv-bulk.md +265 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/kv-key.md +353 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/kv-namespace.md +265 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/login.md +23 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/logout.md +19 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/mtls-certificate.md +69 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/pages.md +175 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/pipelines.md +76 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/queues.md +132 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/r2-bucket.md +342 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/r2-object.md +267 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/r2-sql.md +65 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/rollback.md +40 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/secret.md +308 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/secrets-store-secret.md +100 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/secrets-store-store.md +60 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/setup.md +67 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/tail.md +37 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/telemetry.md +64 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/triggers.md +39 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/types.md +73 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/vectorize.md +941 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/versions.md +95 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/whoami.md +49 -0
- package/templates/base/.claude/skills/wrangler/resources/commands/workflows.md +117 -0
- package/templates/base/.claude/skills/wrangler/resources/commands.md +138 -0
- package/templates/base/.claude/skills/wrangler/resources/configuration.md +2176 -0
- package/templates/base/.claude/skills/wrangler/resources/custom-builds.md +55 -0
- package/templates/base/.claude/skills/wrangler/resources/deprecations.md +279 -0
- package/templates/base/.claude/skills/wrangler/resources/enviroments.md +416 -0
- package/templates/base/.claude/skills/wrangler/resources/extract_sections.py +119 -0
- package/templates/base/.claude/skills/wrangler/resources/process_content.py +94 -0
- package/templates/base/.claude/skills/wrangler/resources/system-enviroments-variables.md +120 -0
- package/templates/base/.dev.vars.example +15 -0
- package/templates/base/.env.example +29 -0
- package/templates/base/.github/workflows/test.yml +127 -0
- package/templates/base/.nycrc.json +16 -0
- package/templates/base/CLAUDE.md +218 -0
- package/templates/base/README.md +670 -0
- package/templates/base/auth-setup-error.png +0 -0
- package/templates/base/config/drizzle.config.ts +10 -0
- package/templates/base/config/eslint.config.js +364 -0
- package/templates/base/config/wrangler.json +76 -0
- package/templates/base/docs/app_spec.txt +879 -0
- package/templates/base/docs/app_spec_template.md +681 -0
- package/templates/base/docs/architecture/README.md +8 -0
- package/templates/base/docs/architecture/data-requirements.md +109 -0
- package/templates/base/docs/architecture/erd.md +91 -0
- package/templates/base/docs/features/feature_list.json +3128 -0
- package/templates/base/docs/hono-boilerplate-plan.md +1774 -0
- package/templates/base/docs/test-coverage-gap-analysis.md +242 -0
- package/templates/base/docs/testing.md +188 -0
- package/templates/base/index.html +16 -0
- package/templates/base/package.json +115 -0
- package/templates/base/playwright.config.ts +158 -0
- package/templates/base/pnpm-lock.yaml +8175 -0
- package/templates/base/scripts/capture-prod-session.ts +250 -0
- package/templates/base/scripts/generate-openapi.ts +23 -0
- package/templates/base/scripts/init.sh +121 -0
- package/templates/base/src/client/__tests__/button.test.tsx +30 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-dashboard-stats-cards-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-quick-action-cards-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-recent-activity-section-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-user-first-name-in-welcome-message-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-user-information-in-sidebar-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-render-dashboard-when-authenticated-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-show-navigation-sidebar-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-unauthenticated-should-redirect-to-login-when-not-authenticated-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/login.test.tsx/Login-Page-should-display-Google-OAuth-login-button-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/login.test.tsx/Login-Page-should-have-a-link-back-to-home-page-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/login.test.tsx/Login-Page-should-render-login-content-without-waiting-for-authentication-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/login.test.tsx/Login-Page-should-render-login-page-at--login-route-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/login.test.tsx/Login-Page-should-show-Terms-of-Service-and-Privacy-Policy-links-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/login.test.tsx/Login-Page-should-trigger-OAuth-flow-when-clicking-login-button-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-404-handling-should-display-404-text-on-not-found-page-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-404-handling-should-have-navigation-options-on-404-page-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-404-handling-should-render-404-page-for-unknown-routes-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-account-page-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-integrations-page-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-settings-page-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-team-page-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-home-page-navigation-should-display-navigation-links-on-home-page-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-home-page-navigation-should-have-correct-link-destinations-on-home-page-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-allow-access-to-home-page-without-authentication-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-allow-access-to-login-page-without-authentication-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-redirect-unauthenticated-users-from-dashboard-to-login-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-redirect-unauthenticated-users-from-settings-to-login-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-redirect-unauthenticated-users-from-team-to-login-1.png +0 -0
- package/templates/base/src/client/__tests__/routes/authenticated-layout.test.tsx +252 -0
- package/templates/base/src/client/__tests__/routes/dashboard.test.tsx +136 -0
- package/templates/base/src/client/__tests__/routes/error-components.test.tsx +186 -0
- package/templates/base/src/client/__tests__/routes/login.test.tsx +112 -0
- package/templates/base/src/client/__tests__/routes/navigation.test.tsx +272 -0
- package/templates/base/src/client/__tests__/routes/root-layout.test.tsx +65 -0
- package/templates/base/src/client/__tests__/setup-browser.ts +15 -0
- package/templates/base/src/client/__tests__/setup.ts +32 -0
- package/templates/base/src/client/__tests__/test-utils.tsx +135 -0
- package/templates/base/src/client/api/.gitkeep +0 -0
- package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-can-be-collapsed-by-default-1.png +0 -0
- package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-expands-when-collapsed-and-expand-button-is-clicked-1.png +0 -0
- package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-handles-logout-button-click-1.png +0 -0
- package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-handles-navigation-clicks-1.png +0 -0
- package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-hides-navigation-labels-when-collapsed-1.png +0 -0
- package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-highlights-active-route-1.png +0 -0
- package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-renders-sidebar-navigation-items-1.png +0 -0
- package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-shows-keyboard-shortcut-hint-when-expanded-1.png +0 -0
- package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-shows-user-info-when-authenticated-1.png +0 -0
- package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-shows-user-initials-in-avatar-fallback-1.png +0 -0
- package/templates/base/src/client/components/__tests__/error-boundary.test.tsx +97 -0
- package/templates/base/src/client/components/__tests__/sidebar.test.tsx +281 -0
- package/templates/base/src/client/components/error-boundary.tsx +68 -0
- package/templates/base/src/client/components/icons.tsx +106 -0
- package/templates/base/src/client/components/layout/.gitkeep +0 -0
- package/templates/base/src/client/components/sidebar.tsx +267 -0
- package/templates/base/src/client/components/ui/.gitkeep +0 -0
- package/templates/base/src/client/components/ui/__tests__/avatar.test.tsx +308 -0
- package/templates/base/src/client/components/ui/__tests__/card.test.tsx +214 -0
- package/templates/base/src/client/components/ui/__tests__/dialog.test.tsx +297 -0
- package/templates/base/src/client/components/ui/__tests__/error-fallback.test.tsx +145 -0
- package/templates/base/src/client/components/ui/__tests__/input.test.tsx +98 -0
- package/templates/base/src/client/components/ui/__tests__/loading-skeleton.test.tsx +139 -0
- package/templates/base/src/client/components/ui/__tests__/skeleton.test.tsx +44 -0
- package/templates/base/src/client/components/ui/__tests__/sonner.test.tsx +28 -0
- package/templates/base/src/client/components/ui/__tests__/tabs.test.tsx +233 -0
- package/templates/base/src/client/components/ui/avatar.tsx +101 -0
- package/templates/base/src/client/components/ui/badge.tsx +46 -0
- package/templates/base/src/client/components/ui/button.tsx +72 -0
- package/templates/base/src/client/components/ui/card.tsx +86 -0
- package/templates/base/src/client/components/ui/dialog.tsx +140 -0
- package/templates/base/src/client/components/ui/error-fallback.tsx +179 -0
- package/templates/base/src/client/components/ui/form.tsx +172 -0
- package/templates/base/src/client/components/ui/input.tsx +24 -0
- package/templates/base/src/client/components/ui/label.tsx +22 -0
- package/templates/base/src/client/components/ui/loading-skeleton.tsx +154 -0
- package/templates/base/src/client/components/ui/separator.tsx +33 -0
- package/templates/base/src/client/components/ui/skeleton.tsx +16 -0
- package/templates/base/src/client/components/ui/sonner.tsx +29 -0
- package/templates/base/src/client/components/ui/tabs.tsx +121 -0
- package/templates/base/src/client/hooks/.gitkeep +0 -0
- package/templates/base/src/client/hooks/__tests__/use-auth.test.tsx +306 -0
- package/templates/base/src/client/hooks/__tests__/use-theme.test.tsx +172 -0
- package/templates/base/src/client/hooks/use-auth.ts +53 -0
- package/templates/base/src/client/hooks/use-theme.tsx +78 -0
- package/templates/base/src/client/index.css +881 -0
- package/templates/base/src/client/lib/query-client.ts +11 -0
- package/templates/base/src/client/lib/utils.ts +7 -0
- package/templates/base/src/client/main.tsx +26 -0
- package/templates/base/src/client/routeTree.gen.ts +258 -0
- package/templates/base/src/client/router.ts +15 -0
- package/templates/base/src/client/routes/$.tsx +77 -0
- package/templates/base/src/client/routes/.gitkeep +0 -0
- package/templates/base/src/client/routes/__root.tsx +34 -0
- package/templates/base/src/client/routes/__tests__/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-display-accept-invitation-button-1.png +0 -0
- package/templates/base/src/client/routes/__tests__/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-display-decline-button-linking-to-homepage-1.png +0 -0
- package/templates/base/src/client/routes/__tests__/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-display-invitation-details--email--workspace--role--1.png +0 -0
- package/templates/base/src/client/routes/__tests__/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-have-a-logo-link-to-homepage-1.png +0 -0
- package/templates/base/src/client/routes/__tests__/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-render-invitation-page-with-inviter-name-and-workspace-1.png +0 -0
- package/templates/base/src/client/routes/__tests__/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-show-terms-of-service-and-privacy-policy-links-1.png +0 -0
- package/templates/base/src/client/routes/__tests__/invite.test.tsx +138 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/account.test.tsx/Account-Page-should-render-Active-Sessions-section-with-session-cards-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/account.test.tsx/Account-Page-should-render-page-with-correct-title--Account--1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/account.test.tsx/Account-Page-should-show-API-Access-section-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/account.test.tsx/Account-Page-should-show-Connected-Accounts-section-with-Google-connected-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/account.test.tsx/Account-Page-should-show-Danger-Zone-section-with-delete-button-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/account.test.tsx/Account-Page-should-show-Security-section-with-Two-Factor-Authentication-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-API-documentation-section-should-display-API-documentation-link-section-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-Create-Webhook-Dialog-should-have-Add-Webhook-trigger-button-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-category-filters-should-display-all-category-buttons-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-display-all-integration-cards-with-names-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-display-category-badges-on-cards-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-show-Configure-button-for-connected-integrations-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-show-Connect-button-for-not-connected-integrations-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-show-Connected-badge-for-connected-integrations-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-Available-Integrations-section-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-Webhooks-section-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-connected-count-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-page-description-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-search-input-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-render-with-correct-title--Integrations--1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-search-functionality-should-filter-integrations-based-on-search-query-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-search-functionality-should-search-by-description-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-search-functionality-should-show-no-results-message-when-search-has-no-matches-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-existing-webhook-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-webhook-events-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-webhook-last-delivery-info-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-webhook-success-status-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-have-Add-Webhook-button-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Account-tab-should-display-connected-accounts-section-with-Google-provider-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Account-tab-should-display-sessions-and-danger-zone-sections-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-display-all-notification-toggle-options-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-display-email-notifications-section-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-display-toggle-switches-for-notification-options-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-have-toggles-checked-by-default-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display--Save-Changes--button-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-personal-information-form-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-profile-picture-section-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-user-email-in-disabled-email-input-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-user-initials-in-avatar-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-user-name-in-the-name-input-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-page-rendering-should-display-all-three-tabs-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-page-rendering-should-display-page-description-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-page-rendering-should-render-with-correct-title--Settings--1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-tab-navigation-should-show-Profile-tab-as-default-active-tab-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-tab-navigation-should-switch-to-Account-tab-when-clicked-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-tab-navigation-should-switch-to-Notifications-tab-when-clicked-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/team.test.tsx/Team-Page-should-display-Active-Members-section-with-member-count-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/team.test.tsx/Team-Page-should-display-Pending-Invitations-section-with-invitation-details-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/team.test.tsx/Team-Page-should-have-invite-member-button-that-can-be-clicked-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/team.test.tsx/Team-Page-should-render-page-with-correct-title-and-description-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/team.test.tsx/Team-Page-should-render-search-input-that-filters-team-members-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/team.test.tsx/Team-Page-should-show-current-user-with---you---indicator-and-role-badge-1.png +0 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/account.test.tsx +324 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/integrations.test.tsx +520 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/settings.test.tsx +414 -0
- package/templates/base/src/client/routes/_authenticated/__tests__/team.test.tsx +374 -0
- package/templates/base/src/client/routes/_authenticated/account.tsx +416 -0
- package/templates/base/src/client/routes/_authenticated/dashboard.tsx +151 -0
- package/templates/base/src/client/routes/_authenticated/integrations.tsx +553 -0
- package/templates/base/src/client/routes/_authenticated/settings.tsx +310 -0
- package/templates/base/src/client/routes/_authenticated/team.tsx +395 -0
- package/templates/base/src/client/routes/_authenticated.tsx +69 -0
- package/templates/base/src/client/routes/index.tsx +155 -0
- package/templates/base/src/client/routes/invite.$token.tsx +191 -0
- package/templates/base/src/client/routes/login.tsx +92 -0
- package/templates/base/src/server/__tests__/fixtures.ts +461 -0
- package/templates/base/src/server/__tests__/mocks/__tests__/db.test.ts +239 -0
- package/templates/base/src/server/__tests__/mocks/__tests__/kv.test.ts +293 -0
- package/templates/base/src/server/__tests__/mocks/__tests__/r2.test.ts +363 -0
- package/templates/base/src/server/__tests__/mocks/db.ts +186 -0
- package/templates/base/src/server/__tests__/mocks/index.ts +33 -0
- package/templates/base/src/server/__tests__/mocks/kv.ts +286 -0
- package/templates/base/src/server/__tests__/mocks/r2.ts +397 -0
- package/templates/base/src/server/__tests__/setup.ts +281 -0
- package/templates/base/src/server/auth/__tests__/guards.test.ts +162 -0
- package/templates/base/src/server/auth/guards.ts +92 -0
- package/templates/base/src/server/auth/permissions.test.ts +45 -0
- package/templates/base/src/server/auth/permissions.ts +139 -0
- package/templates/base/src/server/auth/roles.test.ts +169 -0
- package/templates/base/src/server/auth/roles.ts +141 -0
- package/templates/base/src/server/db/client.ts +12 -0
- package/templates/base/src/server/db/schema/accounts.ts +20 -0
- package/templates/base/src/server/db/schema/audit-logs.ts +26 -0
- package/templates/base/src/server/db/schema/index.ts +7 -0
- package/templates/base/src/server/db/schema/invitations.ts +30 -0
- package/templates/base/src/server/db/schema/refresh-tokens.ts +22 -0
- package/templates/base/src/server/db/schema/user-accounts.ts +25 -0
- package/templates/base/src/server/db/schema/users.ts +33 -0
- package/templates/base/src/server/db/seed.ts +267 -0
- package/templates/base/src/server/env.test.ts +84 -0
- package/templates/base/src/server/env.ts +78 -0
- package/templates/base/src/server/index.ts +82 -0
- package/templates/base/src/server/lib/audit.ts +73 -0
- package/templates/base/src/server/lib/audited-db.test.ts +107 -0
- package/templates/base/src/server/lib/audited-db.ts +154 -0
- package/templates/base/src/server/lib/email.test.ts +116 -0
- package/templates/base/src/server/lib/email.ts +82 -0
- package/templates/base/src/server/lib/errors.test.ts +49 -0
- package/templates/base/src/server/lib/errors.ts +64 -0
- package/templates/base/src/server/lib/oauth.test.ts +238 -0
- package/templates/base/src/server/lib/oauth.ts +113 -0
- package/templates/base/src/server/lib/pagination.test.ts +52 -0
- package/templates/base/src/server/lib/pagination.ts +32 -0
- package/templates/base/src/server/lib/password.test.ts +151 -0
- package/templates/base/src/server/lib/password.ts +151 -0
- package/templates/base/src/server/lib/providers.test.ts +105 -0
- package/templates/base/src/server/lib/providers.ts +62 -0
- package/templates/base/src/server/lib/r2-storage.test.ts +202 -0
- package/templates/base/src/server/lib/r2-storage.ts +107 -0
- package/templates/base/src/server/lib/schema-helpers.ts +16 -0
- package/templates/base/src/server/lib/session.test.ts +758 -0
- package/templates/base/src/server/lib/session.ts +267 -0
- package/templates/base/src/server/lib/tokens.test.ts +208 -0
- package/templates/base/src/server/lib/tokens.ts +65 -0
- package/templates/base/src/server/lib/transaction.test.ts +45 -0
- package/templates/base/src/server/lib/transaction.ts +24 -0
- package/templates/base/src/server/middleware/account.test.ts +201 -0
- package/templates/base/src/server/middleware/account.ts +66 -0
- package/templates/base/src/server/middleware/auth.test.ts +345 -0
- package/templates/base/src/server/middleware/auth.ts +146 -0
- package/templates/base/src/server/middleware/cors.test.ts +88 -0
- package/templates/base/src/server/middleware/cors.ts +26 -0
- package/templates/base/src/server/middleware/error-handler.test.ts +69 -0
- package/templates/base/src/server/middleware/error-handler.ts +43 -0
- package/templates/base/src/server/middleware/index.ts +8 -0
- package/templates/base/src/server/middleware/rate-limit.test.ts +472 -0
- package/templates/base/src/server/middleware/rate-limit.ts +294 -0
- package/templates/base/src/server/middleware/request-context.test.ts +175 -0
- package/templates/base/src/server/middleware/request-context.ts +28 -0
- package/templates/base/src/server/middleware/request-logger.test.ts +92 -0
- package/templates/base/src/server/middleware/request-logger.ts +50 -0
- package/templates/base/src/server/routes/accounts/__tests__/handlers.test.ts +460 -0
- package/templates/base/src/server/routes/accounts/handlers.ts +179 -0
- package/templates/base/src/server/routes/accounts/index.ts +55 -0
- package/templates/base/src/server/routes/accounts/routes.ts +205 -0
- package/templates/base/src/server/routes/accounts/schemas.ts +31 -0
- package/templates/base/src/server/routes/api.ts +37 -0
- package/templates/base/src/server/routes/audits/__tests__/handlers.test.ts +349 -0
- package/templates/base/src/server/routes/audits/handlers.ts +37 -0
- package/templates/base/src/server/routes/audits/index.ts +14 -0
- package/templates/base/src/server/routes/audits/routes.ts +29 -0
- package/templates/base/src/server/routes/audits/schemas.ts +43 -0
- package/templates/base/src/server/routes/auth/__tests__/handlers.test.ts +381 -0
- package/templates/base/src/server/routes/auth/handlers.ts +222 -0
- package/templates/base/src/server/routes/auth/index.ts +37 -0
- package/templates/base/src/server/routes/auth/routes.ts +136 -0
- package/templates/base/src/server/routes/auth/schemas.ts +48 -0
- package/templates/base/src/server/routes/auth/test-login.ts +156 -0
- package/templates/base/src/server/routes/health/__tests__/handlers.test.ts +237 -0
- package/templates/base/src/server/routes/health/handlers.ts +83 -0
- package/templates/base/src/server/routes/health/index.ts +13 -0
- package/templates/base/src/server/routes/health/routes.ts +90 -0
- package/templates/base/src/server/routes/index.ts +53 -0
- package/templates/base/src/server/routes/invitations/__tests__/handlers.test.ts +473 -0
- package/templates/base/src/server/routes/invitations/handlers.ts +71 -0
- package/templates/base/src/server/routes/invitations/index.ts +25 -0
- package/templates/base/src/server/routes/invitations/routes.ts +69 -0
- package/templates/base/src/server/routes/invitations/schemas.ts +39 -0
- package/templates/base/src/server/routes/openapi.ts +14 -0
- package/templates/base/src/server/routes/schemas.ts +53 -0
- package/templates/base/src/server/routes/storage/__tests__/handlers.test.ts +408 -0
- package/templates/base/src/server/routes/storage/handlers.ts +100 -0
- package/templates/base/src/server/routes/storage/index.ts +42 -0
- package/templates/base/src/server/routes/storage/routes.ts +91 -0
- package/templates/base/src/server/routes/storage/schemas.ts +56 -0
- package/templates/base/src/server/routes/users/__tests__/handlers.test.ts +526 -0
- package/templates/base/src/server/routes/users/handlers.ts +228 -0
- package/templates/base/src/server/routes/users/index.ts +67 -0
- package/templates/base/src/server/routes/users/routes.ts +265 -0
- package/templates/base/src/server/routes/users/schemas.ts +67 -0
- package/templates/base/src/server/services/__tests__/accounts.test.ts +764 -0
- package/templates/base/src/server/services/__tests__/audits.test.ts +235 -0
- package/templates/base/src/server/services/__tests__/auth.test.ts +765 -0
- package/templates/base/src/server/services/__tests__/invitations.test.ts +704 -0
- package/templates/base/src/server/services/__tests__/users.test.ts +755 -0
- package/templates/base/src/server/services/accounts.ts +269 -0
- package/templates/base/src/server/services/audits.ts +82 -0
- package/templates/base/src/server/services/auth.ts +225 -0
- package/templates/base/src/server/services/index.ts +6 -0
- package/templates/base/src/server/services/invitations.ts +306 -0
- package/templates/base/src/server/services/users.ts +350 -0
- package/templates/base/src/server/types/auth.ts +36 -0
- package/templates/base/src/server/types/index.ts +117 -0
- package/templates/base/src/shared/schemas/.gitkeep +0 -0
- package/templates/base/src/shared/schemas/__tests__/schemas.test.ts +547 -0
- package/templates/base/src/shared/schemas/account.ts +15 -0
- package/templates/base/src/shared/schemas/index.ts +6 -0
- package/templates/base/src/shared/schemas/invitation.ts +9 -0
- package/templates/base/src/shared/schemas/profile.ts +10 -0
- package/templates/base/src/shared/schemas/user.ts +16 -0
- package/templates/base/src/shared/schemas/webhook.ts +12 -0
- package/templates/base/src/shared/types/.gitkeep +0 -0
- package/templates/base/src/shared/types/account.ts +12 -0
- package/templates/base/src/shared/types/api.ts +1399 -0
- package/templates/base/src/shared/types/auth.ts +24 -0
- package/templates/base/src/shared/types/index.ts +5 -0
- package/templates/base/src/shared/types/user.ts +31 -0
- package/templates/base/src/test/vitest-zod-matcher.ts +37 -0
- package/templates/base/src/test/vitest.d.ts +19 -0
- package/templates/base/tests/e2e/README.md +141 -0
- package/templates/base/tests/e2e/a11y/accessibility.spec.ts +925 -0
- package/templates/base/tests/e2e/a11y/keyboard-navigation.spec.ts +610 -0
- package/templates/base/tests/e2e/api/accounts.spec.ts +148 -0
- package/templates/base/tests/e2e/api/audit-logs.spec.ts +130 -0
- package/templates/base/tests/e2e/api/authenticated-api.spec.ts +311 -0
- package/templates/base/tests/e2e/api/storage.spec.ts +109 -0
- package/templates/base/tests/e2e/auth-flows.unauth.spec.ts +117 -0
- package/templates/base/tests/e2e/auth-logout.unauth.spec.ts +103 -0
- package/templates/base/tests/e2e/auth.setup.ts +115 -0
- package/templates/base/tests/e2e/auth.spec.ts +146 -0
- package/templates/base/tests/e2e/compatibility/cross-browser.spec.ts +152 -0
- package/templates/base/tests/e2e/compatibility/cross-browser.spec.ts-snapshots/login-chromium-chromium-darwin.png +0 -0
- package/templates/base/tests/e2e/crud/account.spec.ts +356 -0
- package/templates/base/tests/e2e/crud/integrations.spec.ts +419 -0
- package/templates/base/tests/e2e/crud/team.spec.ts +287 -0
- package/templates/base/tests/e2e/crud/users.spec.ts +239 -0
- package/templates/base/tests/e2e/errors/error-boundary.spec.ts +428 -0
- package/templates/base/tests/e2e/errors/error-handling.spec.ts +47 -0
- package/templates/base/tests/e2e/errors/error-handling.unauth.spec.ts +205 -0
- package/templates/base/tests/e2e/fixtures.ts +266 -0
- package/templates/base/tests/e2e/forms/validation.spec.ts +569 -0
- package/templates/base/tests/e2e/invitations/invite-flow.unauth.spec.ts +204 -0
- package/templates/base/tests/e2e/journeys/account-lifecycle.spec.ts +314 -0
- package/templates/base/tests/e2e/journeys/audit-investigation.spec.ts +299 -0
- package/templates/base/tests/e2e/journeys/auth-onboarding.spec.ts +232 -0
- package/templates/base/tests/e2e/journeys/critical-flows.spec.ts +281 -0
- package/templates/base/tests/e2e/journeys/error-recovery.spec.ts +354 -0
- package/templates/base/tests/e2e/journeys/file-management.spec.ts +307 -0
- package/templates/base/tests/e2e/journeys/integrations.spec.ts +372 -0
- package/templates/base/tests/e2e/journeys/multi-account.spec.ts +317 -0
- package/templates/base/tests/e2e/journeys/rbac-enforcement.spec.ts +389 -0
- package/templates/base/tests/e2e/journeys/settings-profile.spec.ts +400 -0
- package/templates/base/tests/e2e/journeys/team-collaboration.spec.ts +410 -0
- package/templates/base/tests/e2e/mobile/responsive.spec.ts +178 -0
- package/templates/base/tests/e2e/navigation/routing.spec.ts +371 -0
- package/templates/base/tests/e2e/navigation/sidebar.spec.ts +425 -0
- package/templates/base/tests/e2e/pages/ui-features.spec.ts +393 -0
- package/templates/base/tests/e2e/performance/baselines.spec.ts +162 -0
- package/templates/base/tests/e2e/performance/benchmarks.spec.ts +371 -0
- package/templates/base/tests/e2e/smoke.unauth.spec.ts +196 -0
- package/templates/base/tests/e2e/visual/components.spec.ts +650 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/confirmation-dialog-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/dark-mode-background-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/dark-mode-card-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/dark-mode-sidebar-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/dashboard-card-single-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/dialog-content-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/dialog-with-backdrop-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/empty-search-results-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/input-default-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/input-focus-ring-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/primary-button-focus-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/primary-button-hover-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/primary-button-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/sidebar-active-nav-item-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/sidebar-collapsed-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/sidebar-navigation-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/core-components.spec.ts +192 -0
- package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/account-page-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/create-webhook-dialog-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/dashboard-page-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/delete-account-dialog-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/integrations-page-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/invite-member-dialog-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/login-page-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/settings-account-tab-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/settings-profile-tab-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/sidebar-navigation-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/team-page-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/screenshots.spec.ts +230 -0
- package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/404-page-chromium-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/404-page-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/account-page-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/login-page-chromium-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/login-page-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/settings-page-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/team-invite-dialog-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/team-page-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/webhook-create-dialog-visual-darwin.png +0 -0
- package/templates/base/tests/e2e/visual/theme-colors.spec.ts +293 -0
- package/templates/base/tests/e2e/visual/ui-components.spec.ts +502 -0
- package/templates/base/tests/integration/accounts/crud.test.ts +1402 -0
- package/templates/base/tests/integration/audits/list.test.ts +1133 -0
- package/templates/base/tests/integration/auth/auth-service.test.ts +415 -0
- package/templates/base/tests/integration/auth/invitation-token.test.ts +529 -0
- package/templates/base/tests/integration/auth/logout.test.ts +524 -0
- package/templates/base/tests/integration/auth/oauth.test.ts +768 -0
- package/templates/base/tests/integration/auth/refresh-token.test.ts +364 -0
- package/templates/base/tests/integration/auth/session-expiry.test.ts +569 -0
- package/templates/base/tests/integration/auth/session.test.ts +520 -0
- package/templates/base/tests/integration/auth/super-admin.test.ts +451 -0
- package/templates/base/tests/integration/authorization/analytics-role.test.ts +1026 -0
- package/templates/base/tests/integration/authorization/billing-role.test.ts +776 -0
- package/templates/base/tests/integration/authorization/guards-roles.test.ts +539 -0
- package/templates/base/tests/integration/authorization/multi-tenancy.test.ts +1112 -0
- package/templates/base/tests/integration/authorization/role-hierarchy.test.ts +931 -0
- package/templates/base/tests/integration/authorization/roles.test.ts +1347 -0
- package/templates/base/tests/integration/config/production-behavior.test.ts +536 -0
- package/templates/base/tests/integration/db/constraints.test.ts +695 -0
- package/templates/base/tests/integration/fixtures/accounts.ts +136 -0
- package/templates/base/tests/integration/fixtures/index.ts +232 -0
- package/templates/base/tests/integration/fixtures/invitations.ts +195 -0
- package/templates/base/tests/integration/fixtures/users.ts +144 -0
- package/templates/base/tests/integration/health/health.test.ts +351 -0
- package/templates/base/tests/integration/invitations/crud.test.ts +1457 -0
- package/templates/base/tests/integration/invitations/email.test.ts +506 -0
- package/templates/base/tests/integration/lib/email.test.ts +174 -0
- package/templates/base/tests/integration/lib/oauth.test.ts +368 -0
- package/templates/base/tests/integration/lib/password.test.ts +192 -0
- package/templates/base/tests/integration/lib/schema-helpers.test.ts +129 -0
- package/templates/base/tests/integration/lib/tokens.test.ts +304 -0
- package/templates/base/tests/integration/middleware/auth.test.ts +499 -0
- package/templates/base/tests/integration/middleware/cors.test.ts +334 -0
- package/templates/base/tests/integration/middleware/request-context.test.ts +156 -0
- package/templates/base/tests/integration/middleware/request-logger.test.ts +313 -0
- package/templates/base/tests/integration/performance/response-times.test.ts +509 -0
- package/templates/base/tests/integration/security/cookie-security.test.ts +567 -0
- package/templates/base/tests/integration/security/csrf-protection.test.ts +542 -0
- package/templates/base/tests/integration/security/jwt-validation.test.ts +209 -0
- package/templates/base/tests/integration/security/log-sanitization.test.ts +658 -0
- package/templates/base/tests/integration/security/rate-limiting.test.ts +1251 -0
- package/templates/base/tests/integration/security/sql-injection.test.ts +663 -0
- package/templates/base/tests/integration/security/token-hashing.test.ts +371 -0
- package/templates/base/tests/integration/security/xss-prevention.test.ts +541 -0
- package/templates/base/tests/integration/setup.ts +834 -0
- package/templates/base/tests/integration/smoke.test.ts +288 -0
- package/templates/base/tests/integration/storage/upload.test.ts +1162 -0
- package/templates/base/tests/integration/storage/validation.test.ts +746 -0
- package/templates/base/tests/integration/users/crud.test.ts +1297 -0
- package/templates/base/tests/integration/users/list.test.ts +698 -0
- package/templates/base/tests/integration/vitest.config.ts +80 -0
- package/templates/base/tsconfig.app.json +18 -0
- package/templates/base/tsconfig.json +39 -0
- package/templates/base/tsconfig.node.json +16 -0
- package/templates/base/tsconfig.server.json +26 -0
- package/templates/base/tsconfig.tsbuildinfo +1 -0
- package/templates/base/vite.config.ts +46 -0
- package/templates/base/vitest.config.browser.ts +47 -0
- package/templates/base/vitest.config.frontend.ts +47 -0
- package/templates/base/vitest.config.ts +82 -0
- package/templates/base/vitest.workspace.ts +22 -0
- package/templates/modules/audit-logs/.gitkeep +0 -0
- package/templates/modules/billing/.gitkeep +0 -0
- package/templates/modules/invitations/.gitkeep +0 -0
- package/templates/modules/storage/.gitkeep +0 -0
- package/templates/modules/webhooks/.gitkeep +0 -0
- package/templates/providers/auth-email/.gitkeep +0 -0
- package/templates/providers/auth-github/.gitkeep +0 -0
- package/templates/providers/auth-google/.gitkeep +0 -0
- package/templates/providers/email-resend/.gitkeep +0 -0
- package/templates/providers/email-sendgrid/.gitkeep +0 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { test, expect, isAuthenticated, waitForNavigation } from '../fixtures'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Critical User Journey Tests
|
|
5
|
+
*
|
|
6
|
+
* These tests verify complete user flows, not individual features.
|
|
7
|
+
* They represent the most important paths through the application
|
|
8
|
+
* that must always work.
|
|
9
|
+
*
|
|
10
|
+
* @tags @critical
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
test.describe('Critical User Journeys @critical', () => {
|
|
14
|
+
test.describe('Authentication Journey', () => {
|
|
15
|
+
test('should display complete login page with OAuth option', async ({ page }) => {
|
|
16
|
+
await page.goto('/login')
|
|
17
|
+
|
|
18
|
+
// Verify page loads correctly
|
|
19
|
+
await expect(page.getByText('Welcome back')).toBeVisible()
|
|
20
|
+
|
|
21
|
+
// Verify Google OAuth button is present and enabled
|
|
22
|
+
const googleOAuthButton = page.getByRole('button', { name: /continue with google/i })
|
|
23
|
+
await expect(googleOAuthButton).toBeVisible()
|
|
24
|
+
await expect(googleOAuthButton).toBeEnabled()
|
|
25
|
+
|
|
26
|
+
// Verify the login page has proper structure
|
|
27
|
+
await expect(page.locator('body')).toBeVisible()
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test.describe('Authenticated User Journeys', () => {
|
|
32
|
+
test.beforeEach(async ({ page }) => {
|
|
33
|
+
const authenticated = await isAuthenticated(page)
|
|
34
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('should navigate from dashboard to settings', async ({ page }) => {
|
|
38
|
+
// Start at dashboard
|
|
39
|
+
await page.goto('/dashboard')
|
|
40
|
+
await expect(page).not.toHaveURL(/login/)
|
|
41
|
+
|
|
42
|
+
// Find and click settings link in navigation
|
|
43
|
+
const settingsLink = page.getByRole('link', { name: /settings/i })
|
|
44
|
+
await expect(settingsLink).toBeVisible()
|
|
45
|
+
await settingsLink.click()
|
|
46
|
+
|
|
47
|
+
// Verify settings page loaded
|
|
48
|
+
await waitForNavigation(page, '/settings')
|
|
49
|
+
await expect(page.getByRole('heading', { name: /settings/i })).toBeVisible()
|
|
50
|
+
|
|
51
|
+
// Verify settings tabs are available
|
|
52
|
+
await expect(page.getByRole('tab', { name: /profile/i })).toBeVisible()
|
|
53
|
+
await expect(page.getByRole('tab', { name: /account/i })).toBeVisible()
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('should navigate from dashboard to team management', async ({ page }) => {
|
|
57
|
+
// Start at dashboard
|
|
58
|
+
await page.goto('/dashboard')
|
|
59
|
+
await expect(page).not.toHaveURL(/login/)
|
|
60
|
+
|
|
61
|
+
// Find and click team link in navigation
|
|
62
|
+
const teamLink = page.getByRole('link', { name: /team/i })
|
|
63
|
+
await expect(teamLink).toBeVisible()
|
|
64
|
+
await teamLink.click()
|
|
65
|
+
|
|
66
|
+
// Verify team page loaded
|
|
67
|
+
await waitForNavigation(page, '/team')
|
|
68
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
69
|
+
|
|
70
|
+
// Verify team page elements are present
|
|
71
|
+
await expect(page.getByText('Active Members')).toBeVisible()
|
|
72
|
+
await expect(page.getByRole('button', { name: 'Invite Member' }).first()).toBeVisible()
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
test('should complete team invitation flow', async ({ page }) => {
|
|
76
|
+
// Navigate to team page
|
|
77
|
+
await page.goto('/team')
|
|
78
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
79
|
+
|
|
80
|
+
// Open invite dialog
|
|
81
|
+
const inviteButton = page.getByRole('button', { name: 'Invite Member' }).first()
|
|
82
|
+
await expect(inviteButton).toBeVisible()
|
|
83
|
+
await inviteButton.click()
|
|
84
|
+
|
|
85
|
+
// Verify dialog opened
|
|
86
|
+
await expect(page.getByRole('dialog')).toBeVisible()
|
|
87
|
+
await expect(page.getByRole('heading', { name: /invite team member/i })).toBeVisible()
|
|
88
|
+
|
|
89
|
+
// Fill the email field
|
|
90
|
+
const emailInput = page.getByLabel(/email address/i)
|
|
91
|
+
await expect(emailInput).toBeVisible()
|
|
92
|
+
await emailInput.fill('newmember@example.com')
|
|
93
|
+
|
|
94
|
+
// Select a role (Member is default, try selecting Admin)
|
|
95
|
+
const adminButton = page.getByRole('button', { name: /^admin$/i })
|
|
96
|
+
await expect(adminButton).toBeVisible()
|
|
97
|
+
await adminButton.click()
|
|
98
|
+
|
|
99
|
+
// Verify role description changes
|
|
100
|
+
await expect(page.getByText(/admins can manage team settings/i)).toBeVisible()
|
|
101
|
+
|
|
102
|
+
// Verify Send Invitation button is now enabled
|
|
103
|
+
const sendButton = page.getByRole('button', { name: /send invitation/i })
|
|
104
|
+
await expect(sendButton).toBeEnabled()
|
|
105
|
+
|
|
106
|
+
// Close dialog without submitting (to avoid test data pollution)
|
|
107
|
+
const cancelButton = page.getByRole('button', { name: /cancel/i })
|
|
108
|
+
await cancelButton.click()
|
|
109
|
+
await expect(page.getByRole('dialog')).not.toBeVisible()
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
test('should complete profile update flow', async ({ page }) => {
|
|
113
|
+
// Navigate to settings page
|
|
114
|
+
await page.goto('/settings')
|
|
115
|
+
await expect(page.getByRole('heading', { name: /settings/i })).toBeVisible()
|
|
116
|
+
|
|
117
|
+
// Ensure Profile tab is active
|
|
118
|
+
const profileTab = page.getByRole('tab', { name: /profile/i })
|
|
119
|
+
await expect(profileTab).toBeVisible()
|
|
120
|
+
|
|
121
|
+
// Verify profile form elements
|
|
122
|
+
const nameInput = page.getByLabel(/full name/i)
|
|
123
|
+
await expect(nameInput).toBeVisible()
|
|
124
|
+
await expect(nameInput).toBeEnabled()
|
|
125
|
+
|
|
126
|
+
const emailInput = page.getByLabel(/email address/i)
|
|
127
|
+
await expect(emailInput).toBeVisible()
|
|
128
|
+
await expect(emailInput).toBeDisabled() // Email should be read-only
|
|
129
|
+
|
|
130
|
+
// Verify profile picture section
|
|
131
|
+
await expect(page.getByRole('heading', { name: 'Profile Picture' })).toBeVisible()
|
|
132
|
+
const changePhotoButton = page.getByRole('button', { name: /change photo/i })
|
|
133
|
+
await expect(changePhotoButton).toBeVisible()
|
|
134
|
+
|
|
135
|
+
// Verify save button is present
|
|
136
|
+
const saveButton = page.getByRole('button', { name: /save changes/i })
|
|
137
|
+
await expect(saveButton).toBeVisible()
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
test('should complete full navigation circuit', async ({ page }) => {
|
|
141
|
+
// Step 1: Start at Dashboard
|
|
142
|
+
await page.goto('/dashboard')
|
|
143
|
+
await expect(page).not.toHaveURL(/login/)
|
|
144
|
+
await expect(page).toHaveURL(/dashboard/)
|
|
145
|
+
|
|
146
|
+
// Step 2: Navigate to Team
|
|
147
|
+
const teamLink = page.getByRole('link', { name: /team/i })
|
|
148
|
+
await expect(teamLink).toBeVisible()
|
|
149
|
+
await teamLink.click()
|
|
150
|
+
await waitForNavigation(page, '/team')
|
|
151
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
152
|
+
|
|
153
|
+
// Step 3: Navigate to Settings
|
|
154
|
+
const settingsLink = page.getByRole('link', { name: /settings/i })
|
|
155
|
+
await expect(settingsLink).toBeVisible()
|
|
156
|
+
await settingsLink.click()
|
|
157
|
+
await waitForNavigation(page, '/settings')
|
|
158
|
+
await expect(page.getByRole('heading', { name: /settings/i })).toBeVisible()
|
|
159
|
+
|
|
160
|
+
// Step 4: Navigate to Account
|
|
161
|
+
const accountLink = page.getByRole('link', { name: /account/i })
|
|
162
|
+
await expect(accountLink).toBeVisible()
|
|
163
|
+
await accountLink.click()
|
|
164
|
+
await waitForNavigation(page, '/account')
|
|
165
|
+
await expect(page.getByRole('heading', { name: /^account$/i })).toBeVisible()
|
|
166
|
+
|
|
167
|
+
// Step 5: Navigate to Integrations
|
|
168
|
+
const integrationsLink = page.getByRole('link', { name: /integrations/i })
|
|
169
|
+
await expect(integrationsLink).toBeVisible()
|
|
170
|
+
await integrationsLink.click()
|
|
171
|
+
await waitForNavigation(page, '/integrations')
|
|
172
|
+
await expect(page.getByRole('heading', { name: 'Integrations', exact: true })).toBeVisible()
|
|
173
|
+
|
|
174
|
+
// Step 6: Return to Dashboard (completing the circuit)
|
|
175
|
+
const dashboardLink = page.getByRole('link', { name: /dashboard/i })
|
|
176
|
+
await expect(dashboardLink).toBeVisible()
|
|
177
|
+
await dashboardLink.click()
|
|
178
|
+
await waitForNavigation(page, '/dashboard')
|
|
179
|
+
await expect(page).toHaveURL(/dashboard/)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
test('should complete settings profile update journey', async ({ page }) => {
|
|
183
|
+
// Navigate to settings page
|
|
184
|
+
await page.goto('/settings')
|
|
185
|
+
await expect(page.getByRole('heading', { name: /settings/i })).toBeVisible()
|
|
186
|
+
|
|
187
|
+
// Ensure Profile tab is active
|
|
188
|
+
const profileTab = page.getByRole('tab', { name: /profile/i })
|
|
189
|
+
await expect(profileTab).toBeVisible()
|
|
190
|
+
|
|
191
|
+
// Get the name input and store original value
|
|
192
|
+
const nameInput = page.getByLabel(/full name/i)
|
|
193
|
+
await expect(nameInput).toBeVisible()
|
|
194
|
+
const originalName = await nameInput.inputValue()
|
|
195
|
+
|
|
196
|
+
// Update name with new value
|
|
197
|
+
const testName = 'Test User Updated'
|
|
198
|
+
await nameInput.clear()
|
|
199
|
+
await nameInput.fill(testName)
|
|
200
|
+
|
|
201
|
+
// Click save button
|
|
202
|
+
const saveButton = page.getByRole('button', { name: /save changes/i })
|
|
203
|
+
await expect(saveButton).toBeVisible()
|
|
204
|
+
await saveButton.click()
|
|
205
|
+
|
|
206
|
+
// Wait for update to complete (button should not show spinner after)
|
|
207
|
+
await expect(saveButton).toBeEnabled({ timeout: 5000 })
|
|
208
|
+
|
|
209
|
+
// Verify we stayed on the settings page
|
|
210
|
+
await expect(page).toHaveURL(/settings/)
|
|
211
|
+
await expect(page.getByRole('heading', { name: /settings/i })).toBeVisible()
|
|
212
|
+
|
|
213
|
+
// Restore original value
|
|
214
|
+
await nameInput.clear()
|
|
215
|
+
await nameInput.fill(originalName || '')
|
|
216
|
+
await saveButton.click()
|
|
217
|
+
await expect(saveButton).toBeEnabled({ timeout: 5000 })
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
test('should complete webhook creation journey', async ({ page }) => {
|
|
221
|
+
// Navigate to integrations page
|
|
222
|
+
await page.goto('/integrations')
|
|
223
|
+
await expect(page.getByRole('heading', { name: 'Integrations', exact: true })).toBeVisible()
|
|
224
|
+
|
|
225
|
+
// Click Add Webhook button
|
|
226
|
+
const addWebhookButton = page.getByRole('button', { name: 'Add Webhook' }).first()
|
|
227
|
+
await expect(addWebhookButton).toBeVisible()
|
|
228
|
+
await addWebhookButton.click()
|
|
229
|
+
|
|
230
|
+
// Verify dialog opened (check for Create Webhook heading)
|
|
231
|
+
const createWebhookHeading = page.getByRole('heading', { name: /create webhook/i })
|
|
232
|
+
await expect(createWebhookHeading).toBeVisible()
|
|
233
|
+
|
|
234
|
+
// Fill webhook URL
|
|
235
|
+
const urlInput = page.getByPlaceholder('https://api.example.com/webhooks')
|
|
236
|
+
await expect(urlInput).toBeVisible()
|
|
237
|
+
await urlInput.fill('https://api.test.com/webhook')
|
|
238
|
+
|
|
239
|
+
// Select User Created event
|
|
240
|
+
const userCreatedEvent = page.getByRole('button', { name: 'User Created' })
|
|
241
|
+
await expect(userCreatedEvent).toBeVisible()
|
|
242
|
+
await userCreatedEvent.click()
|
|
243
|
+
|
|
244
|
+
// Verify create button is now enabled (URL filled and event selected)
|
|
245
|
+
const createButton = page.getByRole('button', { name: 'Create Webhook', exact: true })
|
|
246
|
+
await expect(createButton).toBeEnabled()
|
|
247
|
+
|
|
248
|
+
// Cancel to avoid test data pollution
|
|
249
|
+
const cancelButton = page.getByRole('button', { name: 'Cancel' })
|
|
250
|
+
await cancelButton.click()
|
|
251
|
+
await expect(createWebhookHeading).not.toBeVisible()
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
test('should verify account security check journey', async ({ page }) => {
|
|
255
|
+
// Navigate to account page
|
|
256
|
+
await page.goto('/account')
|
|
257
|
+
await expect(page.getByRole('heading', { name: /^account$/i })).toBeVisible()
|
|
258
|
+
|
|
259
|
+
// Verify Security section is visible
|
|
260
|
+
await expect(page.getByRole('heading', { name: /^security$/i })).toBeVisible()
|
|
261
|
+
await expect(page.getByText(/two-factor authentication/i)).toBeVisible()
|
|
262
|
+
|
|
263
|
+
// Verify Connected Accounts section with Google
|
|
264
|
+
await expect(page.getByRole('heading', { name: /connected accounts/i })).toBeVisible()
|
|
265
|
+
await expect(page.getByText('Google')).toBeVisible()
|
|
266
|
+
// Verify Google shows as Connected (find the Connected badge near Google)
|
|
267
|
+
const connectedAccountsSection = page.locator('section').filter({ hasText: 'Connected Accounts' })
|
|
268
|
+
await expect(connectedAccountsSection.getByText('Connected').first()).toBeVisible()
|
|
269
|
+
|
|
270
|
+
// Verify Active Sessions section with current session
|
|
271
|
+
await expect(page.getByRole('heading', { name: /active sessions/i })).toBeVisible()
|
|
272
|
+
await expect(page.getByText('Current', { exact: true })).toBeVisible()
|
|
273
|
+
|
|
274
|
+
// Verify API Access section with Create Key button
|
|
275
|
+
await expect(page.getByRole('heading', { name: /api access/i })).toBeVisible()
|
|
276
|
+
const createKeyButton = page.getByRole('button', { name: /create key/i })
|
|
277
|
+
await expect(createKeyButton).toBeVisible()
|
|
278
|
+
await expect(createKeyButton).toBeEnabled()
|
|
279
|
+
})
|
|
280
|
+
})
|
|
281
|
+
})
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { test, expect, isAuthenticated, apiRequest, getAccountId, closeAllDialogs } from '../fixtures'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Error Recovery and Retry Journey Tests
|
|
5
|
+
*
|
|
6
|
+
* These tests verify application resilience and error handling,
|
|
7
|
+
* including graceful degradation, error display, and recovery flows.
|
|
8
|
+
*
|
|
9
|
+
* @tags @journey @error-handling @resilience
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
test.describe('Error Recovery Journey @journey @error-handling', () => {
|
|
13
|
+
test.describe('API Error Handling', () => {
|
|
14
|
+
test.beforeEach(async ({ page }) => {
|
|
15
|
+
const authenticated = await isAuthenticated(page)
|
|
16
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
17
|
+
|
|
18
|
+
const accountId = getAccountId()
|
|
19
|
+
test.skip(!accountId, 'No account ID available')
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('should handle 404 errors gracefully', async ({ page }) => {
|
|
23
|
+
// Step 1: Request non-existent resource
|
|
24
|
+
const response = await apiRequest(page, 'get', '/api/users/00000000-0000-0000-0000-000000000000')
|
|
25
|
+
|
|
26
|
+
// Step 2: Verify 404 response
|
|
27
|
+
expect(response.status()).toBe(404)
|
|
28
|
+
|
|
29
|
+
const body = await response.json()
|
|
30
|
+
|
|
31
|
+
// Step 3: Verify error structure
|
|
32
|
+
expect(body).toHaveProperty('error')
|
|
33
|
+
expect(body.error).toHaveProperty('message')
|
|
34
|
+
expect(typeof body.error.message).toBe('string')
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('should handle validation errors with details', async ({ page }) => {
|
|
38
|
+
// Step 1: Send invalid data to create endpoint
|
|
39
|
+
const response = await apiRequest(page, 'post', '/api/storage/upload-url', {
|
|
40
|
+
data: {
|
|
41
|
+
// Missing required fields
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// Step 2: Verify validation error
|
|
46
|
+
expect(response.status()).toBe(400)
|
|
47
|
+
|
|
48
|
+
const body = await response.json()
|
|
49
|
+
|
|
50
|
+
// Step 3: Verify error structure
|
|
51
|
+
expect(body).toHaveProperty('error')
|
|
52
|
+
expect(body.error).toHaveProperty('message')
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('should handle invalid UUID format errors', async ({ page }) => {
|
|
56
|
+
// Step 1: Request with invalid ID format
|
|
57
|
+
const response = await apiRequest(page, 'get', '/api/accounts/invalid-uuid')
|
|
58
|
+
|
|
59
|
+
// Step 2: Verify validation error
|
|
60
|
+
expect([400, 422]).toContain(response.status())
|
|
61
|
+
|
|
62
|
+
const body = await response.json()
|
|
63
|
+
|
|
64
|
+
// Step 3: Verify error structure
|
|
65
|
+
expect(body).toHaveProperty('error')
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test.describe('UI Error Display', () => {
|
|
70
|
+
test.beforeEach(async ({ page }) => {
|
|
71
|
+
const authenticated = await isAuthenticated(page)
|
|
72
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
test.afterEach(async ({ page }) => {
|
|
76
|
+
await closeAllDialogs(page)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
test('should handle navigation to non-existent page', async ({ page }) => {
|
|
80
|
+
// Step 1: Navigate to non-existent page
|
|
81
|
+
await page.goto('/non-existent-page-12345')
|
|
82
|
+
|
|
83
|
+
// Step 2: Should either show 404 or redirect to dashboard
|
|
84
|
+
const url = page.url()
|
|
85
|
+
const pageContent = await page.content()
|
|
86
|
+
|
|
87
|
+
// App should handle gracefully - either show error or redirect
|
|
88
|
+
expect(
|
|
89
|
+
url.includes('404') || url.includes('dashboard') || pageContent.includes('not found')
|
|
90
|
+
).toBeTruthy()
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
test('should display loading states during data fetch', async ({ page }) => {
|
|
94
|
+
// Step 1: Navigate to team page
|
|
95
|
+
await page.goto('/team')
|
|
96
|
+
|
|
97
|
+
// Step 2: Page should eventually load content
|
|
98
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible({ timeout: 10000 })
|
|
99
|
+
|
|
100
|
+
// Step 3: Verify page loaded successfully without errors
|
|
101
|
+
await expect(page.getByText(/active members/i)).toBeVisible()
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test.describe('Form Validation Recovery', () => {
|
|
106
|
+
test.beforeEach(async ({ page }) => {
|
|
107
|
+
const authenticated = await isAuthenticated(page)
|
|
108
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
test.afterEach(async ({ page }) => {
|
|
112
|
+
await closeAllDialogs(page)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
test('should recover from invalid form input', async ({ page }) => {
|
|
116
|
+
// Step 1: Navigate to team page
|
|
117
|
+
await page.goto('/team')
|
|
118
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
119
|
+
|
|
120
|
+
// Step 2: Open invite dialog
|
|
121
|
+
const inviteButton = page.locator('button').filter({ hasText: 'Invite Member' }).first()
|
|
122
|
+
await inviteButton.click()
|
|
123
|
+
await expect(page.getByRole('dialog')).toBeVisible()
|
|
124
|
+
|
|
125
|
+
// Step 3: Verify submit is disabled with empty email
|
|
126
|
+
const sendButton = page.getByRole('button', { name: /send invitation/i })
|
|
127
|
+
await expect(sendButton).toBeDisabled()
|
|
128
|
+
|
|
129
|
+
// Step 4: Enter invalid email format (partial)
|
|
130
|
+
const emailInput = page.getByLabel(/email address/i)
|
|
131
|
+
await emailInput.fill('invalid-email')
|
|
132
|
+
|
|
133
|
+
// Step 5: Button may still be enabled but submission would fail
|
|
134
|
+
// Enter valid email to recover
|
|
135
|
+
await emailInput.clear()
|
|
136
|
+
await emailInput.fill('valid@example.com')
|
|
137
|
+
|
|
138
|
+
// Step 6: Verify form recovered - button should be enabled
|
|
139
|
+
await expect(sendButton).toBeEnabled()
|
|
140
|
+
|
|
141
|
+
// Step 7: Cancel to avoid test pollution
|
|
142
|
+
await page.getByRole('button', { name: /cancel/i }).click()
|
|
143
|
+
await expect(page.getByRole('dialog')).not.toBeVisible()
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
test('should handle empty name in profile update', async ({ page }) => {
|
|
147
|
+
// Step 1: Navigate to settings
|
|
148
|
+
await page.goto('/settings')
|
|
149
|
+
await expect(page.getByRole('heading', { name: /settings/i })).toBeVisible()
|
|
150
|
+
|
|
151
|
+
// Step 2: Get the name input
|
|
152
|
+
const nameInput = page.getByLabel(/full name/i)
|
|
153
|
+
await expect(nameInput).toBeVisible()
|
|
154
|
+
|
|
155
|
+
// Step 3: Store original value
|
|
156
|
+
const originalName = await nameInput.inputValue()
|
|
157
|
+
|
|
158
|
+
// Step 4: Clear name and try to save
|
|
159
|
+
await nameInput.clear()
|
|
160
|
+
|
|
161
|
+
// Step 5: The save button should still work but backend validates
|
|
162
|
+
const saveButton = page.getByRole('button', { name: /save changes/i })
|
|
163
|
+
await expect(saveButton).toBeVisible()
|
|
164
|
+
|
|
165
|
+
// Step 6: Restore original name for recovery
|
|
166
|
+
await nameInput.fill(originalName || 'Test User')
|
|
167
|
+
await expect(nameInput).toHaveValue(originalName || 'Test User')
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
test.describe('Network Error Recovery', () => {
|
|
172
|
+
test.beforeEach(async ({ page }) => {
|
|
173
|
+
const authenticated = await isAuthenticated(page)
|
|
174
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
test('should handle page reload without losing context', async ({ page }) => {
|
|
178
|
+
// Step 1: Navigate to dashboard
|
|
179
|
+
await page.goto('/dashboard')
|
|
180
|
+
await expect(page).toHaveURL(/dashboard/)
|
|
181
|
+
|
|
182
|
+
// Step 2: Reload the page
|
|
183
|
+
await page.reload()
|
|
184
|
+
|
|
185
|
+
// Step 3: Verify page recovered
|
|
186
|
+
await expect(page).toHaveURL(/dashboard/)
|
|
187
|
+
await expect(page).not.toHaveURL(/login/)
|
|
188
|
+
|
|
189
|
+
// Step 4: Verify navigation still works
|
|
190
|
+
await expect(page.getByRole('navigation')).toBeVisible()
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
test('should handle back/forward navigation', async ({ page }) => {
|
|
194
|
+
// Step 1: Navigate to dashboard
|
|
195
|
+
await page.goto('/dashboard')
|
|
196
|
+
await expect(page).toHaveURL(/dashboard/)
|
|
197
|
+
|
|
198
|
+
// Step 2: Navigate to team
|
|
199
|
+
await page.goto('/team')
|
|
200
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
201
|
+
|
|
202
|
+
// Step 3: Go back
|
|
203
|
+
await page.goBack()
|
|
204
|
+
await expect(page).toHaveURL(/dashboard/)
|
|
205
|
+
|
|
206
|
+
// Step 4: Go forward
|
|
207
|
+
await page.goForward()
|
|
208
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
209
|
+
})
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
test.describe('API Retry Behavior', () => {
|
|
213
|
+
test.beforeEach(async ({ page }) => {
|
|
214
|
+
const authenticated = await isAuthenticated(page)
|
|
215
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
216
|
+
|
|
217
|
+
const accountId = getAccountId()
|
|
218
|
+
test.skip(!accountId, 'No account ID available')
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
test('should handle multiple rapid API requests', async ({ page }) => {
|
|
222
|
+
// Step 1: Make multiple rapid requests
|
|
223
|
+
const requests = Array(5)
|
|
224
|
+
.fill(null)
|
|
225
|
+
.map(() => apiRequest(page, 'get', '/api/audits?limit=1'))
|
|
226
|
+
|
|
227
|
+
// Step 2: Wait for all requests
|
|
228
|
+
const responses = await Promise.all(requests)
|
|
229
|
+
|
|
230
|
+
// Step 3: All should succeed
|
|
231
|
+
for (const response of responses) {
|
|
232
|
+
expect(response.ok()).toBeTruthy()
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
test('should handle sequential API calls', async ({ page }) => {
|
|
237
|
+
// Step 1: Make sequential calls to different endpoints
|
|
238
|
+
const endpoints = ['/api/audits?limit=1', '/api/users?limit=1', '/api/accounts']
|
|
239
|
+
|
|
240
|
+
for (const endpoint of endpoints) {
|
|
241
|
+
const response = await apiRequest(page, 'get', endpoint)
|
|
242
|
+
expect(response.ok()).toBeTruthy()
|
|
243
|
+
|
|
244
|
+
const body = await response.json()
|
|
245
|
+
expect(body).toHaveProperty('data')
|
|
246
|
+
}
|
|
247
|
+
})
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
test.describe('Dialog Error Handling', () => {
|
|
251
|
+
test.beforeEach(async ({ page }) => {
|
|
252
|
+
const authenticated = await isAuthenticated(page)
|
|
253
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
test.afterEach(async ({ page }) => {
|
|
257
|
+
await closeAllDialogs(page)
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
test('should close dialog on escape key', async ({ page }) => {
|
|
261
|
+
// Step 1: Navigate to team page
|
|
262
|
+
await page.goto('/team')
|
|
263
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
264
|
+
|
|
265
|
+
// Step 2: Open invite dialog
|
|
266
|
+
await page.locator('button').filter({ hasText: 'Invite Member' }).first().click()
|
|
267
|
+
await expect(page.getByRole('dialog')).toBeVisible()
|
|
268
|
+
|
|
269
|
+
// Step 3: Press escape
|
|
270
|
+
await page.keyboard.press('Escape')
|
|
271
|
+
|
|
272
|
+
// Step 4: Dialog should close
|
|
273
|
+
await expect(page.getByRole('dialog')).not.toBeVisible()
|
|
274
|
+
|
|
275
|
+
// Step 5: Page should remain functional
|
|
276
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
test('should allow reopening dialog after cancel', async ({ page }) => {
|
|
280
|
+
// Step 1: Navigate to integrations
|
|
281
|
+
await page.goto('/integrations')
|
|
282
|
+
await expect(page.getByRole('heading', { name: 'Integrations', exact: true })).toBeVisible()
|
|
283
|
+
|
|
284
|
+
// Step 2: Open webhook dialog
|
|
285
|
+
await page.getByRole('button', { name: 'Add Webhook' }).first().click()
|
|
286
|
+
await expect(page.getByRole('heading', { name: /create webhook/i })).toBeVisible()
|
|
287
|
+
|
|
288
|
+
// Step 3: Cancel
|
|
289
|
+
await page.getByRole('button', { name: 'Cancel' }).click()
|
|
290
|
+
await expect(page.getByRole('heading', { name: /create webhook/i })).not.toBeVisible()
|
|
291
|
+
|
|
292
|
+
// Step 4: Reopen dialog
|
|
293
|
+
await page.getByRole('button', { name: 'Add Webhook' }).first().click()
|
|
294
|
+
await expect(page.getByRole('heading', { name: /create webhook/i })).toBeVisible()
|
|
295
|
+
|
|
296
|
+
// Step 5: Clean up
|
|
297
|
+
await page.getByRole('button', { name: 'Cancel' }).click()
|
|
298
|
+
})
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
test.describe('Complete Error Recovery Workflow', () => {
|
|
302
|
+
test.beforeEach(async ({ page }) => {
|
|
303
|
+
const authenticated = await isAuthenticated(page)
|
|
304
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
test.afterEach(async ({ page }) => {
|
|
308
|
+
await closeAllDialogs(page)
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
test('complete error recovery workflow across pages', async ({ page }) => {
|
|
312
|
+
// Step 1: Start at dashboard
|
|
313
|
+
await page.goto('/dashboard')
|
|
314
|
+
await expect(page).toHaveURL(/dashboard/)
|
|
315
|
+
|
|
316
|
+
// Step 2: Try invalid navigation then recover
|
|
317
|
+
await page.goto('/non-existent-12345')
|
|
318
|
+
// Either stays on current page or shows error
|
|
319
|
+
await page.goto('/dashboard')
|
|
320
|
+
await expect(page).toHaveURL(/dashboard/)
|
|
321
|
+
|
|
322
|
+
// Step 3: Navigate to settings and test form recovery
|
|
323
|
+
await page.goto('/settings')
|
|
324
|
+
await expect(page.getByRole('heading', { name: /settings/i })).toBeVisible()
|
|
325
|
+
|
|
326
|
+
const nameInput = page.getByLabel(/full name/i)
|
|
327
|
+
const originalName = await nameInput.inputValue()
|
|
328
|
+
|
|
329
|
+
// Modify and recover
|
|
330
|
+
await nameInput.clear()
|
|
331
|
+
await nameInput.fill(originalName || 'Test')
|
|
332
|
+
await expect(nameInput).toHaveValue(originalName || 'Test')
|
|
333
|
+
|
|
334
|
+
// Step 4: Navigate to team and test dialog recovery
|
|
335
|
+
await page.goto('/team')
|
|
336
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
337
|
+
|
|
338
|
+
await page.locator('button').filter({ hasText: 'Invite Member' }).first().click()
|
|
339
|
+
await expect(page.getByRole('dialog')).toBeVisible()
|
|
340
|
+
|
|
341
|
+
await page.keyboard.press('Escape')
|
|
342
|
+
await expect(page.getByRole('dialog')).not.toBeVisible()
|
|
343
|
+
|
|
344
|
+
// Step 5: Reload and verify session persists
|
|
345
|
+
await page.reload()
|
|
346
|
+
await expect(page).not.toHaveURL(/login/)
|
|
347
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
348
|
+
|
|
349
|
+
// Step 6: Return to dashboard to complete workflow
|
|
350
|
+
await page.goto('/dashboard')
|
|
351
|
+
await expect(page).toHaveURL(/dashboard/)
|
|
352
|
+
})
|
|
353
|
+
})
|
|
354
|
+
})
|