@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,393 @@
|
|
|
1
|
+
import { test, expect, isAuthenticated, closeAllDialogs } from '../fixtures'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* UI Features Gap Tests
|
|
5
|
+
*
|
|
6
|
+
* These tests verify UI feature coverage gaps identified during review,
|
|
7
|
+
* including security settings, notifications, file uploads, and error handling.
|
|
8
|
+
*
|
|
9
|
+
* @tags @ui @features @pages
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
test.describe('UI Features Gap Tests @ui @features @pages', () => {
|
|
13
|
+
test.describe('Account Security - Active Sessions', () => {
|
|
14
|
+
test.beforeEach(async ({ page }) => {
|
|
15
|
+
const authenticated = await isAuthenticated(page)
|
|
16
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test.afterEach(async ({ page }) => {
|
|
20
|
+
await closeAllDialogs(page)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('should display active sessions list in account security', async ({ page }) => {
|
|
24
|
+
await page.goto('/account')
|
|
25
|
+
|
|
26
|
+
// Verify Active Sessions section
|
|
27
|
+
await expect(page.getByRole('heading', { name: /active sessions/i })).toBeVisible()
|
|
28
|
+
|
|
29
|
+
// Verify session list description
|
|
30
|
+
await expect(page.getByText(/devices where you're currently logged in/i)).toBeVisible()
|
|
31
|
+
|
|
32
|
+
// Verify at least one session is displayed (current session)
|
|
33
|
+
await expect(page.getByText(/current/i).first()).toBeVisible()
|
|
34
|
+
|
|
35
|
+
// Verify session shows device/browser info
|
|
36
|
+
await expect(page.getByText(/chrome on|safari on|firefox on|edge on/i).first()).toBeVisible()
|
|
37
|
+
|
|
38
|
+
// Verify session shows activity time
|
|
39
|
+
await expect(page.getByText(/active now|hours ago|minutes ago/i).first()).toBeVisible()
|
|
40
|
+
|
|
41
|
+
// Verify Sign out all button exists for multiple sessions
|
|
42
|
+
const signOutAllButton = page.getByRole('button', { name: /sign out all/i })
|
|
43
|
+
await expect(signOutAllButton).toBeVisible()
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test.describe('Account Security - Danger Zone', () => {
|
|
48
|
+
test.beforeEach(async ({ page }) => {
|
|
49
|
+
const authenticated = await isAuthenticated(page)
|
|
50
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test.afterEach(async ({ page }) => {
|
|
54
|
+
await closeAllDialogs(page)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('should display danger zone with delete confirmation controls', async ({ page }) => {
|
|
58
|
+
await page.goto('/account')
|
|
59
|
+
|
|
60
|
+
// Scroll to danger zone
|
|
61
|
+
const dangerZoneHeading = page.getByRole('heading', { name: /danger zone/i })
|
|
62
|
+
await dangerZoneHeading.scrollIntoViewIfNeeded()
|
|
63
|
+
|
|
64
|
+
// Verify Danger Zone section
|
|
65
|
+
await expect(dangerZoneHeading).toBeVisible()
|
|
66
|
+
|
|
67
|
+
// Verify irreversible actions warning
|
|
68
|
+
await expect(page.getByText(/irreversible and destructive actions/i)).toBeVisible()
|
|
69
|
+
|
|
70
|
+
// Verify Export Data option
|
|
71
|
+
await expect(page.getByText('Export Data')).toBeVisible()
|
|
72
|
+
await expect(page.getByText(/download a copy of all your data/i)).toBeVisible()
|
|
73
|
+
const exportButton = page.getByRole('button', { name: /^export$/i })
|
|
74
|
+
await expect(exportButton).toBeVisible()
|
|
75
|
+
await expect(exportButton).toBeEnabled()
|
|
76
|
+
|
|
77
|
+
// Verify Delete Account option
|
|
78
|
+
await expect(page.getByText('Delete Account').first()).toBeVisible()
|
|
79
|
+
await expect(page.getByText(/permanently delete your account and data/i)).toBeVisible()
|
|
80
|
+
|
|
81
|
+
// Verify Delete button is present and styled as destructive
|
|
82
|
+
const deleteButton = page.getByRole('button', { name: /^delete$/i }).first()
|
|
83
|
+
await expect(deleteButton).toBeVisible()
|
|
84
|
+
await expect(deleteButton).toBeEnabled()
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
test.describe('Account Deletion Confirmation', () => {
|
|
89
|
+
test.beforeEach(async ({ page }) => {
|
|
90
|
+
const authenticated = await isAuthenticated(page)
|
|
91
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test.afterEach(async ({ page }) => {
|
|
95
|
+
await closeAllDialogs(page)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('should show deletion confirmation dialog with email validation', async ({ page }) => {
|
|
99
|
+
await page.goto('/account')
|
|
100
|
+
|
|
101
|
+
// Scroll to and click Delete button
|
|
102
|
+
const dangerZoneHeading = page.getByRole('heading', { name: /danger zone/i })
|
|
103
|
+
await dangerZoneHeading.scrollIntoViewIfNeeded()
|
|
104
|
+
|
|
105
|
+
const deleteButton = page.getByRole('button', { name: /^delete$/i }).first()
|
|
106
|
+
await deleteButton.click()
|
|
107
|
+
|
|
108
|
+
// Verify dialog opens
|
|
109
|
+
await expect(page.getByRole('dialog')).toBeVisible()
|
|
110
|
+
await expect(page.getByRole('heading', { name: /delete account/i })).toBeVisible()
|
|
111
|
+
|
|
112
|
+
// Verify warning message
|
|
113
|
+
await expect(page.getByText(/this action cannot be undone/i)).toBeVisible()
|
|
114
|
+
await expect(page.getByText(/all your data will be permanently deleted/i)).toBeVisible()
|
|
115
|
+
|
|
116
|
+
// Verify email confirmation input
|
|
117
|
+
const confirmInput = page.getByPlaceholder(/enter your email/i)
|
|
118
|
+
await expect(confirmInput).toBeVisible()
|
|
119
|
+
|
|
120
|
+
// Verify Delete Account button is disabled initially
|
|
121
|
+
const confirmDeleteButton = page.getByRole('button', { name: /delete account/i })
|
|
122
|
+
await expect(confirmDeleteButton).toBeDisabled()
|
|
123
|
+
|
|
124
|
+
// Type incorrect email - button should remain disabled
|
|
125
|
+
await confirmInput.fill('wrong@email.com')
|
|
126
|
+
await expect(confirmDeleteButton).toBeDisabled()
|
|
127
|
+
|
|
128
|
+
// Verify Cancel button works
|
|
129
|
+
const cancelButton = page.getByRole('button', { name: /cancel/i })
|
|
130
|
+
await cancelButton.click()
|
|
131
|
+
await expect(page.getByRole('dialog')).not.toBeVisible()
|
|
132
|
+
|
|
133
|
+
// Verify we're still on account page
|
|
134
|
+
await expect(page.getByRole('heading', { name: /^account$/i, level: 1 })).toBeVisible()
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
test.describe('Settings - Notification Preferences', () => {
|
|
139
|
+
test.beforeEach(async ({ page }) => {
|
|
140
|
+
const authenticated = await isAuthenticated(page)
|
|
141
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test.afterEach(async ({ page }) => {
|
|
145
|
+
await closeAllDialogs(page)
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
test('should persist notification preferences on toggle', async ({ page }) => {
|
|
149
|
+
await page.goto('/settings')
|
|
150
|
+
|
|
151
|
+
// Switch to Notifications tab
|
|
152
|
+
const notificationsTab = page.getByRole('tab', { name: /notifications/i })
|
|
153
|
+
await expect(notificationsTab).toBeVisible()
|
|
154
|
+
await notificationsTab.click()
|
|
155
|
+
await expect(notificationsTab).toHaveAttribute('data-state', 'active')
|
|
156
|
+
|
|
157
|
+
// Verify Email Notifications section
|
|
158
|
+
await expect(page.getByRole('heading', { name: /email notifications/i })).toBeVisible()
|
|
159
|
+
|
|
160
|
+
// Find Team Invitations toggle
|
|
161
|
+
const teamInvitationsRow = page.locator('div').filter({ hasText: /^Team Invitations/ })
|
|
162
|
+
const toggleSwitch = teamInvitationsRow.getByRole('switch').first()
|
|
163
|
+
await expect(toggleSwitch).toBeVisible()
|
|
164
|
+
|
|
165
|
+
// Get initial state
|
|
166
|
+
const initialState = await toggleSwitch.getAttribute('aria-checked')
|
|
167
|
+
|
|
168
|
+
// Toggle the switch
|
|
169
|
+
await toggleSwitch.click()
|
|
170
|
+
|
|
171
|
+
// Verify state changed
|
|
172
|
+
const newState = await toggleSwitch.getAttribute('aria-checked')
|
|
173
|
+
expect(newState).not.toBe(initialState)
|
|
174
|
+
|
|
175
|
+
// Reload page to verify persistence
|
|
176
|
+
await page.reload()
|
|
177
|
+
|
|
178
|
+
// Navigate back to notifications tab
|
|
179
|
+
const reloadedNotificationsTab = page.getByRole('tab', { name: /notifications/i })
|
|
180
|
+
await reloadedNotificationsTab.click()
|
|
181
|
+
|
|
182
|
+
// Find the toggle again and check state persisted
|
|
183
|
+
const reloadedRow = page.locator('div').filter({ hasText: /^Team Invitations/ })
|
|
184
|
+
const reloadedToggle = reloadedRow.getByRole('switch').first()
|
|
185
|
+
|
|
186
|
+
const persistedState = await reloadedToggle.getAttribute('aria-checked')
|
|
187
|
+
|
|
188
|
+
// Restore original state if it changed
|
|
189
|
+
if (persistedState !== initialState) {
|
|
190
|
+
await reloadedToggle.click()
|
|
191
|
+
}
|
|
192
|
+
})
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
test.describe('Settings - Connected Accounts', () => {
|
|
196
|
+
test.beforeEach(async ({ page }) => {
|
|
197
|
+
const authenticated = await isAuthenticated(page)
|
|
198
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
test.afterEach(async ({ page }) => {
|
|
202
|
+
await closeAllDialogs(page)
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
test('should display connected accounts in settings', async ({ page }) => {
|
|
206
|
+
await page.goto('/settings')
|
|
207
|
+
|
|
208
|
+
// Switch to Account tab
|
|
209
|
+
const accountTab = page.getByRole('tab', { name: /account/i })
|
|
210
|
+
await expect(accountTab).toBeVisible()
|
|
211
|
+
await accountTab.click()
|
|
212
|
+
await expect(accountTab).toHaveAttribute('data-state', 'active')
|
|
213
|
+
|
|
214
|
+
// Verify Connected Accounts section
|
|
215
|
+
await expect(page.getByRole('heading', { name: /connected accounts/i })).toBeVisible()
|
|
216
|
+
await expect(page.getByText(/manage your connected oauth providers/i)).toBeVisible()
|
|
217
|
+
|
|
218
|
+
// Verify Google provider is shown
|
|
219
|
+
await expect(page.getByText('Google')).toBeVisible()
|
|
220
|
+
|
|
221
|
+
// Verify connected status indicator
|
|
222
|
+
await expect(page.getByText(/connected/i).first()).toBeVisible()
|
|
223
|
+
|
|
224
|
+
// Verify Sessions section is also present
|
|
225
|
+
await expect(page.getByRole('heading', { name: /sessions/i })).toBeVisible()
|
|
226
|
+
await expect(page.getByText(/current session/i)).toBeVisible()
|
|
227
|
+
})
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
test.describe('File Upload - Cancellation', () => {
|
|
231
|
+
test.beforeEach(async ({ page }) => {
|
|
232
|
+
const authenticated = await isAuthenticated(page)
|
|
233
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
test.afterEach(async ({ page }) => {
|
|
237
|
+
await closeAllDialogs(page)
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
test('should allow cancellation of file upload flow', async ({ page }) => {
|
|
241
|
+
await page.goto('/settings')
|
|
242
|
+
|
|
243
|
+
// Verify Profile Picture section exists
|
|
244
|
+
await expect(page.getByRole('heading', { name: 'Profile Picture' })).toBeVisible()
|
|
245
|
+
|
|
246
|
+
// Verify Change Photo button is present
|
|
247
|
+
const changePhotoButton = page.getByRole('button', { name: /change photo/i })
|
|
248
|
+
await expect(changePhotoButton).toBeVisible()
|
|
249
|
+
await expect(changePhotoButton).toBeEnabled()
|
|
250
|
+
|
|
251
|
+
// Verify file input exists
|
|
252
|
+
const fileInput = page.locator('input[type="file"]')
|
|
253
|
+
await expect(fileInput).toHaveCount(1)
|
|
254
|
+
|
|
255
|
+
// Verify file input accepts images
|
|
256
|
+
const acceptAttr = await fileInput.getAttribute('accept')
|
|
257
|
+
expect(acceptAttr).toContain('image/')
|
|
258
|
+
|
|
259
|
+
// Click the change photo button to initiate upload flow
|
|
260
|
+
await changePhotoButton.click()
|
|
261
|
+
|
|
262
|
+
// The file dialog would open - since we can't interact with native file dialogs,
|
|
263
|
+
// verify the input can be programmatically triggered and the page remains functional
|
|
264
|
+
await expect(page.getByRole('heading', { name: 'Profile Picture' })).toBeVisible()
|
|
265
|
+
|
|
266
|
+
// Verify the page is still functional after cancellation (no dialog opened)
|
|
267
|
+
await expect(page.getByRole('heading', { name: /settings/i })).toBeVisible()
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
test.describe('Network Errors - Retry Option', () => {
|
|
272
|
+
test.beforeEach(async ({ page }) => {
|
|
273
|
+
const authenticated = await isAuthenticated(page)
|
|
274
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
test.afterEach(async ({ page }) => {
|
|
278
|
+
await closeAllDialogs(page)
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
test('should handle network errors and allow retry', async ({ page }) => {
|
|
282
|
+
// Navigate to a page that loads data
|
|
283
|
+
await page.goto('/team')
|
|
284
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
285
|
+
|
|
286
|
+
// Simulate network failure by blocking API requests
|
|
287
|
+
await page.route('**/api/**', (route) => {
|
|
288
|
+
route.abort('failed')
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
// Try to open invite dialog which makes API calls
|
|
292
|
+
const inviteButton = page.locator('button').filter({ hasText: 'Invite Member' }).first()
|
|
293
|
+
if (await inviteButton.isVisible()) {
|
|
294
|
+
await inviteButton.click()
|
|
295
|
+
|
|
296
|
+
// The dialog should still open
|
|
297
|
+
await expect(page.getByRole('dialog')).toBeVisible({ timeout: 5000 }).catch(() => {
|
|
298
|
+
// Dialog may not open due to network error
|
|
299
|
+
})
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Remove route blocking
|
|
303
|
+
await page.unroute('**/api/**')
|
|
304
|
+
|
|
305
|
+
// Reload page to verify recovery
|
|
306
|
+
await page.reload()
|
|
307
|
+
|
|
308
|
+
// Page should recover and display correctly
|
|
309
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
310
|
+
|
|
311
|
+
// Verify navigation still works after error recovery
|
|
312
|
+
await page.goto('/dashboard')
|
|
313
|
+
await expect(page).toHaveURL(/dashboard/)
|
|
314
|
+
|
|
315
|
+
await page.goto('/team')
|
|
316
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
317
|
+
})
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
test.describe('File Upload - Invalid File Types', () => {
|
|
321
|
+
test.beforeEach(async ({ page }) => {
|
|
322
|
+
const authenticated = await isAuthenticated(page)
|
|
323
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
test.afterEach(async ({ page }) => {
|
|
327
|
+
await closeAllDialogs(page)
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
test('should reject invalid file types with error message', async ({ page }) => {
|
|
331
|
+
await page.goto('/settings')
|
|
332
|
+
|
|
333
|
+
// Verify Profile Picture section
|
|
334
|
+
await expect(page.getByRole('heading', { name: 'Profile Picture' })).toBeVisible()
|
|
335
|
+
|
|
336
|
+
// Get file input
|
|
337
|
+
const fileInput = page.locator('input[type="file"]')
|
|
338
|
+
await expect(fileInput).toHaveCount(1)
|
|
339
|
+
|
|
340
|
+
// Verify the input has accept attribute limiting file types
|
|
341
|
+
const acceptAttr = await fileInput.getAttribute('accept')
|
|
342
|
+
expect(acceptAttr).toContain('image/')
|
|
343
|
+
|
|
344
|
+
// Try to simulate uploading an invalid file type
|
|
345
|
+
// The browser's native file picker will typically filter by accept attribute
|
|
346
|
+
// but we can test the API validation layer
|
|
347
|
+
const response = await page.request.post('/api/storage/upload-url', {
|
|
348
|
+
data: {
|
|
349
|
+
filename: 'malicious.exe',
|
|
350
|
+
contentType: 'application/x-msdownload',
|
|
351
|
+
},
|
|
352
|
+
failOnStatusCode: false,
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
// Should reject non-allowed file types (either at API or storage level)
|
|
356
|
+
// The status could be 400 (validation) or 200 (R2 handles it) depending on implementation
|
|
357
|
+
const body = await response.json()
|
|
358
|
+
|
|
359
|
+
if (response.status() === 400) {
|
|
360
|
+
// Validation error - verify error structure
|
|
361
|
+
expect(body).toHaveProperty('error')
|
|
362
|
+
expect(body.error).toHaveProperty('message')
|
|
363
|
+
} else if (response.status() === 200) {
|
|
364
|
+
// Storage configured but file type may still be blocked by other means
|
|
365
|
+
expect(body).toHaveProperty('url')
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Verify page still works after invalid file type attempt
|
|
369
|
+
await expect(page.getByRole('heading', { name: /settings/i })).toBeVisible()
|
|
370
|
+
await expect(page.getByRole('heading', { name: 'Profile Picture' })).toBeVisible()
|
|
371
|
+
|
|
372
|
+
// Verify file size hint is displayed
|
|
373
|
+
await expect(page.getByText(/max 2mb/i)).toBeVisible()
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
test('should display file type restrictions to user', async ({ page }) => {
|
|
377
|
+
await page.goto('/settings')
|
|
378
|
+
|
|
379
|
+
// Verify the file input accepts only images
|
|
380
|
+
const fileInput = page.locator('input[type="file"]')
|
|
381
|
+
const acceptAttr = await fileInput.getAttribute('accept')
|
|
382
|
+
|
|
383
|
+
// Should accept image types
|
|
384
|
+
expect(acceptAttr).toMatch(/image\//i)
|
|
385
|
+
|
|
386
|
+
// Verify the UI shows allowed file types or size restrictions
|
|
387
|
+
await expect(page.getByText(/max 2mb/i)).toBeVisible()
|
|
388
|
+
|
|
389
|
+
// The profile picture section should have clear guidance
|
|
390
|
+
await expect(page.getByText(/your profile picture is visible to other team members/i)).toBeVisible()
|
|
391
|
+
})
|
|
392
|
+
})
|
|
393
|
+
})
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { test, expect, isAuthenticated } from '../fixtures'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Performance Baseline Tests
|
|
5
|
+
*
|
|
6
|
+
* These tests establish performance baselines for key pages.
|
|
7
|
+
* They measure page load times and ensure they stay within acceptable limits.
|
|
8
|
+
*
|
|
9
|
+
* @tags @performance @baseline
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// Performance thresholds (in milliseconds)
|
|
13
|
+
const THRESHOLDS = {
|
|
14
|
+
pageLoad: 5000, // Max time for page to be fully interactive
|
|
15
|
+
firstPaint: 2000, // Max time to first meaningful paint
|
|
16
|
+
apiResponse: 1000, // Max time for API responses
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
test.describe('Performance Baselines @performance @baseline', () => {
|
|
20
|
+
test.describe('Public Pages', () => {
|
|
21
|
+
test('login page loads within threshold', async ({ page }) => {
|
|
22
|
+
const startTime = Date.now()
|
|
23
|
+
|
|
24
|
+
await page.goto('/login', { waitUntil: 'networkidle' })
|
|
25
|
+
|
|
26
|
+
const loadTime = Date.now() - startTime
|
|
27
|
+
|
|
28
|
+
// Verify page loaded
|
|
29
|
+
await expect(page.getByText('Welcome back')).toBeVisible()
|
|
30
|
+
|
|
31
|
+
// Check load time is within threshold
|
|
32
|
+
expect(loadTime).toBeLessThan(THRESHOLDS.pageLoad)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('404 page loads within threshold', async ({ page }) => {
|
|
36
|
+
const startTime = Date.now()
|
|
37
|
+
|
|
38
|
+
await page.goto('/non-existent-page', { waitUntil: 'domcontentloaded' })
|
|
39
|
+
|
|
40
|
+
const loadTime = Date.now() - startTime
|
|
41
|
+
|
|
42
|
+
// Verify 404 content
|
|
43
|
+
await expect(page.getByText('404').first()).toBeVisible()
|
|
44
|
+
|
|
45
|
+
// Check load time
|
|
46
|
+
expect(loadTime).toBeLessThan(THRESHOLDS.pageLoad)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test.describe('Authenticated Pages', () => {
|
|
51
|
+
test.beforeEach(async ({ page }) => {
|
|
52
|
+
const authenticated = await isAuthenticated(page)
|
|
53
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('dashboard page loads within threshold', async ({ page }) => {
|
|
57
|
+
const startTime = Date.now()
|
|
58
|
+
|
|
59
|
+
await page.goto('/dashboard', { waitUntil: 'networkidle' })
|
|
60
|
+
|
|
61
|
+
const loadTime = Date.now() - startTime
|
|
62
|
+
|
|
63
|
+
// Verify page loaded
|
|
64
|
+
await expect(page.getByRole('navigation')).toBeVisible()
|
|
65
|
+
|
|
66
|
+
// Check load time
|
|
67
|
+
expect(loadTime).toBeLessThan(THRESHOLDS.pageLoad)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
test('team page loads within threshold', async ({ page }) => {
|
|
71
|
+
const startTime = Date.now()
|
|
72
|
+
|
|
73
|
+
await page.goto('/team', { waitUntil: 'networkidle' })
|
|
74
|
+
|
|
75
|
+
const loadTime = Date.now() - startTime
|
|
76
|
+
|
|
77
|
+
// Verify page loaded
|
|
78
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
79
|
+
|
|
80
|
+
// Check load time
|
|
81
|
+
expect(loadTime).toBeLessThan(THRESHOLDS.pageLoad)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
test('settings page loads within threshold', async ({ page }) => {
|
|
85
|
+
const startTime = Date.now()
|
|
86
|
+
|
|
87
|
+
await page.goto('/settings', { waitUntil: 'networkidle' })
|
|
88
|
+
|
|
89
|
+
const loadTime = Date.now() - startTime
|
|
90
|
+
|
|
91
|
+
// Verify page loaded
|
|
92
|
+
await expect(page.getByRole('heading', { name: /settings/i })).toBeVisible()
|
|
93
|
+
|
|
94
|
+
// Check load time
|
|
95
|
+
expect(loadTime).toBeLessThan(THRESHOLDS.pageLoad)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('integrations page loads within threshold', async ({ page }) => {
|
|
99
|
+
const startTime = Date.now()
|
|
100
|
+
|
|
101
|
+
await page.goto('/integrations', { waitUntil: 'networkidle' })
|
|
102
|
+
|
|
103
|
+
const loadTime = Date.now() - startTime
|
|
104
|
+
|
|
105
|
+
// Verify page loaded
|
|
106
|
+
await expect(page.getByRole('heading', { name: 'Integrations', exact: true })).toBeVisible()
|
|
107
|
+
|
|
108
|
+
// Check load time
|
|
109
|
+
expect(loadTime).toBeLessThan(THRESHOLDS.pageLoad)
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
test.describe('API Performance', () => {
|
|
114
|
+
test.beforeEach(async ({ page }) => {
|
|
115
|
+
const authenticated = await isAuthenticated(page)
|
|
116
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
test('API responses within threshold', async ({ page }) => {
|
|
120
|
+
// Navigate to dashboard first to establish session
|
|
121
|
+
await page.goto('/dashboard')
|
|
122
|
+
await expect(page.getByRole('navigation')).toBeVisible()
|
|
123
|
+
|
|
124
|
+
// Test auth/me endpoint performance
|
|
125
|
+
const startTime = Date.now()
|
|
126
|
+
const response = await page.request.get('/auth/me')
|
|
127
|
+
const responseTime = Date.now() - startTime
|
|
128
|
+
|
|
129
|
+
expect(response.ok()).toBeTruthy()
|
|
130
|
+
expect(responseTime).toBeLessThan(THRESHOLDS.apiResponse)
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
test.describe('Navigation Performance', () => {
|
|
135
|
+
test.beforeEach(async ({ page }) => {
|
|
136
|
+
const authenticated = await isAuthenticated(page)
|
|
137
|
+
test.skip(!authenticated, 'No authenticated session available')
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
test('navigation between pages is responsive', async ({ page }) => {
|
|
141
|
+
// Start at dashboard
|
|
142
|
+
await page.goto('/dashboard', { waitUntil: 'networkidle' })
|
|
143
|
+
await expect(page.getByRole('navigation')).toBeVisible()
|
|
144
|
+
|
|
145
|
+
// Navigate to team - measure time
|
|
146
|
+
const teamStart = Date.now()
|
|
147
|
+
await page.goto('/team', { waitUntil: 'domcontentloaded' })
|
|
148
|
+
await expect(page.getByRole('heading', { name: /team members/i })).toBeVisible()
|
|
149
|
+
const teamTime = Date.now() - teamStart
|
|
150
|
+
|
|
151
|
+
// Navigate to settings - measure time
|
|
152
|
+
const settingsStart = Date.now()
|
|
153
|
+
await page.goto('/settings', { waitUntil: 'domcontentloaded' })
|
|
154
|
+
await expect(page.getByRole('heading', { name: /settings/i })).toBeVisible()
|
|
155
|
+
const settingsTime = Date.now() - settingsStart
|
|
156
|
+
|
|
157
|
+
// Both navigations should be fast
|
|
158
|
+
expect(teamTime).toBeLessThan(THRESHOLDS.pageLoad)
|
|
159
|
+
expect(settingsTime).toBeLessThan(THRESHOLDS.pageLoad)
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
})
|