@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,375 @@
1
+ /**
2
+ * Generic Entity Form POM
3
+ *
4
+ * Page Object Model for entity create/edit forms in Default theme.
5
+ * Uses standardized data-cy selectors from entities.json.
6
+ *
7
+ * Convention: {slug}-{component}-{detail}
8
+ * Examples: tasks-form, customers-field-name, tasks-form-submit
9
+ *
10
+ * Usage:
11
+ * const taskForm = EntityForm.for('tasks')
12
+ * const customerForm = EntityForm.for('customers')
13
+ */
14
+
15
+ // Import entity configs from theme
16
+ import entitiesConfig from '../../fixtures/entities.json'
17
+
18
+ export interface EntityConfig {
19
+ slug: string
20
+ singular: string
21
+ plural: string
22
+ tableName: string
23
+ fields: string[]
24
+ sections: string[]
25
+ filters: string[]
26
+ }
27
+
28
+ export class EntityForm {
29
+ private config: EntityConfig
30
+ private slug: string
31
+
32
+ /**
33
+ * Create a new EntityForm POM instance from entity config
34
+ */
35
+ constructor(entityKey: string) {
36
+ const config = entitiesConfig.entities[entityKey as keyof typeof entitiesConfig.entities]
37
+ if (!config) {
38
+ throw new Error(`Unknown entity: ${entityKey}. Available: ${Object.keys(entitiesConfig.entities).join(', ')}`)
39
+ }
40
+ this.config = config as EntityConfig
41
+ this.slug = config.slug
42
+ }
43
+
44
+ // ============================================
45
+ // STATIC FACTORY METHOD
46
+ // ============================================
47
+
48
+ /**
49
+ * Create an EntityForm from entity key
50
+ */
51
+ static for(entityKey: string): EntityForm {
52
+ return new EntityForm(entityKey)
53
+ }
54
+
55
+ // ============================================
56
+ // DYNAMIC SELECTORS (from entities.json convention)
57
+ // ============================================
58
+
59
+ /**
60
+ * Get selectors for this entity form following the standard convention
61
+ */
62
+ get selectors() {
63
+ const slug = this.slug
64
+ return {
65
+ // Page and form containers
66
+ page: `[data-cy="${slug}-form-page"]`,
67
+ form: `[data-cy="${slug}-form"]`,
68
+ pageTitle: '[data-cy="page-title"]',
69
+
70
+ // Buttons
71
+ submitButton: `[data-cy="${slug}-form-submit"]`,
72
+ cancelButton: `[data-cy="${slug}-form-cancel"]`,
73
+
74
+ // Sections
75
+ section: (sectionName: string) => `[data-cy="${slug}-section-${sectionName}"]`,
76
+
77
+ // Fields
78
+ field: (fieldName: string) => `[data-cy="${slug}-field-${fieldName}"]`,
79
+ fieldInput: (fieldName: string) => `[data-cy="${slug}-field-${fieldName}"] input`,
80
+ fieldTextarea: (fieldName: string) => `[data-cy="${slug}-field-${fieldName}"] textarea`,
81
+ fieldSelect: (fieldName: string) => `[data-cy="${slug}-field-${fieldName}"] [role="combobox"]`,
82
+ fieldCheckbox: (fieldName: string) => `[data-cy="${slug}-field-${fieldName}"] input[type="checkbox"]`,
83
+ fieldOption: (fieldName: string, value: string) => `[data-cy="${slug}-field-${fieldName}-option-${value}"]`,
84
+ fieldError: (fieldName: string) => `[data-cy="${slug}-field-${fieldName}-error"]`,
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Get the entity config
90
+ */
91
+ get entityConfig(): EntityConfig {
92
+ return this.config
93
+ }
94
+
95
+ /**
96
+ * Get available fields for this entity
97
+ */
98
+ get fields(): string[] {
99
+ return this.config.fields
100
+ }
101
+
102
+ /**
103
+ * Get available sections for this entity
104
+ */
105
+ get sections(): string[] {
106
+ return this.config.sections
107
+ }
108
+
109
+ // ============================================
110
+ // VALIDATION METHODS
111
+ // ============================================
112
+
113
+ /**
114
+ * Validate the form page is visible
115
+ */
116
+ validatePageVisible() {
117
+ cy.get(this.selectors.page).should('be.visible')
118
+ return this
119
+ }
120
+
121
+ /**
122
+ * Validate the form is visible
123
+ */
124
+ validateFormVisible() {
125
+ cy.get(this.selectors.form).should('be.visible')
126
+ return this
127
+ }
128
+
129
+ /**
130
+ * Validate the page title text
131
+ */
132
+ validatePageTitle(expectedTitle: string) {
133
+ cy.get(this.selectors.pageTitle).should('contain.text', expectedTitle)
134
+ return this
135
+ }
136
+
137
+ /**
138
+ * Validate a section is visible
139
+ */
140
+ validateSectionVisible(sectionName: string) {
141
+ cy.get(this.selectors.section(sectionName)).should('be.visible')
142
+ return this
143
+ }
144
+
145
+ /**
146
+ * Validate a field is visible
147
+ */
148
+ validateFieldVisible(fieldName: string) {
149
+ cy.get(this.selectors.field(fieldName)).should('be.visible')
150
+ return this
151
+ }
152
+
153
+ /**
154
+ * Validate a field has an error message
155
+ */
156
+ validateFieldHasError(fieldName: string, errorMessage?: string) {
157
+ const errorSelector = this.selectors.fieldError(fieldName)
158
+ cy.get(errorSelector).should('be.visible')
159
+ if (errorMessage) {
160
+ cy.get(errorSelector).should('contain.text', errorMessage)
161
+ }
162
+ return this
163
+ }
164
+
165
+ /**
166
+ * Validate submit button is enabled
167
+ */
168
+ validateSubmitEnabled() {
169
+ cy.get(this.selectors.submitButton).should('not.be.disabled')
170
+ return this
171
+ }
172
+
173
+ /**
174
+ * Validate submit button is disabled
175
+ */
176
+ validateSubmitDisabled() {
177
+ cy.get(this.selectors.submitButton).should('be.disabled')
178
+ return this
179
+ }
180
+
181
+ // ============================================
182
+ // INPUT METHODS
183
+ // ============================================
184
+
185
+ /**
186
+ * Type into a text input field
187
+ */
188
+ typeInField(fieldName: string, value: string) {
189
+ cy.get(this.selectors.fieldInput(fieldName)).clear().type(value)
190
+ return this
191
+ }
192
+
193
+ /**
194
+ * Type into a textarea field
195
+ */
196
+ typeInTextarea(fieldName: string, value: string) {
197
+ cy.get(this.selectors.fieldTextarea(fieldName)).clear().type(value)
198
+ return this
199
+ }
200
+
201
+ /**
202
+ * Clear a text input field
203
+ */
204
+ clearField(fieldName: string) {
205
+ cy.get(this.selectors.fieldInput(fieldName)).clear()
206
+ return this
207
+ }
208
+
209
+ /**
210
+ * Select an option from a select/combobox field
211
+ */
212
+ selectOption(fieldName: string, optionValue: string) {
213
+ cy.get(this.selectors.fieldSelect(fieldName)).click()
214
+ cy.get(this.selectors.fieldOption(fieldName, optionValue)).click()
215
+ return this
216
+ }
217
+
218
+ /**
219
+ * Check a checkbox field
220
+ */
221
+ checkField(fieldName: string) {
222
+ cy.get(this.selectors.fieldCheckbox(fieldName)).check()
223
+ return this
224
+ }
225
+
226
+ /**
227
+ * Uncheck a checkbox field
228
+ */
229
+ uncheckField(fieldName: string) {
230
+ cy.get(this.selectors.fieldCheckbox(fieldName)).uncheck()
231
+ return this
232
+ }
233
+
234
+ /**
235
+ * Fill a date input field
236
+ */
237
+ fillDate(fieldName: string, dateString: string) {
238
+ cy.get(this.selectors.fieldInput(fieldName)).clear().type(dateString)
239
+ return this
240
+ }
241
+
242
+ /**
243
+ * Fill a field (alias for typeInField)
244
+ */
245
+ fillField(fieldName: string, value: string) {
246
+ // Try input first, then textarea
247
+ cy.get(this.selectors.field(fieldName)).then($field => {
248
+ const hasInput = $field.find('input:not([type="checkbox"])').length > 0
249
+ const hasTextarea = $field.find('textarea').length > 0
250
+
251
+ if (hasInput) {
252
+ this.typeInField(fieldName, value)
253
+ } else if (hasTextarea) {
254
+ this.typeInTextarea(fieldName, value)
255
+ }
256
+ })
257
+ return this
258
+ }
259
+
260
+ // ============================================
261
+ // FORM SUBMISSION METHODS
262
+ // ============================================
263
+
264
+ /**
265
+ * Click the submit button
266
+ */
267
+ submit() {
268
+ cy.get(this.selectors.submitButton).click()
269
+ return this
270
+ }
271
+
272
+ /**
273
+ * Click the cancel button
274
+ */
275
+ cancel() {
276
+ cy.get(this.selectors.cancelButton).click()
277
+ return this
278
+ }
279
+
280
+ // ============================================
281
+ // BULK FILL METHODS
282
+ // ============================================
283
+
284
+ /**
285
+ * Fill multiple fields at once
286
+ */
287
+ fillForm(data: Record<string, string | boolean>) {
288
+ Object.entries(data).forEach(([fieldName, value]) => {
289
+ if (typeof value === 'boolean') {
290
+ if (value) {
291
+ this.checkField(fieldName)
292
+ } else {
293
+ this.uncheckField(fieldName)
294
+ }
295
+ } else {
296
+ // Try input first, then textarea
297
+ cy.get(this.selectors.field(fieldName)).then($field => {
298
+ const hasInput = $field.find('input:not([type="checkbox"])').length > 0
299
+ const hasTextarea = $field.find('textarea').length > 0
300
+ const hasSelect = $field.find('[role="combobox"]').length > 0
301
+
302
+ if (hasInput) {
303
+ this.typeInField(fieldName, value)
304
+ } else if (hasTextarea) {
305
+ this.typeInTextarea(fieldName, value)
306
+ } else if (hasSelect) {
307
+ this.selectOption(fieldName, value)
308
+ }
309
+ })
310
+ }
311
+ })
312
+ return this
313
+ }
314
+
315
+ // ============================================
316
+ // NAVIGATION METHODS
317
+ // ============================================
318
+
319
+ /**
320
+ * Visit the create form page
321
+ */
322
+ visitCreate() {
323
+ cy.visit(`/dashboard/${this.slug}/create`)
324
+ this.validatePageVisible()
325
+ return this
326
+ }
327
+
328
+ /**
329
+ * Visit the edit form page
330
+ */
331
+ visitEdit(id: string) {
332
+ cy.visit(`/dashboard/${this.slug}/${id}/edit`)
333
+ this.validatePageVisible()
334
+ return this
335
+ }
336
+
337
+ /**
338
+ * Wait for form to be ready (all fields loaded)
339
+ */
340
+ waitForFormReady() {
341
+ cy.get(this.selectors.form).should('be.visible')
342
+ cy.get(this.selectors.submitButton).should('be.visible')
343
+ return this
344
+ }
345
+
346
+ // ============================================
347
+ // ASSERTION HELPERS
348
+ // ============================================
349
+
350
+ /**
351
+ * Assert field has specific value
352
+ */
353
+ assertFieldValue(fieldName: string, expectedValue: string) {
354
+ cy.get(this.selectors.fieldInput(fieldName)).should('have.value', expectedValue)
355
+ return this
356
+ }
357
+
358
+ /**
359
+ * Assert textarea has specific value
360
+ */
361
+ assertTextareaValue(fieldName: string, expectedValue: string) {
362
+ cy.get(this.selectors.fieldTextarea(fieldName)).should('have.value', expectedValue)
363
+ return this
364
+ }
365
+
366
+ /**
367
+ * Assert select displays specific option
368
+ */
369
+ assertSelectValue(fieldName: string, expectedText: string) {
370
+ cy.get(this.selectors.fieldSelect(fieldName)).should('contain.text', expectedText)
371
+ return this
372
+ }
373
+ }
374
+
375
+ export default EntityForm