@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.
Files changed (220) hide show
  1. package/package.json +1 -1
  2. package/tests/cypress/e2e/_devtools/access.bdd.md +262 -0
  3. package/tests/cypress/e2e/_devtools/access.cy.ts +171 -0
  4. package/tests/cypress/e2e/_devtools/navigation.bdd.md +261 -0
  5. package/tests/cypress/e2e/_devtools/navigation.cy.ts +157 -0
  6. package/tests/cypress/e2e/_devtools/pages.bdd.md +303 -0
  7. package/tests/cypress/e2e/_devtools/pages.cy.ts +184 -0
  8. package/tests/cypress/e2e/_docs/README.md +215 -0
  9. package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin-teams.narration.json +155 -0
  10. package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin.cy.ts +390 -0
  11. package/tests/cypress/e2e/_docs/tutorials/teams-system.doc.cy.ts +349 -0
  12. package/tests/cypress/e2e/_docs/tutorials/teams-system.narration.json +165 -0
  13. package/tests/cypress/e2e/_selectors/auth.cy.ts +306 -0
  14. package/tests/cypress/e2e/_selectors/billing.cy.ts +89 -0
  15. package/tests/cypress/e2e/_selectors/dashboard-mobile.cy.ts +113 -0
  16. package/tests/cypress/e2e/_selectors/dashboard-navigation.cy.ts +89 -0
  17. package/tests/cypress/e2e/_selectors/dashboard-sidebar.cy.ts +60 -0
  18. package/tests/cypress/e2e/_selectors/dashboard-topnav.cy.ts +146 -0
  19. package/tests/cypress/e2e/_selectors/devtools.cy.ts +210 -0
  20. package/tests/cypress/e2e/_selectors/global-search.cy.ts +88 -0
  21. package/tests/cypress/e2e/_selectors/pages-editor.cy.ts +179 -0
  22. package/tests/cypress/e2e/_selectors/posts-editor.cy.ts +282 -0
  23. package/tests/cypress/e2e/_selectors/public.cy.ts +112 -0
  24. package/tests/cypress/e2e/_selectors/settings-api-keys.cy.ts +228 -0
  25. package/tests/cypress/e2e/_selectors/settings-billing.cy.ts +105 -0
  26. package/tests/cypress/e2e/_selectors/settings-layout.cy.ts +119 -0
  27. package/tests/cypress/e2e/_selectors/settings-password.cy.ts +71 -0
  28. package/tests/cypress/e2e/_selectors/settings-profile.cy.ts +82 -0
  29. package/tests/cypress/e2e/_selectors/settings-teams.cy.ts +68 -0
  30. package/tests/cypress/e2e/_selectors/superadmin.cy.ts +185 -0
  31. package/tests/cypress/e2e/_selectors/tasks.cy.ts +242 -0
  32. package/tests/cypress/e2e/_selectors/taxonomies.cy.ts +126 -0
  33. package/tests/cypress/e2e/_selectors/teams.cy.ts +142 -0
  34. package/tests/cypress/e2e/_superadmin/all-teams.bdd.md +261 -0
  35. package/tests/cypress/e2e/_superadmin/all-teams.cy.ts +177 -0
  36. package/tests/cypress/e2e/_superadmin/all-users.bdd.md +406 -0
  37. package/tests/cypress/e2e/_superadmin/all-users.cy.ts +294 -0
  38. package/tests/cypress/e2e/_superadmin/dashboard.bdd.md +235 -0
  39. package/tests/cypress/e2e/_superadmin/dashboard.cy.ts +149 -0
  40. package/tests/cypress/e2e/_superadmin/subscriptions-overview.bdd.md +290 -0
  41. package/tests/cypress/e2e/_superadmin/subscriptions-overview.cy.ts +194 -0
  42. package/tests/cypress/e2e/ai/ai-usage.cy.ts +209 -0
  43. package/tests/cypress/e2e/ai/chat-api.cy.ts +107 -0
  44. package/tests/cypress/e2e/ai/guardrails.cy.ts +332 -0
  45. package/tests/cypress/e2e/api/billing/BillingAPIController.js +319 -0
  46. package/tests/cypress/e2e/api/billing/check-action.cy.ts +326 -0
  47. package/tests/cypress/e2e/api/billing/checkout.cy.ts +358 -0
  48. package/tests/cypress/e2e/api/billing/lifecycle.cy.ts +423 -0
  49. package/tests/cypress/e2e/api/billing/plans/README.md +345 -0
  50. package/tests/cypress/e2e/api/billing/plans/business.cy.ts +412 -0
  51. package/tests/cypress/e2e/api/billing/plans/downgrade.cy.ts +510 -0
  52. package/tests/cypress/e2e/api/billing/plans/fixtures/billing-plans.json +163 -0
  53. package/tests/cypress/e2e/api/billing/plans/free.cy.ts +500 -0
  54. package/tests/cypress/e2e/api/billing/plans/pro.cy.ts +497 -0
  55. package/tests/cypress/e2e/api/billing/plans/starter.cy.ts +342 -0
  56. package/tests/cypress/e2e/api/billing/portal.cy.ts +313 -0
  57. package/tests/cypress/e2e/api/devtools/registries.bdd.md +300 -0
  58. package/tests/cypress/e2e/api/devtools/registries.cy.ts +368 -0
  59. package/tests/cypress/e2e/api/entities/blocks-scope.cy.ts +396 -0
  60. package/tests/cypress/e2e/api/entities/customers-crud.cy.ts +648 -0
  61. package/tests/cypress/e2e/api/entities/customers-metas.cy.ts +839 -0
  62. package/tests/cypress/e2e/api/entities/pages-crud.cy.ts +425 -0
  63. package/tests/cypress/e2e/api/entities/pages-status.cy.ts +335 -0
  64. package/tests/cypress/e2e/api/entities/post-categories-crud.cy.ts +610 -0
  65. package/tests/cypress/e2e/api/entities/posts-crud.cy.ts +709 -0
  66. package/tests/cypress/e2e/api/entities/posts-status.cy.ts +396 -0
  67. package/tests/cypress/e2e/api/entities/tasks-crud.cy.ts +602 -0
  68. package/tests/cypress/e2e/api/entities/tasks-metas.cy.ts +878 -0
  69. package/tests/cypress/e2e/api/entities/users-crud.cy.ts +469 -0
  70. package/tests/cypress/e2e/api/entities/users-metas.cy.ts +913 -0
  71. package/tests/cypress/e2e/api/entities/users-security.cy.ts +375 -0
  72. package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.bdd.md +375 -0
  73. package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.cy.ts +346 -0
  74. package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.bdd.md +451 -0
  75. package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.cy.ts +447 -0
  76. package/tests/cypress/e2e/api/scheduled-actions/scheduling.bdd.md +649 -0
  77. package/tests/cypress/e2e/api/scheduled-actions/scheduling.cy.ts +333 -0
  78. package/tests/cypress/e2e/api/settings/api-keys.crud.cy.ts +923 -0
  79. package/tests/cypress/e2e/uat/auth/app-roles/developer-login.bdd.md +231 -0
  80. package/tests/cypress/e2e/uat/auth/app-roles/developer-login.cy.ts +144 -0
  81. package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.bdd.md +118 -0
  82. package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.cy.ts +84 -0
  83. package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.bdd.md +288 -0
  84. package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.cy.ts +188 -0
  85. package/tests/cypress/e2e/uat/auth/login-logout.bdd.md +160 -0
  86. package/tests/cypress/e2e/uat/auth/login-logout.cy.ts +116 -0
  87. package/tests/cypress/e2e/uat/auth/password-reset.bdd.md +289 -0
  88. package/tests/cypress/e2e/uat/auth/password-reset.cy.ts +200 -0
  89. package/tests/cypress/e2e/uat/auth/team-roles/admin-login.bdd.md +225 -0
  90. package/tests/cypress/e2e/uat/auth/team-roles/admin-login.cy.ts +148 -0
  91. package/tests/cypress/e2e/uat/auth/team-roles/member-login.bdd.md +251 -0
  92. package/tests/cypress/e2e/uat/auth/team-roles/member-login.cy.ts +163 -0
  93. package/tests/cypress/e2e/uat/auth/team-roles/owner-login.bdd.md +231 -0
  94. package/tests/cypress/e2e/uat/auth/team-roles/owner-login.cy.ts +141 -0
  95. package/tests/cypress/e2e/uat/billing/extended.bdd.md +273 -0
  96. package/tests/cypress/e2e/uat/billing/extended.cy.ts +209 -0
  97. package/tests/cypress/e2e/uat/billing/feature-gates.bdd.md +407 -0
  98. package/tests/cypress/e2e/uat/billing/feature-gates.cy.ts +307 -0
  99. package/tests/cypress/e2e/uat/billing/page.bdd.md +329 -0
  100. package/tests/cypress/e2e/uat/billing/page.cy.ts +250 -0
  101. package/tests/cypress/e2e/uat/billing/status.bdd.md +190 -0
  102. package/tests/cypress/e2e/uat/billing/status.cy.ts +145 -0
  103. package/tests/cypress/e2e/uat/billing/team-switch.bdd.md +156 -0
  104. package/tests/cypress/e2e/uat/billing/team-switch.cy.ts +122 -0
  105. package/tests/cypress/e2e/uat/billing/usage.bdd.md +218 -0
  106. package/tests/cypress/e2e/uat/billing/usage.cy.ts +176 -0
  107. package/tests/cypress/e2e/uat/blocks/hero.bdd.md +124 -0
  108. package/tests/cypress/e2e/uat/blocks/hero.cy.ts +56 -0
  109. package/tests/cypress/e2e/uat/devtools/api-tester.cy.ts +390 -0
  110. package/tests/cypress/e2e/uat/entities/customers/member.bdd.md +275 -0
  111. package/tests/cypress/e2e/uat/entities/customers/member.cy.ts +122 -0
  112. package/tests/cypress/e2e/uat/entities/customers/owner.bdd.md +243 -0
  113. package/tests/cypress/e2e/uat/entities/customers/owner.cy.ts +165 -0
  114. package/tests/cypress/e2e/uat/entities/pages/block-crud.bdd.md +476 -0
  115. package/tests/cypress/e2e/uat/entities/pages/block-crud.cy.ts +486 -0
  116. package/tests/cypress/e2e/uat/entities/pages/block-editor.bdd.md +460 -0
  117. package/tests/cypress/e2e/uat/entities/pages/block-editor.cy.ts +301 -0
  118. package/tests/cypress/e2e/uat/entities/pages/list.bdd.md +432 -0
  119. package/tests/cypress/e2e/uat/entities/pages/list.cy.ts +273 -0
  120. package/tests/cypress/e2e/uat/entities/pages/public-rendering.bdd.md +696 -0
  121. package/tests/cypress/e2e/uat/entities/pages/public-rendering.cy.ts +340 -0
  122. package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.bdd.md +161 -0
  123. package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.cy.ts +104 -0
  124. package/tests/cypress/e2e/uat/entities/posts/categories.bdd.md +375 -0
  125. package/tests/cypress/e2e/uat/entities/posts/categories.cy.ts +241 -0
  126. package/tests/cypress/e2e/uat/entities/posts/editor.bdd.md +429 -0
  127. package/tests/cypress/e2e/uat/entities/posts/editor.cy.ts +257 -0
  128. package/tests/cypress/e2e/uat/entities/posts/list.bdd.md +340 -0
  129. package/tests/cypress/e2e/uat/entities/posts/list.cy.ts +177 -0
  130. package/tests/cypress/e2e/uat/entities/posts/public.bdd.md +614 -0
  131. package/tests/cypress/e2e/uat/entities/posts/public.cy.ts +249 -0
  132. package/tests/cypress/e2e/uat/entities/tasks/member.bdd.md +222 -0
  133. package/tests/cypress/e2e/uat/entities/tasks/member.cy.ts +165 -0
  134. package/tests/cypress/e2e/uat/entities/tasks/owner.bdd.md +419 -0
  135. package/tests/cypress/e2e/uat/entities/tasks/owner.cy.ts +191 -0
  136. package/tests/cypress/e2e/uat/roles/editor-role.bdd.md +552 -0
  137. package/tests/cypress/e2e/uat/roles/editor-role.cy.ts +210 -0
  138. package/tests/cypress/e2e/uat/roles/member-restrictions.bdd.md +450 -0
  139. package/tests/cypress/e2e/uat/roles/member-restrictions.cy.ts +189 -0
  140. package/tests/cypress/e2e/uat/roles/owner-full-crud.bdd.md +530 -0
  141. package/tests/cypress/e2e/uat/roles/owner-full-crud.cy.ts +247 -0
  142. package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.bdd.md +736 -0
  143. package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.cy.ts +740 -0
  144. package/tests/cypress/e2e/uat/teams/roles-matrix.bdd.md +553 -0
  145. package/tests/cypress/e2e/uat/teams/roles-matrix.cy.ts +185 -0
  146. package/tests/cypress/e2e/uat/teams/switcher.bdd.md +1151 -0
  147. package/tests/cypress/e2e/uat/teams/switcher.cy.ts +497 -0
  148. package/tests/cypress/e2e/uat/teams/team-switcher.md +198 -0
  149. package/tests/cypress/fixtures/blocks.json +218 -0
  150. package/tests/cypress/fixtures/entities.json +78 -0
  151. package/tests/cypress/fixtures/page-builder.json +21 -0
  152. package/tests/cypress/src/components/CategoriesPOM.ts +382 -0
  153. package/tests/cypress/src/components/CustomersPOM.ts +439 -0
  154. package/tests/cypress/src/components/DevKeyringPOM.ts +160 -0
  155. package/tests/cypress/src/components/EntityForm.ts +375 -0
  156. package/tests/cypress/src/components/EntityList.ts +389 -0
  157. package/tests/cypress/src/components/PageBuilderPOM.ts +710 -0
  158. package/tests/cypress/src/components/PostEditorPOM.ts +370 -0
  159. package/tests/cypress/src/components/PostsListPOM.ts +223 -0
  160. package/tests/cypress/src/components/PublicPagePOM.ts +447 -0
  161. package/tests/cypress/src/components/PublicPostPOM.ts +146 -0
  162. package/tests/cypress/src/components/TasksPOM.ts +272 -0
  163. package/tests/cypress/src/components/TeamSwitcherPOM.ts +450 -0
  164. package/tests/cypress/src/components/index.ts +21 -0
  165. package/tests/cypress/src/controllers/ApiKeysAPIController.js +178 -0
  166. package/tests/cypress/src/controllers/BaseAPIController.js +317 -0
  167. package/tests/cypress/src/controllers/CustomerAPIController.js +251 -0
  168. package/tests/cypress/src/controllers/PagesAPIController.js +226 -0
  169. package/tests/cypress/src/controllers/PostsAPIController.js +250 -0
  170. package/tests/cypress/src/controllers/TaskAPIController.js +240 -0
  171. package/tests/cypress/src/controllers/UsersAPIController.js +242 -0
  172. package/tests/cypress/src/controllers/index.js +25 -0
  173. package/tests/cypress/src/core/AuthPOM.ts +450 -0
  174. package/tests/cypress/src/core/BasePOM.ts +86 -0
  175. package/tests/cypress/src/core/BlockEditorBasePOM.ts +576 -0
  176. package/tests/cypress/src/core/DashboardEntityPOM.ts +692 -0
  177. package/tests/cypress/src/core/index.ts +14 -0
  178. package/tests/cypress/src/entities/CustomersPOM.ts +172 -0
  179. package/tests/cypress/src/entities/PagesPOM.ts +137 -0
  180. package/tests/cypress/src/entities/PostsPOM.ts +137 -0
  181. package/tests/cypress/src/entities/TasksPOM.ts +176 -0
  182. package/tests/cypress/src/entities/index.ts +14 -0
  183. package/tests/cypress/src/features/BillingPOM.ts +385 -0
  184. package/tests/cypress/src/features/DashboardPOM.ts +245 -0
  185. package/tests/cypress/src/features/DevtoolsPOM.ts +739 -0
  186. package/tests/cypress/src/features/PageBuilderPOM.ts +263 -0
  187. package/tests/cypress/src/features/PostEditorPOM.ts +313 -0
  188. package/tests/cypress/src/features/ScheduledActionsPOM.ts +463 -0
  189. package/tests/cypress/src/features/SettingsPOM.ts +362 -0
  190. package/tests/cypress/src/features/SuperadminPOM.ts +331 -0
  191. package/tests/cypress/src/features/SuperadminTeamRolesPOM.ts +285 -0
  192. package/tests/cypress/src/features/index.ts +28 -0
  193. package/tests/cypress/src/helpers/ApiInterceptor.ts +177 -0
  194. package/tests/cypress/src/index.ts +101 -0
  195. package/tests/cypress/src/pages/dashboard/Dashboard.js +677 -0
  196. package/tests/cypress/src/pages/dashboard/DashboardPage.js +43 -0
  197. package/tests/cypress/src/pages/dashboard/DashboardStats.js +546 -0
  198. package/tests/cypress/src/pages/dashboard/index.js +6 -0
  199. package/tests/cypress/src/pages/index.js +5 -0
  200. package/tests/cypress/src/pages/public/FeaturesPage.js +28 -0
  201. package/tests/cypress/src/pages/public/LandingPage.js +69 -0
  202. package/tests/cypress/src/pages/public/PricingPage.js +33 -0
  203. package/tests/cypress/src/pages/public/index.js +6 -0
  204. package/tests/cypress/src/selectors.ts +46 -0
  205. package/tests/cypress/src/session-helpers.ts +500 -0
  206. package/tests/cypress/support/doc-commands.ts +260 -0
  207. package/tests/cypress.config.ts +150 -0
  208. package/tests/jest/components/post-header.test.tsx +377 -0
  209. package/tests/jest/config/role-config.test.ts +529 -0
  210. package/tests/jest/jest.config.ts +81 -0
  211. package/tests/jest/langchain/COVERAGE.md +372 -0
  212. package/tests/jest/langchain/guardrails.test.ts +465 -0
  213. package/tests/jest/langchain/streaming.test.ts +367 -0
  214. package/tests/jest/langchain/token-tracker.test.ts +455 -0
  215. package/tests/jest/langchain/tracer-callbacks.test.ts +881 -0
  216. package/tests/jest/langchain/tracer.test.ts +823 -0
  217. package/tests/jest/user-roles/role-helpers.test.ts +432 -0
  218. package/tests/jest/validation/categories.test.ts +429 -0
  219. package/tests/jest/validation/posts.test.ts +546 -0
  220. package/tests/tsconfig.json +15 -0
@@ -0,0 +1,385 @@
1
+ /**
2
+ * Billing Page Object Model
3
+ *
4
+ * Encapsulates interactions with the billing settings page:
5
+ * - /dashboard/settings/billing
6
+ *
7
+ * UI Elements:
8
+ * - Current plan card with usage
9
+ * - Billing history (invoices)
10
+ * - Payment method
11
+ * - Plan features
12
+ *
13
+ * @version 3.0 - Uses centralized selectors from cySelector()
14
+ */
15
+
16
+ import { BasePOM } from '../core/BasePOM'
17
+ import { cySelector } from '../selectors'
18
+
19
+ export class BillingPOM extends BasePOM {
20
+ /**
21
+ * Selectors using centralized cySelector()
22
+ */
23
+ get selectors() {
24
+ return {
25
+ main: cySelector('settings.billing.main'),
26
+ header: cySelector('settings.billing.header'),
27
+ upgradePlan: cySelector('settings.billing.upgradePlan'),
28
+ addPayment: cySelector('settings.billing.addPayment'),
29
+ invoicesTable: cySelector('settings.billing.invoicesTableAlt'),
30
+ invoicesRow: cySelector('settings.billing.invoicesRow'),
31
+ invoicesLoadMore: cySelector('settings.billing.invoicesLoadMore'),
32
+ invoiceStatusBadge: cySelector('settings.billing.invoiceStatusBadge'),
33
+ paymentMethod: cySelector('settings.billing.paymentMethod'),
34
+ usage: cySelector('settings.billing.usage'),
35
+ usageDashboard: cySelector('settings.billing.usageDashboard'),
36
+ pricingTable: cySelector('settings.pricing.table'),
37
+ pricingSettingsTable: cySelector('settings.pricing.settingsTable'),
38
+ featurePlaceholder: (feature: string) => cySelector('settings.features.placeholder', { feature }),
39
+ featureContent: (feature: string) => cySelector('settings.features.content', { feature }),
40
+ placeholderUpgradeBtn: cySelector('settings.features.placeholderUpgradeBtn'),
41
+ }
42
+ }
43
+
44
+ // Factory method for clean instantiation
45
+ static create(): BillingPOM {
46
+ return new BillingPOM()
47
+ }
48
+
49
+ // ============================================================
50
+ // NAVIGATION
51
+ // ============================================================
52
+
53
+ /**
54
+ * Visit billing settings page
55
+ * Uses failOnStatusCode: false to handle intermittent 500 errors
56
+ */
57
+ visitBilling(): BillingPOM {
58
+ cy.visit('/dashboard/settings/billing', { timeout: 60000, failOnStatusCode: false })
59
+ cy.url().should('include', '/billing')
60
+ return this
61
+ }
62
+
63
+ /**
64
+ * Visit pricing page
65
+ */
66
+ visitPricing(): BillingPOM {
67
+ cy.visit('/pricing', { timeout: 30000 })
68
+ return this
69
+ }
70
+
71
+ // ============================================================
72
+ // SELECTORS
73
+ // ============================================================
74
+
75
+ /**
76
+ * Main billing container
77
+ */
78
+ getBillingMain(): Cypress.Chainable<JQuery<HTMLElement>> {
79
+ return cy.get(this.selectors.main)
80
+ }
81
+
82
+ /**
83
+ * Billing header
84
+ */
85
+ getBillingHeader(): Cypress.Chainable<JQuery<HTMLElement>> {
86
+ return cy.get(this.selectors.header)
87
+ }
88
+
89
+ /**
90
+ * Upgrade plan button
91
+ */
92
+ getUpgradeButton(): Cypress.Chainable<JQuery<HTMLElement>> {
93
+ return cy.get(this.selectors.upgradePlan)
94
+ }
95
+
96
+ /**
97
+ * Add payment method button
98
+ */
99
+ getAddPaymentButton(): Cypress.Chainable<JQuery<HTMLElement>> {
100
+ return cy.get(this.selectors.addPayment)
101
+ }
102
+
103
+ /**
104
+ * Load more invoices button
105
+ */
106
+ getLoadMoreInvoicesButton(): Cypress.Chainable<JQuery<HTMLElement>> {
107
+ return cy.get(this.selectors.invoicesLoadMore)
108
+ }
109
+
110
+ /**
111
+ * Invoices table
112
+ */
113
+ getInvoicesTable(): Cypress.Chainable<JQuery<HTMLElement>> {
114
+ return cy.get(this.selectors.invoicesTable)
115
+ }
116
+
117
+ /**
118
+ * Invoice rows
119
+ */
120
+ getInvoiceRows(): Cypress.Chainable<JQuery<HTMLElement>> {
121
+ return cy.get(this.selectors.invoicesRow)
122
+ }
123
+
124
+ /**
125
+ * Invoice status badges
126
+ */
127
+ getInvoiceStatusBadge(): Cypress.Chainable<JQuery<HTMLElement>> {
128
+ return cy.get(this.selectors.invoiceStatusBadge)
129
+ }
130
+
131
+ // ============================================================
132
+ // ASSERTIONS
133
+ // ============================================================
134
+
135
+ /**
136
+ * Assert billing page is visible
137
+ */
138
+ assertBillingPageVisible(): BillingPOM {
139
+ this.getBillingMain().should('be.visible')
140
+ this.getBillingHeader().should('be.visible')
141
+ return this
142
+ }
143
+
144
+ /**
145
+ * Assert current plan is displayed
146
+ * @param planName Expected plan name (e.g., "Free", "Pro")
147
+ */
148
+ assertCurrentPlan(planName: string): BillingPOM {
149
+ cy.contains(planName).should('be.visible')
150
+ return this
151
+ }
152
+
153
+ /**
154
+ * Assert upgrade button is visible
155
+ */
156
+ assertUpgradeButtonVisible(): BillingPOM {
157
+ this.getUpgradeButton().should('be.visible')
158
+ return this
159
+ }
160
+
161
+ /**
162
+ * Assert invoices are displayed
163
+ * @param count Expected number of invoices (0 for empty state)
164
+ */
165
+ assertInvoicesCount(count: number): BillingPOM {
166
+ if (count === 0) {
167
+ // Empty state
168
+ cy.contains(/no invoices|sin facturas/i).should('be.visible')
169
+ } else {
170
+ this.getInvoiceRows().should('have.length.at.least', count)
171
+ }
172
+ return this
173
+ }
174
+
175
+ /**
176
+ * Assert no payment method message
177
+ */
178
+ assertNoPaymentMethod(): BillingPOM {
179
+ // Match both English and Spanish:
180
+ // EN: "No payment method configured"
181
+ // ES: "No hay método de pago configurado"
182
+ cy.contains(/no payment method configured|no hay método de pago configurado/i).should('be.visible')
183
+ return this
184
+ }
185
+
186
+ /**
187
+ * Assert usage is displayed
188
+ */
189
+ assertUsageVisible(): BillingPOM {
190
+ // Check for usage numbers (format: X / Y)
191
+ cy.contains(/\d+\s*\/\s*\d+/).should('be.visible')
192
+ return this
193
+ }
194
+
195
+ // ============================================================
196
+ // ACTIONS
197
+ // ============================================================
198
+
199
+ /**
200
+ * Click upgrade button
201
+ */
202
+ clickUpgrade(): BillingPOM {
203
+ this.getUpgradeButton().click()
204
+ return this
205
+ }
206
+
207
+ /**
208
+ * Click add payment button
209
+ */
210
+ clickAddPayment(): BillingPOM {
211
+ this.getAddPaymentButton().click()
212
+ return this
213
+ }
214
+
215
+ /**
216
+ * Load more invoices
217
+ */
218
+ loadMoreInvoices(): BillingPOM {
219
+ this.getLoadMoreInvoicesButton().click()
220
+ return this
221
+ }
222
+
223
+ // ============================================================
224
+ // FEATURE GATE ASSERTIONS
225
+ // ============================================================
226
+
227
+ /**
228
+ * Assert feature is blocked (shows upgrade message)
229
+ * @param featureName Name of the blocked feature
230
+ */
231
+ assertFeatureBlocked(featureName: string): BillingPOM {
232
+ cy.contains(new RegExp(`(upgrade|plan required|not available)`, 'i')).should('be.visible')
233
+ return this
234
+ }
235
+
236
+ /**
237
+ * Assert feature is available
238
+ * @param featureName Name of the feature
239
+ */
240
+ assertFeatureAvailable(featureName: string): BillingPOM {
241
+ // No upgrade message for this feature
242
+ cy.contains(featureName).should('be.visible')
243
+ return this
244
+ }
245
+
246
+ // ============================================================
247
+ // PRICING PAGE METHODS
248
+ // ============================================================
249
+
250
+ /**
251
+ * Visit pricing settings page
252
+ */
253
+ visitPricingSettings(): BillingPOM {
254
+ cy.visit('/dashboard/settings/pricing', { timeout: 30000 })
255
+ return this
256
+ }
257
+
258
+ /**
259
+ * Get pricing table
260
+ */
261
+ getPricingTable(): Cypress.Chainable<JQuery<HTMLElement>> {
262
+ return cy.get(`${this.selectors.pricingTable}, ${this.selectors.pricingSettingsTable}`)
263
+ }
264
+
265
+ /**
266
+ * Assert pricing table is visible
267
+ */
268
+ assertPricingTableVisible(): BillingPOM {
269
+ this.getPricingTable().should('be.visible')
270
+ return this
271
+ }
272
+
273
+ // ============================================================
274
+ // FEATURE PAGES METHODS
275
+ // ============================================================
276
+
277
+ /**
278
+ * Visit feature analytics page
279
+ */
280
+ visitAnalyticsFeature(): BillingPOM {
281
+ cy.visit('/dashboard/features/analytics', { timeout: 30000 })
282
+ return this
283
+ }
284
+
285
+ /**
286
+ * Visit feature webhooks page
287
+ */
288
+ visitWebhooksFeature(): BillingPOM {
289
+ cy.visit('/dashboard/features/webhooks', { timeout: 30000 })
290
+ return this
291
+ }
292
+
293
+ /**
294
+ * Visit feature automation page
295
+ */
296
+ visitAutomationFeature(): BillingPOM {
297
+ cy.visit('/dashboard/features/automation', { timeout: 30000 })
298
+ return this
299
+ }
300
+
301
+ /**
302
+ * Get feature placeholder
303
+ */
304
+ getFeaturePlaceholder(feature: string): Cypress.Chainable<JQuery<HTMLElement>> {
305
+ return cy.get(this.selectors.featurePlaceholder(feature))
306
+ }
307
+
308
+ /**
309
+ * Assert feature placeholder is visible
310
+ */
311
+ assertFeaturePlaceholderVisible(feature: string): BillingPOM {
312
+ this.getFeaturePlaceholder(feature).should('be.visible')
313
+ return this
314
+ }
315
+
316
+ /**
317
+ * Assert feature content is visible (user has access)
318
+ */
319
+ assertFeatureContentVisible(feature: string): BillingPOM {
320
+ cy.get(this.selectors.featureContent(feature)).should('be.visible')
321
+ return this
322
+ }
323
+
324
+ /**
325
+ * Get placeholder upgrade button
326
+ */
327
+ getPlaceholderUpgradeButton(): Cypress.Chainable<JQuery<HTMLElement>> {
328
+ return cy.get(this.selectors.placeholderUpgradeBtn)
329
+ }
330
+
331
+ /**
332
+ * Click placeholder upgrade button
333
+ */
334
+ clickPlaceholderUpgrade(): BillingPOM {
335
+ this.getPlaceholderUpgradeButton().click()
336
+ return this
337
+ }
338
+
339
+ // ============================================================
340
+ // USAGE METHODS
341
+ // ============================================================
342
+
343
+ /**
344
+ * Get usage section
345
+ */
346
+ getUsageSection(): Cypress.Chainable<JQuery<HTMLElement>> {
347
+ return cy.get(`${this.selectors.usage}, ${this.selectors.usageDashboard}`)
348
+ }
349
+
350
+ /**
351
+ * Assert usage limit is displayed
352
+ * @param limitName Name of the limit (e.g., "tasks", "customers")
353
+ * @param current Current usage (optional, just checks format if not provided)
354
+ * @param max Maximum allowed (optional)
355
+ */
356
+ assertUsageLimit(limitName: string, current?: number, max?: number): BillingPOM {
357
+ if (current !== undefined && max !== undefined) {
358
+ cy.contains(new RegExp(`${current}\\s*/\\s*${max}`, 'i')).should('be.visible')
359
+ } else {
360
+ // Just check for X / Y format
361
+ cy.contains(/\d+\s*\/\s*\d+/).should('be.visible')
362
+ }
363
+ return this
364
+ }
365
+
366
+ // ============================================================
367
+ // PAYMENT METHODS
368
+ // ============================================================
369
+
370
+ /**
371
+ * Get payment method section
372
+ */
373
+ getPaymentMethodSection(): Cypress.Chainable<JQuery<HTMLElement>> {
374
+ const paymentMethodAlt = cySelector('settings.billing.paymentMethodAlt')
375
+ return cy.get(`${this.selectors.paymentMethod}, ${paymentMethodAlt}`)
376
+ }
377
+
378
+ /**
379
+ * Assert payment method exists
380
+ */
381
+ assertPaymentMethodExists(): BillingPOM {
382
+ this.getPaymentMethodSection().should('be.visible')
383
+ return this
384
+ }
385
+ }
@@ -0,0 +1,245 @@
1
+ /**
2
+ * DashboardPOM - Page Object Model for Dashboard Navigation
3
+ *
4
+ * Handles dashboard shell navigation and access control:
5
+ * - Sidebar navigation links (nav-link-entity-{slug})
6
+ * - Entity page access verification
7
+ * - Quick create menu
8
+ * - Dashboard page access
9
+ *
10
+ * Uses selectors from centralized selectors.ts
11
+ *
12
+ * NOTE: For CRUD operations on entities, use entity-specific POMs:
13
+ * - CustomersPOM, TasksPOM, etc. from entities/
14
+ * - These extend DashboardEntityPOM for full CRUD support
15
+ *
16
+ * NOTE: For team switching, use TeamSwitcherPOM from components/
17
+ */
18
+
19
+ import { BasePOM } from '../core/BasePOM'
20
+ import { cySelector } from '../selectors'
21
+
22
+ export class DashboardPOM extends BasePOM {
23
+ // ============================================
24
+ // FACTORY METHOD
25
+ // ============================================
26
+
27
+ static create(): DashboardPOM {
28
+ return new DashboardPOM()
29
+ }
30
+
31
+ // ============================================
32
+ // SELECTORS
33
+ // ============================================
34
+
35
+ get selectors() {
36
+ return {
37
+ // Navigation
38
+ navMain: cySelector('dashboard.navigation.main'),
39
+ navDashboard: cySelector('dashboard.navigation.dashboardLink'),
40
+ navEntity: (slug: string) => cySelector('dashboard.navigation.entityLink', { slug }),
41
+ navSection: (id: string) => cySelector('dashboard.navigation.section', { id }),
42
+ navSectionLabel: (id: string) => cySelector('dashboard.navigation.sectionLabel', { id }),
43
+ navSectionItem: (sectionId: string, itemId: string) => cySelector('dashboard.navigation.sectionItem', { sectionId, itemId }),
44
+
45
+ // Shell
46
+ shellContainer: cySelector('dashboard.shell.container'),
47
+ sidebarToggle: cySelector('dashboard.shell.sidebarToggle'),
48
+ quickCreateButton: cySelector('dashboard.shell.quickCreateButton'),
49
+ quickCreateDropdown: cySelector('dashboard.shell.quickCreateDropdown'),
50
+ quickCreateLink: (slug: string) => cySelector('dashboard.shell.quickCreateLink', { slug }),
51
+
52
+ // Topnav
53
+ topnavSidebarToggle: cySelector('dashboard.topnav.sidebarToggle'),
54
+ topnavHeader: cySelector('dashboard.topnav.header'),
55
+ topnavLogo: cySelector('dashboard.topnav.logo'),
56
+ topnavSearchSection: cySelector('dashboard.topnav.searchSection'),
57
+ topnavActions: cySelector('dashboard.topnav.actions'),
58
+ topnavNotifications: cySelector('dashboard.topnav.notifications'),
59
+ topnavHelp: cySelector('dashboard.topnav.help'),
60
+ topnavThemeToggle: cySelector('dashboard.topnav.themeToggle'),
61
+ topnavAdmin: cySelector('dashboard.topnav.admin'),
62
+ topnavDevzone: cySelector('dashboard.topnav.devzone'),
63
+ topnavUserMenuTrigger: cySelector('dashboard.topnav.userMenuTrigger'),
64
+ topnavUserMenu: cySelector('dashboard.topnav.userMenu'),
65
+ topnavMenuItem: (icon: string) => cySelector('dashboard.topnav.menuItem', { icon }),
66
+ topnavMenuAction: (action: string) => cySelector('dashboard.topnav.menuAction', { action }),
67
+ topnavUserLoading: cySelector('dashboard.topnav.userLoading'),
68
+ topnavSignin: cySelector('dashboard.topnav.signin'),
69
+ topnavSignup: cySelector('dashboard.topnav.signup'),
70
+
71
+ // Sidebar
72
+ sidebarMain: cySelector('dashboard.sidebar.main'),
73
+ sidebarHeader: cySelector('dashboard.sidebar.header'),
74
+ sidebarContent: cySelector('dashboard.sidebar.content'),
75
+ sidebarFooter: cySelector('dashboard.sidebar.footer'),
76
+
77
+ // Mobile Topbar
78
+ mobileTopbarHeader: cySelector('dashboard.mobile.topbar.header'),
79
+ mobileTopbarUserProfile: cySelector('dashboard.mobile.topbar.userProfile'),
80
+ mobileTopbarNotifications: cySelector('dashboard.mobile.topbar.notifications'),
81
+ mobileTopbarThemeToggle: cySelector('dashboard.mobile.topbar.themeToggle'),
82
+
83
+ // Mobile Bottom Nav
84
+ mobileBottomNav: cySelector('dashboard.mobile.bottomNav.nav'),
85
+ mobileBottomNavItem: (id: string) => cySelector('dashboard.mobile.bottomNav.item', { id }),
86
+
87
+ // Mobile More Sheet
88
+ mobileMoreSheetContent: cySelector('dashboard.mobile.moreSheet.content'),
89
+ mobileMoreSheetItem: (id: string) => cySelector('dashboard.mobile.moreSheet.item', { id }),
90
+ mobileMoreSheetAdmin: cySelector('dashboard.mobile.moreSheet.adminLink'),
91
+ mobileMoreSheetTeamSwitcher: cySelector('dashboard.mobile.moreSheet.teamSwitcher'),
92
+ mobileMoreSheetSignout: cySelector('dashboard.mobile.moreSheet.signoutButton'),
93
+
94
+ // Mobile Quick Create
95
+ mobileQuickCreateContent: cySelector('dashboard.mobile.quickCreateSheet.content'),
96
+ mobileQuickCreateItem: (slug: string) => cySelector('dashboard.mobile.quickCreateSheet.item', { slug }),
97
+
98
+ // Entity table (for verifying entity pages)
99
+ entityPage: (slug: string) => cySelector('entities.page.container', { slug }),
100
+ entityTable: (slug: string) => cySelector('entities.table.container', { slug }),
101
+ entityAddButton: (slug: string) => cySelector('entities.table.addButton', { slug }),
102
+ }
103
+ }
104
+
105
+ // ============================================
106
+ // NAVIGATION
107
+ // ============================================
108
+
109
+ /**
110
+ * Navigate to main dashboard
111
+ */
112
+ visitDashboard() {
113
+ cy.visit('/dashboard', { timeout: 60000 })
114
+ return this
115
+ }
116
+
117
+ /**
118
+ * Navigate to an entity page
119
+ */
120
+ visitEntity(slug: string) {
121
+ cy.visit(`/dashboard/${slug}`, { timeout: 60000 })
122
+ return this
123
+ }
124
+
125
+ /**
126
+ * Navigate to entity via sidebar link
127
+ */
128
+ clickEntityNav(slug: string) {
129
+ cy.get(this.selectors.navEntity(slug)).click()
130
+ return this
131
+ }
132
+
133
+ /**
134
+ * Navigate to dashboard via sidebar link
135
+ */
136
+ clickDashboardNav() {
137
+ cy.get(this.selectors.navDashboard).click()
138
+ return this
139
+ }
140
+
141
+ // ============================================
142
+ // QUICK CREATE
143
+ // ============================================
144
+
145
+ /**
146
+ * Open quick create dropdown
147
+ */
148
+ openQuickCreate() {
149
+ cy.get(this.selectors.quickCreateButton).click()
150
+ return this
151
+ }
152
+
153
+ /**
154
+ * Click quick create link for an entity
155
+ */
156
+ quickCreate(slug: string) {
157
+ this.openQuickCreate()
158
+ cy.get(this.selectors.quickCreateLink(slug)).click()
159
+ return this
160
+ }
161
+
162
+ // ============================================
163
+ // ASSERTIONS
164
+ // ============================================
165
+
166
+ /**
167
+ * Assert dashboard page is visible
168
+ */
169
+ assertDashboardVisible() {
170
+ cy.url().should('include', '/dashboard')
171
+ return this
172
+ }
173
+
174
+ /**
175
+ * Assert entity nav link is visible
176
+ */
177
+ assertEntityNavVisible(slug: string) {
178
+ cy.get(this.selectors.navEntity(slug)).should('be.visible')
179
+ return this
180
+ }
181
+
182
+ /**
183
+ * Assert entity nav link is NOT visible (restricted access)
184
+ */
185
+ assertEntityNavNotVisible(slug: string) {
186
+ cy.get(this.selectors.navEntity(slug)).should('not.exist')
187
+ return this
188
+ }
189
+
190
+ /**
191
+ * Assert entity page is accessible (table container visible)
192
+ */
193
+ assertEntityPageVisible(slug: string) {
194
+ cy.get(this.selectors.entityTable(slug)).should('be.visible')
195
+ return this
196
+ }
197
+
198
+ /**
199
+ * Assert entity add button is visible (create permission)
200
+ */
201
+ assertEntityAddButtonVisible(slug: string) {
202
+ cy.get(this.selectors.entityAddButton(slug)).should('be.visible')
203
+ return this
204
+ }
205
+
206
+ /**
207
+ * Assert entity add button is NOT visible (no create permission)
208
+ */
209
+ assertEntityAddButtonNotVisible(slug: string) {
210
+ cy.get(this.selectors.entityAddButton(slug)).should('not.exist')
211
+ return this
212
+ }
213
+
214
+ /**
215
+ * Assert quick create button is visible
216
+ */
217
+ assertQuickCreateVisible() {
218
+ cy.get(this.selectors.quickCreateButton).should('be.visible')
219
+ return this
220
+ }
221
+
222
+ // ============================================
223
+ // WAITS
224
+ // ============================================
225
+
226
+ /**
227
+ * Wait for dashboard to be fully loaded
228
+ */
229
+ waitForDashboard() {
230
+ cy.url().should('include', '/dashboard')
231
+ cy.get(this.selectors.navMain, { timeout: 15000 }).should('be.visible')
232
+ return this
233
+ }
234
+
235
+ /**
236
+ * Wait for entity page to be loaded
237
+ */
238
+ waitForEntityPage(slug: string) {
239
+ cy.url().should('include', `/dashboard/${slug}`)
240
+ cy.get(this.selectors.entityTable(slug), { timeout: 15000 }).should('be.visible')
241
+ return this
242
+ }
243
+ }
244
+
245
+ export default DashboardPOM