@nextsparkjs/theme-default 0.1.0-beta.20 → 0.1.0-beta.21
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.config.ts +150 -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,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SuperadminTeamRolesPOM - Page Object Model for Admin Team Roles Matrix
|
|
3
|
+
*
|
|
4
|
+
* Tests the consolidated permissions matrix that shows:
|
|
5
|
+
* - All team roles with hierarchy levels
|
|
6
|
+
* - Permissions grouped by category
|
|
7
|
+
* - Visual indicators for permission grants (checkmarks)
|
|
8
|
+
* - Dangerous permissions highlighted
|
|
9
|
+
*
|
|
10
|
+
* @version 3.0 - Uses centralized selectors from cySelector()
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // Verify matrix displays all roles
|
|
14
|
+
* SuperadminTeamRolesPOM.create()
|
|
15
|
+
* .visit()
|
|
16
|
+
* .verifyRolesDisplayed(['owner', 'admin', 'member', 'editor', 'viewer'])
|
|
17
|
+
*
|
|
18
|
+
* // Check editor permissions
|
|
19
|
+
* SuperadminTeamRolesPOM.create()
|
|
20
|
+
* .visit()
|
|
21
|
+
* .verifyHasPermission('editor', 'customers.list')
|
|
22
|
+
* .verifyNoPermission('editor', 'customers.create')
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { BasePOM } from '../core/BasePOM'
|
|
26
|
+
import { cySelector } from '../selectors'
|
|
27
|
+
|
|
28
|
+
export interface RoleHierarchy {
|
|
29
|
+
role: string
|
|
30
|
+
level: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class SuperadminTeamRolesPOM extends BasePOM {
|
|
34
|
+
// ============================================
|
|
35
|
+
// FACTORY METHOD
|
|
36
|
+
// ============================================
|
|
37
|
+
|
|
38
|
+
static create(): SuperadminTeamRolesPOM {
|
|
39
|
+
return new SuperadminTeamRolesPOM()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ============================================
|
|
43
|
+
// SELECTORS using centralized cySelector()
|
|
44
|
+
// ============================================
|
|
45
|
+
|
|
46
|
+
get selectors() {
|
|
47
|
+
return {
|
|
48
|
+
// Page structure
|
|
49
|
+
pageTitle: 'h1',
|
|
50
|
+
backButton: cySelector('superadmin.teamRoles.backButton'),
|
|
51
|
+
|
|
52
|
+
// Stats cards (use contains since no specific data-cy)
|
|
53
|
+
statsCard: '.grid-cols-1 .border',
|
|
54
|
+
|
|
55
|
+
// Role cards in hierarchy section
|
|
56
|
+
roleCard: (role: string) => cySelector('superadmin.teamRoles.roleCard', { role }),
|
|
57
|
+
roleHierarchyBadge: '.font-semibold',
|
|
58
|
+
|
|
59
|
+
// Permissions matrix table
|
|
60
|
+
matrixTable: '.rounded-md.border table',
|
|
61
|
+
permissionRow: (permission: string) =>
|
|
62
|
+
cySelector('superadmin.permissions.row', { permission: permission.replace(/\./g, '-') }),
|
|
63
|
+
|
|
64
|
+
// Category headers
|
|
65
|
+
categoryHeader: '.bg-muted\\/50',
|
|
66
|
+
|
|
67
|
+
// Permission checkmarks and X marks (Lucide icons with Tailwind classes)
|
|
68
|
+
// Note: These are SVG elements with the class applied
|
|
69
|
+
checkmark: 'svg.lucide-check, .text-green-600',
|
|
70
|
+
xMark: 'svg.lucide-x',
|
|
71
|
+
|
|
72
|
+
// Dangerous permission badge (Badge component with variant="destructive")
|
|
73
|
+
dangerousBadge: '[class*="destructive"]',
|
|
74
|
+
|
|
75
|
+
// Legend section
|
|
76
|
+
legend: '.bg-muted\\/30',
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ============================================
|
|
81
|
+
// NAVIGATION
|
|
82
|
+
// ============================================
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Navigate to Team Roles page
|
|
86
|
+
*/
|
|
87
|
+
visit() {
|
|
88
|
+
cy.visit('/superadmin/team-roles')
|
|
89
|
+
this.waitForPageLoad()
|
|
90
|
+
return this
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Wait for page to fully load
|
|
95
|
+
*/
|
|
96
|
+
waitForPageLoad() {
|
|
97
|
+
cy.get(this.selectors.matrixTable, { timeout: 15000 }).should('be.visible')
|
|
98
|
+
return this
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ============================================
|
|
102
|
+
// ROLE CARDS (HIERARCHY SECTION)
|
|
103
|
+
// ============================================
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get a role card by role name
|
|
107
|
+
*/
|
|
108
|
+
getRoleCard(role: string) {
|
|
109
|
+
return cy.get(this.selectors.roleCard(role))
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Verify all expected roles are displayed
|
|
114
|
+
*/
|
|
115
|
+
verifyRolesDisplayed(expectedRoles: string[]) {
|
|
116
|
+
for (const role of expectedRoles) {
|
|
117
|
+
this.getRoleCard(role).should('be.visible')
|
|
118
|
+
}
|
|
119
|
+
return this
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Verify role hierarchy level
|
|
124
|
+
*/
|
|
125
|
+
verifyRoleHierarchy(role: string, expectedLevel: number) {
|
|
126
|
+
this.getRoleCard(role)
|
|
127
|
+
.find('.font-semibold')
|
|
128
|
+
.first()
|
|
129
|
+
.should('contain', expectedLevel.toString())
|
|
130
|
+
return this
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get permission count text for a role
|
|
135
|
+
*/
|
|
136
|
+
getPermissionCount(role: string) {
|
|
137
|
+
return this.getRoleCard(role).find('.text-muted-foreground')
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Verify role has expected permission count
|
|
142
|
+
*/
|
|
143
|
+
verifyPermissionCount(role: string, expectedCount: number) {
|
|
144
|
+
this.getPermissionCount(role).should('contain', `${expectedCount} permissions`)
|
|
145
|
+
return this
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ============================================
|
|
149
|
+
// PERMISSIONS MATRIX
|
|
150
|
+
// ============================================
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get a permission row by permission ID
|
|
154
|
+
*/
|
|
155
|
+
getPermissionRow(permission: string) {
|
|
156
|
+
return cy.get(this.selectors.permissionRow(permission))
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get column index for a role in the matrix
|
|
161
|
+
* Roles are sorted by hierarchy: owner, admin, member, editor, viewer
|
|
162
|
+
*/
|
|
163
|
+
private getRoleColumnIndex(role: string): number {
|
|
164
|
+
const roleOrder = ['owner', 'admin', 'member', 'editor', 'viewer']
|
|
165
|
+
const index = roleOrder.indexOf(role)
|
|
166
|
+
// +2 because first column is permission name
|
|
167
|
+
return index >= 0 ? index + 2 : -1
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Verify a role has a specific permission (green checkmark)
|
|
172
|
+
*/
|
|
173
|
+
verifyHasPermission(role: string, permission: string) {
|
|
174
|
+
const colIndex = this.getRoleColumnIndex(role)
|
|
175
|
+
this.getPermissionRow(permission)
|
|
176
|
+
.find(`td:nth-child(${colIndex})`)
|
|
177
|
+
.find(this.selectors.checkmark)
|
|
178
|
+
.should('exist')
|
|
179
|
+
return this
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Verify a role does NOT have a specific permission (red X)
|
|
184
|
+
*/
|
|
185
|
+
verifyNoPermission(role: string, permission: string) {
|
|
186
|
+
const colIndex = this.getRoleColumnIndex(role)
|
|
187
|
+
this.getPermissionRow(permission)
|
|
188
|
+
.find(`td:nth-child(${colIndex})`)
|
|
189
|
+
.find(this.selectors.xMark)
|
|
190
|
+
.should('exist')
|
|
191
|
+
return this
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Verify a permission is marked as dangerous
|
|
196
|
+
* The dangerous badge contains text "dangerous" with destructive styling
|
|
197
|
+
*/
|
|
198
|
+
verifyDangerousPermission(permission: string) {
|
|
199
|
+
this.getPermissionRow(permission)
|
|
200
|
+
.scrollIntoView()
|
|
201
|
+
.contains('dangerous')
|
|
202
|
+
.should('be.visible')
|
|
203
|
+
return this
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Verify permission row shows permission ID with dangerous styling
|
|
208
|
+
*/
|
|
209
|
+
verifyDangerousPermissionText(permission: string) {
|
|
210
|
+
this.getPermissionRow(permission)
|
|
211
|
+
.find('.text-red-600')
|
|
212
|
+
.should('contain', permission)
|
|
213
|
+
return this
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ============================================
|
|
217
|
+
// CATEGORY HEADERS
|
|
218
|
+
// ============================================
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get all category headers
|
|
222
|
+
*/
|
|
223
|
+
getCategoryHeaders() {
|
|
224
|
+
return cy.get(this.selectors.categoryHeader)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Verify expected categories are present
|
|
229
|
+
*/
|
|
230
|
+
verifyCategoriesPresent(categories: string[]) {
|
|
231
|
+
for (const category of categories) {
|
|
232
|
+
this.getCategoryHeaders().should('contain', category)
|
|
233
|
+
}
|
|
234
|
+
return this
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ============================================
|
|
238
|
+
// STATS CARDS
|
|
239
|
+
// ============================================
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Verify stats card shows expected value
|
|
243
|
+
*/
|
|
244
|
+
verifyStatsCard(title: string, value: string) {
|
|
245
|
+
cy.contains('.font-medium', title)
|
|
246
|
+
.parents('.border')
|
|
247
|
+
.find('.text-2xl')
|
|
248
|
+
.should('contain', value)
|
|
249
|
+
return this
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ============================================
|
|
253
|
+
// ASSERTIONS
|
|
254
|
+
// ============================================
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Verify owner has all permissions (all checkmarks)
|
|
258
|
+
*/
|
|
259
|
+
verifyOwnerHasAllPermissions() {
|
|
260
|
+
// Owner column should have no X marks
|
|
261
|
+
cy.get(this.selectors.matrixTable)
|
|
262
|
+
.find('tbody tr:not(.bg-muted\\/50)')
|
|
263
|
+
.each(($row) => {
|
|
264
|
+
cy.wrap($row)
|
|
265
|
+
.find('td:nth-child(2)') // Owner is first role column
|
|
266
|
+
.find(this.selectors.checkmark)
|
|
267
|
+
.should('exist')
|
|
268
|
+
})
|
|
269
|
+
return this
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Verify editor has specific permission set
|
|
274
|
+
*/
|
|
275
|
+
verifyEditorPermissions(expected: { permission: string; hasAccess: boolean }[]) {
|
|
276
|
+
for (const { permission, hasAccess } of expected) {
|
|
277
|
+
if (hasAccess) {
|
|
278
|
+
this.verifyHasPermission('editor', permission)
|
|
279
|
+
} else {
|
|
280
|
+
this.verifyNoPermission('editor', permission)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return this
|
|
284
|
+
}
|
|
285
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature POM exports
|
|
3
|
+
*
|
|
4
|
+
* Specialized POMs for complex features:
|
|
5
|
+
* - PageBuilderPOM: Create/edit pages with blocks
|
|
6
|
+
* - PostEditorPOM: Create/edit posts with blocks
|
|
7
|
+
* - PublicPagePOM: Test public page rendering
|
|
8
|
+
* - PublicPostPOM: Test public post rendering
|
|
9
|
+
* - AdminTeamRolesPOM: Admin team roles matrix
|
|
10
|
+
* - DashboardPOM: Dashboard navigation and shell
|
|
11
|
+
* - SettingsPOM: Settings area (profile, team, billing)
|
|
12
|
+
* - AdminPOM: Superadmin area
|
|
13
|
+
* - BillingPOM: Billing settings
|
|
14
|
+
* - DevtoolsPOM: Developer tools area
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export { PageBuilderPOM, type PageFormData, type BlockData as PageBlockData } from './PageBuilderPOM'
|
|
18
|
+
export { PostEditorPOM, type PostFormData, type BlockData as PostBlockData } from './PostEditorPOM'
|
|
19
|
+
export { AdminTeamRolesPOM, type RoleHierarchy } from './AdminTeamRolesPOM'
|
|
20
|
+
export { DashboardPOM } from './DashboardPOM'
|
|
21
|
+
export { SettingsPOM } from './SettingsPOM'
|
|
22
|
+
export { AdminPOM } from './AdminPOM'
|
|
23
|
+
export { BillingPOM } from './BillingPOM'
|
|
24
|
+
export { DevtoolsPOM } from './DevtoolsPOM'
|
|
25
|
+
|
|
26
|
+
// Re-export public POMs from components (until migrated)
|
|
27
|
+
export { PublicPagePOM } from '../components/PublicPagePOM'
|
|
28
|
+
export { PublicPostPOM } from '../components/PublicPostPOM'
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ApiInterceptor - Helper para waits determinísticos en Cypress
|
|
3
|
+
*
|
|
4
|
+
* Reemplaza cy.wait(ms) poco fiables con waits basados en cy.intercept()
|
|
5
|
+
* que esperan respuestas reales de la API.
|
|
6
|
+
*
|
|
7
|
+
* Uso básico:
|
|
8
|
+
* const api = new ApiInterceptor('customers')
|
|
9
|
+
* api.setupCrudIntercepts()
|
|
10
|
+
* cy.visit('/dashboard/customers')
|
|
11
|
+
* api.waitForList()
|
|
12
|
+
*
|
|
13
|
+
* Uso con ruta custom:
|
|
14
|
+
* const api = new ApiInterceptor({
|
|
15
|
+
* slug: 'categories',
|
|
16
|
+
* customPath: '/api/v1/post-categories'
|
|
17
|
+
* })
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export interface ApiInterceptorConfig {
|
|
21
|
+
/** Entity slug - usado para generar aliases */
|
|
22
|
+
slug: string
|
|
23
|
+
/** Ruta API custom (ej: '/api/v1/post-categories') */
|
|
24
|
+
customPath?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class ApiInterceptor {
|
|
28
|
+
private slug: string
|
|
29
|
+
private endpoint: string
|
|
30
|
+
|
|
31
|
+
constructor(slugOrConfig: string | ApiInterceptorConfig) {
|
|
32
|
+
if (typeof slugOrConfig === 'string') {
|
|
33
|
+
this.slug = slugOrConfig
|
|
34
|
+
this.endpoint = `/api/v1/${slugOrConfig}`
|
|
35
|
+
} else {
|
|
36
|
+
this.slug = slugOrConfig.slug
|
|
37
|
+
this.endpoint = slugOrConfig.customPath || `/api/v1/${slugOrConfig.slug}`
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ============================================
|
|
42
|
+
// ACCESSORS
|
|
43
|
+
// ============================================
|
|
44
|
+
|
|
45
|
+
/** Get the API endpoint path */
|
|
46
|
+
get path(): string {
|
|
47
|
+
return this.endpoint
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Get the entity slug */
|
|
51
|
+
get entitySlug(): string {
|
|
52
|
+
return this.slug
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Get alias names for all operations */
|
|
56
|
+
get aliases() {
|
|
57
|
+
return {
|
|
58
|
+
list: `${this.slug}List`,
|
|
59
|
+
create: `${this.slug}Create`,
|
|
60
|
+
update: `${this.slug}Update`,
|
|
61
|
+
delete: `${this.slug}Delete`
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ============================================
|
|
66
|
+
// INTERCEPT SETUP
|
|
67
|
+
// ============================================
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Setup intercepts for all CRUD operations
|
|
71
|
+
* Call this BEFORE navigation in beforeEach or at test start
|
|
72
|
+
*
|
|
73
|
+
* Note: We intercept both PUT and PATCH for updates since different
|
|
74
|
+
* APIs may use different HTTP methods for updates.
|
|
75
|
+
*/
|
|
76
|
+
setupCrudIntercepts(): this {
|
|
77
|
+
cy.intercept('GET', `${this.endpoint}*`).as(this.aliases.list)
|
|
78
|
+
cy.intercept('POST', this.endpoint).as(this.aliases.create)
|
|
79
|
+
// Intercept both PUT and PATCH for updates (APIs may use either)
|
|
80
|
+
cy.intercept('PUT', `${this.endpoint}/*`).as(this.aliases.update)
|
|
81
|
+
cy.intercept('PATCH', `${this.endpoint}/*`).as(`${this.aliases.update}Patch`)
|
|
82
|
+
cy.intercept('DELETE', `${this.endpoint}/*`).as(this.aliases.delete)
|
|
83
|
+
return this
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Setup only list + create intercepts
|
|
88
|
+
* Useful for list pages with inline create
|
|
89
|
+
*/
|
|
90
|
+
setupListIntercepts(): this {
|
|
91
|
+
cy.intercept('GET', `${this.endpoint}*`).as(this.aliases.list)
|
|
92
|
+
cy.intercept('POST', this.endpoint).as(this.aliases.create)
|
|
93
|
+
return this
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ============================================
|
|
97
|
+
// WAIT METHODS
|
|
98
|
+
// ============================================
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Wait for list response (GET)
|
|
102
|
+
* Use after navigation or after mutations to wait for refresh
|
|
103
|
+
*/
|
|
104
|
+
waitForList(timeout = 10000): Cypress.Chainable {
|
|
105
|
+
return cy.wait(`@${this.aliases.list}`, { timeout })
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Wait for create response (POST) and validate success status
|
|
110
|
+
*/
|
|
111
|
+
waitForCreate(timeout = 10000): Cypress.Chainable {
|
|
112
|
+
return cy.wait(`@${this.aliases.create}`, { timeout })
|
|
113
|
+
.its('response.statusCode')
|
|
114
|
+
.should('be.oneOf', [200, 201])
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Wait for update response (PATCH or PUT) and validate success status
|
|
119
|
+
* Waits for PATCH first (more common), falls back to PUT
|
|
120
|
+
*/
|
|
121
|
+
waitForUpdate(timeout = 10000): Cypress.Chainable {
|
|
122
|
+
// Try PATCH first (more common in modern APIs), fall back to PUT
|
|
123
|
+
return cy.wait(`@${this.aliases.update}Patch`, { timeout })
|
|
124
|
+
.its('response.statusCode')
|
|
125
|
+
.should('be.oneOf', [200, 201])
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Wait for delete response (DELETE) and validate success status
|
|
130
|
+
*/
|
|
131
|
+
waitForDelete(timeout = 10000): Cypress.Chainable {
|
|
132
|
+
return cy.wait(`@${this.aliases.delete}`, { timeout })
|
|
133
|
+
.its('response.statusCode')
|
|
134
|
+
.should('be.oneOf', [200, 204])
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ============================================
|
|
138
|
+
// CONVENIENCE METHODS
|
|
139
|
+
// ============================================
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Wait for list refresh (alias for waitForList)
|
|
143
|
+
* Semantic name for use after create/update/delete
|
|
144
|
+
*/
|
|
145
|
+
waitForRefresh(timeout = 10000): Cypress.Chainable {
|
|
146
|
+
return this.waitForList(timeout)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Wait for create + list refresh
|
|
151
|
+
* Common pattern: create entity, wait for success, wait for list to refresh
|
|
152
|
+
*/
|
|
153
|
+
waitForCreateAndRefresh(timeout = 10000): Cypress.Chainable {
|
|
154
|
+
this.waitForCreate(timeout)
|
|
155
|
+
return this.waitForList(timeout)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Wait for update + list refresh
|
|
160
|
+
* Common pattern: update entity, wait for success, wait for list to refresh
|
|
161
|
+
*/
|
|
162
|
+
waitForUpdateAndRefresh(timeout = 10000): Cypress.Chainable {
|
|
163
|
+
this.waitForUpdate(timeout)
|
|
164
|
+
return this.waitForList(timeout)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Wait for delete + list refresh
|
|
169
|
+
* Common pattern: delete entity, wait for success, wait for list to refresh
|
|
170
|
+
*/
|
|
171
|
+
waitForDeleteAndRefresh(timeout = 10000): Cypress.Chainable {
|
|
172
|
+
this.waitForDelete(timeout)
|
|
173
|
+
return this.waitForList(timeout)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export default ApiInterceptor
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default Theme - Cypress POM Exports
|
|
3
|
+
*
|
|
4
|
+
* Centralized exports for all Default theme Page Object Models and helpers.
|
|
5
|
+
*
|
|
6
|
+
* Architecture (v2.0):
|
|
7
|
+
* - core/: Base classes (BasePOM, DashboardEntityPOM, BlockEditorBasePOM, AuthPOM)
|
|
8
|
+
* - entities/: Entity POMs extending DashboardEntityPOM (TasksPOM, CustomersPOM, etc.)
|
|
9
|
+
* - features/: Feature POMs for complex UIs (PageBuilderPOM, PostEditorPOM)
|
|
10
|
+
* - helpers/: Utility classes (ApiInterceptor)
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* // New architecture (recommended)
|
|
14
|
+
* import { TasksPOM, CustomersPOM, AuthPOM, PageBuilderPOM } from '../src'
|
|
15
|
+
* const tasks = TasksPOM.create()
|
|
16
|
+
* tasks.visitList().waitForList().clickAdd()
|
|
17
|
+
*
|
|
18
|
+
* // Session helpers
|
|
19
|
+
* import { loginAsOwner, loginAsMember } from '../src'
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
// ============================================
|
|
23
|
+
// CORE - Base Classes
|
|
24
|
+
// ============================================
|
|
25
|
+
export {
|
|
26
|
+
BasePOM,
|
|
27
|
+
DashboardEntityPOM,
|
|
28
|
+
BlockEditorBasePOM,
|
|
29
|
+
AuthPOM,
|
|
30
|
+
type EntityConfig,
|
|
31
|
+
type SignupData
|
|
32
|
+
} from './core'
|
|
33
|
+
|
|
34
|
+
// ============================================
|
|
35
|
+
// ENTITIES - Entity POMs (extend DashboardEntityPOM)
|
|
36
|
+
// New instance-based POMs - use .create() factory method
|
|
37
|
+
// ============================================
|
|
38
|
+
export {
|
|
39
|
+
TasksPOM as TasksPOMv2,
|
|
40
|
+
CustomersPOM as CustomersPOMv2,
|
|
41
|
+
PostsPOM as PostsPOMv2,
|
|
42
|
+
PagesPOM as PagesPOMv2,
|
|
43
|
+
type TaskFormData,
|
|
44
|
+
type CustomerFormData,
|
|
45
|
+
type PostListFilters,
|
|
46
|
+
type PageListFilters
|
|
47
|
+
} from './entities'
|
|
48
|
+
|
|
49
|
+
// ============================================
|
|
50
|
+
// FEATURES - Feature POMs (block editors, public pages)
|
|
51
|
+
// New instance-based POMs - use .create() factory method
|
|
52
|
+
// ============================================
|
|
53
|
+
export {
|
|
54
|
+
PageBuilderPOM as PageBuilderPOMv2,
|
|
55
|
+
PostEditorPOM as PostEditorPOMv2,
|
|
56
|
+
AdminTeamRolesPOM,
|
|
57
|
+
PublicPagePOM,
|
|
58
|
+
PublicPostPOM,
|
|
59
|
+
type PageFormData,
|
|
60
|
+
type PostFormData,
|
|
61
|
+
type PageBlockData,
|
|
62
|
+
type PostBlockData,
|
|
63
|
+
type RoleHierarchy
|
|
64
|
+
} from './features'
|
|
65
|
+
|
|
66
|
+
// ============================================
|
|
67
|
+
// HELPERS
|
|
68
|
+
// ============================================
|
|
69
|
+
export { ApiInterceptor, type ApiInterceptorConfig } from './helpers/ApiInterceptor'
|
|
70
|
+
|
|
71
|
+
// ============================================
|
|
72
|
+
// SESSION HELPERS
|
|
73
|
+
// ============================================
|
|
74
|
+
export {
|
|
75
|
+
DEFAULT_THEME_USERS,
|
|
76
|
+
loginAsDefaultOwner,
|
|
77
|
+
loginAsDefaultAdmin,
|
|
78
|
+
loginAsDefaultMember,
|
|
79
|
+
loginAsDefaultEditor,
|
|
80
|
+
loginAsDefaultViewer,
|
|
81
|
+
loginAsOwner,
|
|
82
|
+
loginAsMember,
|
|
83
|
+
loginAsAdmin,
|
|
84
|
+
loginAsEditor,
|
|
85
|
+
loginAsViewer,
|
|
86
|
+
} from './session-helpers'
|
|
87
|
+
|
|
88
|
+
// ============================================
|
|
89
|
+
// LEGACY/STATIC POMs (backward compatible - use v2 for new code)
|
|
90
|
+
// These use static methods and work with existing tests
|
|
91
|
+
// ============================================
|
|
92
|
+
export { TasksPOM } from './components/TasksPOM'
|
|
93
|
+
export { CustomersPOM } from './components/CustomersPOM'
|
|
94
|
+
export { PageBuilderPOM } from './components/PageBuilderPOM'
|
|
95
|
+
export { PostEditorPOM } from './components/PostEditorPOM'
|
|
96
|
+
export { PostsListPOM } from './components/PostsListPOM'
|
|
97
|
+
export { CategoriesPOM } from './components/CategoriesPOM'
|
|
98
|
+
|
|
99
|
+
// Generic entity components
|
|
100
|
+
export { EntityList } from './components/EntityList'
|
|
101
|
+
export { EntityForm } from './components/EntityForm'
|