@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,242 @@
1
+ /**
2
+ * UsersAPIController - Controller for interacting with the Users API
3
+ * Encapsulates all CRUD operations for /api/v1/users endpoints
4
+ *
5
+ * NOTE: Users is a GLOBAL entity - does NOT require x-team-id header
6
+ *
7
+ * Requires:
8
+ * - API Key with users:read, users:write scopes (or superadmin with *)
9
+ */
10
+ const BaseAPIController = require('./BaseAPIController')
11
+ const entitiesConfig = require('../../fixtures/entities.json')
12
+
13
+ const { slug } = entitiesConfig.entities.users
14
+
15
+ class UsersAPIController extends BaseAPIController {
16
+ /**
17
+ * @param {string} baseUrl - Base URL for API requests
18
+ * @param {string|null} apiKey - API key for authentication
19
+ * NOTE: Does NOT accept teamId - users is a global entity
20
+ */
21
+ constructor(baseUrl = 'http://localhost:5173', apiKey = null) {
22
+ // NO pasar teamId (null) para entidades globales
23
+ super(baseUrl, apiKey, null, { slug })
24
+ }
25
+
26
+ // ============================================================
27
+ // SEMANTIC ALIASES (for backward compatibility)
28
+ // ============================================================
29
+
30
+ /**
31
+ * GET /api/v1/users - Get list of users
32
+ * @param {Object} options - Query options
33
+ * @param {number} [options.page] - Page number
34
+ * @param {number} [options.limit] - Results per page
35
+ * @param {string} [options.role] - Filter by role ('member', 'superadmin')
36
+ * @param {string} [options.metas] - Metadata parameter ('all', 'key1,key2', etc.)
37
+ * @param {Object} [options.headers] - Additional headers
38
+ * @returns {Cypress.Chainable} Cypress response
39
+ */
40
+ getUsers(options = {}) {
41
+ return this.list(options)
42
+ }
43
+
44
+ /**
45
+ * GET /api/v1/users/{id} - Get specific user by ID or email
46
+ * @param {string} identifier - User ID or email
47
+ * @param {Object} options - Additional options
48
+ * @returns {Cypress.Chainable} Cypress response
49
+ */
50
+ getUserById(identifier, options = {}) {
51
+ return this.getById(identifier, options)
52
+ }
53
+
54
+ /**
55
+ * POST /api/v1/users - Create new user
56
+ * @param {Object} userData - User data
57
+ * @param {string} userData.email - User email (required)
58
+ * @param {string} userData.firstName - User first name (required)
59
+ * @param {string} userData.lastName - User last name (required)
60
+ * @param {string} userData.country - User country (required, min 2 chars)
61
+ * @param {string} [userData.image] - User image URL
62
+ * @param {string} [userData.language] - User language (default: "en")
63
+ * @param {string} [userData.timezone] - User timezone (default: "UTC")
64
+ * @param {string} [userData.role] - User role (default: "member")
65
+ * @param {Object} options - Additional options
66
+ * @returns {Cypress.Chainable} Cypress response
67
+ */
68
+ createUser(userData, options = {}) {
69
+ return this.create(userData, options)
70
+ }
71
+
72
+ /**
73
+ * PATCH /api/v1/users/{id} - Update user
74
+ * @param {string} identifier - User ID or email
75
+ * @param {Object} updateData - Data to update
76
+ * @param {Object} options - Additional options
77
+ * @returns {Cypress.Chainable} Cypress response
78
+ */
79
+ updateUser(identifier, updateData, options = {}) {
80
+ return this.update(identifier, updateData, options)
81
+ }
82
+
83
+ /**
84
+ * DELETE /api/v1/users/{id} - Delete user
85
+ * @param {string} identifier - User ID or email
86
+ * @param {Object} options - Additional options
87
+ * @returns {Cypress.Chainable} Cypress response
88
+ */
89
+ deleteUser(identifier, options = {}) {
90
+ return this.delete(identifier, options)
91
+ }
92
+
93
+ // ============================================================
94
+ // DATA GENERATORS
95
+ // ============================================================
96
+
97
+ /**
98
+ * Generate random user data for testing
99
+ * Required by BaseAPIController.createTestEntity()
100
+ * @param {Object} overrides - Specific data to override
101
+ * @returns {Object} Generated user data
102
+ */
103
+ generateRandomData(overrides = {}) {
104
+ return this.generateRandomUserData(overrides)
105
+ }
106
+
107
+ /**
108
+ * Generate random user data for testing
109
+ * @param {Object} overrides - Specific data to override
110
+ * @returns {Object} Generated user data
111
+ */
112
+ generateRandomUserData(overrides = {}) {
113
+ const timestamp = Date.now()
114
+ const randomId = Math.random().toString(36).substring(2, 8)
115
+
116
+ return {
117
+ email: `testuser_${timestamp}_${randomId}@nextspark.dev`,
118
+ firstName: `TestUser${randomId}`,
119
+ lastName: 'Cypress',
120
+ country: 'US',
121
+ role: 'member',
122
+ language: 'en',
123
+ timezone: 'UTC',
124
+ ...overrides
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Create a test user and return its data
130
+ * @param {Object} userData - User data (optional)
131
+ * @returns {Cypress.Chainable} Promise resolving with created user data
132
+ */
133
+ createTestUser(userData = {}) {
134
+ return this.createTestEntity(userData)
135
+ }
136
+
137
+ /**
138
+ * Clean up a test user (delete it)
139
+ * @param {string} identifier - User ID or email
140
+ * @returns {Cypress.Chainable} Delete response
141
+ */
142
+ cleanupTestUser(identifier) {
143
+ return this.cleanup(identifier)
144
+ }
145
+
146
+ // ============================================================
147
+ // ENTITY-SPECIFIC VALIDATORS
148
+ // ============================================================
149
+
150
+ /**
151
+ * Validate user object structure
152
+ * @param {Object} user - User object
153
+ * @param {boolean} allowMetas - If metas property is allowed
154
+ */
155
+ validateUserObject(user, allowMetas = false) {
156
+ // Base fields from BaseAPIController
157
+ this.validateBaseEntityFields(user)
158
+
159
+ // Required entity fields
160
+ expect(user).to.have.property('email')
161
+ expect(user.email).to.be.a('string')
162
+
163
+ expect(user).to.have.property('firstName')
164
+ expect(user.firstName).to.be.a('string')
165
+
166
+ expect(user).to.have.property('role')
167
+ expect(user.role).to.be.oneOf(['member', 'colaborator', 'admin', 'superadmin'])
168
+
169
+ expect(user).to.have.property('emailVerified')
170
+ expect(user.emailVerified).to.be.a('boolean')
171
+
172
+ // Optional fields that can be null
173
+ if (user.name !== null && user.name !== undefined) {
174
+ expect(user.name).to.be.a('string')
175
+ }
176
+
177
+ if (user.lastName !== null && user.lastName !== undefined) {
178
+ expect(user.lastName).to.be.a('string')
179
+ }
180
+
181
+ if (user.country !== null && user.country !== undefined) {
182
+ expect(user.country).to.be.a('string')
183
+ }
184
+
185
+ if (user.timezone !== null && user.timezone !== undefined) {
186
+ expect(user.timezone).to.be.a('string')
187
+ }
188
+
189
+ if (user.language !== null && user.language !== undefined) {
190
+ expect(user.language).to.be.a('string')
191
+ }
192
+
193
+ if (user.image !== null && user.image !== undefined) {
194
+ expect(user.image).to.be.a('string')
195
+ }
196
+
197
+ // Validate metas if present
198
+ if (allowMetas && user.hasOwnProperty('metas')) {
199
+ expect(user.metas).to.be.an('object')
200
+ }
201
+ }
202
+
203
+ // ============================================================
204
+ // METADATA HELPERS
205
+ // ============================================================
206
+
207
+ /**
208
+ * Generate sample metadata for testing
209
+ * @param {string} type - Type of metadata ('uiPreferences', 'securityPreferences', 'notificationPreferences')
210
+ * @returns {Object} Sample metadata
211
+ */
212
+ generateSampleMetadata(type = 'uiPreferences') {
213
+ const sampleMetas = {
214
+ uiPreferences: {
215
+ theme: 'dark',
216
+ sidebarCollapsed: false,
217
+ language: 'en',
218
+ density: 'comfortable'
219
+ },
220
+ securityPreferences: {
221
+ twoFactorEnabled: false,
222
+ sessionTimeout: 3600,
223
+ trustedDevices: []
224
+ },
225
+ notificationPreferences: {
226
+ emailEnabled: true,
227
+ pushEnabled: false,
228
+ digestFrequency: 'daily'
229
+ }
230
+ }
231
+
232
+ return { [type]: sampleMetas[type] || sampleMetas.uiPreferences }
233
+ }
234
+ }
235
+
236
+ // Export class for use in tests
237
+ module.exports = UsersAPIController
238
+
239
+ // For global use in Cypress
240
+ if (typeof window !== 'undefined') {
241
+ window.UsersAPIController = UsersAPIController
242
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Cypress API Controllers
3
+ *
4
+ * Centralized exports for all API controllers.
5
+ * All controllers extend BaseAPIController and guarantee:
6
+ * - Consistent Authorization header handling
7
+ * - Consistent x-team-id header handling (when teamId configured)
8
+ * - Standard CRUD operations
9
+ * - Common validators
10
+ */
11
+
12
+ module.exports = {
13
+ // Base class
14
+ BaseAPIController: require('./BaseAPIController'),
15
+
16
+ // Entity-specific controllers (team-scoped)
17
+ TasksAPIController: require('./TaskAPIController'),
18
+ CustomersAPIController: require('./CustomerAPIController'),
19
+ PostsAPIController: require('./PostsAPIController'),
20
+ PagesAPIController: require('./PagesAPIController'),
21
+
22
+ // Entity-specific controllers (global - no team required)
23
+ UsersAPIController: require('./UsersAPIController'),
24
+ ApiKeysAPIController: require('./ApiKeysAPIController')
25
+ }
@@ -0,0 +1,450 @@
1
+ /**
2
+ * AuthPOM - Page Object Model for authentication pages
3
+ *
4
+ * Provides methods for:
5
+ * - Login (email/password, Google OAuth)
6
+ * - Signup (email/password, Google OAuth)
7
+ * - Password reset flow
8
+ * - Email verification
9
+ * - Dev keyring (quick login in development)
10
+ *
11
+ * @example
12
+ * const auth = new AuthPOM()
13
+ * auth.visitLogin()
14
+ * .login('user@example.com', 'password')
15
+ * .waitForDashboard()
16
+ */
17
+
18
+ import { BasePOM } from './BasePOM'
19
+ import { cySelector } from '../selectors'
20
+
21
+ export interface SignupData {
22
+ firstName: string
23
+ lastName: string
24
+ email: string
25
+ password: string
26
+ confirmPassword?: string
27
+ }
28
+
29
+ export class AuthPOM extends BasePOM {
30
+ // ============================================
31
+ // SELECTORS (from centralized selectors.ts)
32
+ // ============================================
33
+
34
+ get selectors() {
35
+ return {
36
+ // Login - Structure
37
+ loginCard: cySelector('auth.login.card'),
38
+ loginHeader: cySelector('auth.login.header'),
39
+ loginFooter: cySelector('auth.login.footer'),
40
+ loginForm: cySelector('auth.login.form'),
41
+ loginOptions: cySelector('auth.login.options'),
42
+ // Login - Inputs
43
+ loginEmail: cySelector('auth.login.emailInput'),
44
+ loginPassword: cySelector('auth.login.passwordInput'),
45
+ loginEmailError: cySelector('auth.login.emailError'),
46
+ loginPasswordError: cySelector('auth.login.passwordError'),
47
+ // Login - Buttons
48
+ loginSubmit: cySelector('auth.login.submit'),
49
+ loginGoogle: cySelector('auth.login.googleSignin'),
50
+ loginShowEmail: cySelector('auth.login.showEmail'),
51
+ loginHideEmail: cySelector('auth.login.hideEmail'),
52
+ // Login - Links & Misc
53
+ loginForgotPassword: cySelector('auth.login.forgotPassword'),
54
+ loginSignupLink: cySelector('auth.login.signupLink'),
55
+ loginInviteBanner: cySelector('auth.login.inviteBanner'),
56
+ loginError: cySelector('auth.login.errorAlert'),
57
+ loginRememberCheckbox: cySelector('auth.login.rememberCheckbox'),
58
+
59
+ // Signup
60
+ signupForm: cySelector('auth.signup.form'),
61
+ signupFirstName: cySelector('auth.signup.firstName'),
62
+ signupLastName: cySelector('auth.signup.lastName'),
63
+ signupEmail: cySelector('auth.signup.email'),
64
+ signupPassword: cySelector('auth.signup.password'),
65
+ signupConfirmPassword: cySelector('auth.signup.confirmPassword'),
66
+ signupSubmit: cySelector('auth.signup.submitButton'),
67
+ signupGoogle: cySelector('auth.signup.googleButton'),
68
+ signupLoginLink: cySelector('auth.signup.loginLink'),
69
+ signupInviteBanner: cySelector('auth.signup.inviteBanner'),
70
+ signupError: cySelector('auth.signup.error'),
71
+
72
+ // Forgot Password
73
+ forgotPasswordForm: cySelector('auth.forgotPassword.form'),
74
+ forgotPasswordEmail: cySelector('auth.forgotPassword.email'),
75
+ forgotPasswordSubmit: cySelector('auth.forgotPassword.submitButton'),
76
+ forgotPasswordBack: cySelector('auth.forgotPassword.backToLogin'),
77
+ forgotPasswordSuccess: cySelector('auth.forgotPassword.successMessage'),
78
+ forgotPasswordSuccessBack: cySelector('auth.forgotPassword.successBack'),
79
+ forgotPasswordRetry: cySelector('auth.forgotPassword.retryButton'),
80
+ forgotPasswordError: cySelector('auth.forgotPassword.error'),
81
+
82
+ // Reset Password
83
+ resetPasswordForm: cySelector('auth.resetPassword.form'),
84
+ resetPasswordPassword: cySelector('auth.resetPassword.password'),
85
+ resetPasswordConfirm: cySelector('auth.resetPassword.confirmPassword'),
86
+ resetPasswordSubmit: cySelector('auth.resetPassword.submitButton'),
87
+ resetPasswordError: cySelector('auth.resetPassword.error'),
88
+
89
+ // Verify Email
90
+ verifyEmailContainer: cySelector('auth.verifyEmail.container'),
91
+ verifyEmailResend: cySelector('auth.verifyEmail.resendButton'),
92
+ verifyEmailSuccess: cySelector('auth.verifyEmail.successMessage'),
93
+ verifyEmailError: cySelector('auth.verifyEmail.error'),
94
+
95
+ // Dev Keyring
96
+ devKeyring: cySelector('auth.devKeyring.container'),
97
+ devKeyringTrigger: cySelector('auth.devKeyring.trigger'),
98
+ devKeyringContent: cySelector('auth.devKeyring.content'),
99
+ devKeyringUser: (index: number) =>
100
+ cySelector('auth.devKeyring.user', { index }),
101
+
102
+ // Logout (from dashboard)
103
+ userMenuTrigger: cySelector('dashboard.topnav.userMenuTrigger'),
104
+ logoutAction: cySelector('dashboard.topnav.menuAction', { action: 'signOut' }),
105
+ mobileLogout: cySelector('dashboard.topnav.mobileSignout')
106
+ }
107
+ }
108
+
109
+ // ============================================
110
+ // FACTORY METHOD
111
+ // ============================================
112
+
113
+ static create(): AuthPOM {
114
+ return new AuthPOM()
115
+ }
116
+
117
+ // ============================================
118
+ // NAVIGATION
119
+ // ============================================
120
+
121
+ visitLogin() {
122
+ cy.visit('/login')
123
+ return this
124
+ }
125
+
126
+ visitSignup() {
127
+ cy.visit('/signup')
128
+ return this
129
+ }
130
+
131
+ visitForgotPassword() {
132
+ cy.visit('/forgot-password')
133
+ return this
134
+ }
135
+
136
+ visitResetPassword(token: string) {
137
+ cy.visit(`/reset-password?token=${token}`)
138
+ return this
139
+ }
140
+
141
+ // ============================================
142
+ // LOGIN ACTIONS
143
+ // ============================================
144
+
145
+ /**
146
+ * Login with email and password
147
+ */
148
+ login(email: string, password: string) {
149
+ cy.get(this.selectors.loginEmail).clear().type(email)
150
+ cy.get(this.selectors.loginPassword).clear().type(password)
151
+ cy.get(this.selectors.loginSubmit).click()
152
+ return this
153
+ }
154
+
155
+ /**
156
+ * Click on "Show email login" button (if email form is hidden by default)
157
+ */
158
+ showEmailLogin() {
159
+ cy.get(this.selectors.loginShowEmail).click()
160
+ return this
161
+ }
162
+
163
+ /**
164
+ * Click Google login button
165
+ */
166
+ loginWithGoogle() {
167
+ cy.get(this.selectors.loginGoogle).click()
168
+ return this
169
+ }
170
+
171
+ /**
172
+ * Click forgot password link
173
+ */
174
+ clickForgotPassword() {
175
+ cy.get(this.selectors.loginForgotPassword).click()
176
+ return this
177
+ }
178
+
179
+ /**
180
+ * Click signup link from login page
181
+ */
182
+ clickSignupLink() {
183
+ cy.get(this.selectors.loginSignupLink).click()
184
+ return this
185
+ }
186
+
187
+ // ============================================
188
+ // SIGNUP ACTIONS
189
+ // ============================================
190
+
191
+ /**
192
+ * Fill and submit signup form
193
+ */
194
+ signup(data: SignupData) {
195
+ cy.get(this.selectors.signupFirstName).clear().type(data.firstName)
196
+ cy.get(this.selectors.signupLastName).clear().type(data.lastName)
197
+ cy.get(this.selectors.signupEmail).clear().type(data.email)
198
+ cy.get(this.selectors.signupPassword).clear().type(data.password)
199
+ if (data.confirmPassword) {
200
+ cy.get(this.selectors.signupConfirmPassword).clear().type(data.confirmPassword)
201
+ }
202
+ cy.get(this.selectors.signupSubmit).click()
203
+ return this
204
+ }
205
+
206
+ /**
207
+ * Click Google signup button
208
+ */
209
+ signupWithGoogle() {
210
+ cy.get(this.selectors.signupGoogle).click()
211
+ return this
212
+ }
213
+
214
+ /**
215
+ * Click login link from signup page
216
+ */
217
+ clickLoginLink() {
218
+ cy.get(this.selectors.signupLoginLink).click()
219
+ return this
220
+ }
221
+
222
+ // ============================================
223
+ // FORGOT PASSWORD ACTIONS
224
+ // ============================================
225
+
226
+ /**
227
+ * Request password reset
228
+ */
229
+ requestPasswordReset(email: string) {
230
+ cy.get(this.selectors.forgotPasswordEmail).clear().type(email)
231
+ cy.get(this.selectors.forgotPasswordSubmit).click()
232
+ return this
233
+ }
234
+
235
+ /**
236
+ * Go back to login from forgot password
237
+ */
238
+ backToLogin() {
239
+ cy.get(this.selectors.forgotPasswordBack).click()
240
+ return this
241
+ }
242
+
243
+ // ============================================
244
+ // RESET PASSWORD ACTIONS
245
+ // ============================================
246
+
247
+ /**
248
+ * Reset password with new password
249
+ */
250
+ resetPassword(password: string, confirmPassword?: string) {
251
+ cy.get(this.selectors.resetPasswordPassword).clear().type(password)
252
+ cy.get(this.selectors.resetPasswordConfirm)
253
+ .clear()
254
+ .type(confirmPassword || password)
255
+ cy.get(this.selectors.resetPasswordSubmit).click()
256
+ return this
257
+ }
258
+
259
+ // ============================================
260
+ // EMAIL VERIFICATION ACTIONS
261
+ // ============================================
262
+
263
+ /**
264
+ * Resend verification email
265
+ */
266
+ resendVerificationEmail() {
267
+ cy.get(this.selectors.verifyEmailResend).click()
268
+ return this
269
+ }
270
+
271
+ // ============================================
272
+ // DEV KEYRING ACTIONS
273
+ // ============================================
274
+
275
+ /**
276
+ * Open dev keyring dropdown
277
+ */
278
+ openDevKeyring() {
279
+ cy.get(this.selectors.devKeyringTrigger).click()
280
+ return this
281
+ }
282
+
283
+ /**
284
+ * Login as a dev user by index
285
+ */
286
+ loginAsDevUser(index: number) {
287
+ this.openDevKeyring()
288
+ cy.get(this.selectors.devKeyringUser(index)).click()
289
+ return this
290
+ }
291
+
292
+ /**
293
+ * Quick login using dev keyring (combines opening and clicking)
294
+ */
295
+ devLogin(userIndex: number = 0) {
296
+ return this.loginAsDevUser(userIndex)
297
+ }
298
+
299
+ // ============================================
300
+ // LOGOUT ACTIONS
301
+ // ============================================
302
+
303
+ /**
304
+ * Logout from the application (clicks user menu, then signOut action)
305
+ */
306
+ logout() {
307
+ cy.get(this.selectors.userMenuTrigger).click()
308
+ cy.get(this.selectors.logoutAction).click()
309
+ return this
310
+ }
311
+
312
+ /**
313
+ * Logout from mobile menu
314
+ */
315
+ logoutMobile() {
316
+ cy.get(this.selectors.mobileLogout).click()
317
+ return this
318
+ }
319
+
320
+ // ============================================
321
+ // WAITS
322
+ // ============================================
323
+
324
+ /**
325
+ * Wait for login form to be visible
326
+ */
327
+ waitForLoginForm() {
328
+ cy.get(this.selectors.loginForm, { timeout: 10000 }).should('be.visible')
329
+ return this
330
+ }
331
+
332
+ /**
333
+ * Wait for signup form to be visible
334
+ */
335
+ waitForSignupForm() {
336
+ cy.get(this.selectors.signupForm, { timeout: 10000 }).should('be.visible')
337
+ return this
338
+ }
339
+
340
+ /**
341
+ * Wait for redirect to dashboard after successful login
342
+ */
343
+ waitForDashboard() {
344
+ cy.url({ timeout: 15000 }).should('include', '/dashboard')
345
+ return this
346
+ }
347
+
348
+ /**
349
+ * Wait for password reset success message
350
+ */
351
+ waitForPasswordResetSuccess() {
352
+ cy.get(this.selectors.forgotPasswordSuccess, { timeout: 10000 }).should('be.visible')
353
+ return this
354
+ }
355
+
356
+ // ============================================
357
+ // ASSERTIONS
358
+ // ============================================
359
+
360
+ /**
361
+ * Assert login form is visible
362
+ */
363
+ assertLoginFormVisible() {
364
+ cy.get(this.selectors.loginForm).should('be.visible')
365
+ return this
366
+ }
367
+
368
+ /**
369
+ * Assert signup form is visible
370
+ */
371
+ assertSignupFormVisible() {
372
+ cy.get(this.selectors.signupForm).should('be.visible')
373
+ return this
374
+ }
375
+
376
+ /**
377
+ * Assert login error is shown
378
+ */
379
+ assertLoginError(message?: string) {
380
+ cy.get(this.selectors.loginError).should('be.visible')
381
+ if (message) {
382
+ cy.get(this.selectors.loginError).should('contain.text', message)
383
+ }
384
+ return this
385
+ }
386
+
387
+ /**
388
+ * Assert signup error is shown
389
+ */
390
+ assertSignupError(message?: string) {
391
+ cy.get(this.selectors.signupError).should('be.visible')
392
+ if (message) {
393
+ cy.get(this.selectors.signupError).should('contain.text', message)
394
+ }
395
+ return this
396
+ }
397
+
398
+ /**
399
+ * Assert forgot password error is shown
400
+ */
401
+ assertForgotPasswordError(message?: string) {
402
+ cy.get(this.selectors.forgotPasswordError).should('be.visible')
403
+ if (message) {
404
+ cy.get(this.selectors.forgotPasswordError).should('contain.text', message)
405
+ }
406
+ return this
407
+ }
408
+
409
+ /**
410
+ * Assert invite banner is visible
411
+ */
412
+ assertInviteBannerVisible() {
413
+ cy.get(this.selectors.loginInviteBanner).should('be.visible')
414
+ return this
415
+ }
416
+
417
+ /**
418
+ * Assert user is on login page
419
+ */
420
+ assertOnLoginPage() {
421
+ cy.url().should('include', '/login')
422
+ return this
423
+ }
424
+
425
+ /**
426
+ * Assert user is on signup page
427
+ */
428
+ assertOnSignupPage() {
429
+ cy.url().should('include', '/signup')
430
+ return this
431
+ }
432
+
433
+ /**
434
+ * Assert user is on dashboard
435
+ */
436
+ assertOnDashboard() {
437
+ cy.url().should('include', '/dashboard')
438
+ return this
439
+ }
440
+
441
+ /**
442
+ * Assert dev keyring is visible (dev environment only)
443
+ */
444
+ assertDevKeyringVisible() {
445
+ cy.get(this.selectors.devKeyring).should('be.visible')
446
+ return this
447
+ }
448
+ }
449
+
450
+ export default AuthPOM