@nextsparkjs/ai-workflow 0.1.0-beta.100

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 (272) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -0
  3. package/claude/_docs/workflows-optimizations.md +359 -0
  4. package/claude/agents/api-tester.md +634 -0
  5. package/claude/agents/architecture-supervisor.md +1351 -0
  6. package/claude/agents/backend-developer.md +997 -0
  7. package/claude/agents/backend-validator.md +417 -0
  8. package/claude/agents/bdd-docs-writer.md +737 -0
  9. package/claude/agents/block-developer.md +677 -0
  10. package/claude/agents/code-reviewer.md +1432 -0
  11. package/claude/agents/db-developer.md +721 -0
  12. package/claude/agents/db-validator.md +407 -0
  13. package/claude/agents/demo-video-generator.md +493 -0
  14. package/claude/agents/documentation-writer.md +1268 -0
  15. package/claude/agents/frontend-developer.md +1234 -0
  16. package/claude/agents/frontend-validator.md +777 -0
  17. package/claude/agents/functional-validator.md +630 -0
  18. package/claude/agents/mock-analyst.md +387 -0
  19. package/claude/agents/product-manager.md +963 -0
  20. package/claude/agents/qa-automation.md +1762 -0
  21. package/claude/agents/release-manager.md +634 -0
  22. package/claude/agents/selectors-translator.md +262 -0
  23. package/claude/agents/unit-test-writer.md +785 -0
  24. package/claude/agents/visual-comparator.md +329 -0
  25. package/claude/agents/workflow-maintainer.md +352 -0
  26. package/claude/commands/do/README.md +88 -0
  27. package/claude/commands/do/create-api.md +64 -0
  28. package/claude/commands/do/create-entity.md +66 -0
  29. package/claude/commands/do/create-migration.md +64 -0
  30. package/claude/commands/do/create-plugin.md +56 -0
  31. package/claude/commands/do/create-theme.md +70 -0
  32. package/claude/commands/do/mock-data.md +67 -0
  33. package/claude/commands/do/reset-db.md +71 -0
  34. package/claude/commands/do/setup-scheduled-action.md +75 -0
  35. package/claude/commands/do/sync-code-review.md +117 -0
  36. package/claude/commands/do/update-selectors.md +112 -0
  37. package/claude/commands/do/use-skills.md +90 -0
  38. package/claude/commands/do/validate-blocks.md +69 -0
  39. package/claude/commands/how-to/README.md +261 -0
  40. package/claude/commands/how-to/add-metadata.md +692 -0
  41. package/claude/commands/how-to/add-taxonomies.md +806 -0
  42. package/claude/commands/how-to/add-translations.md +571 -0
  43. package/claude/commands/how-to/create-api.md +577 -0
  44. package/claude/commands/how-to/create-block.md +575 -0
  45. package/claude/commands/how-to/create-child-entities.md +771 -0
  46. package/claude/commands/how-to/create-entity.md +597 -0
  47. package/claude/commands/how-to/create-migrations.md +605 -0
  48. package/claude/commands/how-to/create-plugin.md +654 -0
  49. package/claude/commands/how-to/customize-app.md +481 -0
  50. package/claude/commands/how-to/customize-dashboard.md +553 -0
  51. package/claude/commands/how-to/customize-theme.md +438 -0
  52. package/claude/commands/how-to/define-features-flows.md +632 -0
  53. package/claude/commands/how-to/deploy.md +507 -0
  54. package/claude/commands/how-to/handle-file-uploads.md +746 -0
  55. package/claude/commands/how-to/implement-search.md +1001 -0
  56. package/claude/commands/how-to/install-plugins.md +352 -0
  57. package/claude/commands/how-to/manage-test-coverage.md +984 -0
  58. package/claude/commands/how-to/run-tests.md +400 -0
  59. package/claude/commands/how-to/set-app-languages.md +601 -0
  60. package/claude/commands/how-to/set-plans-and-permissions.md +575 -0
  61. package/claude/commands/how-to/set-scheduled-actions.md +527 -0
  62. package/claude/commands/how-to/set-user-roles-and-permissions.md +550 -0
  63. package/claude/commands/how-to/setup-authentication.md +388 -0
  64. package/claude/commands/how-to/setup-claude-code.md +440 -0
  65. package/claude/commands/how-to/setup-database.md +274 -0
  66. package/claude/commands/how-to/setup-email-providers.md +598 -0
  67. package/claude/commands/how-to/setup-mobile-dev.md +627 -0
  68. package/claude/commands/how-to/start.md +500 -0
  69. package/claude/commands/how-to/use-devtools.md +639 -0
  70. package/claude/commands/how-to/use-superadmin.md +622 -0
  71. package/claude/commands/session/README.md +193 -0
  72. package/claude/commands/session/block-create.md +190 -0
  73. package/claude/commands/session/block-list.md +203 -0
  74. package/claude/commands/session/block-update.md +192 -0
  75. package/claude/commands/session/block-validate.md +218 -0
  76. package/claude/commands/session/changelog.md +115 -0
  77. package/claude/commands/session/close.md +225 -0
  78. package/claude/commands/session/commit.md +174 -0
  79. package/claude/commands/session/db-entity.md +206 -0
  80. package/claude/commands/session/db-fix.md +212 -0
  81. package/claude/commands/session/db-sample.md +206 -0
  82. package/claude/commands/session/demo.md +178 -0
  83. package/claude/commands/session/doc-bdd.md +207 -0
  84. package/claude/commands/session/doc-feature.md +218 -0
  85. package/claude/commands/session/doc-read.md +225 -0
  86. package/claude/commands/session/execute.md +204 -0
  87. package/claude/commands/session/explain.md +202 -0
  88. package/claude/commands/session/fix-bug.md +210 -0
  89. package/claude/commands/session/fix-build.md +182 -0
  90. package/claude/commands/session/fix-test.md +189 -0
  91. package/claude/commands/session/pending.md +232 -0
  92. package/claude/commands/session/refine.md +188 -0
  93. package/claude/commands/session/resume.md +192 -0
  94. package/claude/commands/session/review.md +192 -0
  95. package/claude/commands/session/scope-change.md +181 -0
  96. package/claude/commands/session/start-blocks.md +347 -0
  97. package/claude/commands/session/start.md +604 -0
  98. package/claude/commands/session/status.md +169 -0
  99. package/claude/commands/session/test-fix.md +221 -0
  100. package/claude/commands/session/test-run.md +203 -0
  101. package/claude/commands/session/test-write.md +242 -0
  102. package/claude/commands/session/validate.md +162 -0
  103. package/claude/config/context.json +40 -0
  104. package/claude/config/github.json +69 -0
  105. package/claude/config/github.schema.json +106 -0
  106. package/claude/config/team.json +46 -0
  107. package/claude/config/team.schema.json +106 -0
  108. package/claude/config/workspace.json +43 -0
  109. package/claude/config/workspace.schema.json +75 -0
  110. package/claude/skills/README.md +228 -0
  111. package/claude/skills/accessibility/SKILL.md +573 -0
  112. package/claude/skills/api-bypass-layers/SKILL.md +550 -0
  113. package/claude/skills/asana-integration/SKILL.md +499 -0
  114. package/claude/skills/better-auth/SKILL.md +666 -0
  115. package/claude/skills/billing-subscriptions/SKILL.md +660 -0
  116. package/claude/skills/block-decision-matrix/SKILL.md +359 -0
  117. package/claude/skills/clickup-integration/SKILL.md +434 -0
  118. package/claude/skills/core-theme-responsibilities/SKILL.md +485 -0
  119. package/claude/skills/create-plugin/SKILL.md +425 -0
  120. package/claude/skills/create-theme/SKILL.md +331 -0
  121. package/claude/skills/cypress-api/SKILL.md +511 -0
  122. package/claude/skills/cypress-api/scripts/generate-api-controller.py +329 -0
  123. package/claude/skills/cypress-api/scripts/generate-api-test.py +930 -0
  124. package/claude/skills/cypress-e2e/SKILL.md +526 -0
  125. package/claude/skills/cypress-e2e/scripts/extract-selectors.py +383 -0
  126. package/claude/skills/cypress-e2e/scripts/generate-uat-test.py +788 -0
  127. package/claude/skills/cypress-selectors/SKILL.md +309 -0
  128. package/claude/skills/cypress-selectors/scripts/extract-missing.py +243 -0
  129. package/claude/skills/cypress-selectors/scripts/generate-block-selectors.py +283 -0
  130. package/claude/skills/cypress-selectors/scripts/validate-selectors.py +145 -0
  131. package/claude/skills/database-migrations/SKILL.md +335 -0
  132. package/claude/skills/database-migrations/scripts/generate-sample-data.py +284 -0
  133. package/claude/skills/database-migrations/scripts/validate-migration.py +323 -0
  134. package/claude/skills/design-system/SKILL.md +682 -0
  135. package/claude/skills/documentation/SKILL.md +540 -0
  136. package/claude/skills/entity-api/SKILL.md +482 -0
  137. package/claude/skills/entity-system/SKILL.md +635 -0
  138. package/claude/skills/entity-system/scripts/generate-child-migration.py +298 -0
  139. package/claude/skills/entity-system/scripts/generate-metas-migration.py +233 -0
  140. package/claude/skills/entity-system/scripts/generate-migration.py +382 -0
  141. package/claude/skills/entity-system/scripts/generate-sample-data.py +418 -0
  142. package/claude/skills/entity-system/scripts/scaffold-entity.py +661 -0
  143. package/claude/skills/github/SKILL.md +467 -0
  144. package/claude/skills/i18n-nextintl/SKILL.md +302 -0
  145. package/claude/skills/i18n-nextintl/scripts/add-translation.py +243 -0
  146. package/claude/skills/i18n-nextintl/scripts/extract-hardcoded.py +246 -0
  147. package/claude/skills/i18n-nextintl/scripts/validate-translations.py +260 -0
  148. package/claude/skills/impact-analysis/SKILL.md +203 -0
  149. package/claude/skills/jest-unit/SKILL.md +306 -0
  150. package/claude/skills/jest-unit/references/component-testing.md +371 -0
  151. package/claude/skills/jest-unit/references/mocking-patterns.md +380 -0
  152. package/claude/skills/jest-unit/references/service-hook-testing.md +454 -0
  153. package/claude/skills/jira-integration/SKILL.md +539 -0
  154. package/claude/skills/media-library/SKILL.md +743 -0
  155. package/claude/skills/mock-analysis/SKILL.md +276 -0
  156. package/claude/skills/monorepo-architecture/SKILL.md +162 -0
  157. package/claude/skills/nextjs-api-development/SKILL.md +364 -0
  158. package/claude/skills/nextjs-api-development/scripts/generate-crud-tests.py +456 -0
  159. package/claude/skills/nextjs-api-development/scripts/scaffold-endpoint.py +481 -0
  160. package/claude/skills/nextjs-api-development/scripts/validate-api.py +283 -0
  161. package/claude/skills/notion-integration/SKILL.md +641 -0
  162. package/claude/skills/npm-development-workflow/SKILL.md +480 -0
  163. package/claude/skills/page-builder-blocks/SKILL.md +530 -0
  164. package/claude/skills/page-builder-blocks/scripts/scaffold-block.py +444 -0
  165. package/claude/skills/permissions-system/SKILL.md +619 -0
  166. package/claude/skills/plugins/SKILL.md +340 -0
  167. package/claude/skills/plugins/references/plugin-templates.md +414 -0
  168. package/claude/skills/plugins/references/plugin-testing.md +353 -0
  169. package/claude/skills/plugins/references/plugin-types.md +198 -0
  170. package/claude/skills/plugins/scripts/scaffold-plugin.py +443 -0
  171. package/claude/skills/pom-patterns/SKILL.md +452 -0
  172. package/claude/skills/pom-patterns/scripts/generate-pom.py +392 -0
  173. package/claude/skills/rate-limiting/SKILL.md +342 -0
  174. package/claude/skills/react-best-practices/AGENTS.md +2410 -0
  175. package/claude/skills/react-best-practices/README.md +123 -0
  176. package/claude/skills/react-best-practices/SKILL.md +125 -0
  177. package/claude/skills/react-best-practices/metadata.json +15 -0
  178. package/claude/skills/react-best-practices/rules/_sections.md +46 -0
  179. package/claude/skills/react-best-practices/rules/_template.md +28 -0
  180. package/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  181. package/claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
  182. package/claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
  183. package/claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
  184. package/claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
  185. package/claude/skills/react-best-practices/rules/async-parallel.md +28 -0
  186. package/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  187. package/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  188. package/claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
  189. package/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  190. package/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  191. package/claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
  192. package/claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
  193. package/claude/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
  194. package/claude/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  195. package/claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  196. package/claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
  197. package/claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  198. package/claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  199. package/claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  200. package/claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  201. package/claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
  202. package/claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  203. package/claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
  204. package/claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  205. package/claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  206. package/claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  207. package/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  208. package/claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
  209. package/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  210. package/claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  211. package/claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  212. package/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  213. package/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  214. package/claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  215. package/claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  216. package/claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  217. package/claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  218. package/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  219. package/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  220. package/claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
  221. package/claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  222. package/claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  223. package/claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  224. package/claude/skills/react-best-practices/rules/server-cache-react.md +76 -0
  225. package/claude/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
  226. package/claude/skills/react-best-practices/rules/server-serialization.md +38 -0
  227. package/claude/skills/react-patterns/SKILL.md +688 -0
  228. package/claude/skills/registry-system/SKILL.md +331 -0
  229. package/claude/skills/scheduled-actions/SKILL.md +671 -0
  230. package/claude/skills/scope-enforcement/SKILL.md +542 -0
  231. package/claude/skills/scope-enforcement/scripts/validate-scope.py +357 -0
  232. package/claude/skills/server-actions/SKILL.md +493 -0
  233. package/claude/skills/service-layer/SKILL.md +587 -0
  234. package/claude/skills/session-management/SKILL.md +266 -0
  235. package/claude/skills/session-management/scripts/create-session.py +166 -0
  236. package/claude/skills/session-management/scripts/iteration-close.sh +105 -0
  237. package/claude/skills/session-management/scripts/iteration-init.sh +180 -0
  238. package/claude/skills/session-management/scripts/session-archive.sh +87 -0
  239. package/claude/skills/session-management/scripts/session-close.sh +133 -0
  240. package/claude/skills/session-management/scripts/session-init.sh +225 -0
  241. package/claude/skills/session-management/scripts/session-list.sh +163 -0
  242. package/claude/skills/session-management/scripts/split-plan.sh +116 -0
  243. package/claude/skills/shadcn-components/SKILL.md +586 -0
  244. package/claude/skills/shadcn-theming/SKILL.md +446 -0
  245. package/claude/skills/suspense-loading/SKILL.md +280 -0
  246. package/claude/skills/tailwind-theming/SKILL.md +507 -0
  247. package/claude/skills/tanstack-query/SKILL.md +608 -0
  248. package/claude/skills/test-coverage/SKILL.md +239 -0
  249. package/claude/skills/web-design-guidelines/SKILL.md +39 -0
  250. package/claude/skills/zod-validation/SKILL.md +537 -0
  251. package/claude/templates/blocks/progress.md +86 -0
  252. package/claude/templates/iteration/changes.md +61 -0
  253. package/claude/templates/iteration/progress.md +55 -0
  254. package/claude/templates/log.md +31 -0
  255. package/claude/templates/story/context.md +77 -0
  256. package/claude/templates/story/pendings.md +37 -0
  257. package/claude/templates/story/plan.md +299 -0
  258. package/claude/templates/story/requirements.md +109 -0
  259. package/claude/templates/story/scope.json +10 -0
  260. package/claude/templates/story/tests.md +91 -0
  261. package/claude/templates/task/progress.md +58 -0
  262. package/claude/templates/task/requirements.md +54 -0
  263. package/claude/workflows/README.md +154 -0
  264. package/claude/workflows/blocks.md +614 -0
  265. package/claude/workflows/story.md +1207 -0
  266. package/claude/workflows/task.md +927 -0
  267. package/claude/workflows/tweak.md +527 -0
  268. package/cursor/.gitkeep +0 -0
  269. package/package.json +35 -0
  270. package/scripts/postinstall.mjs +198 -0
  271. package/scripts/setup.mjs +282 -0
  272. package/scripts/sync.mjs +209 -0
@@ -0,0 +1,788 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Generate UAT Test Script
4
+
5
+ Generates a UAT test file and optional BDD documentation for an entity.
6
+
7
+ Usage:
8
+ python generate-uat-test.py --entity ENTITY --role ROLE [--theme THEME] [--with-bdd]
9
+
10
+ Options:
11
+ --entity ENTITY Entity name (e.g., tasks, customers)
12
+ --theme THEME Theme name (default: default)
13
+ --role ROLE Role name (owner, admin, member, editor, viewer)
14
+ --session SESSION Session name for @scope tag (optional)
15
+ --with-bdd Generate BDD documentation file
16
+ --dry-run Preview without writing to file
17
+ """
18
+
19
+ import os
20
+ import sys
21
+ import re
22
+ import argparse
23
+ from pathlib import Path
24
+ from datetime import datetime
25
+ from typing import Optional
26
+
27
+
28
+ def to_pascal_case(name: str) -> str:
29
+ """Convert kebab-case/snake_case to PascalCase."""
30
+ return ''.join(x.title() for x in re.split(r'[-_]', name))
31
+
32
+
33
+ def to_singular(name: str) -> str:
34
+ """Convert plural to singular (simple English rules)."""
35
+ if name.endswith('ies'):
36
+ return name[:-3] + 'y'
37
+ elif name.endswith('es'):
38
+ return name[:-2]
39
+ elif name.endswith('s'):
40
+ return name[:-1]
41
+ return name
42
+
43
+
44
+ def get_login_helper(role: str) -> str:
45
+ """Get the login helper function name for a role."""
46
+ role_map = {
47
+ 'owner': 'loginAsOwner',
48
+ 'admin': 'loginAsAdmin',
49
+ 'member': 'loginAsMember',
50
+ 'editor': 'loginAsEditor',
51
+ 'viewer': 'loginAsViewer',
52
+ 'superadmin': 'loginAsSuperadmin',
53
+ 'developer': 'loginAsDeveloper',
54
+ }
55
+ return role_map.get(role.lower(), 'loginAsOwner')
56
+
57
+
58
+ def get_role_access_level(role: str) -> str:
59
+ """Get access level description for a role."""
60
+ access_map = {
61
+ 'owner': 'Full CRUD Access',
62
+ 'admin': 'Full CRUD Access',
63
+ 'member': 'Limited Access',
64
+ 'editor': 'Edit Access',
65
+ 'viewer': 'Read-Only Access',
66
+ }
67
+ return access_map.get(role.lower(), 'Standard Access')
68
+
69
+
70
+ def generate_test_content(
71
+ entity: str,
72
+ role: str,
73
+ theme: str,
74
+ session: Optional[str] = None
75
+ ) -> str:
76
+ """Generate the UAT test file content."""
77
+ singular = to_singular(entity)
78
+ pascal_singular = to_pascal_case(singular)
79
+ pascal_plural = to_pascal_case(entity)
80
+ role_upper = role.upper()
81
+ entity_upper = entity.upper()
82
+ login_helper = get_login_helper(role)
83
+ access_level = get_role_access_level(role)
84
+ timestamp = datetime.now().strftime('%Y-%m-%d')
85
+
86
+ # Build tags
87
+ tags = [f"'@uat'", f"'@feat-{entity}'", f"'@role-{role}'", "'@crud'", "'@regression'"]
88
+ if session:
89
+ tags.append(f"'@scope-{session}'")
90
+ tags_str = ', '.join(tags)
91
+
92
+ return f'''/// <reference types="cypress" />
93
+
94
+ /**
95
+ * {pascal_plural} CRUD - {role.title()} Role ({access_level})
96
+ *
97
+ * Generated: {timestamp}
98
+ * Theme: {theme}
99
+ *
100
+ * UAT tests for {entity} entity with {role.title()} role permissions.
101
+ */
102
+
103
+ import * as allure from 'allure-cypress'
104
+
105
+ import {{ {pascal_plural}POM }} from '../../src/entities/{pascal_plural}POM'
106
+ import {{ {login_helper} }} from '../../src/session-helpers'
107
+
108
+ describe('{pascal_plural} CRUD - {role.title()} Role ({access_level})', {{
109
+ tags: [{tags_str}]
110
+ }}, () => {{
111
+ const pom = {pascal_plural}POM.create()
112
+
113
+ beforeEach(() => {{
114
+ allure.epic('UAT')
115
+ allure.feature('{pascal_plural}')
116
+ allure.story('{role.title()} Permissions')
117
+ pom.setupApiIntercepts()
118
+ {login_helper}()
119
+ pom.visitList()
120
+ pom.api.waitForList()
121
+ pom.waitForList()
122
+ }})
123
+
124
+ // ============================================================
125
+ // CREATE - {role.title()} can create {entity}
126
+ // ============================================================
127
+ describe('CREATE - {role.title()} can create {entity}', {{ tags: '@smoke' }}, () => {{
128
+ it('{role_upper}_{entity_upper}_CREATE_001: should create new {singular} successfully', {{ tags: '@smoke' }}, () => {{
129
+ allure.severity('critical')
130
+
131
+ const entityName = `{role.title()} {pascal_singular} ${{Date.now()}}`
132
+
133
+ // Click create button
134
+ pom.clickAdd()
135
+
136
+ // Validate form is visible
137
+ pom.waitForForm()
138
+
139
+ // TODO: Fill required fields based on entity schema
140
+ // pom.fillTextField('title', entityName)
141
+
142
+ // Submit form
143
+ pom.submitForm()
144
+
145
+ // Wait for API response
146
+ pom.api.waitForCreate()
147
+
148
+ // Validate redirect to list
149
+ cy.url().should('include', `/dashboard/${{pom.entitySlug}}`)
150
+
151
+ // Validate entity appears in list
152
+ pom.assert{pascal_singular}InList(entityName)
153
+
154
+ cy.log('Created {singular} successfully')
155
+ }})
156
+
157
+ it('{role_upper}_{entity_upper}_CREATE_002: should create {singular} with all fields', () => {{
158
+ const entityName = `Full {pascal_singular} ${{Date.now()}}`
159
+
160
+ // Click create button
161
+ pom.clickAdd()
162
+
163
+ // Validate form is visible
164
+ pom.waitForForm()
165
+
166
+ // TODO: Fill all fields based on entity schema
167
+ // pom.fillTextField('title', entityName)
168
+ // pom.fillTextarea('description', 'Description text')
169
+ // pom.selectOption('status', 'active')
170
+
171
+ // Submit form
172
+ pom.submitForm()
173
+
174
+ // Wait for API response
175
+ pom.api.waitForCreate()
176
+
177
+ // Validate entity appears in list
178
+ cy.url().should('include', `/dashboard/${{pom.entitySlug}}`)
179
+ pom.assert{pascal_singular}InList(entityName)
180
+
181
+ cy.log('Created full {singular} successfully')
182
+ }})
183
+ }})
184
+
185
+ // ============================================================
186
+ // READ - {role.title()} can read {entity}
187
+ // ============================================================
188
+ describe('READ - {role.title()} can read {entity}', {{ tags: '@smoke' }}, () => {{
189
+ it('{role_upper}_{entity_upper}_READ_001: should view {singular} list', {{ tags: '@smoke' }}, () => {{
190
+ allure.severity('critical')
191
+ // Validate list is visible
192
+ pom.assertTableVisible()
193
+
194
+ cy.log('{role.title()} can view {singular} list')
195
+ }})
196
+
197
+ it('{role_upper}_{entity_upper}_READ_002: should view {singular} details', () => {{
198
+ // Check if there are entities to view
199
+ cy.get('body').then($body => {{
200
+ if ($body.find(pom.selectors.rowGeneric).length > 0) {{
201
+ // Click the first row (navigation via onClick)
202
+ cy.get(pom.selectors.rowGeneric).first().click()
203
+
204
+ // Should navigate to detail page
205
+ cy.url().should('match', new RegExp(`/dashboard/${{pom.entitySlug}}/[a-z0-9-]+`))
206
+
207
+ cy.log('{role.title()} can view {singular} details')
208
+ }} else {{
209
+ cy.log('No {entity} available to view details')
210
+ }}
211
+ }})
212
+ }})
213
+ }})
214
+
215
+ // ============================================================
216
+ // UPDATE - {role.title()} can update {entity}
217
+ // ============================================================
218
+ describe('UPDATE - {role.title()} can update {entity}', () => {{
219
+ it('{role_upper}_{entity_upper}_UPDATE_001: should edit {singular} successfully', () => {{
220
+ // Check if there are entities to edit
221
+ cy.get('body').then($body => {{
222
+ if ($body.find(pom.selectors.rowActionEditGeneric).length > 0) {{
223
+ // Click edit button on first entity
224
+ cy.get(pom.selectors.rowActionEditGeneric).first().click()
225
+
226
+ // Validate form is visible
227
+ pom.waitForForm()
228
+
229
+ // TODO: Update entity-specific fields
230
+ const updatedName = `Updated {pascal_singular} ${{Date.now()}}`
231
+ // pom.fillTextField('title', updatedName)
232
+
233
+ // Submit form
234
+ pom.submitForm()
235
+
236
+ // Wait for API response
237
+ pom.api.waitForUpdate()
238
+
239
+ // Validate update
240
+ cy.url().should('include', `/dashboard/${{pom.entitySlug}}`)
241
+
242
+ cy.log('{role.title()} updated {singular} successfully')
243
+ }} else {{
244
+ cy.log('No {entity} available to edit')
245
+ }}
246
+ }})
247
+ }})
248
+ }})
249
+
250
+ // ============================================================
251
+ // DELETE - {role.title()} can delete {entity}
252
+ // ============================================================
253
+ describe('DELETE - {role.title()} can delete {entity}', () => {{
254
+ it('{role_upper}_{entity_upper}_DELETE_001: should delete {singular} successfully', () => {{
255
+ // First, create an entity to delete
256
+ const entityName = `Delete Test ${{Date.now()}}`
257
+
258
+ pom.clickAdd()
259
+ pom.waitForForm()
260
+ // TODO: Fill required fields
261
+ // pom.fillTextField('title', entityName)
262
+ pom.submitForm()
263
+ pom.api.waitForCreate()
264
+
265
+ // Navigate back to list and wait for it to load
266
+ pom.visitList()
267
+ pom.waitForList()
268
+
269
+ // Wait for entity to appear in the list
270
+ pom.assert{pascal_singular}InList(entityName)
271
+
272
+ // Delete the entity
273
+ pom.clickRowByText(entityName)
274
+ pom.waitForDetail()
275
+
276
+ // Click delete button
277
+ pom.clickDelete()
278
+
279
+ // Confirm deletion (2-step)
280
+ cy.get(pom.selectors.deleteConfirm).should('be.visible').click()
281
+ cy.get(pom.selectors.parentDeleteConfirm).should('be.visible').click()
282
+
283
+ // Wait for delete API response
284
+ pom.api.waitForDelete()
285
+
286
+ // Navigate to list and verify deletion
287
+ pom.visitList()
288
+ pom.api.waitForList()
289
+ pom.waitForList()
290
+ pom.assert{pascal_singular}NotInList(entityName)
291
+
292
+ cy.log('{role.title()} deleted {singular} successfully')
293
+ }})
294
+ }})
295
+
296
+ after(() => {{
297
+ cy.log('{pascal_plural} CRUD tests completed')
298
+ }})
299
+ }})
300
+ '''
301
+
302
+
303
+ def generate_bdd_content(
304
+ entity: str,
305
+ role: str,
306
+ theme: str
307
+ ) -> str:
308
+ """Generate the BDD documentation file content."""
309
+ singular = to_singular(entity)
310
+ singular_es = singular # Would need proper translation
311
+ pascal_singular = to_pascal_case(singular)
312
+ pascal_plural = to_pascal_case(entity)
313
+ role_upper = role.upper()
314
+ entity_upper = entity.upper()
315
+ access_level = get_role_access_level(role)
316
+
317
+ # Spanish translations (simplified)
318
+ role_es = {
319
+ 'owner': 'Owner',
320
+ 'admin': 'Admin',
321
+ 'member': 'Member',
322
+ 'editor': 'Editor',
323
+ 'viewer': 'Viewer',
324
+ }.get(role.lower(), role.title())
325
+
326
+ return f'''# {pascal_plural} UI - {role.title()} Role (Format: BDD/Gherkin - Bilingual)
327
+
328
+ > **Test File:** `{entity}-{role}.cy.ts`
329
+ > **Format:** Behavior-Driven Development (BDD) with Given/When/Then
330
+ > **Languages:** English / Spanish (side-by-side)
331
+ > **Total Tests:** 6
332
+
333
+ ---
334
+
335
+ ## Feature: {pascal_plural} Management - {role.title()} Role ({access_level})
336
+
337
+ <table>
338
+ <tr>
339
+ <th width="50%">English</th>
340
+ <th width="50%">Espanol</th>
341
+ </tr>
342
+ <tr>
343
+ <td>
344
+
345
+ As a **{role.title()}**
346
+ I want to **manage {entity} through the dashboard UI**
347
+ So that **I can create, read, update, and delete {entity} for my team**
348
+
349
+ </td>
350
+ <td>
351
+
352
+ Como **{role_es}**
353
+ Quiero **gestionar {entity} a traves del dashboard**
354
+ Para **crear, leer, actualizar y eliminar {entity} de mi equipo**
355
+
356
+ </td>
357
+ </tr>
358
+ </table>
359
+
360
+ ### Background
361
+
362
+ <table>
363
+ <tr>
364
+ <th width="50%">English</th>
365
+ <th width="50%">Espanol</th>
366
+ </tr>
367
+ <tr>
368
+ <td>
369
+
370
+ ```gherkin
371
+ Given I am logged in as {role.title()}
372
+ And I have navigated to the {pascal_plural} dashboard
373
+ And the {entity} list has loaded successfully
374
+ ```
375
+
376
+ </td>
377
+ <td>
378
+
379
+ ```gherkin
380
+ Given estoy logueado como {role_es}
381
+ And he navegado al dashboard de {pascal_plural}
382
+ And la lista de {entity} ha cargado exitosamente
383
+ ```
384
+
385
+ </td>
386
+ </tr>
387
+ </table>
388
+
389
+ ---
390
+
391
+ ## CREATE - {role.title()} can create {entity} `@smoke`
392
+
393
+ ### {role_upper}_{entity_upper}_CREATE_001: Create new {singular} successfully `@smoke` `@critical`
394
+
395
+ <table>
396
+ <tr>
397
+ <th width="50%">English</th>
398
+ <th width="50%">Espanol</th>
399
+ </tr>
400
+ <tr>
401
+ <td>
402
+
403
+ ```gherkin
404
+ Scenario: {role.title()} creates a simple {singular}
405
+
406
+ Given I am logged in as {role.title()}
407
+ And I am on the {pascal_plural} list page
408
+ When I click the "Add" button
409
+ Then the {singular} creation form should appear
410
+
411
+ When I enter "New {pascal_singular}" in the Title field
412
+ And I click the "Save" button
413
+ Then the form should submit successfully
414
+ And I should see a success message
415
+ And I should be redirected to the {entity} list
416
+ And I should see "New {pascal_singular}" in the {singular} list
417
+ ```
418
+
419
+ </td>
420
+ <td>
421
+
422
+ ```gherkin
423
+ Scenario: {role_es} crea un/a {singular_es} simple
424
+
425
+ Given estoy logueado como {role_es}
426
+ And estoy en la pagina de lista de {pascal_plural}
427
+ When hago clic en el boton "Agregar"
428
+ Then deberia aparecer el formulario de creacion
429
+
430
+ When ingreso "Nuevo/a {pascal_singular}" en el campo Titulo
431
+ And hago clic en el boton "Guardar"
432
+ Then el formulario deberia enviarse exitosamente
433
+ And deberia ver un mensaje de exito
434
+ And deberia ser redirigido a la lista de {entity}
435
+ And deberia ver "Nuevo/a {pascal_singular}" en la lista
436
+ ```
437
+
438
+ </td>
439
+ </tr>
440
+ </table>
441
+
442
+ **Visual Flow:**
443
+ ```
444
+ [{pascal_plural} List] -> [Click Add] -> [Form Modal] -> [Fill Title] -> [Save] -> [List with new {singular}]
445
+ ```
446
+
447
+ ---
448
+
449
+ ### {role_upper}_{entity_upper}_CREATE_002: Create {singular} with all fields
450
+
451
+ <table>
452
+ <tr>
453
+ <th width="50%">English</th>
454
+ <th width="50%">Espanol</th>
455
+ </tr>
456
+ <tr>
457
+ <td>
458
+
459
+ ```gherkin
460
+ Scenario: {role.title()} creates a {singular} with complete information
461
+
462
+ Given I am logged in as {role.title()}
463
+ And I am on the {pascal_plural} list page
464
+ When I click the "Add" button
465
+ Then the {singular} creation form should appear
466
+
467
+ When I fill in all available fields
468
+ And I click the "Save" button
469
+ Then the form should submit successfully
470
+ And the {singular} should be created with all provided values
471
+ And I should see the {singular} in the list
472
+ ```
473
+
474
+ </td>
475
+ <td>
476
+
477
+ ```gherkin
478
+ Scenario: {role_es} crea un/a {singular_es} con informacion completa
479
+
480
+ Given estoy logueado como {role_es}
481
+ And estoy en la pagina de lista de {pascal_plural}
482
+ When hago clic en el boton "Agregar"
483
+ Then deberia aparecer el formulario de creacion
484
+
485
+ When completo todos los campos disponibles
486
+ And hago clic en el boton "Guardar"
487
+ Then el formulario deberia enviarse exitosamente
488
+ And el/la {singular_es} deberia crearse con todos los valores
489
+ And deberia ver el/la {singular_es} en la lista
490
+ ```
491
+
492
+ </td>
493
+ </tr>
494
+ </table>
495
+
496
+ ---
497
+
498
+ ## READ - {role.title()} can read {entity} `@smoke`
499
+
500
+ ### {role_upper}_{entity_upper}_READ_001: View {singular} list `@smoke` `@critical`
501
+
502
+ <table>
503
+ <tr>
504
+ <th width="50%">English</th>
505
+ <th width="50%">Espanol</th>
506
+ </tr>
507
+ <tr>
508
+ <td>
509
+
510
+ ```gherkin
511
+ Scenario: {role.title()} can view the {entity} table
512
+
513
+ Given I am logged in as {role.title()}
514
+ When I navigate to the {pascal_plural} dashboard
515
+ Then I should see the {entity} table
516
+ And the table should display {singular} information
517
+ ```
518
+
519
+ </td>
520
+ <td>
521
+
522
+ ```gherkin
523
+ Scenario: {role_es} puede ver la tabla de {entity}
524
+
525
+ Given estoy logueado como {role_es}
526
+ When navego al dashboard de {pascal_plural}
527
+ Then deberia ver la tabla de {entity}
528
+ And la tabla deberia mostrar informacion de {singular_es}
529
+ ```
530
+
531
+ </td>
532
+ </tr>
533
+ </table>
534
+
535
+ ---
536
+
537
+ ### {role_upper}_{entity_upper}_READ_002: View {singular} details
538
+
539
+ <table>
540
+ <tr>
541
+ <th width="50%">English</th>
542
+ <th width="50%">Espanol</th>
543
+ </tr>
544
+ <tr>
545
+ <td>
546
+
547
+ ```gherkin
548
+ Scenario: {role.title()} can view individual {singular} details
549
+
550
+ Given I am logged in as {role.title()}
551
+ And there is at least one {singular} in the list
552
+ When I click on a {singular} row
553
+ Then I should be navigated to the {singular} detail page
554
+ And the URL should contain the {singular} ID
555
+ And I should see the complete {singular} information
556
+ ```
557
+
558
+ </td>
559
+ <td>
560
+
561
+ ```gherkin
562
+ Scenario: {role_es} puede ver detalles de un/a {singular_es}
563
+
564
+ Given estoy logueado como {role_es}
565
+ And existe al menos un/a {singular_es} en la lista
566
+ When hago clic en una fila de {singular_es}
567
+ Then deberia ser navegado a la pagina de detalle
568
+ And la URL deberia contener el ID del/la {singular_es}
569
+ And deberia ver la informacion completa
570
+ ```
571
+
572
+ </td>
573
+ </tr>
574
+ </table>
575
+
576
+ ---
577
+
578
+ ## UPDATE - {role.title()} can update {entity}
579
+
580
+ ### {role_upper}_{entity_upper}_UPDATE_001: Edit existing {singular}
581
+
582
+ <table>
583
+ <tr>
584
+ <th width="50%">English</th>
585
+ <th width="50%">Espanol</th>
586
+ </tr>
587
+ <tr>
588
+ <td>
589
+
590
+ ```gherkin
591
+ Scenario: {role.title()} can modify {singular} information
592
+
593
+ Given I am logged in as {role.title()}
594
+ And there is at least one {singular} in the list
595
+ When I click the "Edit" button on a {singular} row
596
+ Then the {singular} edit form should appear
597
+ And the form should be pre-filled with current {singular} data
598
+
599
+ When I change the Title to "Updated {pascal_singular}"
600
+ And I click the "Save" button
601
+ Then the changes should be saved successfully
602
+ And I should be redirected to the {entity} list
603
+ And I should see "Updated {pascal_singular}" in the list
604
+ ```
605
+
606
+ </td>
607
+ <td>
608
+
609
+ ```gherkin
610
+ Scenario: {role_es} puede modificar informacion de {singular_es}
611
+
612
+ Given estoy logueado como {role_es}
613
+ And existe al menos un/a {singular_es} en la lista
614
+ When hago clic en el boton "Editar" de una fila
615
+ Then deberia aparecer el formulario de edicion
616
+ And el formulario deberia estar pre-llenado con datos actuales
617
+
618
+ When cambio el Titulo a "Actualizado/a {pascal_singular}"
619
+ And hago clic en el boton "Guardar"
620
+ Then los cambios deberian guardarse exitosamente
621
+ And deberia ser redirigido a la lista de {entity}
622
+ And deberia ver "Actualizado/a {pascal_singular}" en la lista
623
+ ```
624
+
625
+ </td>
626
+ </tr>
627
+ </table>
628
+
629
+ ---
630
+
631
+ ## DELETE - {role.title()} can delete {entity}
632
+
633
+ ### {role_upper}_{entity_upper}_DELETE_001: Delete existing {singular} `@critical`
634
+
635
+ <table>
636
+ <tr>
637
+ <th width="50%">English</th>
638
+ <th width="50%">Espanol</th>
639
+ </tr>
640
+ <tr>
641
+ <td>
642
+
643
+ ```gherkin
644
+ Scenario: {role.title()} can permanently delete a {singular}
645
+
646
+ Given I am logged in as {role.title()}
647
+ And I have created a {singular} called "{pascal_singular} to Delete"
648
+ When I click on the {singular} to view details
649
+ And I click the "Delete" button
650
+ Then a confirmation dialog should appear
651
+
652
+ When I confirm the deletion
653
+ Then a second confirmation dialog should appear
654
+ When I confirm again
655
+ Then the {singular} should be deleted
656
+ And I should be redirected to the {entity} list
657
+ And "{pascal_singular} to Delete" should no longer appear in the list
658
+ ```
659
+
660
+ </td>
661
+ <td>
662
+
663
+ ```gherkin
664
+ Scenario: {role_es} puede eliminar permanentemente un/a {singular_es}
665
+
666
+ Given estoy logueado como {role_es}
667
+ And he creado un/a {singular_es} llamado/a "{pascal_singular} a Eliminar"
668
+ When hago clic en el/la {singular_es} para ver detalles
669
+ And hago clic en el boton "Eliminar"
670
+ Then deberia aparecer un dialogo de confirmacion
671
+
672
+ When confirmo la eliminacion
673
+ Then deberia aparecer un segundo dialogo de confirmacion
674
+ When confirmo nuevamente
675
+ Then el/la {singular_es} deberia ser eliminado/a
676
+ And deberia ser redirigido a la lista de {entity}
677
+ And "{pascal_singular} a Eliminar" ya no deberia aparecer en la lista
678
+ ```
679
+
680
+ </td>
681
+ </tr>
682
+ </table>
683
+
684
+ **Deletion Flow (2-step confirmation):**
685
+ ```
686
+ [Detail Page] -> [Delete Button] -> [Confirm Dialog 1] -> [Confirm Dialog 2] -> [{pascal_singular} Deleted]
687
+ ```
688
+
689
+ > **Note:** The double confirmation is a safety feature to prevent accidental deletions.
690
+
691
+ ---
692
+
693
+ ## Summary
694
+
695
+ | Test ID | Operation | Description | Tags |
696
+ |---------|-----------|-------------|------|
697
+ | {role_upper}_{entity_upper}_CREATE_001 | CREATE | Create {singular} with title | `@smoke` `@critical` |
698
+ | {role_upper}_{entity_upper}_CREATE_002 | CREATE | Create {singular} with all fields | |
699
+ | {role_upper}_{entity_upper}_READ_001 | READ | View {singular} list | `@smoke` `@critical` |
700
+ | {role_upper}_{entity_upper}_READ_002 | READ | View {singular} details | |
701
+ | {role_upper}_{entity_upper}_UPDATE_001 | UPDATE | Edit existing {singular} | |
702
+ | {role_upper}_{entity_upper}_DELETE_001 | DELETE | Delete {singular} | `@critical` |
703
+ '''
704
+
705
+
706
+ def main():
707
+ parser = argparse.ArgumentParser(description='Generate UAT test file')
708
+ parser.add_argument('--entity', required=True, help='Entity name (e.g., tasks)')
709
+ parser.add_argument('--theme', default='default', help='Theme name')
710
+ parser.add_argument('--role', required=True, help='Role name (owner, admin, member, editor, viewer)')
711
+ parser.add_argument('--session', default=None, help='Session name for @scope tag')
712
+ parser.add_argument('--with-bdd', action='store_true', help='Generate BDD documentation')
713
+ parser.add_argument('--dry-run', action='store_true', help='Preview without writing')
714
+ parser.add_argument('--output', default=None, help='Output directory path')
715
+
716
+ args = parser.parse_args()
717
+
718
+ entity = args.entity.lower()
719
+ role = args.role.lower()
720
+ theme = args.theme
721
+
722
+ print(f"\n{'=' * 60}")
723
+ print("GENERATING UAT TEST")
724
+ print(f"{'=' * 60}")
725
+ print(f"Entity: {entity}")
726
+ print(f"Role: {role}")
727
+ print(f"Theme: {theme}")
728
+ print(f"Session: {args.session or '(none)'}")
729
+ print(f"With BDD: {args.with_bdd}")
730
+ print(f"{'=' * 60}\n")
731
+
732
+ # Generate test content
733
+ test_content = generate_test_content(entity, role, theme, args.session)
734
+
735
+ # Determine output paths
736
+ if args.output:
737
+ output_dir = Path(args.output)
738
+ else:
739
+ output_dir = Path(f'contents/themes/{theme}/tests/cypress/e2e/uat/{entity}')
740
+
741
+ test_file = output_dir / f'{entity}-{role}.cy.ts'
742
+ bdd_file = output_dir / f'{entity}-{role}.bdd.md'
743
+
744
+ if args.dry_run:
745
+ print("DRY RUN - Generated test content:\n")
746
+ print("-" * 60)
747
+ print(test_content[:2000] + "\n... (truncated)")
748
+ print("-" * 60)
749
+
750
+ if args.with_bdd:
751
+ bdd_content = generate_bdd_content(entity, role, theme)
752
+ print("\nDRY RUN - Generated BDD content:\n")
753
+ print("-" * 60)
754
+ print(bdd_content[:2000] + "\n... (truncated)")
755
+ print("-" * 60)
756
+
757
+ print("\nRun without --dry-run to write files.")
758
+ return 0
759
+
760
+ # Create directories
761
+ output_dir.mkdir(parents=True, exist_ok=True)
762
+
763
+ # Write test file
764
+ with open(test_file, 'w', encoding='utf-8') as f:
765
+ f.write(test_content)
766
+ print(f"Test file generated: {test_file}")
767
+
768
+ # Write BDD file if requested
769
+ if args.with_bdd:
770
+ bdd_content = generate_bdd_content(entity, role, theme)
771
+ with open(bdd_file, 'w', encoding='utf-8') as f:
772
+ f.write(bdd_content)
773
+ print(f"BDD file generated: {bdd_file}")
774
+
775
+ print(f"\n{'=' * 60}")
776
+ print("NEXT STEPS:")
777
+ print("=" * 60)
778
+ print(f"1. Review generated file(s)")
779
+ print(f"2. Customize TODO sections based on entity schema")
780
+ print(f"3. Ensure {to_pascal_case(entity)}POM exists in src/entities/")
781
+ print(f"4. Run tests: pnpm cy:run --spec \"{test_file}\"")
782
+ print("=" * 60 + "\n")
783
+
784
+ return 0
785
+
786
+
787
+ if __name__ == '__main__':
788
+ sys.exit(main())