@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.
- package/LICENSE +21 -0
- package/README.md +115 -0
- package/claude/_docs/workflows-optimizations.md +359 -0
- package/claude/agents/api-tester.md +634 -0
- package/claude/agents/architecture-supervisor.md +1351 -0
- package/claude/agents/backend-developer.md +997 -0
- package/claude/agents/backend-validator.md +417 -0
- package/claude/agents/bdd-docs-writer.md +737 -0
- package/claude/agents/block-developer.md +677 -0
- package/claude/agents/code-reviewer.md +1432 -0
- package/claude/agents/db-developer.md +721 -0
- package/claude/agents/db-validator.md +407 -0
- package/claude/agents/demo-video-generator.md +493 -0
- package/claude/agents/documentation-writer.md +1268 -0
- package/claude/agents/frontend-developer.md +1234 -0
- package/claude/agents/frontend-validator.md +777 -0
- package/claude/agents/functional-validator.md +630 -0
- package/claude/agents/mock-analyst.md +387 -0
- package/claude/agents/product-manager.md +963 -0
- package/claude/agents/qa-automation.md +1762 -0
- package/claude/agents/release-manager.md +634 -0
- package/claude/agents/selectors-translator.md +262 -0
- package/claude/agents/unit-test-writer.md +785 -0
- package/claude/agents/visual-comparator.md +329 -0
- package/claude/agents/workflow-maintainer.md +352 -0
- package/claude/commands/do/README.md +88 -0
- package/claude/commands/do/create-api.md +64 -0
- package/claude/commands/do/create-entity.md +66 -0
- package/claude/commands/do/create-migration.md +64 -0
- package/claude/commands/do/create-plugin.md +56 -0
- package/claude/commands/do/create-theme.md +70 -0
- package/claude/commands/do/mock-data.md +67 -0
- package/claude/commands/do/reset-db.md +71 -0
- package/claude/commands/do/setup-scheduled-action.md +75 -0
- package/claude/commands/do/sync-code-review.md +117 -0
- package/claude/commands/do/update-selectors.md +112 -0
- package/claude/commands/do/use-skills.md +90 -0
- package/claude/commands/do/validate-blocks.md +69 -0
- package/claude/commands/how-to/README.md +261 -0
- package/claude/commands/how-to/add-metadata.md +692 -0
- package/claude/commands/how-to/add-taxonomies.md +806 -0
- package/claude/commands/how-to/add-translations.md +571 -0
- package/claude/commands/how-to/create-api.md +577 -0
- package/claude/commands/how-to/create-block.md +575 -0
- package/claude/commands/how-to/create-child-entities.md +771 -0
- package/claude/commands/how-to/create-entity.md +597 -0
- package/claude/commands/how-to/create-migrations.md +605 -0
- package/claude/commands/how-to/create-plugin.md +654 -0
- package/claude/commands/how-to/customize-app.md +481 -0
- package/claude/commands/how-to/customize-dashboard.md +553 -0
- package/claude/commands/how-to/customize-theme.md +438 -0
- package/claude/commands/how-to/define-features-flows.md +632 -0
- package/claude/commands/how-to/deploy.md +507 -0
- package/claude/commands/how-to/handle-file-uploads.md +746 -0
- package/claude/commands/how-to/implement-search.md +1001 -0
- package/claude/commands/how-to/install-plugins.md +352 -0
- package/claude/commands/how-to/manage-test-coverage.md +984 -0
- package/claude/commands/how-to/run-tests.md +400 -0
- package/claude/commands/how-to/set-app-languages.md +601 -0
- package/claude/commands/how-to/set-plans-and-permissions.md +575 -0
- package/claude/commands/how-to/set-scheduled-actions.md +527 -0
- package/claude/commands/how-to/set-user-roles-and-permissions.md +550 -0
- package/claude/commands/how-to/setup-authentication.md +388 -0
- package/claude/commands/how-to/setup-claude-code.md +440 -0
- package/claude/commands/how-to/setup-database.md +274 -0
- package/claude/commands/how-to/setup-email-providers.md +598 -0
- package/claude/commands/how-to/setup-mobile-dev.md +627 -0
- package/claude/commands/how-to/start.md +500 -0
- package/claude/commands/how-to/use-devtools.md +639 -0
- package/claude/commands/how-to/use-superadmin.md +622 -0
- package/claude/commands/session/README.md +193 -0
- package/claude/commands/session/block-create.md +190 -0
- package/claude/commands/session/block-list.md +203 -0
- package/claude/commands/session/block-update.md +192 -0
- package/claude/commands/session/block-validate.md +218 -0
- package/claude/commands/session/changelog.md +115 -0
- package/claude/commands/session/close.md +225 -0
- package/claude/commands/session/commit.md +174 -0
- package/claude/commands/session/db-entity.md +206 -0
- package/claude/commands/session/db-fix.md +212 -0
- package/claude/commands/session/db-sample.md +206 -0
- package/claude/commands/session/demo.md +178 -0
- package/claude/commands/session/doc-bdd.md +207 -0
- package/claude/commands/session/doc-feature.md +218 -0
- package/claude/commands/session/doc-read.md +225 -0
- package/claude/commands/session/execute.md +204 -0
- package/claude/commands/session/explain.md +202 -0
- package/claude/commands/session/fix-bug.md +210 -0
- package/claude/commands/session/fix-build.md +182 -0
- package/claude/commands/session/fix-test.md +189 -0
- package/claude/commands/session/pending.md +232 -0
- package/claude/commands/session/refine.md +188 -0
- package/claude/commands/session/resume.md +192 -0
- package/claude/commands/session/review.md +192 -0
- package/claude/commands/session/scope-change.md +181 -0
- package/claude/commands/session/start-blocks.md +347 -0
- package/claude/commands/session/start.md +604 -0
- package/claude/commands/session/status.md +169 -0
- package/claude/commands/session/test-fix.md +221 -0
- package/claude/commands/session/test-run.md +203 -0
- package/claude/commands/session/test-write.md +242 -0
- package/claude/commands/session/validate.md +162 -0
- package/claude/config/context.json +40 -0
- package/claude/config/github.json +69 -0
- package/claude/config/github.schema.json +106 -0
- package/claude/config/team.json +46 -0
- package/claude/config/team.schema.json +106 -0
- package/claude/config/workspace.json +43 -0
- package/claude/config/workspace.schema.json +75 -0
- package/claude/skills/README.md +228 -0
- package/claude/skills/accessibility/SKILL.md +573 -0
- package/claude/skills/api-bypass-layers/SKILL.md +550 -0
- package/claude/skills/asana-integration/SKILL.md +499 -0
- package/claude/skills/better-auth/SKILL.md +666 -0
- package/claude/skills/billing-subscriptions/SKILL.md +660 -0
- package/claude/skills/block-decision-matrix/SKILL.md +359 -0
- package/claude/skills/clickup-integration/SKILL.md +434 -0
- package/claude/skills/core-theme-responsibilities/SKILL.md +485 -0
- package/claude/skills/create-plugin/SKILL.md +425 -0
- package/claude/skills/create-theme/SKILL.md +331 -0
- package/claude/skills/cypress-api/SKILL.md +511 -0
- package/claude/skills/cypress-api/scripts/generate-api-controller.py +329 -0
- package/claude/skills/cypress-api/scripts/generate-api-test.py +930 -0
- package/claude/skills/cypress-e2e/SKILL.md +526 -0
- package/claude/skills/cypress-e2e/scripts/extract-selectors.py +383 -0
- package/claude/skills/cypress-e2e/scripts/generate-uat-test.py +788 -0
- package/claude/skills/cypress-selectors/SKILL.md +309 -0
- package/claude/skills/cypress-selectors/scripts/extract-missing.py +243 -0
- package/claude/skills/cypress-selectors/scripts/generate-block-selectors.py +283 -0
- package/claude/skills/cypress-selectors/scripts/validate-selectors.py +145 -0
- package/claude/skills/database-migrations/SKILL.md +335 -0
- package/claude/skills/database-migrations/scripts/generate-sample-data.py +284 -0
- package/claude/skills/database-migrations/scripts/validate-migration.py +323 -0
- package/claude/skills/design-system/SKILL.md +682 -0
- package/claude/skills/documentation/SKILL.md +540 -0
- package/claude/skills/entity-api/SKILL.md +482 -0
- package/claude/skills/entity-system/SKILL.md +635 -0
- package/claude/skills/entity-system/scripts/generate-child-migration.py +298 -0
- package/claude/skills/entity-system/scripts/generate-metas-migration.py +233 -0
- package/claude/skills/entity-system/scripts/generate-migration.py +382 -0
- package/claude/skills/entity-system/scripts/generate-sample-data.py +418 -0
- package/claude/skills/entity-system/scripts/scaffold-entity.py +661 -0
- package/claude/skills/github/SKILL.md +467 -0
- package/claude/skills/i18n-nextintl/SKILL.md +302 -0
- package/claude/skills/i18n-nextintl/scripts/add-translation.py +243 -0
- package/claude/skills/i18n-nextintl/scripts/extract-hardcoded.py +246 -0
- package/claude/skills/i18n-nextintl/scripts/validate-translations.py +260 -0
- package/claude/skills/impact-analysis/SKILL.md +203 -0
- package/claude/skills/jest-unit/SKILL.md +306 -0
- package/claude/skills/jest-unit/references/component-testing.md +371 -0
- package/claude/skills/jest-unit/references/mocking-patterns.md +380 -0
- package/claude/skills/jest-unit/references/service-hook-testing.md +454 -0
- package/claude/skills/jira-integration/SKILL.md +539 -0
- package/claude/skills/media-library/SKILL.md +743 -0
- package/claude/skills/mock-analysis/SKILL.md +276 -0
- package/claude/skills/monorepo-architecture/SKILL.md +162 -0
- package/claude/skills/nextjs-api-development/SKILL.md +364 -0
- package/claude/skills/nextjs-api-development/scripts/generate-crud-tests.py +456 -0
- package/claude/skills/nextjs-api-development/scripts/scaffold-endpoint.py +481 -0
- package/claude/skills/nextjs-api-development/scripts/validate-api.py +283 -0
- package/claude/skills/notion-integration/SKILL.md +641 -0
- package/claude/skills/npm-development-workflow/SKILL.md +480 -0
- package/claude/skills/page-builder-blocks/SKILL.md +530 -0
- package/claude/skills/page-builder-blocks/scripts/scaffold-block.py +444 -0
- package/claude/skills/permissions-system/SKILL.md +619 -0
- package/claude/skills/plugins/SKILL.md +340 -0
- package/claude/skills/plugins/references/plugin-templates.md +414 -0
- package/claude/skills/plugins/references/plugin-testing.md +353 -0
- package/claude/skills/plugins/references/plugin-types.md +198 -0
- package/claude/skills/plugins/scripts/scaffold-plugin.py +443 -0
- package/claude/skills/pom-patterns/SKILL.md +452 -0
- package/claude/skills/pom-patterns/scripts/generate-pom.py +392 -0
- package/claude/skills/rate-limiting/SKILL.md +342 -0
- package/claude/skills/react-best-practices/AGENTS.md +2410 -0
- package/claude/skills/react-best-practices/README.md +123 -0
- package/claude/skills/react-best-practices/SKILL.md +125 -0
- package/claude/skills/react-best-practices/metadata.json +15 -0
- package/claude/skills/react-best-practices/rules/_sections.md +46 -0
- package/claude/skills/react-best-practices/rules/_template.md +28 -0
- package/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
- package/claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
- package/claude/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/claude/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/claude/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/claude/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/claude/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/claude/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/claude/skills/react-patterns/SKILL.md +688 -0
- package/claude/skills/registry-system/SKILL.md +331 -0
- package/claude/skills/scheduled-actions/SKILL.md +671 -0
- package/claude/skills/scope-enforcement/SKILL.md +542 -0
- package/claude/skills/scope-enforcement/scripts/validate-scope.py +357 -0
- package/claude/skills/server-actions/SKILL.md +493 -0
- package/claude/skills/service-layer/SKILL.md +587 -0
- package/claude/skills/session-management/SKILL.md +266 -0
- package/claude/skills/session-management/scripts/create-session.py +166 -0
- package/claude/skills/session-management/scripts/iteration-close.sh +105 -0
- package/claude/skills/session-management/scripts/iteration-init.sh +180 -0
- package/claude/skills/session-management/scripts/session-archive.sh +87 -0
- package/claude/skills/session-management/scripts/session-close.sh +133 -0
- package/claude/skills/session-management/scripts/session-init.sh +225 -0
- package/claude/skills/session-management/scripts/session-list.sh +163 -0
- package/claude/skills/session-management/scripts/split-plan.sh +116 -0
- package/claude/skills/shadcn-components/SKILL.md +586 -0
- package/claude/skills/shadcn-theming/SKILL.md +446 -0
- package/claude/skills/suspense-loading/SKILL.md +280 -0
- package/claude/skills/tailwind-theming/SKILL.md +507 -0
- package/claude/skills/tanstack-query/SKILL.md +608 -0
- package/claude/skills/test-coverage/SKILL.md +239 -0
- package/claude/skills/web-design-guidelines/SKILL.md +39 -0
- package/claude/skills/zod-validation/SKILL.md +537 -0
- package/claude/templates/blocks/progress.md +86 -0
- package/claude/templates/iteration/changes.md +61 -0
- package/claude/templates/iteration/progress.md +55 -0
- package/claude/templates/log.md +31 -0
- package/claude/templates/story/context.md +77 -0
- package/claude/templates/story/pendings.md +37 -0
- package/claude/templates/story/plan.md +299 -0
- package/claude/templates/story/requirements.md +109 -0
- package/claude/templates/story/scope.json +10 -0
- package/claude/templates/story/tests.md +91 -0
- package/claude/templates/task/progress.md +58 -0
- package/claude/templates/task/requirements.md +54 -0
- package/claude/workflows/README.md +154 -0
- package/claude/workflows/blocks.md +614 -0
- package/claude/workflows/story.md +1207 -0
- package/claude/workflows/task.md +927 -0
- package/claude/workflows/tweak.md +527 -0
- package/cursor/.gitkeep +0 -0
- package/package.json +35 -0
- package/scripts/postinstall.mjs +198 -0
- package/scripts/setup.mjs +282 -0
- package/scripts/sync.mjs +209 -0
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pom-patterns
|
|
3
|
+
description: |
|
|
4
|
+
Page Object Model patterns for Cypress tests with hierarchical structure.
|
|
5
|
+
Covers BasePOM, DashboardEntityPOM, entity POMs, and selector integration.
|
|
6
|
+
Use this skill when creating new POMs or extending existing ones.
|
|
7
|
+
allowed-tools: Read, Glob, Grep, Bash(python:*)
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# POM Patterns Skill
|
|
12
|
+
|
|
13
|
+
Patterns and tools for creating Page Object Models (POMs) for Cypress tests.
|
|
14
|
+
|
|
15
|
+
## Architecture Overview
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
contents/themes/{theme}/tests/cypress/src/
|
|
19
|
+
├── core/
|
|
20
|
+
│ ├── BasePOM.ts # Base class for all POMs
|
|
21
|
+
│ └── DashboardEntityPOM.ts # Entity POM base (CRUD operations)
|
|
22
|
+
├── entities/
|
|
23
|
+
│ ├── TasksPOM.ts # Entity-specific POM
|
|
24
|
+
│ ├── PostsPOM.ts # Entity-specific POM
|
|
25
|
+
│ └── {Entity}POM.ts # Pattern: extend DashboardEntityPOM
|
|
26
|
+
├── features/
|
|
27
|
+
│ └── {Feature}POM.ts # Non-entity feature POMs
|
|
28
|
+
├── selectors.ts # Re-exports from lib/selectors.ts
|
|
29
|
+
└── fixtures/
|
|
30
|
+
└── entities.json # Auto-generated entity config
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## When to Use This Skill
|
|
34
|
+
|
|
35
|
+
- Creating a new entity POM
|
|
36
|
+
- Creating a feature-specific POM
|
|
37
|
+
- Extending DashboardEntityPOM with custom methods
|
|
38
|
+
- Understanding POM inheritance hierarchy
|
|
39
|
+
- Working with selectors in tests
|
|
40
|
+
|
|
41
|
+
## POM Hierarchy
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
BasePOM
|
|
45
|
+
│
|
|
46
|
+
├── DashboardEntityPOM (entities with CRUD)
|
|
47
|
+
│ ├── TasksPOM
|
|
48
|
+
│ ├── PostsPOM
|
|
49
|
+
│ └── {Entity}POM
|
|
50
|
+
│
|
|
51
|
+
└── {Feature}POM (non-entity features)
|
|
52
|
+
├── AuthPOM
|
|
53
|
+
├── OnboardingPOM
|
|
54
|
+
└── SettingsPOM
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Core Concepts
|
|
58
|
+
|
|
59
|
+
### 1. BasePOM
|
|
60
|
+
|
|
61
|
+
**Location:** `contents/themes/{theme}/tests/cypress/src/core/BasePOM.ts`
|
|
62
|
+
|
|
63
|
+
Provides:
|
|
64
|
+
- Selector pattern replacement (`{index}`, `{id}`)
|
|
65
|
+
- Fluent interface support (return `this`)
|
|
66
|
+
- `cy()` helper method for cleaner selectors
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// Key methods
|
|
70
|
+
export abstract class BasePOM {
|
|
71
|
+
// Get Cypress chainable by selector
|
|
72
|
+
protected cy(selector: string): Cypress.Chainable<JQuery<HTMLElement>> {
|
|
73
|
+
return cy.get(`[data-cy="${selector}"]`)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Replace placeholders in selector patterns
|
|
77
|
+
protected replacePattern(pattern: string, replacements: Record<string, string>): string {
|
|
78
|
+
let result = pattern
|
|
79
|
+
for (const [key, value] of Object.entries(replacements)) {
|
|
80
|
+
result = result.replace(`{${key}}`, value)
|
|
81
|
+
}
|
|
82
|
+
return result
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 2. DashboardEntityPOM
|
|
88
|
+
|
|
89
|
+
**Location:** `contents/themes/{theme}/tests/cypress/src/core/DashboardEntityPOM.ts`
|
|
90
|
+
|
|
91
|
+
Extends BasePOM with:
|
|
92
|
+
- Standard CRUD navigation (`visitList()`, `visitCreate()`, `visitEdit()`)
|
|
93
|
+
- Table operations (`getTableRow()`, `selectRow()`, `selectAllRows()`)
|
|
94
|
+
- Form operations (`getField()`, `fillField()`)
|
|
95
|
+
- API interceptors (`interceptList()`, `interceptCreate()`, `interceptUpdate()`, `interceptDelete()`)
|
|
96
|
+
- Bulk actions (`executeBulkAction()`)
|
|
97
|
+
- Status management (`changeStatus()`)
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
export class DashboardEntityPOM extends BasePOM {
|
|
101
|
+
protected entitySlug: string
|
|
102
|
+
|
|
103
|
+
constructor(entitySlug: string) {
|
|
104
|
+
super()
|
|
105
|
+
this.entitySlug = entitySlug
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Navigation
|
|
109
|
+
visitList(): this { /* ... */ return this }
|
|
110
|
+
visitCreate(): this { /* ... */ return this }
|
|
111
|
+
visitEdit(id: string): this { /* ... */ return this }
|
|
112
|
+
|
|
113
|
+
// Table operations
|
|
114
|
+
getTableRow(index: number): Cypress.Chainable { /* ... */ }
|
|
115
|
+
clickTableRow(index: number): this { /* ... */ return this }
|
|
116
|
+
|
|
117
|
+
// API Interceptors
|
|
118
|
+
interceptList(alias: string = 'getList'): this { /* ... */ return this }
|
|
119
|
+
interceptCreate(alias: string = 'postCreate'): this { /* ... */ return this }
|
|
120
|
+
|
|
121
|
+
// Form operations
|
|
122
|
+
fillField(fieldName: string, value: string): this { /* ... */ return this }
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 3. Entity POM Pattern
|
|
127
|
+
|
|
128
|
+
**Location:** `contents/themes/{theme}/tests/cypress/src/entities/{Entity}POM.ts`
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
import { DashboardEntityPOM } from '../core/DashboardEntityPOM'
|
|
132
|
+
import { cySelector } from '../selectors'
|
|
133
|
+
import entitiesConfig from '../fixtures/entities.json'
|
|
134
|
+
|
|
135
|
+
// Form interface based on entity fields
|
|
136
|
+
interface TaskFormData {
|
|
137
|
+
title?: string
|
|
138
|
+
description?: string
|
|
139
|
+
priority?: string
|
|
140
|
+
status?: string
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export class TasksPOM extends DashboardEntityPOM {
|
|
144
|
+
constructor() {
|
|
145
|
+
// Use entity slug from config
|
|
146
|
+
super(entitiesConfig.entities.tasks.slug)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Factory pattern (MANDATORY)
|
|
150
|
+
static create(): TasksPOM {
|
|
151
|
+
return new TasksPOM()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Entity-specific selectors
|
|
155
|
+
get elements() {
|
|
156
|
+
return {
|
|
157
|
+
// Use cySelector for all selectors
|
|
158
|
+
priorityFilter: cySelector('entities.tasks.filters.priority'),
|
|
159
|
+
statusBadge: cySelector('entities.tasks.list.statusBadge'),
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Entity-specific form filling
|
|
164
|
+
fillTaskForm(data: TaskFormData): this {
|
|
165
|
+
if (data.title) this.fillField('title', data.title)
|
|
166
|
+
if (data.description) this.fillField('description', data.description)
|
|
167
|
+
if (data.priority) this.selectField('priority', data.priority)
|
|
168
|
+
if (data.status) this.selectField('status', data.status)
|
|
169
|
+
return this
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Entity-specific workflows
|
|
173
|
+
createTask(data: TaskFormData): this {
|
|
174
|
+
return this
|
|
175
|
+
.visitCreate()
|
|
176
|
+
.interceptCreate()
|
|
177
|
+
.fillTaskForm(data)
|
|
178
|
+
.submitForm()
|
|
179
|
+
.waitForCreate()
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Selector Integration
|
|
185
|
+
|
|
186
|
+
### Using cySelector()
|
|
187
|
+
|
|
188
|
+
**CRITICAL: Always use `cySelector()` from the selectors module, never hardcode selectors.**
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { cySelector, sel } from '../selectors'
|
|
192
|
+
|
|
193
|
+
class MyPOM extends BasePOM {
|
|
194
|
+
get elements() {
|
|
195
|
+
return {
|
|
196
|
+
// ✅ CORRECT - Use cySelector
|
|
197
|
+
loginForm: cySelector('auth.login.form'),
|
|
198
|
+
submitButton: cySelector('auth.login.submit'),
|
|
199
|
+
|
|
200
|
+
// For dynamic selectors with replacements
|
|
201
|
+
tableRow: (id: string) => cySelector('entities.tasks.row', { id }),
|
|
202
|
+
faqItem: (index: number) => cySelector('blocks.faqAccordion.item', { index: String(index) }),
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ❌ WRONG - Never hardcode selectors
|
|
207
|
+
// get loginForm() { return cy.get('[data-cy="login-form"]') }
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Selector Paths
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// Core selectors (from CORE_SELECTORS)
|
|
215
|
+
cySelector('auth.login.form') // Login form
|
|
216
|
+
cySelector('auth.login.submit') // Submit button
|
|
217
|
+
cySelector('dashboard.sidebar') // Sidebar
|
|
218
|
+
cySelector('common.toast.success') // Success toast
|
|
219
|
+
|
|
220
|
+
// Entity selectors (from CORE_SELECTORS)
|
|
221
|
+
cySelector('entities.{entity}.list.table') // Entity table
|
|
222
|
+
cySelector('entities.{entity}.list.row') // Table row (needs {id})
|
|
223
|
+
cySelector('entities.{entity}.form.submit') // Form submit
|
|
224
|
+
|
|
225
|
+
// Block selectors (from BLOCK_SELECTORS)
|
|
226
|
+
cySelector('blocks.hero.container') // Hero block
|
|
227
|
+
cySelector('blocks.faqAccordion.item', { index: '0' }) // FAQ item
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## API Interceptor Pattern
|
|
231
|
+
|
|
232
|
+
**CRITICAL: Use interceptors for deterministic waits, never `cy.wait(timeout)`.**
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
class TasksPOM extends DashboardEntityPOM {
|
|
236
|
+
// Intercept before action
|
|
237
|
+
interceptList(alias: string = 'getTasksList'): this {
|
|
238
|
+
cy.intercept('GET', `/api/v1/entities/${this.entitySlug}*`).as(alias)
|
|
239
|
+
return this
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Wait after action
|
|
243
|
+
waitForList(alias: string = 'getTasksList'): this {
|
|
244
|
+
cy.wait(`@${alias}`)
|
|
245
|
+
return this
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Combined pattern
|
|
249
|
+
loadList(): this {
|
|
250
|
+
return this
|
|
251
|
+
.interceptList()
|
|
252
|
+
.visitList()
|
|
253
|
+
.waitForList()
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Fluent Interface
|
|
259
|
+
|
|
260
|
+
**All methods that perform actions should return `this` for chaining.**
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
class TasksPOM extends DashboardEntityPOM {
|
|
264
|
+
// ✅ CORRECT - Returns this for chaining
|
|
265
|
+
fillTitle(value: string): this {
|
|
266
|
+
cy.get(this.elements.titleInput).type(value)
|
|
267
|
+
return this
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ❌ WRONG - Breaks the chain
|
|
271
|
+
fillTitle(value: string): void {
|
|
272
|
+
cy.get(this.elements.titleInput).type(value)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Usage with fluent interface
|
|
277
|
+
TasksPOM.create()
|
|
278
|
+
.visitCreate()
|
|
279
|
+
.interceptCreate()
|
|
280
|
+
.fillTitle('My Task')
|
|
281
|
+
.fillDescription('Description')
|
|
282
|
+
.submitForm()
|
|
283
|
+
.waitForCreate()
|
|
284
|
+
.assertSuccessToast()
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## entities.json Fixture
|
|
288
|
+
|
|
289
|
+
**Location:** `contents/themes/{theme}/tests/cypress/fixtures/entities.json`
|
|
290
|
+
|
|
291
|
+
Auto-generated fixture containing entity configurations:
|
|
292
|
+
|
|
293
|
+
```json
|
|
294
|
+
{
|
|
295
|
+
"entities": {
|
|
296
|
+
"tasks": {
|
|
297
|
+
"slug": "tasks",
|
|
298
|
+
"singular": "Task",
|
|
299
|
+
"plural": "Tasks",
|
|
300
|
+
"tableName": "tasks",
|
|
301
|
+
"fields": {
|
|
302
|
+
"title": { "type": "text", "required": true },
|
|
303
|
+
"description": { "type": "textarea" },
|
|
304
|
+
"priority": { "type": "select", "options": ["low", "medium", "high"] },
|
|
305
|
+
"status": { "type": "select", "options": ["draft", "active", "completed"] }
|
|
306
|
+
},
|
|
307
|
+
"filters": ["status", "priority"]
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
**Usage in POM:**
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
import entitiesConfig from '../fixtures/entities.json'
|
|
317
|
+
|
|
318
|
+
class TasksPOM extends DashboardEntityPOM {
|
|
319
|
+
constructor() {
|
|
320
|
+
super(entitiesConfig.entities.tasks.slug)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
get entityConfig() {
|
|
324
|
+
return entitiesConfig.entities.tasks
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Scripts
|
|
330
|
+
|
|
331
|
+
### Generate Entity POM
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
# Generate a new entity POM
|
|
335
|
+
python3 .claude/skills/pom-patterns/scripts/generate-pom.py \
|
|
336
|
+
--entity products \
|
|
337
|
+
--theme default
|
|
338
|
+
|
|
339
|
+
# Preview without writing
|
|
340
|
+
python3 .claude/skills/pom-patterns/scripts/generate-pom.py \
|
|
341
|
+
--entity products \
|
|
342
|
+
--theme default \
|
|
343
|
+
--dry-run
|
|
344
|
+
|
|
345
|
+
# Specify custom fields
|
|
346
|
+
python3 .claude/skills/pom-patterns/scripts/generate-pom.py \
|
|
347
|
+
--entity products \
|
|
348
|
+
--theme default \
|
|
349
|
+
--fields "title,description,price,category,status"
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Standard Methods
|
|
353
|
+
|
|
354
|
+
### Navigation Methods
|
|
355
|
+
|
|
356
|
+
| Method | Description |
|
|
357
|
+
|--------|-------------|
|
|
358
|
+
| `visitList()` | Navigate to entity list page |
|
|
359
|
+
| `visitCreate()` | Navigate to create form |
|
|
360
|
+
| `visitEdit(id)` | Navigate to edit form |
|
|
361
|
+
| `visitView(id)` | Navigate to detail view |
|
|
362
|
+
|
|
363
|
+
### Table Methods
|
|
364
|
+
|
|
365
|
+
| Method | Description |
|
|
366
|
+
|--------|-------------|
|
|
367
|
+
| `getTableRow(index)` | Get row by index |
|
|
368
|
+
| `clickTableRow(index)` | Click row by index |
|
|
369
|
+
| `selectRow(index)` | Select row checkbox |
|
|
370
|
+
| `selectAllRows()` | Select all rows |
|
|
371
|
+
| `getRowCount()` | Get number of rows |
|
|
372
|
+
|
|
373
|
+
### Form Methods
|
|
374
|
+
|
|
375
|
+
| Method | Description |
|
|
376
|
+
|--------|-------------|
|
|
377
|
+
| `fillField(name, value)` | Fill text field |
|
|
378
|
+
| `selectField(name, value)` | Select dropdown option |
|
|
379
|
+
| `checkField(name)` | Check checkbox |
|
|
380
|
+
| `submitForm()` | Click submit button |
|
|
381
|
+
|
|
382
|
+
### Assertion Methods
|
|
383
|
+
|
|
384
|
+
| Method | Description |
|
|
385
|
+
|--------|-------------|
|
|
386
|
+
| `assertSuccessToast()` | Assert success toast visible |
|
|
387
|
+
| `assertErrorToast()` | Assert error toast visible |
|
|
388
|
+
| `assertOnListPage()` | Assert on list page |
|
|
389
|
+
| `assertOnCreatePage()` | Assert on create page |
|
|
390
|
+
| `assertRowExists(text)` | Assert table row with text |
|
|
391
|
+
|
|
392
|
+
### Interceptor Methods
|
|
393
|
+
|
|
394
|
+
| Method | Description |
|
|
395
|
+
|--------|-------------|
|
|
396
|
+
| `interceptList()` | Intercept GET list request |
|
|
397
|
+
| `interceptCreate()` | Intercept POST create request |
|
|
398
|
+
| `interceptUpdate()` | Intercept PATCH update request |
|
|
399
|
+
| `interceptDelete()` | Intercept DELETE request |
|
|
400
|
+
| `waitForList()` | Wait for list response |
|
|
401
|
+
| `waitForCreate()` | Wait for create response |
|
|
402
|
+
|
|
403
|
+
## Anti-Patterns
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
// ❌ NEVER: Hardcoded selectors
|
|
407
|
+
cy.get('[data-cy="task-title"]')
|
|
408
|
+
|
|
409
|
+
// ✅ CORRECT: Use cySelector
|
|
410
|
+
cy.get(cySelector('entities.tasks.form.title'))
|
|
411
|
+
|
|
412
|
+
// ❌ NEVER: Fixed timeouts
|
|
413
|
+
cy.wait(3000)
|
|
414
|
+
|
|
415
|
+
// ✅ CORRECT: Use interceptors
|
|
416
|
+
this.interceptCreate().submitForm().waitForCreate()
|
|
417
|
+
|
|
418
|
+
// ❌ NEVER: Direct page visits without interceptor
|
|
419
|
+
visitList() {
|
|
420
|
+
cy.visit('/dashboard/tasks')
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// ✅ CORRECT: Intercept before navigation
|
|
424
|
+
loadList() {
|
|
425
|
+
return this.interceptList().visitList().waitForList()
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// ❌ NEVER: Breaking fluent interface
|
|
429
|
+
fillTitle(value: string): void { ... }
|
|
430
|
+
|
|
431
|
+
// ✅ CORRECT: Return this
|
|
432
|
+
fillTitle(value: string): this { ... return this }
|
|
433
|
+
|
|
434
|
+
// ❌ NEVER: Missing factory pattern
|
|
435
|
+
const pom = new TasksPOM()
|
|
436
|
+
|
|
437
|
+
// ✅ CORRECT: Use factory
|
|
438
|
+
const pom = TasksPOM.create()
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
## Checklist
|
|
442
|
+
|
|
443
|
+
Before finalizing a POM:
|
|
444
|
+
|
|
445
|
+
- [ ] Extends correct base class (DashboardEntityPOM for entities)
|
|
446
|
+
- [ ] Uses factory pattern (`static create()`)
|
|
447
|
+
- [ ] All methods return `this` (fluent interface)
|
|
448
|
+
- [ ] Uses `cySelector()` for all selectors (no hardcoded strings)
|
|
449
|
+
- [ ] Uses API interceptors for all async operations
|
|
450
|
+
- [ ] Form interface defined based on entity fields
|
|
451
|
+
- [ ] Entity-specific methods documented
|
|
452
|
+
- [ ] Follows naming convention: `{Entity}POM.ts`
|