@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,250 @@
1
+ /**
2
+ * PostsAPIController - Controller for interacting with the Posts API
3
+ * Encapsulates all CRUD operations for /api/v1/posts endpoints
4
+ *
5
+ * Requires:
6
+ * - API Key with posts:read, posts:write scopes (or superadmin with *)
7
+ * - x-team-id header for team context
8
+ *
9
+ * Entity characteristics:
10
+ * - Required fields: slug, title, blocks, locale
11
+ * - Optional fields: excerpt, featuredImage, SEO fields, categoryIds
12
+ * - Unique constraint: slug + locale
13
+ * - Relations: post_taxonomy_relations (many-to-many with taxonomies)
14
+ * - Uses PATCH for updates (standard)
15
+ */
16
+ const BaseAPIController = require('./BaseAPIController')
17
+ const entitiesConfig = require('../../fixtures/entities.json')
18
+
19
+ const { slug } = entitiesConfig.entities.posts
20
+
21
+ class PostsAPIController extends BaseAPIController {
22
+ /**
23
+ * @param {string} baseUrl - Base URL for API requests
24
+ * @param {string|null} apiKey - API key for authentication
25
+ * @param {string|null} teamId - Team ID for x-team-id header
26
+ */
27
+ constructor(baseUrl = 'http://localhost:5173', apiKey = null, teamId = null) {
28
+ super(baseUrl, apiKey, teamId, { slug })
29
+ }
30
+
31
+ // ============================================================
32
+ // SEMANTIC ALIASES (for better readability in tests)
33
+ // ============================================================
34
+
35
+ /**
36
+ * GET /api/v1/posts - List posts
37
+ * @param {Object} options - Query options
38
+ * @param {number} [options.page] - Page number
39
+ * @param {number} [options.limit] - Results per page
40
+ * @param {string} [options.status] - Filter by status (draft, published, scheduled, archived)
41
+ * @param {string} [options.locale] - Filter by locale
42
+ * @param {boolean} [options.published] - Filter by published flag
43
+ * @param {string} [options.search] - Search in title/excerpt
44
+ * @param {string} [options.metas] - Metadata parameter
45
+ * @returns {Cypress.Chainable} Cypress response
46
+ */
47
+ getPosts(options = {}) {
48
+ return this.list(options)
49
+ }
50
+
51
+ /**
52
+ * GET /api/v1/posts/{id} - Get post by ID
53
+ * @param {string} id - Post ID
54
+ * @param {Object} options - Additional options
55
+ * @returns {Cypress.Chainable} Cypress response
56
+ */
57
+ getPostById(id, options = {}) {
58
+ return this.getById(id, options)
59
+ }
60
+
61
+ /**
62
+ * POST /api/v1/posts - Create post
63
+ * @param {Object} postData - Post data
64
+ * @param {string} postData.slug - Post slug (required)
65
+ * @param {string} postData.title - Post title (required)
66
+ * @param {string} postData.locale - Post locale (required)
67
+ * @param {Array} postData.blocks - Post blocks (required)
68
+ * @param {string} [postData.excerpt] - Post excerpt
69
+ * @param {string} [postData.featuredImage] - Featured image URL
70
+ * @param {string} [postData.status] - Status (draft, published, scheduled, archived)
71
+ * @param {boolean} [postData.published] - Published flag
72
+ * @param {string[]} [postData.categoryIds] - Category IDs
73
+ * @param {string} [postData.seoTitle] - SEO title
74
+ * @param {string} [postData.seoDescription] - SEO description
75
+ * @param {Object} [postData.metas] - Metadata object
76
+ * @returns {Cypress.Chainable} Cypress response
77
+ */
78
+ createPost(postData, options = {}) {
79
+ return this.create(postData, options)
80
+ }
81
+
82
+ /**
83
+ * PUT /api/v1/posts/{id} - Update post
84
+ * @param {string} id - Post ID
85
+ * @param {Object} updateData - Data to update
86
+ * @returns {Cypress.Chainable} Cypress response
87
+ */
88
+ updatePost(id, updateData, options = {}) {
89
+ return this.update(id, updateData, options)
90
+ }
91
+
92
+ /**
93
+ * DELETE /api/v1/posts/{id} - Delete post
94
+ * @param {string} id - Post ID
95
+ * @returns {Cypress.Chainable} Cypress response
96
+ */
97
+ deletePost(id, options = {}) {
98
+ return this.delete(id, options)
99
+ }
100
+
101
+ // ============================================================
102
+ // DATA GENERATORS
103
+ // ============================================================
104
+
105
+ /**
106
+ * Generate random post data for testing
107
+ * @param {Object} overrides - Specific data to override
108
+ * @returns {Object} Generated post data
109
+ */
110
+ generateRandomData(overrides = {}) {
111
+ return PostsAPIController.generateRandomPostData(overrides)
112
+ }
113
+
114
+ /**
115
+ * Static method to generate random post data
116
+ * @param {Object} overrides - Specific data to override
117
+ * @returns {Object} Generated post data
118
+ */
119
+ static generateRandomPostData(overrides = {}) {
120
+ const timestamp = Date.now()
121
+ const randomId = Math.random().toString(36).substring(2, 8)
122
+
123
+ return {
124
+ slug: `test-post-${randomId}-${timestamp}`,
125
+ title: `Test Post ${randomId}`,
126
+ excerpt: `Test excerpt for post ${randomId}`,
127
+ locale: 'en',
128
+ published: false,
129
+ status: 'draft',
130
+ blocks: [],
131
+ categoryIds: [],
132
+ ...overrides
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Create a test post and return its data
138
+ * @param {Object} overrides - Data overrides
139
+ * @returns {Cypress.Chainable} Promise resolving with created post data
140
+ */
141
+ createTestPost(overrides = {}) {
142
+ return this.createTestEntity(overrides)
143
+ }
144
+
145
+ /**
146
+ * Clean up a test post
147
+ * @param {string} id - Post ID
148
+ * @returns {Cypress.Chainable} Delete response
149
+ */
150
+ cleanupTestPost(id) {
151
+ return this.cleanup(id)
152
+ }
153
+
154
+ // ============================================================
155
+ // ENTITY-SPECIFIC VALIDATORS
156
+ // ============================================================
157
+
158
+ /**
159
+ * Validate post object structure
160
+ * @param {Object} post - Post object
161
+ * @param {boolean} allowMetas - If metas property is allowed
162
+ */
163
+ validatePostObject(post, allowMetas = false) {
164
+ // Base fields
165
+ this.validateBaseEntityFields(post)
166
+
167
+ // Required post fields
168
+ expect(post).to.have.property('slug')
169
+ expect(post.slug).to.be.a('string')
170
+
171
+ expect(post).to.have.property('title')
172
+ expect(post.title).to.be.a('string')
173
+
174
+ expect(post).to.have.property('locale')
175
+ expect(post.locale).to.be.a('string')
176
+
177
+ expect(post).to.have.property('blocks')
178
+ expect(post.blocks).to.be.an('array')
179
+
180
+ // Status field (if present)
181
+ if (post.hasOwnProperty('status') && post.status !== null) {
182
+ expect(post.status).to.be.oneOf(['draft', 'published', 'scheduled', 'archived'])
183
+ }
184
+
185
+ // Published flag (if present)
186
+ if (post.hasOwnProperty('published')) {
187
+ expect(post.published).to.be.a('boolean')
188
+ }
189
+
190
+ // Categories relation (if present)
191
+ if (post.hasOwnProperty('categories')) {
192
+ expect(post.categories).to.be.an('array')
193
+ }
194
+
195
+ // Optional string fields
196
+ if (post.excerpt !== null && post.excerpt !== undefined) {
197
+ expect(post.excerpt).to.be.a('string')
198
+ }
199
+
200
+ if (post.featuredImage !== null && post.featuredImage !== undefined) {
201
+ expect(post.featuredImage).to.be.a('string')
202
+ }
203
+
204
+ // Metas if allowed
205
+ if (allowMetas && post.hasOwnProperty('metas')) {
206
+ expect(post.metas).to.be.an('object')
207
+ }
208
+ }
209
+
210
+ // ============================================================
211
+ // METADATA HELPERS
212
+ // ============================================================
213
+
214
+ /**
215
+ * Generate sample metadata for testing
216
+ * @param {string} type - Type of metadata ('seo', 'social', 'analytics')
217
+ * @returns {Object} Sample metadata
218
+ */
219
+ generateSampleMetadata(type = 'seo') {
220
+ const sampleMetas = {
221
+ seo: {
222
+ seoTitle: 'Custom SEO Title',
223
+ seoDescription: 'Custom SEO description for search engines',
224
+ seoKeywords: 'test, post, cypress',
225
+ noindex: false,
226
+ nofollow: false
227
+ },
228
+ social: {
229
+ ogImage: '/images/og-image.jpg',
230
+ twitterCard: 'summary_large_image',
231
+ shareText: 'Check out this post!'
232
+ },
233
+ analytics: {
234
+ trackViews: true,
235
+ conversionGoal: 'signup',
236
+ utmSource: 'test'
237
+ }
238
+ }
239
+
240
+ return { [type]: sampleMetas[type] || sampleMetas.seo }
241
+ }
242
+ }
243
+
244
+ // Export for CommonJS
245
+ module.exports = PostsAPIController
246
+
247
+ // For global use in Cypress
248
+ if (typeof window !== 'undefined') {
249
+ window.PostsAPIController = PostsAPIController
250
+ }
@@ -0,0 +1,240 @@
1
+ /**
2
+ * TaskAPIController - Controller for interacting with the Tasks API
3
+ * Encapsulates all CRUD operations for /api/v1/tasks endpoints
4
+ *
5
+ * Requires:
6
+ * - API Key with tasks:read, tasks:write scopes (or superadmin with *)
7
+ * - x-team-id header for team context
8
+ */
9
+ const BaseAPIController = require('./BaseAPIController')
10
+ const entitiesConfig = require('../../fixtures/entities.json')
11
+
12
+ const { slug } = entitiesConfig.entities.tasks
13
+
14
+ class TaskAPIController extends BaseAPIController {
15
+ /**
16
+ * @param {string} baseUrl - Base URL for API requests
17
+ * @param {string|null} apiKey - API key for authentication
18
+ * @param {string|null} teamId - Team ID for x-team-id header
19
+ */
20
+ constructor(baseUrl = 'http://localhost:5173', apiKey = null, teamId = null) {
21
+ super(baseUrl, apiKey, teamId, { slug })
22
+ }
23
+
24
+ // ============================================================
25
+ // SEMANTIC ALIASES (for backward compatibility)
26
+ // ============================================================
27
+
28
+ /**
29
+ * GET /api/v1/tasks - Get list of tasks
30
+ * @param {Object} options - Query options
31
+ * @param {number} [options.page] - Page number
32
+ * @param {number} [options.limit] - Results per page
33
+ * @param {string} [options.status] - Filter by status (todo, in-progress, review, done, blocked)
34
+ * @param {string} [options.priority] - Filter by priority (low, medium, high, urgent)
35
+ * @param {string} [options.metas] - Metadata parameter ('all', 'key1,key2', etc.)
36
+ * @param {string} [options.search] - Search in title/description
37
+ * @param {Object} [options.headers] - Additional headers
38
+ * @returns {Cypress.Chainable} Cypress response
39
+ */
40
+ getTasks(options = {}) {
41
+ return this.list(options)
42
+ }
43
+
44
+ /**
45
+ * GET /api/v1/tasks/{id} - Get specific task by ID
46
+ * @param {string} id - Task ID
47
+ * @param {Object} options - Additional options
48
+ * @returns {Cypress.Chainable} Cypress response
49
+ */
50
+ getTaskById(id, options = {}) {
51
+ return this.getById(id, options)
52
+ }
53
+
54
+ /**
55
+ * POST /api/v1/tasks - Create new task
56
+ * @param {Object} taskData - Task data
57
+ * @param {string} taskData.title - Task title (required)
58
+ * @param {string} [taskData.description] - Task description
59
+ * @param {string} [taskData.status] - Status: todo, in-progress, review, done, blocked
60
+ * @param {string} [taskData.priority] - Priority: low, medium, high, urgent
61
+ * @param {string[]} [taskData.tags] - Array of tags
62
+ * @param {string} [taskData.dueDate] - Due date YYYY-MM-DD
63
+ * @param {number} [taskData.estimatedHours] - Estimated hours
64
+ * @param {Object} [taskData.metas] - Metadata object
65
+ * @param {Object} options - Additional options
66
+ * @returns {Cypress.Chainable} Cypress response
67
+ */
68
+ createTask(taskData, options = {}) {
69
+ return this.create(taskData, options)
70
+ }
71
+
72
+ /**
73
+ * PATCH /api/v1/tasks/{id} - Update task
74
+ * @param {string} id - Task ID
75
+ * @param {Object} updateData - Data to update
76
+ * @param {Object} options - Additional options
77
+ * @returns {Cypress.Chainable} Cypress response
78
+ */
79
+ updateTask(id, updateData, options = {}) {
80
+ return this.update(id, updateData, options)
81
+ }
82
+
83
+ /**
84
+ * DELETE /api/v1/tasks/{id} - Delete task
85
+ * @param {string} id - Task ID
86
+ * @param {Object} options - Additional options
87
+ * @returns {Cypress.Chainable} Cypress response
88
+ */
89
+ deleteTask(id, options = {}) {
90
+ return this.delete(id, options)
91
+ }
92
+
93
+ // ============================================================
94
+ // DATA GENERATORS
95
+ // ============================================================
96
+
97
+ /**
98
+ * Generate random task data for testing
99
+ * @param {Object} overrides - Specific data to override
100
+ * @returns {Object} Generated task data
101
+ */
102
+ generateRandomData(overrides = {}) {
103
+ return this.generateRandomTaskData(overrides)
104
+ }
105
+
106
+ /**
107
+ * Generate random task data for testing
108
+ * @param {Object} overrides - Specific data to override
109
+ * @returns {Object} Generated task data
110
+ */
111
+ generateRandomTaskData(overrides = {}) {
112
+ const timestamp = Date.now()
113
+ const randomId = Math.random().toString(36).substring(2, 8)
114
+
115
+ return {
116
+ title: `Test Task ${randomId} - ${timestamp}`,
117
+ description: `Description for test task created at ${new Date().toISOString()}`,
118
+ status: 'todo',
119
+ priority: 'medium',
120
+ tags: [],
121
+ ...overrides
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Create a test task and return its data
127
+ * @param {Object} taskData - Task data (optional)
128
+ * @returns {Cypress.Chainable} Promise resolving with created task data
129
+ */
130
+ createTestTask(taskData = {}) {
131
+ return this.createTestEntity(taskData)
132
+ }
133
+
134
+ /**
135
+ * Clean up a test task (delete it)
136
+ * @param {string} id - Task ID
137
+ * @returns {Cypress.Chainable} Delete response
138
+ */
139
+ cleanupTestTask(id) {
140
+ return this.cleanup(id)
141
+ }
142
+
143
+ // ============================================================
144
+ // ENTITY-SPECIFIC VALIDATORS
145
+ // ============================================================
146
+
147
+ /**
148
+ * Validate task object structure
149
+ * @param {Object} task - Task object
150
+ * @param {boolean} allowMetas - If metas property is allowed
151
+ */
152
+ validateTaskObject(task, allowMetas = false) {
153
+ // Base fields
154
+ this.validateBaseEntityFields(task)
155
+
156
+ // Required entity fields
157
+ expect(task).to.have.property('title')
158
+ expect(task.title).to.be.a('string')
159
+
160
+ // Optional fields with defaults
161
+ expect(task).to.have.property('status')
162
+ expect(task.status).to.be.oneOf(['todo', 'in-progress', 'review', 'done', 'blocked'])
163
+
164
+ expect(task).to.have.property('priority')
165
+ expect(task.priority).to.be.oneOf(['low', 'medium', 'high', 'urgent'])
166
+
167
+ expect(task).to.have.property('completed')
168
+ expect(task.completed).to.be.a('boolean')
169
+
170
+ expect(task).to.have.property('tags')
171
+ expect(task.tags).to.be.an('array')
172
+
173
+ // Optional fields that can be null
174
+ if (task.description !== null && task.description !== undefined) {
175
+ expect(task.description).to.be.a('string')
176
+ }
177
+
178
+ if (task.dueDate !== null && task.dueDate !== undefined) {
179
+ expect(task.dueDate).to.be.a('string')
180
+ }
181
+
182
+ if (task.estimatedHours !== null && task.estimatedHours !== undefined) {
183
+ // Note: NUMERIC type comes back as string from PostgreSQL
184
+ expect(typeof task.estimatedHours === 'number' || typeof task.estimatedHours === 'string').to.be.true
185
+ }
186
+
187
+ // Validate metas if present
188
+ if (allowMetas && task.hasOwnProperty('metas')) {
189
+ expect(task.metas).to.be.an('object')
190
+ }
191
+ }
192
+
193
+ // ============================================================
194
+ // METADATA HELPERS
195
+ // ============================================================
196
+
197
+ /**
198
+ * Generate sample metadata for testing
199
+ * @param {string} type - Type of metadata ('uiPreferences', 'notifications', 'tracking', 'customFields')
200
+ * @returns {Object} Sample metadata
201
+ */
202
+ generateSampleMetadata(type = 'uiPreferences') {
203
+ const sampleMetas = {
204
+ uiPreferences: {
205
+ colorLabel: 'blue',
206
+ showInKanban: true,
207
+ collapsed: false,
208
+ customIcon: 'star'
209
+ },
210
+ notifications: {
211
+ emailOnDue: true,
212
+ reminderDays: 3,
213
+ notifyAssignee: true,
214
+ channels: ['email', 'slack']
215
+ },
216
+ tracking: {
217
+ actualHours: 5.5,
218
+ startedAt: '2025-12-01T10:00:00Z',
219
+ completedAt: null,
220
+ progressPercent: 75
221
+ },
222
+ customFields: {
223
+ clientRef: 'PRJ-001',
224
+ department: 'Engineering',
225
+ billable: true,
226
+ hourlyRate: 150
227
+ }
228
+ }
229
+
230
+ return { [type]: sampleMetas[type] || sampleMetas.uiPreferences }
231
+ }
232
+ }
233
+
234
+ // Export class for use in tests
235
+ module.exports = TaskAPIController
236
+
237
+ // For global use in Cypress
238
+ if (typeof window !== 'undefined') {
239
+ window.TaskAPIController = TaskAPIController
240
+ }