@nextsparkjs/theme-default 0.1.0-beta.20 → 0.1.0-beta.22
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/package.json +1 -1
- package/tests/cypress/e2e/_devtools/access.bdd.md +262 -0
- package/tests/cypress/e2e/_devtools/access.cy.ts +171 -0
- package/tests/cypress/e2e/_devtools/navigation.bdd.md +261 -0
- package/tests/cypress/e2e/_devtools/navigation.cy.ts +157 -0
- package/tests/cypress/e2e/_devtools/pages.bdd.md +303 -0
- package/tests/cypress/e2e/_devtools/pages.cy.ts +184 -0
- package/tests/cypress/e2e/_docs/README.md +215 -0
- package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin-teams.narration.json +155 -0
- package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin.cy.ts +390 -0
- package/tests/cypress/e2e/_docs/tutorials/teams-system.doc.cy.ts +349 -0
- package/tests/cypress/e2e/_docs/tutorials/teams-system.narration.json +165 -0
- package/tests/cypress/e2e/_selectors/auth.cy.ts +306 -0
- package/tests/cypress/e2e/_selectors/billing.cy.ts +89 -0
- package/tests/cypress/e2e/_selectors/dashboard-mobile.cy.ts +113 -0
- package/tests/cypress/e2e/_selectors/dashboard-navigation.cy.ts +89 -0
- package/tests/cypress/e2e/_selectors/dashboard-sidebar.cy.ts +60 -0
- package/tests/cypress/e2e/_selectors/dashboard-topnav.cy.ts +146 -0
- package/tests/cypress/e2e/_selectors/devtools.cy.ts +210 -0
- package/tests/cypress/e2e/_selectors/global-search.cy.ts +88 -0
- package/tests/cypress/e2e/_selectors/pages-editor.cy.ts +179 -0
- package/tests/cypress/e2e/_selectors/posts-editor.cy.ts +282 -0
- package/tests/cypress/e2e/_selectors/public.cy.ts +112 -0
- package/tests/cypress/e2e/_selectors/settings-api-keys.cy.ts +228 -0
- package/tests/cypress/e2e/_selectors/settings-billing.cy.ts +105 -0
- package/tests/cypress/e2e/_selectors/settings-layout.cy.ts +119 -0
- package/tests/cypress/e2e/_selectors/settings-password.cy.ts +71 -0
- package/tests/cypress/e2e/_selectors/settings-profile.cy.ts +82 -0
- package/tests/cypress/e2e/_selectors/settings-teams.cy.ts +68 -0
- package/tests/cypress/e2e/_selectors/superadmin.cy.ts +185 -0
- package/tests/cypress/e2e/_selectors/tasks.cy.ts +242 -0
- package/tests/cypress/e2e/_selectors/taxonomies.cy.ts +126 -0
- package/tests/cypress/e2e/_selectors/teams.cy.ts +142 -0
- package/tests/cypress/e2e/_superadmin/all-teams.bdd.md +261 -0
- package/tests/cypress/e2e/_superadmin/all-teams.cy.ts +177 -0
- package/tests/cypress/e2e/_superadmin/all-users.bdd.md +406 -0
- package/tests/cypress/e2e/_superadmin/all-users.cy.ts +294 -0
- package/tests/cypress/e2e/_superadmin/dashboard.bdd.md +235 -0
- package/tests/cypress/e2e/_superadmin/dashboard.cy.ts +149 -0
- package/tests/cypress/e2e/_superadmin/subscriptions-overview.bdd.md +290 -0
- package/tests/cypress/e2e/_superadmin/subscriptions-overview.cy.ts +194 -0
- package/tests/cypress/e2e/ai/ai-usage.cy.ts +209 -0
- package/tests/cypress/e2e/ai/chat-api.cy.ts +107 -0
- package/tests/cypress/e2e/ai/guardrails.cy.ts +332 -0
- package/tests/cypress/e2e/api/billing/BillingAPIController.js +319 -0
- package/tests/cypress/e2e/api/billing/check-action.cy.ts +326 -0
- package/tests/cypress/e2e/api/billing/checkout.cy.ts +358 -0
- package/tests/cypress/e2e/api/billing/lifecycle.cy.ts +423 -0
- package/tests/cypress/e2e/api/billing/plans/README.md +345 -0
- package/tests/cypress/e2e/api/billing/plans/business.cy.ts +412 -0
- package/tests/cypress/e2e/api/billing/plans/downgrade.cy.ts +510 -0
- package/tests/cypress/e2e/api/billing/plans/fixtures/billing-plans.json +163 -0
- package/tests/cypress/e2e/api/billing/plans/free.cy.ts +500 -0
- package/tests/cypress/e2e/api/billing/plans/pro.cy.ts +497 -0
- package/tests/cypress/e2e/api/billing/plans/starter.cy.ts +342 -0
- package/tests/cypress/e2e/api/billing/portal.cy.ts +313 -0
- package/tests/cypress/e2e/api/devtools/registries.bdd.md +300 -0
- package/tests/cypress/e2e/api/devtools/registries.cy.ts +368 -0
- package/tests/cypress/e2e/api/entities/blocks-scope.cy.ts +396 -0
- package/tests/cypress/e2e/api/entities/customers-crud.cy.ts +648 -0
- package/tests/cypress/e2e/api/entities/customers-metas.cy.ts +839 -0
- package/tests/cypress/e2e/api/entities/pages-crud.cy.ts +425 -0
- package/tests/cypress/e2e/api/entities/pages-status.cy.ts +335 -0
- package/tests/cypress/e2e/api/entities/post-categories-crud.cy.ts +610 -0
- package/tests/cypress/e2e/api/entities/posts-crud.cy.ts +709 -0
- package/tests/cypress/e2e/api/entities/posts-status.cy.ts +396 -0
- package/tests/cypress/e2e/api/entities/tasks-crud.cy.ts +602 -0
- package/tests/cypress/e2e/api/entities/tasks-metas.cy.ts +878 -0
- package/tests/cypress/e2e/api/entities/users-crud.cy.ts +469 -0
- package/tests/cypress/e2e/api/entities/users-metas.cy.ts +913 -0
- package/tests/cypress/e2e/api/entities/users-security.cy.ts +375 -0
- package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.bdd.md +375 -0
- package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.cy.ts +346 -0
- package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.bdd.md +451 -0
- package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.cy.ts +447 -0
- package/tests/cypress/e2e/api/scheduled-actions/scheduling.bdd.md +649 -0
- package/tests/cypress/e2e/api/scheduled-actions/scheduling.cy.ts +333 -0
- package/tests/cypress/e2e/api/settings/api-keys.crud.cy.ts +923 -0
- package/tests/cypress/e2e/uat/auth/app-roles/developer-login.bdd.md +231 -0
- package/tests/cypress/e2e/uat/auth/app-roles/developer-login.cy.ts +144 -0
- package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.bdd.md +118 -0
- package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.cy.ts +84 -0
- package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.bdd.md +288 -0
- package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.cy.ts +188 -0
- package/tests/cypress/e2e/uat/auth/login-logout.bdd.md +160 -0
- package/tests/cypress/e2e/uat/auth/login-logout.cy.ts +116 -0
- package/tests/cypress/e2e/uat/auth/password-reset.bdd.md +289 -0
- package/tests/cypress/e2e/uat/auth/password-reset.cy.ts +200 -0
- package/tests/cypress/e2e/uat/auth/team-roles/admin-login.bdd.md +225 -0
- package/tests/cypress/e2e/uat/auth/team-roles/admin-login.cy.ts +148 -0
- package/tests/cypress/e2e/uat/auth/team-roles/member-login.bdd.md +251 -0
- package/tests/cypress/e2e/uat/auth/team-roles/member-login.cy.ts +163 -0
- package/tests/cypress/e2e/uat/auth/team-roles/owner-login.bdd.md +231 -0
- package/tests/cypress/e2e/uat/auth/team-roles/owner-login.cy.ts +141 -0
- package/tests/cypress/e2e/uat/billing/extended.bdd.md +273 -0
- package/tests/cypress/e2e/uat/billing/extended.cy.ts +209 -0
- package/tests/cypress/e2e/uat/billing/feature-gates.bdd.md +407 -0
- package/tests/cypress/e2e/uat/billing/feature-gates.cy.ts +307 -0
- package/tests/cypress/e2e/uat/billing/page.bdd.md +329 -0
- package/tests/cypress/e2e/uat/billing/page.cy.ts +250 -0
- package/tests/cypress/e2e/uat/billing/status.bdd.md +190 -0
- package/tests/cypress/e2e/uat/billing/status.cy.ts +145 -0
- package/tests/cypress/e2e/uat/billing/team-switch.bdd.md +156 -0
- package/tests/cypress/e2e/uat/billing/team-switch.cy.ts +122 -0
- package/tests/cypress/e2e/uat/billing/usage.bdd.md +218 -0
- package/tests/cypress/e2e/uat/billing/usage.cy.ts +176 -0
- package/tests/cypress/e2e/uat/blocks/hero.bdd.md +124 -0
- package/tests/cypress/e2e/uat/blocks/hero.cy.ts +56 -0
- package/tests/cypress/e2e/uat/devtools/api-tester.cy.ts +390 -0
- package/tests/cypress/e2e/uat/entities/customers/member.bdd.md +275 -0
- package/tests/cypress/e2e/uat/entities/customers/member.cy.ts +122 -0
- package/tests/cypress/e2e/uat/entities/customers/owner.bdd.md +243 -0
- package/tests/cypress/e2e/uat/entities/customers/owner.cy.ts +165 -0
- package/tests/cypress/e2e/uat/entities/pages/block-crud.bdd.md +476 -0
- package/tests/cypress/e2e/uat/entities/pages/block-crud.cy.ts +486 -0
- package/tests/cypress/e2e/uat/entities/pages/block-editor.bdd.md +460 -0
- package/tests/cypress/e2e/uat/entities/pages/block-editor.cy.ts +301 -0
- package/tests/cypress/e2e/uat/entities/pages/list.bdd.md +432 -0
- package/tests/cypress/e2e/uat/entities/pages/list.cy.ts +273 -0
- package/tests/cypress/e2e/uat/entities/pages/public-rendering.bdd.md +696 -0
- package/tests/cypress/e2e/uat/entities/pages/public-rendering.cy.ts +340 -0
- package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.bdd.md +161 -0
- package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.cy.ts +104 -0
- package/tests/cypress/e2e/uat/entities/posts/categories.bdd.md +375 -0
- package/tests/cypress/e2e/uat/entities/posts/categories.cy.ts +241 -0
- package/tests/cypress/e2e/uat/entities/posts/editor.bdd.md +429 -0
- package/tests/cypress/e2e/uat/entities/posts/editor.cy.ts +257 -0
- package/tests/cypress/e2e/uat/entities/posts/list.bdd.md +340 -0
- package/tests/cypress/e2e/uat/entities/posts/list.cy.ts +177 -0
- package/tests/cypress/e2e/uat/entities/posts/public.bdd.md +614 -0
- package/tests/cypress/e2e/uat/entities/posts/public.cy.ts +249 -0
- package/tests/cypress/e2e/uat/entities/tasks/member.bdd.md +222 -0
- package/tests/cypress/e2e/uat/entities/tasks/member.cy.ts +165 -0
- package/tests/cypress/e2e/uat/entities/tasks/owner.bdd.md +419 -0
- package/tests/cypress/e2e/uat/entities/tasks/owner.cy.ts +191 -0
- package/tests/cypress/e2e/uat/roles/editor-role.bdd.md +552 -0
- package/tests/cypress/e2e/uat/roles/editor-role.cy.ts +210 -0
- package/tests/cypress/e2e/uat/roles/member-restrictions.bdd.md +450 -0
- package/tests/cypress/e2e/uat/roles/member-restrictions.cy.ts +189 -0
- package/tests/cypress/e2e/uat/roles/owner-full-crud.bdd.md +530 -0
- package/tests/cypress/e2e/uat/roles/owner-full-crud.cy.ts +247 -0
- package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.bdd.md +736 -0
- package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.cy.ts +740 -0
- package/tests/cypress/e2e/uat/teams/roles-matrix.bdd.md +553 -0
- package/tests/cypress/e2e/uat/teams/roles-matrix.cy.ts +185 -0
- package/tests/cypress/e2e/uat/teams/switcher.bdd.md +1151 -0
- package/tests/cypress/e2e/uat/teams/switcher.cy.ts +497 -0
- package/tests/cypress/e2e/uat/teams/team-switcher.md +198 -0
- package/tests/cypress/fixtures/blocks.json +218 -0
- package/tests/cypress/fixtures/entities.json +78 -0
- package/tests/cypress/fixtures/page-builder.json +21 -0
- package/tests/cypress/src/components/CategoriesPOM.ts +382 -0
- package/tests/cypress/src/components/CustomersPOM.ts +439 -0
- package/tests/cypress/src/components/DevKeyringPOM.ts +160 -0
- package/tests/cypress/src/components/EntityForm.ts +375 -0
- package/tests/cypress/src/components/EntityList.ts +389 -0
- package/tests/cypress/src/components/PageBuilderPOM.ts +710 -0
- package/tests/cypress/src/components/PostEditorPOM.ts +370 -0
- package/tests/cypress/src/components/PostsListPOM.ts +223 -0
- package/tests/cypress/src/components/PublicPagePOM.ts +447 -0
- package/tests/cypress/src/components/PublicPostPOM.ts +146 -0
- package/tests/cypress/src/components/TasksPOM.ts +272 -0
- package/tests/cypress/src/components/TeamSwitcherPOM.ts +450 -0
- package/tests/cypress/src/components/index.ts +21 -0
- package/tests/cypress/src/controllers/ApiKeysAPIController.js +178 -0
- package/tests/cypress/src/controllers/BaseAPIController.js +317 -0
- package/tests/cypress/src/controllers/CustomerAPIController.js +251 -0
- package/tests/cypress/src/controllers/PagesAPIController.js +226 -0
- package/tests/cypress/src/controllers/PostsAPIController.js +250 -0
- package/tests/cypress/src/controllers/TaskAPIController.js +240 -0
- package/tests/cypress/src/controllers/UsersAPIController.js +242 -0
- package/tests/cypress/src/controllers/index.js +25 -0
- package/tests/cypress/src/core/AuthPOM.ts +450 -0
- package/tests/cypress/src/core/BasePOM.ts +86 -0
- package/tests/cypress/src/core/BlockEditorBasePOM.ts +576 -0
- package/tests/cypress/src/core/DashboardEntityPOM.ts +692 -0
- package/tests/cypress/src/core/index.ts +14 -0
- package/tests/cypress/src/entities/CustomersPOM.ts +172 -0
- package/tests/cypress/src/entities/PagesPOM.ts +137 -0
- package/tests/cypress/src/entities/PostsPOM.ts +137 -0
- package/tests/cypress/src/entities/TasksPOM.ts +176 -0
- package/tests/cypress/src/entities/index.ts +14 -0
- package/tests/cypress/src/features/BillingPOM.ts +385 -0
- package/tests/cypress/src/features/DashboardPOM.ts +245 -0
- package/tests/cypress/src/features/DevtoolsPOM.ts +739 -0
- package/tests/cypress/src/features/PageBuilderPOM.ts +263 -0
- package/tests/cypress/src/features/PostEditorPOM.ts +313 -0
- package/tests/cypress/src/features/ScheduledActionsPOM.ts +463 -0
- package/tests/cypress/src/features/SettingsPOM.ts +362 -0
- package/tests/cypress/src/features/SuperadminPOM.ts +331 -0
- package/tests/cypress/src/features/SuperadminTeamRolesPOM.ts +285 -0
- package/tests/cypress/src/features/index.ts +28 -0
- package/tests/cypress/src/helpers/ApiInterceptor.ts +177 -0
- package/tests/cypress/src/index.ts +101 -0
- package/tests/cypress/src/pages/dashboard/Dashboard.js +677 -0
- package/tests/cypress/src/pages/dashboard/DashboardPage.js +43 -0
- package/tests/cypress/src/pages/dashboard/DashboardStats.js +546 -0
- package/tests/cypress/src/pages/dashboard/index.js +6 -0
- package/tests/cypress/src/pages/index.js +5 -0
- package/tests/cypress/src/pages/public/FeaturesPage.js +28 -0
- package/tests/cypress/src/pages/public/LandingPage.js +69 -0
- package/tests/cypress/src/pages/public/PricingPage.js +33 -0
- package/tests/cypress/src/pages/public/index.js +6 -0
- package/tests/cypress/src/selectors.ts +46 -0
- package/tests/cypress/src/session-helpers.ts +500 -0
- package/tests/cypress/support/doc-commands.ts +260 -0
- package/tests/cypress/support/e2e.ts +89 -0
- package/tests/cypress.config.ts +165 -0
- package/tests/jest/components/post-header.test.tsx +377 -0
- package/tests/jest/config/role-config.test.ts +529 -0
- package/tests/jest/jest.config.ts +81 -0
- package/tests/jest/langchain/COVERAGE.md +372 -0
- package/tests/jest/langchain/guardrails.test.ts +465 -0
- package/tests/jest/langchain/streaming.test.ts +367 -0
- package/tests/jest/langchain/token-tracker.test.ts +455 -0
- package/tests/jest/langchain/tracer-callbacks.test.ts +881 -0
- package/tests/jest/langchain/tracer.test.ts +823 -0
- package/tests/jest/user-roles/role-helpers.test.ts +432 -0
- package/tests/jest/validation/categories.test.ts +429 -0
- package/tests/jest/validation/posts.test.ts +546 -0
- package/tests/tsconfig.json +15 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme Selectors for Cypress Tests
|
|
3
|
+
*
|
|
4
|
+
* This file re-exports from the main selectors in lib/.
|
|
5
|
+
* The lib/selectors.ts is the source of truth, placed there so
|
|
6
|
+
* block components can import it (tests/ is excluded from TypeScript).
|
|
7
|
+
*
|
|
8
|
+
* Architecture:
|
|
9
|
+
* - Core selectors: `core/lib/test/core-selectors.ts`
|
|
10
|
+
* - Theme selectors (source): `lib/selectors.ts`
|
|
11
|
+
* - Theme selectors (tests): This file (re-exports)
|
|
12
|
+
*
|
|
13
|
+
* @example POM usage:
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { cySelector, sel, SELECTORS } from '../selectors'
|
|
16
|
+
*
|
|
17
|
+
* class MyPOM extends BasePOM {
|
|
18
|
+
* get elements() {
|
|
19
|
+
* return {
|
|
20
|
+
* loginForm: cySelector('auth.login.form'),
|
|
21
|
+
* submitButton: cySelector('auth.login.submit'),
|
|
22
|
+
* heroBlock: cySelector('blocks.hero.container'),
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
// Re-export everything from the lib selectors
|
|
30
|
+
export {
|
|
31
|
+
BLOCK_SELECTORS,
|
|
32
|
+
THEME_SELECTORS,
|
|
33
|
+
SELECTORS,
|
|
34
|
+
sel,
|
|
35
|
+
s,
|
|
36
|
+
selDev,
|
|
37
|
+
cySelector,
|
|
38
|
+
entitySelectors,
|
|
39
|
+
CORE_SELECTORS,
|
|
40
|
+
} from '../../../lib/selectors'
|
|
41
|
+
|
|
42
|
+
export type {
|
|
43
|
+
ThemeSelectorsType,
|
|
44
|
+
BlockSelectorsType,
|
|
45
|
+
Replacements,
|
|
46
|
+
} from '../../../lib/selectors'
|
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default Theme Session Helpers
|
|
3
|
+
*
|
|
4
|
+
* Direct login functions for Default theme tests using theme-specific users.
|
|
5
|
+
* These helpers don't depend on ACTIVE_THEME environment variable.
|
|
6
|
+
*
|
|
7
|
+
* EXPERIMENTAL: Uses API-based login instead of UI login.
|
|
8
|
+
* Hypothesis: API login is faster and more stable than DevKeyring UI login,
|
|
9
|
+
* especially with slow dev servers (Turbopack on-demand compilation).
|
|
10
|
+
*
|
|
11
|
+
* Test file: cypress/e2e/_experimental/api-login-test.cy.ts
|
|
12
|
+
* Fallback: If API fails, falls back to UI login with DevKeyring.
|
|
13
|
+
*
|
|
14
|
+
* IMPORTANT: After login, this helper sets activeTeamId in localStorage.
|
|
15
|
+
* This is required because all entity API calls include x-team-id header
|
|
16
|
+
* which is read from localStorage.activeTeamId (see core/lib/api/entities.ts).
|
|
17
|
+
* Without this, API calls return 400 "Team context required".
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { DevKeyringPOM as DevKeyring } from './components/DevKeyringPOM'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Default Theme Test Users
|
|
24
|
+
* Teams: Everpoint Labs, Ironvale Global, Riverstone Ventures
|
|
25
|
+
*/
|
|
26
|
+
export const DEFAULT_THEME_USERS = {
|
|
27
|
+
OWNER: 'carlos.mendoza@nextspark.dev', // Everpoint Labs (owner), Riverstone (member)
|
|
28
|
+
ADMIN: 'james.wilson@nextspark.dev', // Everpoint Labs (admin)
|
|
29
|
+
MEMBER: 'emily.johnson@nextspark.dev', // Everpoint (member), Riverstone (admin)
|
|
30
|
+
EDITOR: 'diego.ramirez@nextspark.dev', // Everpoint Labs (editor) - custom role
|
|
31
|
+
VIEWER: 'sarah.davis@nextspark.dev', // Ironvale Global (viewer)
|
|
32
|
+
} as const
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Core System Users (from core/migrations/090_sample_data.sql)
|
|
36
|
+
* These users have special global roles, not team-based roles
|
|
37
|
+
*/
|
|
38
|
+
export const CORE_USERS = {
|
|
39
|
+
SUPERADMIN: 'superadmin@nextspark.dev', // Global superadmin role - Admin access
|
|
40
|
+
DEVELOPER: 'developer@nextspark.dev', // Global developer role - Dev Zone access
|
|
41
|
+
} as const
|
|
42
|
+
|
|
43
|
+
// Common password for demo users (team-based)
|
|
44
|
+
const TEST_PASSWORD = 'Test1234'
|
|
45
|
+
|
|
46
|
+
// Password for core system users (superadmin/developer)
|
|
47
|
+
const CORE_PASSWORD = 'Pandora1234'
|
|
48
|
+
|
|
49
|
+
// Extended timeout for dev server compilation
|
|
50
|
+
const API_TIMEOUT = 30000
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Sets up team context after login (requires page to be loaded for localStorage access)
|
|
54
|
+
*
|
|
55
|
+
* This is CRITICAL for entity API calls to work:
|
|
56
|
+
* 1. Fetches user's teams from /api/v1/teams
|
|
57
|
+
* 2. Sets activeTeamId in localStorage (used by frontend to add x-team-id header)
|
|
58
|
+
* 3. Calls /api/v1/teams/switch to set server-side team cookie
|
|
59
|
+
*
|
|
60
|
+
* Without this, all entity API calls return 400 "Team context required"
|
|
61
|
+
*
|
|
62
|
+
* @param preferredRole - Optional role to filter teams by (e.g., 'member' to select team where user is member)
|
|
63
|
+
*/
|
|
64
|
+
function setupTeamContext(preferredRole?: string) {
|
|
65
|
+
cy.request({
|
|
66
|
+
method: 'GET',
|
|
67
|
+
url: '/api/v1/teams',
|
|
68
|
+
timeout: API_TIMEOUT,
|
|
69
|
+
failOnStatusCode: false
|
|
70
|
+
}).then((teamsResponse) => {
|
|
71
|
+
if (teamsResponse.status === 200 && teamsResponse.body?.data?.length > 0) {
|
|
72
|
+
const teams = teamsResponse.body.data
|
|
73
|
+
|
|
74
|
+
// If preferredRole specified, find team where user has that role
|
|
75
|
+
let selectedTeam = teams[0]
|
|
76
|
+
if (preferredRole) {
|
|
77
|
+
const teamWithRole = teams.find((t: { role: string }) => t.role === preferredRole)
|
|
78
|
+
if (teamWithRole) {
|
|
79
|
+
selectedTeam = teamWithRole
|
|
80
|
+
cy.log(`✅ Found team with role "${preferredRole}": ${selectedTeam.name}`)
|
|
81
|
+
} else {
|
|
82
|
+
cy.log(`⚠️ No team found with role "${preferredRole}", using first team`)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const teamId = selectedTeam.id
|
|
87
|
+
|
|
88
|
+
cy.log(`✅ Setting active team: ${selectedTeam.name} (${teamId}) - role: ${selectedTeam.role}`)
|
|
89
|
+
|
|
90
|
+
// Set in localStorage (used by frontend buildHeaders() to add x-team-id)
|
|
91
|
+
cy.window().then((win) => {
|
|
92
|
+
win.localStorage.setItem('activeTeamId', teamId)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// Call teams/switch to set server-side cookie (for SSR/layouts)
|
|
96
|
+
cy.request({
|
|
97
|
+
method: 'POST',
|
|
98
|
+
url: '/api/v1/teams/switch',
|
|
99
|
+
body: { teamId },
|
|
100
|
+
timeout: API_TIMEOUT,
|
|
101
|
+
failOnStatusCode: false
|
|
102
|
+
})
|
|
103
|
+
} else {
|
|
104
|
+
cy.log(`⚠️ No teams found for user, API calls requiring team context will fail`)
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Login via API (faster and more stable than UI)
|
|
111
|
+
* Returns true if API login succeeded, false if fallback to UI was needed.
|
|
112
|
+
*
|
|
113
|
+
* @param email - User email to login
|
|
114
|
+
* @param password - Optional password (defaults to TEST_PASSWORD for demo users)
|
|
115
|
+
*/
|
|
116
|
+
function apiLogin(email: string, password: string = TEST_PASSWORD): Cypress.Chainable<boolean> {
|
|
117
|
+
return cy.request({
|
|
118
|
+
method: 'POST',
|
|
119
|
+
url: '/api/auth/sign-in/email',
|
|
120
|
+
body: { email, password },
|
|
121
|
+
timeout: API_TIMEOUT,
|
|
122
|
+
failOnStatusCode: false
|
|
123
|
+
}).then((response) => {
|
|
124
|
+
if (response.status === 200) {
|
|
125
|
+
return true
|
|
126
|
+
} else {
|
|
127
|
+
cy.log(`⚠️ API login failed with status ${response.status}, falling back to UI login`)
|
|
128
|
+
// Fallback to UI login if API fails
|
|
129
|
+
cy.visit('/login', { timeout: 60000 })
|
|
130
|
+
const devKeyring = new DevKeyring()
|
|
131
|
+
devKeyring.validateVisible()
|
|
132
|
+
devKeyring.quickLoginByEmail(email)
|
|
133
|
+
return false
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Login as Default Theme Owner
|
|
140
|
+
* Session is cached and reused across tests
|
|
141
|
+
*
|
|
142
|
+
* Flow:
|
|
143
|
+
* 1. API login (or UI fallback)
|
|
144
|
+
* 2. Visit dashboard to load page context
|
|
145
|
+
* 3. Setup team context (sets localStorage.activeTeamId)
|
|
146
|
+
*/
|
|
147
|
+
export function loginAsDefaultOwner() {
|
|
148
|
+
cy.session('default-owner-session', () => {
|
|
149
|
+
apiLogin(DEFAULT_THEME_USERS.OWNER).then((apiLoginSucceeded) => {
|
|
150
|
+
// If API login succeeded, we need to visit a page before setting localStorage
|
|
151
|
+
if (apiLoginSucceeded) {
|
|
152
|
+
cy.visit('/dashboard', { timeout: 60000 })
|
|
153
|
+
}
|
|
154
|
+
// URL assertion to ensure page loaded
|
|
155
|
+
cy.url().should('include', '/dashboard')
|
|
156
|
+
// Setup team context (requires page to be loaded for localStorage)
|
|
157
|
+
setupTeamContext()
|
|
158
|
+
})
|
|
159
|
+
}, {
|
|
160
|
+
validate: () => {
|
|
161
|
+
// Validate auth session exists
|
|
162
|
+
cy.request({
|
|
163
|
+
url: '/api/auth/get-session',
|
|
164
|
+
timeout: API_TIMEOUT,
|
|
165
|
+
failOnStatusCode: false
|
|
166
|
+
}).its('status').should('eq', 200)
|
|
167
|
+
|
|
168
|
+
// Validate team context exists in localStorage
|
|
169
|
+
// This ensures API calls will have x-team-id header
|
|
170
|
+
cy.window().then((win) => {
|
|
171
|
+
const teamId = win.localStorage.getItem('activeTeamId')
|
|
172
|
+
expect(teamId, 'activeTeamId should exist in localStorage').to.not.be.null
|
|
173
|
+
expect(teamId, 'activeTeamId should not be empty').to.not.be.empty
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Login as Default Theme Admin
|
|
181
|
+
* Session is cached and reused across tests
|
|
182
|
+
*/
|
|
183
|
+
export function loginAsDefaultAdmin() {
|
|
184
|
+
cy.session('default-admin-session', () => {
|
|
185
|
+
apiLogin(DEFAULT_THEME_USERS.ADMIN).then((apiLoginSucceeded) => {
|
|
186
|
+
if (apiLoginSucceeded) {
|
|
187
|
+
cy.visit('/dashboard', { timeout: 60000 })
|
|
188
|
+
}
|
|
189
|
+
cy.url().should('include', '/dashboard')
|
|
190
|
+
setupTeamContext()
|
|
191
|
+
})
|
|
192
|
+
}, {
|
|
193
|
+
validate: () => {
|
|
194
|
+
cy.request({
|
|
195
|
+
url: '/api/auth/get-session',
|
|
196
|
+
timeout: API_TIMEOUT,
|
|
197
|
+
failOnStatusCode: false
|
|
198
|
+
}).its('status').should('eq', 200)
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Login as Default Theme Member
|
|
205
|
+
* Session is cached and reused across tests
|
|
206
|
+
*
|
|
207
|
+
* Note: Emily Johnson is member of Everpoint but admin of Riverstone.
|
|
208
|
+
* We explicitly select the team where she has 'member' role.
|
|
209
|
+
*/
|
|
210
|
+
export function loginAsDefaultMember() {
|
|
211
|
+
cy.session('default-member-session', () => {
|
|
212
|
+
apiLogin(DEFAULT_THEME_USERS.MEMBER).then((apiLoginSucceeded) => {
|
|
213
|
+
if (apiLoginSucceeded) {
|
|
214
|
+
cy.visit('/dashboard', { timeout: 60000 })
|
|
215
|
+
}
|
|
216
|
+
cy.url().should('include', '/dashboard')
|
|
217
|
+
// Explicitly select team where user is member (not admin)
|
|
218
|
+
setupTeamContext('member')
|
|
219
|
+
})
|
|
220
|
+
}, {
|
|
221
|
+
validate: () => {
|
|
222
|
+
cy.request({
|
|
223
|
+
url: '/api/auth/get-session',
|
|
224
|
+
timeout: API_TIMEOUT,
|
|
225
|
+
failOnStatusCode: false
|
|
226
|
+
}).its('status').should('eq', 200)
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Login as Default Theme Viewer
|
|
233
|
+
* Session is cached and reused across tests
|
|
234
|
+
*/
|
|
235
|
+
export function loginAsDefaultViewer() {
|
|
236
|
+
cy.session('default-viewer-session', () => {
|
|
237
|
+
apiLogin(DEFAULT_THEME_USERS.VIEWER).then((apiLoginSucceeded) => {
|
|
238
|
+
if (apiLoginSucceeded) {
|
|
239
|
+
cy.visit('/dashboard', { timeout: 60000 })
|
|
240
|
+
}
|
|
241
|
+
cy.url().should('include', '/dashboard')
|
|
242
|
+
setupTeamContext()
|
|
243
|
+
})
|
|
244
|
+
}, {
|
|
245
|
+
validate: () => {
|
|
246
|
+
cy.request({
|
|
247
|
+
url: '/api/auth/get-session',
|
|
248
|
+
timeout: API_TIMEOUT,
|
|
249
|
+
failOnStatusCode: false
|
|
250
|
+
}).its('status').should('eq', 200)
|
|
251
|
+
}
|
|
252
|
+
})
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Login as Default Theme Editor
|
|
257
|
+
* Session is cached and reused across tests
|
|
258
|
+
*
|
|
259
|
+
* Editor is a custom role with limited permissions:
|
|
260
|
+
* - Can view/list customers but cannot create/update/delete
|
|
261
|
+
* - Cannot access Admin or Dev Zone
|
|
262
|
+
*/
|
|
263
|
+
export function loginAsDefaultEditor() {
|
|
264
|
+
cy.session('default-editor-session', () => {
|
|
265
|
+
apiLogin(DEFAULT_THEME_USERS.EDITOR).then((apiLoginSucceeded) => {
|
|
266
|
+
if (apiLoginSucceeded) {
|
|
267
|
+
cy.visit('/dashboard', { timeout: 60000 })
|
|
268
|
+
}
|
|
269
|
+
cy.url().should('include', '/dashboard')
|
|
270
|
+
setupTeamContext()
|
|
271
|
+
})
|
|
272
|
+
}, {
|
|
273
|
+
validate: () => {
|
|
274
|
+
cy.request({
|
|
275
|
+
url: '/api/auth/get-session',
|
|
276
|
+
timeout: API_TIMEOUT,
|
|
277
|
+
failOnStatusCode: false
|
|
278
|
+
}).its('status').should('eq', 200)
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Login as Superadmin (core system user)
|
|
285
|
+
* Session is cached and reused across tests
|
|
286
|
+
*
|
|
287
|
+
* Superadmin has global access:
|
|
288
|
+
* - Full Admin access
|
|
289
|
+
* - Not team-based (no setupTeamContext needed)
|
|
290
|
+
*/
|
|
291
|
+
export function loginAsDefaultSuperadmin() {
|
|
292
|
+
cy.session('default-superadmin-session', () => {
|
|
293
|
+
apiLogin(CORE_USERS.SUPERADMIN, CORE_PASSWORD).then((apiLoginSucceeded) => {
|
|
294
|
+
if (apiLoginSucceeded) {
|
|
295
|
+
cy.visit('/superadmin', { timeout: 60000 })
|
|
296
|
+
}
|
|
297
|
+
// Superadmin should land on superadmin panel or dashboard
|
|
298
|
+
cy.url().should('satisfy', (url: string) => {
|
|
299
|
+
return url.includes('/superadmin') || url.includes('/dashboard')
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
}, {
|
|
303
|
+
validate: () => {
|
|
304
|
+
cy.request({
|
|
305
|
+
url: '/api/auth/get-session',
|
|
306
|
+
timeout: API_TIMEOUT,
|
|
307
|
+
failOnStatusCode: false
|
|
308
|
+
}).its('status').should('eq', 200)
|
|
309
|
+
}
|
|
310
|
+
})
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Login as Developer (core system user)
|
|
315
|
+
* Session is cached and reused across tests
|
|
316
|
+
*
|
|
317
|
+
* Developer has:
|
|
318
|
+
* - Dev Zone access
|
|
319
|
+
* - Not team-based (no setupTeamContext needed)
|
|
320
|
+
*/
|
|
321
|
+
export function loginAsDefaultDeveloper() {
|
|
322
|
+
cy.session('default-developer-session', () => {
|
|
323
|
+
apiLogin(CORE_USERS.DEVELOPER, CORE_PASSWORD).then((apiLoginSucceeded) => {
|
|
324
|
+
if (apiLoginSucceeded) {
|
|
325
|
+
cy.visit('/devtools', { timeout: 60000 })
|
|
326
|
+
}
|
|
327
|
+
// Developer should land on devtools or dashboard
|
|
328
|
+
cy.url().should('satisfy', (url: string) => {
|
|
329
|
+
return url.includes('/devtools') || url.includes('/dashboard')
|
|
330
|
+
})
|
|
331
|
+
})
|
|
332
|
+
}, {
|
|
333
|
+
validate: () => {
|
|
334
|
+
cy.request({
|
|
335
|
+
url: '/api/auth/get-session',
|
|
336
|
+
timeout: API_TIMEOUT,
|
|
337
|
+
failOnStatusCode: false
|
|
338
|
+
}).its('status').should('eq', 200)
|
|
339
|
+
}
|
|
340
|
+
})
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Aliases for convenience
|
|
344
|
+
export const loginAsOwner = loginAsDefaultOwner
|
|
345
|
+
export const loginAsMember = loginAsDefaultMember
|
|
346
|
+
export const loginAsAdmin = loginAsDefaultAdmin
|
|
347
|
+
export const loginAsEditor = loginAsDefaultEditor
|
|
348
|
+
export const loginAsViewer = loginAsDefaultViewer
|
|
349
|
+
export const loginAsSuperadmin = loginAsDefaultSuperadmin
|
|
350
|
+
export const loginAsDeveloper = loginAsDefaultDeveloper
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Returns theme users for backwards compatibility with external helper pattern.
|
|
354
|
+
* Used by tests that import { getThemeUsers } from session-helpers.
|
|
355
|
+
*/
|
|
356
|
+
export function getThemeUsers() {
|
|
357
|
+
return DEFAULT_THEME_USERS
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// ============================================================
|
|
361
|
+
// BILLING TEST USERS
|
|
362
|
+
// ============================================================
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Billing Test Users - Teams with different subscription plans
|
|
366
|
+
*
|
|
367
|
+
* These users/teams are used to test billing features from different plan perspectives:
|
|
368
|
+
* - Free Plan: Carlos's personal team (team-personal-carlos-001)
|
|
369
|
+
* - Pro Plan: Everpoint Labs (team-everpoint-001)
|
|
370
|
+
* - Enterprise Plan: Ironvale Global (team-ironvale-002)
|
|
371
|
+
*/
|
|
372
|
+
export const BILLING_TEAMS = {
|
|
373
|
+
FREE: {
|
|
374
|
+
teamId: 'team-personal-carlos-001',
|
|
375
|
+
name: 'Carlos Personal',
|
|
376
|
+
planSlug: 'free',
|
|
377
|
+
owner: 'carlos.mendoza@nextspark.dev'
|
|
378
|
+
},
|
|
379
|
+
PRO: {
|
|
380
|
+
teamId: 'team-everpoint-001',
|
|
381
|
+
name: 'Everpoint Labs',
|
|
382
|
+
planSlug: 'pro',
|
|
383
|
+
owner: 'carlos.mendoza@nextspark.dev'
|
|
384
|
+
},
|
|
385
|
+
ENTERPRISE: {
|
|
386
|
+
teamId: 'team-ironvale-002',
|
|
387
|
+
name: 'Ironvale Global',
|
|
388
|
+
planSlug: 'enterprise',
|
|
389
|
+
owner: 'ana.garcia@nextspark.dev'
|
|
390
|
+
}
|
|
391
|
+
} as const
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Switch to a specific team after login
|
|
395
|
+
* @param teamId - Team ID to switch to
|
|
396
|
+
*/
|
|
397
|
+
function switchToTeam(teamId: string) {
|
|
398
|
+
cy.window().then((win) => {
|
|
399
|
+
win.localStorage.setItem('activeTeamId', teamId)
|
|
400
|
+
})
|
|
401
|
+
|
|
402
|
+
cy.request({
|
|
403
|
+
method: 'POST',
|
|
404
|
+
url: '/api/v1/teams/switch',
|
|
405
|
+
body: { teamId },
|
|
406
|
+
timeout: API_TIMEOUT,
|
|
407
|
+
failOnStatusCode: false
|
|
408
|
+
})
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Login as Carlos and switch to Free plan team
|
|
413
|
+
* Used for testing Free plan restrictions
|
|
414
|
+
*/
|
|
415
|
+
export function loginAsFreePlanUser() {
|
|
416
|
+
cy.session('billing-free-plan-session', () => {
|
|
417
|
+
apiLogin(BILLING_TEAMS.FREE.owner).then((apiLoginSucceeded) => {
|
|
418
|
+
if (apiLoginSucceeded) {
|
|
419
|
+
cy.visit('/dashboard', { timeout: 60000, failOnStatusCode: false })
|
|
420
|
+
}
|
|
421
|
+
cy.url().should('include', '/dashboard')
|
|
422
|
+
// Switch to the Free team
|
|
423
|
+
switchToTeam(BILLING_TEAMS.FREE.teamId)
|
|
424
|
+
})
|
|
425
|
+
}, {
|
|
426
|
+
validate: () => {
|
|
427
|
+
cy.request({
|
|
428
|
+
url: '/api/auth/get-session',
|
|
429
|
+
timeout: API_TIMEOUT,
|
|
430
|
+
failOnStatusCode: false
|
|
431
|
+
}).its('status').should('eq', 200)
|
|
432
|
+
|
|
433
|
+
cy.window().then((win) => {
|
|
434
|
+
const teamId = win.localStorage.getItem('activeTeamId')
|
|
435
|
+
expect(teamId).to.eq(BILLING_TEAMS.FREE.teamId)
|
|
436
|
+
})
|
|
437
|
+
}
|
|
438
|
+
})
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Login as Carlos and switch to Pro plan team (Everpoint)
|
|
443
|
+
* Used for testing Pro plan features
|
|
444
|
+
*/
|
|
445
|
+
export function loginAsProPlanUser() {
|
|
446
|
+
cy.session('billing-pro-plan-session', () => {
|
|
447
|
+
apiLogin(BILLING_TEAMS.PRO.owner).then((apiLoginSucceeded) => {
|
|
448
|
+
if (apiLoginSucceeded) {
|
|
449
|
+
cy.visit('/dashboard', { timeout: 60000, failOnStatusCode: false })
|
|
450
|
+
}
|
|
451
|
+
cy.url().should('include', '/dashboard')
|
|
452
|
+
// Switch to the Pro team
|
|
453
|
+
switchToTeam(BILLING_TEAMS.PRO.teamId)
|
|
454
|
+
})
|
|
455
|
+
}, {
|
|
456
|
+
validate: () => {
|
|
457
|
+
cy.request({
|
|
458
|
+
url: '/api/auth/get-session',
|
|
459
|
+
timeout: API_TIMEOUT,
|
|
460
|
+
failOnStatusCode: false
|
|
461
|
+
}).its('status').should('eq', 200)
|
|
462
|
+
|
|
463
|
+
cy.window().then((win) => {
|
|
464
|
+
const teamId = win.localStorage.getItem('activeTeamId')
|
|
465
|
+
expect(teamId).to.eq(BILLING_TEAMS.PRO.teamId)
|
|
466
|
+
})
|
|
467
|
+
}
|
|
468
|
+
})
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Login as Ana and switch to Enterprise plan team (Ironvale)
|
|
473
|
+
* Used for testing Enterprise plan features
|
|
474
|
+
*/
|
|
475
|
+
export function loginAsEnterprisePlanUser() {
|
|
476
|
+
cy.session('billing-enterprise-plan-session', () => {
|
|
477
|
+
// Ana is owner of Ironvale
|
|
478
|
+
apiLogin(BILLING_TEAMS.ENTERPRISE.owner).then((apiLoginSucceeded) => {
|
|
479
|
+
if (apiLoginSucceeded) {
|
|
480
|
+
cy.visit('/dashboard', { timeout: 60000, failOnStatusCode: false })
|
|
481
|
+
}
|
|
482
|
+
cy.url().should('include', '/dashboard')
|
|
483
|
+
// Switch to the Enterprise team
|
|
484
|
+
switchToTeam(BILLING_TEAMS.ENTERPRISE.teamId)
|
|
485
|
+
})
|
|
486
|
+
}, {
|
|
487
|
+
validate: () => {
|
|
488
|
+
cy.request({
|
|
489
|
+
url: '/api/auth/get-session',
|
|
490
|
+
timeout: API_TIMEOUT,
|
|
491
|
+
failOnStatusCode: false
|
|
492
|
+
}).its('status').should('eq', 200)
|
|
493
|
+
|
|
494
|
+
cy.window().then((win) => {
|
|
495
|
+
const teamId = win.localStorage.getItem('activeTeamId')
|
|
496
|
+
expect(teamId).to.eq(BILLING_TEAMS.ENTERPRISE.teamId)
|
|
497
|
+
})
|
|
498
|
+
}
|
|
499
|
+
})
|
|
500
|
+
}
|