@nextsparkjs/theme-default 0.1.0-beta.51 → 0.1.0-beta.54
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/package.json +3 -3
- package/tests/cypress/e2e/_utils/selectors/dashboard-topnav.bdd.md +49 -2
- package/tests/cypress/e2e/_utils/selectors/dashboard-topnav.cy.ts +22 -1
- package/tests/cypress/e2e/_utils/selectors/patterns.bdd.md +388 -0
- package/tests/cypress/e2e/_utils/selectors/patterns.cy.ts +392 -0
- package/tests/cypress/src/features/DashboardPOM.ts +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextsparkjs/theme-default",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.54",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./config/theme.config.ts",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"react-dom": "^19.0.0",
|
|
18
18
|
"react-markdown": "^10.1.0",
|
|
19
19
|
"zod": "^4.0.0",
|
|
20
|
-
"@nextsparkjs/core": "0.1.0-beta.
|
|
21
|
-
"@nextsparkjs/testing": "0.1.0-beta.
|
|
20
|
+
"@nextsparkjs/core": "0.1.0-beta.54",
|
|
21
|
+
"@nextsparkjs/testing": "0.1.0-beta.54"
|
|
22
22
|
},
|
|
23
23
|
"nextspark": {
|
|
24
24
|
"type": "theme",
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
feature: Dashboard Topnav UI Selectors Validation
|
|
3
3
|
priority: high
|
|
4
4
|
tags: [selectors, topnav, dashboard, ui-validation]
|
|
5
|
-
grepTags: [ui-selectors, dashboard, topnav, SEL_TNAV_001, SEL_TNAV_002, SEL_TNAV_003, SEL_TNAV_004, SEL_TNAV_005, SEL_TNAV_006]
|
|
6
|
-
coverage:
|
|
5
|
+
grepTags: [ui-selectors, dashboard, topnav, SEL_TNAV_001, SEL_TNAV_002, SEL_TNAV_003, SEL_TNAV_004, SEL_TNAV_005, SEL_TNAV_006, SEL_TNAV_007]
|
|
6
|
+
coverage: 7
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Dashboard Topnav UI Selectors Validation
|
|
@@ -263,6 +263,53 @@ Then deberia encontrar el indicador de estado de carga del usuario
|
|
|
263
263
|
|
|
264
264
|
---
|
|
265
265
|
|
|
266
|
+
## @test SEL_TNAV_007: Settings Menu
|
|
267
|
+
|
|
268
|
+
### Metadata
|
|
269
|
+
- **Priority:** Medium
|
|
270
|
+
- **Type:** Selector Validation
|
|
271
|
+
- **Tags:** topnav, settings-menu, dropdown
|
|
272
|
+
- **Grep:** `@ui-selectors` `@dashboard` `@topnav` `@SEL_TNAV_007`
|
|
273
|
+
- **Status:** Active (3 passing, 0 skipped)
|
|
274
|
+
|
|
275
|
+
```gherkin:en
|
|
276
|
+
Scenario: Settings menu opens and shows links
|
|
277
|
+
|
|
278
|
+
Given I am logged in as a developer user
|
|
279
|
+
And the settings menu is enabled in theme config
|
|
280
|
+
And I navigate to the dashboard
|
|
281
|
+
Then I should find the settings menu trigger
|
|
282
|
+
When I click on the settings menu trigger
|
|
283
|
+
Then I should see the settings menu content
|
|
284
|
+
And I should find settings menu links (e.g., patterns)
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
```gherkin:es
|
|
288
|
+
Scenario: Menu de configuracion se abre y muestra links
|
|
289
|
+
|
|
290
|
+
Given estoy logueado como usuario developer
|
|
291
|
+
And el menu de configuracion esta habilitado en la config del tema
|
|
292
|
+
And navego al dashboard
|
|
293
|
+
Then deberia encontrar el trigger del menu de configuracion
|
|
294
|
+
When hago click en el trigger del menu de configuracion
|
|
295
|
+
Then deberia ver el contenido del menu de configuracion
|
|
296
|
+
And deberia encontrar links del menu de configuracion (ej. patrones)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Expected Results
|
|
300
|
+
| Test ID | Selector Path | POM Accessor | data-cy Value | Status |
|
|
301
|
+
|---------|---------------|--------------|---------------|--------|
|
|
302
|
+
| SEL_TNAV_007_01 | dashboard.topnav.settingsMenu.trigger | dashboard.selectors.topnavSettingsMenuTrigger | topnav-settings-menu-trigger | Implemented |
|
|
303
|
+
| SEL_TNAV_007_02 | dashboard.topnav.settingsMenu.content | dashboard.selectors.topnavSettingsMenuContent | topnav-settings-menu | Implemented |
|
|
304
|
+
| SEL_TNAV_007_03 | dashboard.topnav.settingsMenu.link(index) | dashboard.selectors.topnavSettingsMenuLink(0) | topnav-settings-link-0 | Implemented |
|
|
305
|
+
|
|
306
|
+
### Notes
|
|
307
|
+
- Settings menu must be enabled in theme config (TOPBAR_CONFIG.settingsMenu)
|
|
308
|
+
- Links are dynamically generated from config
|
|
309
|
+
- Common links include: Patterns
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
266
313
|
## Related Components
|
|
267
314
|
|
|
268
315
|
| Component | File | Selectors |
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* - SEL_TNAV_004: User Menu (5 selectors)
|
|
22
22
|
* - SEL_TNAV_005: Quick Create (3 selectors)
|
|
23
23
|
* - SEL_TNAV_006: Loading State (1 skipped - transient state)
|
|
24
|
+
* - SEL_TNAV_007: Settings Menu (3 selectors)
|
|
24
25
|
*
|
|
25
26
|
* NOTE: Public navbar tests (logo, signin, signup) are in public.cy.ts
|
|
26
27
|
*/
|
|
@@ -149,8 +150,28 @@ describe('Dashboard Topnav Selectors Validation', { tags: ['@ui-selectors', '@da
|
|
|
149
150
|
// NOTE: Only visible during auth loading - transient state
|
|
150
151
|
// ============================================
|
|
151
152
|
describe('SEL_TNAV_006: Loading State', { tags: '@SEL_TNAV_006' }, () => {
|
|
152
|
-
it.skip('should find user loading state (only visible during auth loading)', () => {
|
|
153
|
+
it.skip('SEL_TNAV_006_01: should find user loading state (only visible during auth loading)', { tags: '@SEL_TNAV_006_01' }, () => {
|
|
153
154
|
cy.get(dashboard.selectors.topnavUserLoading).should('exist')
|
|
154
155
|
})
|
|
155
156
|
})
|
|
157
|
+
|
|
158
|
+
// ============================================
|
|
159
|
+
// SEL_TNAV_007: SETTINGS MENU (3 selectors)
|
|
160
|
+
// NOTE: settingsMenu must be enabled in theme config
|
|
161
|
+
// ============================================
|
|
162
|
+
describe('SEL_TNAV_007: Settings Menu', { tags: '@SEL_TNAV_007' }, () => {
|
|
163
|
+
it('SEL_TNAV_007_01: should find settings menu trigger', { tags: '@SEL_TNAV_007_01' }, () => {
|
|
164
|
+
cy.get(dashboard.selectors.topnavSettingsMenuTrigger).should('exist')
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
it('SEL_TNAV_007_02: should find settings menu content when opened', { tags: '@SEL_TNAV_007_02' }, () => {
|
|
168
|
+
cy.get(dashboard.selectors.topnavSettingsMenuTrigger).click()
|
|
169
|
+
cy.get(dashboard.selectors.topnavSettingsMenuContent).should('be.visible')
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('SEL_TNAV_007_03: should find settings menu link when opened', { tags: '@SEL_TNAV_007_03' }, () => {
|
|
173
|
+
cy.get(dashboard.selectors.topnavSettingsMenuTrigger).click()
|
|
174
|
+
cy.get(dashboard.selectors.topnavSettingsMenuLink(0)).should('exist')
|
|
175
|
+
})
|
|
176
|
+
})
|
|
156
177
|
})
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
---
|
|
2
|
+
feature: Patterns UI Selectors Validation
|
|
3
|
+
priority: high
|
|
4
|
+
tags: [selectors, patterns, ui-validation]
|
|
5
|
+
grepTags: [ui-selectors, patterns, feat-patterns, SEL_PAT_001, SEL_PAT_002, SEL_PAT_003, SEL_PAT_004, SEL_PAT_005, SEL_PAT_006, SEL_PAT_007, SEL_PAT_008]
|
|
6
|
+
coverage: 8
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Patterns UI Selectors Validation
|
|
10
|
+
|
|
11
|
+
> Validates that patterns-specific selectors exist in the DOM. This is a lightweight test that ONLY checks selector presence, not functionality. Validates KEY DIFFERENCES from standard entity editor: no slug input and no patterns tab in block picker.
|
|
12
|
+
|
|
13
|
+
**Login:** Uses Developer via `loginAsDefaultDeveloper()`.
|
|
14
|
+
|
|
15
|
+
**Dependencies:**
|
|
16
|
+
- Sample patterns must exist (from seed data)
|
|
17
|
+
- At least one pattern must have usages (for reports tests)
|
|
18
|
+
|
|
19
|
+
## @test SEL_PAT_001: Patterns List Page Selectors
|
|
20
|
+
|
|
21
|
+
### Metadata
|
|
22
|
+
- **Priority:** High
|
|
23
|
+
- **Type:** Selector Validation
|
|
24
|
+
- **Tags:** patterns, list, page
|
|
25
|
+
- **Grep:** `@ui-selectors` `@patterns` `@feat-patterns` `@SEL_PAT_001`
|
|
26
|
+
- **Status:** Active (5 passing, 0 skipped)
|
|
27
|
+
|
|
28
|
+
```gherkin:en
|
|
29
|
+
Scenario: Patterns list page has complete selector coverage
|
|
30
|
+
|
|
31
|
+
Given I am logged in as a developer user
|
|
32
|
+
And I navigate to the patterns list page
|
|
33
|
+
Then I should find the page container
|
|
34
|
+
And I should find the page title
|
|
35
|
+
And I should find the add button
|
|
36
|
+
And I should find the search container
|
|
37
|
+
And I should find the table container
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```gherkin:es
|
|
41
|
+
Scenario: Pagina de lista de patrones tiene cobertura completa de selectores
|
|
42
|
+
|
|
43
|
+
Given estoy logueado como usuario developer
|
|
44
|
+
And navego a la pagina de lista de patrones
|
|
45
|
+
Then deberia encontrar el contenedor de pagina
|
|
46
|
+
And deberia encontrar el titulo de pagina
|
|
47
|
+
And deberia encontrar el boton de agregar
|
|
48
|
+
And deberia encontrar el contenedor de busqueda
|
|
49
|
+
And deberia encontrar el contenedor de tabla
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Expected Results
|
|
53
|
+
| Test ID | Selector Path | Status |
|
|
54
|
+
|---------|---------------|--------|
|
|
55
|
+
| SEL_PAT_001_01 | patterns.selectors.page | Implemented |
|
|
56
|
+
| SEL_PAT_001_02 | patterns.selectors.title | Implemented |
|
|
57
|
+
| SEL_PAT_001_03 | patterns.selectors.addBtn | Implemented |
|
|
58
|
+
| SEL_PAT_001_04 | patterns.selectors.searchContainer | Implemented |
|
|
59
|
+
| SEL_PAT_001_05 | patterns.selectors.table | Implemented |
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## @test SEL_PAT_002: Patterns List Table Actions
|
|
64
|
+
|
|
65
|
+
### Metadata
|
|
66
|
+
- **Priority:** High
|
|
67
|
+
- **Type:** Selector Validation
|
|
68
|
+
- **Tags:** patterns, list, actions, table
|
|
69
|
+
- **Grep:** `@ui-selectors` `@patterns` `@feat-patterns` `@SEL_PAT_002`
|
|
70
|
+
- **Status:** Active (4 passing, 0 skipped)
|
|
71
|
+
|
|
72
|
+
```gherkin:en
|
|
73
|
+
Scenario: Patterns list table has all row action selectors
|
|
74
|
+
|
|
75
|
+
Given I am logged in as a developer user
|
|
76
|
+
And I navigate to the patterns list page
|
|
77
|
+
And at least one pattern exists in the database
|
|
78
|
+
Then I should find the row menu for the first pattern
|
|
79
|
+
When I click the row menu
|
|
80
|
+
Then I should find the edit action
|
|
81
|
+
And I should find the delete action
|
|
82
|
+
And I should find the usages quick action
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```gherkin:es
|
|
86
|
+
Scenario: Tabla de lista de patrones tiene todos los selectores de acciones de fila
|
|
87
|
+
|
|
88
|
+
Given estoy logueado como usuario developer
|
|
89
|
+
And navego a la pagina de lista de patrones
|
|
90
|
+
And al menos un patron existe en la base de datos
|
|
91
|
+
Then deberia encontrar el menu de fila del primer patron
|
|
92
|
+
When hago click en el menu de fila
|
|
93
|
+
Then deberia encontrar la accion de editar
|
|
94
|
+
And deberia encontrar la accion de eliminar
|
|
95
|
+
And deberia encontrar la accion rapida de usos
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Expected Results
|
|
99
|
+
| Test ID | Selector Path | Status |
|
|
100
|
+
|---------|---------------|--------|
|
|
101
|
+
| SEL_PAT_002_01 | patterns.selectors.rowMenu(id) | Implemented |
|
|
102
|
+
| SEL_PAT_002_02 | patterns.selectors.rowAction('edit', id) | Implemented |
|
|
103
|
+
| SEL_PAT_002_03 | patterns.selectors.rowAction('delete', id) | Implemented |
|
|
104
|
+
| SEL_PAT_002_04 | patterns.selectors.rowAction('usages', id) | Implemented |
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## @test SEL_PAT_003: Patterns Editor Header - KEY DIFFERENCES
|
|
109
|
+
|
|
110
|
+
### Metadata
|
|
111
|
+
- **Priority:** High
|
|
112
|
+
- **Type:** Selector Validation
|
|
113
|
+
- **Tags:** patterns, editor, header, differences
|
|
114
|
+
- **Grep:** `@ui-selectors` `@patterns` `@feat-patterns` `@SEL_PAT_003`
|
|
115
|
+
- **Status:** Active (5 passing, 0 skipped)
|
|
116
|
+
|
|
117
|
+
```gherkin:en
|
|
118
|
+
Scenario: Patterns editor header validates key differences from standard editor
|
|
119
|
+
|
|
120
|
+
Given I am logged in as a developer user
|
|
121
|
+
And I navigate to create a new pattern
|
|
122
|
+
And the editor is loaded
|
|
123
|
+
Then I should find the header container
|
|
124
|
+
And I should find the title input
|
|
125
|
+
And I should NOT find the slug input (patterns-specific)
|
|
126
|
+
And I should find the save button
|
|
127
|
+
And I should find the view mode toggle
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```gherkin:es
|
|
131
|
+
Scenario: Header del editor de patrones valida diferencias clave del editor estandar
|
|
132
|
+
|
|
133
|
+
Given estoy logueado como usuario developer
|
|
134
|
+
And navego a crear un nuevo patron
|
|
135
|
+
And el editor esta cargado
|
|
136
|
+
Then deberia encontrar el contenedor del header
|
|
137
|
+
And deberia encontrar el input de titulo
|
|
138
|
+
And NO deberia encontrar el input de slug (especifico de patrones)
|
|
139
|
+
And deberia encontrar el boton de guardar
|
|
140
|
+
And deberia encontrar el toggle de modo de vista
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Expected Results
|
|
144
|
+
| Test ID | Selector Path | Assertion | Status |
|
|
145
|
+
|---------|---------------|-----------|--------|
|
|
146
|
+
| SEL_PAT_003_01 | blockEditor.header.container | should exist | Implemented |
|
|
147
|
+
| SEL_PAT_003_02 | blockEditor.header.titleInput | should exist | Implemented |
|
|
148
|
+
| SEL_PAT_003_03 | blockEditor.header.slugInput | should NOT exist | **KEY DIFFERENCE** |
|
|
149
|
+
| SEL_PAT_003_04 | blockEditor.header.saveButton | should exist | Implemented |
|
|
150
|
+
| SEL_PAT_003_05 | blockEditor.header.viewToggle | should exist | Implemented |
|
|
151
|
+
|
|
152
|
+
### Notes
|
|
153
|
+
- **KEY DIFFERENCE:** Patterns do not have slugs, so the slug input should NOT exist.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## @test SEL_PAT_004: Patterns Editor Block Picker - KEY DIFFERENCES
|
|
158
|
+
|
|
159
|
+
### Metadata
|
|
160
|
+
- **Priority:** High
|
|
161
|
+
- **Type:** Selector Validation
|
|
162
|
+
- **Tags:** patterns, editor, block-picker, differences
|
|
163
|
+
- **Grep:** `@ui-selectors` `@patterns` `@feat-patterns` `@SEL_PAT_004`
|
|
164
|
+
- **Status:** Active (5 passing, 0 skipped)
|
|
165
|
+
|
|
166
|
+
```gherkin:en
|
|
167
|
+
Scenario: Patterns block picker validates key differences from standard editor
|
|
168
|
+
|
|
169
|
+
Given I am logged in as a developer user
|
|
170
|
+
And I navigate to create a new pattern
|
|
171
|
+
And the editor is loaded
|
|
172
|
+
Then I should find the block picker container
|
|
173
|
+
And I should find the blocks tab
|
|
174
|
+
And I should NOT find the patterns tab (patterns-specific)
|
|
175
|
+
And I should find the config tab
|
|
176
|
+
And I should find the search input
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
```gherkin:es
|
|
180
|
+
Scenario: Block picker de patrones valida diferencias clave del editor estandar
|
|
181
|
+
|
|
182
|
+
Given estoy logueado como usuario developer
|
|
183
|
+
And navego a crear un nuevo patron
|
|
184
|
+
And el editor esta cargado
|
|
185
|
+
Then deberia encontrar el contenedor del block picker
|
|
186
|
+
And deberia encontrar la pestana de bloques
|
|
187
|
+
And NO deberia encontrar la pestana de patrones (especifico de patrones)
|
|
188
|
+
And deberia encontrar la pestana de configuracion
|
|
189
|
+
And deberia encontrar el input de busqueda
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Expected Results
|
|
193
|
+
| Test ID | Selector Path | Assertion | Status |
|
|
194
|
+
|---------|---------------|-----------|--------|
|
|
195
|
+
| SEL_PAT_004_01 | blockEditor.blockPicker.container | should exist | Implemented |
|
|
196
|
+
| SEL_PAT_004_02 | blockEditor.blockPicker.tabBlocks | should exist | Implemented |
|
|
197
|
+
| SEL_PAT_004_03 | blockEditor.blockPicker.tabPatterns | should NOT exist | **KEY DIFFERENCE** |
|
|
198
|
+
| SEL_PAT_004_04 | blockEditor.blockPicker.tabConfig | should exist | Implemented |
|
|
199
|
+
| SEL_PAT_004_05 | blockEditor.blockPicker.searchInput | should exist | Implemented |
|
|
200
|
+
|
|
201
|
+
### Notes
|
|
202
|
+
- **KEY DIFFERENCE:** Patterns cannot contain other patterns (to prevent recursion), so the patterns tab should NOT exist.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## @test SEL_PAT_005: Patterns Reports Page
|
|
207
|
+
|
|
208
|
+
### Metadata
|
|
209
|
+
- **Priority:** Medium
|
|
210
|
+
- **Type:** Selector Validation
|
|
211
|
+
- **Tags:** patterns, reports, usages
|
|
212
|
+
- **Grep:** `@ui-selectors` `@patterns` `@feat-patterns` `@SEL_PAT_005`
|
|
213
|
+
- **Status:** Active (4 passing, 0 skipped)
|
|
214
|
+
|
|
215
|
+
```gherkin:en
|
|
216
|
+
Scenario: Pattern usages report page has complete structure
|
|
217
|
+
|
|
218
|
+
Given I am logged in as a developer user
|
|
219
|
+
And I navigate to the patterns list page
|
|
220
|
+
And I click the usages action on the first pattern
|
|
221
|
+
Then I should find the report container
|
|
222
|
+
And I should find the back button
|
|
223
|
+
And I should find the page title
|
|
224
|
+
And I should find the edit button
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
```gherkin:es
|
|
228
|
+
Scenario: Pagina de reporte de usos de patrones tiene estructura completa
|
|
229
|
+
|
|
230
|
+
Given estoy logueado como usuario developer
|
|
231
|
+
And navego a la pagina de lista de patrones
|
|
232
|
+
And hago click en la accion de usos del primer patron
|
|
233
|
+
Then deberia encontrar el contenedor del reporte
|
|
234
|
+
And deberia encontrar el boton de volver
|
|
235
|
+
And deberia encontrar el titulo de pagina
|
|
236
|
+
And deberia encontrar el boton de editar
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Expected Results
|
|
240
|
+
| Test ID | Selector Path | Status |
|
|
241
|
+
|---------|---------------|--------|
|
|
242
|
+
| SEL_PAT_005_01 | patterns.patternSelectors.usageReport.container | Implemented |
|
|
243
|
+
| SEL_PAT_005_02 | patterns.selectors.backButton | Implemented |
|
|
244
|
+
| SEL_PAT_005_03 | patterns.selectors.headerTitle | Implemented |
|
|
245
|
+
| SEL_PAT_005_04 | patterns.selectors.editButton | Implemented |
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## @test SEL_PAT_006: Pattern Usage Stats
|
|
250
|
+
|
|
251
|
+
### Metadata
|
|
252
|
+
- **Priority:** Medium
|
|
253
|
+
- **Type:** Selector Validation
|
|
254
|
+
- **Tags:** patterns, reports, stats
|
|
255
|
+
- **Grep:** `@ui-selectors` `@patterns` `@feat-patterns` `@SEL_PAT_006`
|
|
256
|
+
- **Status:** Active (3 passing, 0 skipped)
|
|
257
|
+
|
|
258
|
+
```gherkin:en
|
|
259
|
+
Scenario: Pattern usage stats have all required selectors
|
|
260
|
+
|
|
261
|
+
Given I am logged in as a developer user
|
|
262
|
+
And I navigate to a pattern's usages page
|
|
263
|
+
Then I should find the stats container
|
|
264
|
+
And I should find the total usage card
|
|
265
|
+
And I should find usage by type cards (if usages exist)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
```gherkin:es
|
|
269
|
+
Scenario: Estadisticas de uso de patron tienen todos los selectores requeridos
|
|
270
|
+
|
|
271
|
+
Given estoy logueado como usuario developer
|
|
272
|
+
And navego a la pagina de usos de un patron
|
|
273
|
+
Then deberia encontrar el contenedor de estadisticas
|
|
274
|
+
And deberia encontrar la tarjeta de uso total
|
|
275
|
+
And deberia encontrar las tarjetas de uso por tipo (si existen usos)
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Expected Results
|
|
279
|
+
| Test ID | Selector Path | Status |
|
|
280
|
+
|---------|---------------|--------|
|
|
281
|
+
| SEL_PAT_006_01 | patterns.patternSelectors.usageStats.container | Implemented |
|
|
282
|
+
| SEL_PAT_006_02 | patterns.patternSelectors.usageStats.total | Implemented |
|
|
283
|
+
| SEL_PAT_006_03 | patterns.patternSelectors.usageStats.byType(type) | Conditional |
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## @test SEL_PAT_007: Pattern Usage Report Controls
|
|
288
|
+
|
|
289
|
+
### Metadata
|
|
290
|
+
- **Priority:** Medium
|
|
291
|
+
- **Type:** Selector Validation
|
|
292
|
+
- **Tags:** patterns, reports, controls, pagination
|
|
293
|
+
- **Grep:** `@ui-selectors` `@patterns` `@feat-patterns` `@SEL_PAT_007`
|
|
294
|
+
- **Status:** Active (6 passing, 0 skipped)
|
|
295
|
+
|
|
296
|
+
```gherkin:en
|
|
297
|
+
Scenario: Pattern usage report controls have all required selectors
|
|
298
|
+
|
|
299
|
+
Given I am logged in as a developer user
|
|
300
|
+
And I navigate to a pattern's usages page
|
|
301
|
+
Then I should find the report container
|
|
302
|
+
And I should find the filter select
|
|
303
|
+
And I should find the pagination container
|
|
304
|
+
And I should find the prev page button
|
|
305
|
+
And I should find the next page button
|
|
306
|
+
And I should find the results info
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
```gherkin:es
|
|
310
|
+
Scenario: Controles de reporte de uso de patron tienen todos los selectores requeridos
|
|
311
|
+
|
|
312
|
+
Given estoy logueado como usuario developer
|
|
313
|
+
And navego a la pagina de usos de un patron
|
|
314
|
+
Then deberia encontrar el contenedor del reporte
|
|
315
|
+
And deberia encontrar el select de filtro
|
|
316
|
+
And deberia encontrar el contenedor de paginacion
|
|
317
|
+
And deberia encontrar el boton de pagina anterior
|
|
318
|
+
And deberia encontrar el boton de pagina siguiente
|
|
319
|
+
And deberia encontrar la info de resultados
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Expected Results
|
|
323
|
+
| Test ID | Selector Path | Status |
|
|
324
|
+
|---------|---------------|--------|
|
|
325
|
+
| SEL_PAT_007_01 | patterns.patternSelectors.usageReport.container | Implemented |
|
|
326
|
+
| SEL_PAT_007_02 | patterns.patternSelectors.usageReport.filterSelect | Implemented |
|
|
327
|
+
| SEL_PAT_007_03 | patterns.patternSelectors.usageReport.pagination | Implemented |
|
|
328
|
+
| SEL_PAT_007_04 | patterns.patternSelectors.usageReport.prevPage | Implemented |
|
|
329
|
+
| SEL_PAT_007_05 | patterns.patternSelectors.usageReport.nextPage | Implemented |
|
|
330
|
+
| SEL_PAT_007_06 | patterns.patternSelectors.usageReport.resultsInfo | Implemented |
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## @test SEL_PAT_008: Pattern Usage Table
|
|
335
|
+
|
|
336
|
+
### Metadata
|
|
337
|
+
- **Priority:** Medium
|
|
338
|
+
- **Type:** Selector Validation
|
|
339
|
+
- **Tags:** patterns, reports, table
|
|
340
|
+
- **Grep:** `@ui-selectors` `@patterns` `@feat-patterns` `@SEL_PAT_008`
|
|
341
|
+
- **Status:** Partial (1 passing, 2 skipped)
|
|
342
|
+
|
|
343
|
+
```gherkin:en
|
|
344
|
+
Scenario: Pattern usage table has all required selectors
|
|
345
|
+
|
|
346
|
+
Given I am logged in as a developer user
|
|
347
|
+
And I navigate to a pattern's usages page
|
|
348
|
+
Then I should find the usage table container (or empty state)
|
|
349
|
+
And I should find usage rows (if pattern has usages)
|
|
350
|
+
And I should find view links in usage rows (if pattern has usages)
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
```gherkin:es
|
|
354
|
+
Scenario: Tabla de usos de patron tiene todos los selectores requeridos
|
|
355
|
+
|
|
356
|
+
Given estoy logueado como usuario developer
|
|
357
|
+
And navego a la pagina de usos de un patron
|
|
358
|
+
Then deberia encontrar el contenedor de tabla de usos (o estado vacio)
|
|
359
|
+
And deberia encontrar filas de uso (si el patron tiene usos)
|
|
360
|
+
And deberia encontrar links de ver en filas de uso (si el patron tiene usos)
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Expected Results
|
|
364
|
+
| Test ID | Selector Path | Status |
|
|
365
|
+
|---------|---------------|--------|
|
|
366
|
+
| SEL_PAT_008_01 | patterns.patternSelectors.usageTable.container/empty | Implemented |
|
|
367
|
+
| SEL_PAT_008_02 | [data-cy^="pattern-usage-row-"] | **Skipped** |
|
|
368
|
+
| SEL_PAT_008_03 | [data-cy^="pattern-usage-view-"] | **Skipped** |
|
|
369
|
+
|
|
370
|
+
### Notes
|
|
371
|
+
- Tests SEL_PAT_008_02 and SEL_PAT_008_03 are skipped because they require the pattern to have actual usages.
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Related Components
|
|
376
|
+
|
|
377
|
+
| Component | File | Key Selectors |
|
|
378
|
+
|-----------|------|---------------|
|
|
379
|
+
| PatternsListPage | `packages/core/src/app/[locale]/(auth)/dashboard/patterns/page.tsx` | page, title, addBtn, table |
|
|
380
|
+
| PatternEditor | `packages/core/src/components/page-builder/PageBuilder.tsx` | header.*, blockPicker.* |
|
|
381
|
+
| PatternUsagesPage | `packages/core/src/app/[locale]/(auth)/dashboard/patterns/[id]/usages/page.tsx` | usageReport.*, usageStats.* |
|
|
382
|
+
|
|
383
|
+
## Related POMs
|
|
384
|
+
|
|
385
|
+
| POM | File | Usage |
|
|
386
|
+
|-----|------|-------|
|
|
387
|
+
| PatternsPOM | `themes/default/tests/cypress/src/entities/PatternsPOM.ts` | List operations, entity selectors |
|
|
388
|
+
| PageBuilderPOM | `themes/default/tests/cypress/src/features/PageBuilderPOM.ts` | Editor selectors |
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI Selectors Validation: Patterns
|
|
3
|
+
*
|
|
4
|
+
* This test validates that patterns-specific selectors exist in the DOM.
|
|
5
|
+
* This is a lightweight test that ONLY checks selector presence, not functionality.
|
|
6
|
+
*
|
|
7
|
+
* Purpose:
|
|
8
|
+
* - Validate PatternsPOM and PageBuilderPOM selectors work correctly
|
|
9
|
+
* - Ensure all patterns-specific selectors are implemented
|
|
10
|
+
* - Validate KEY DIFFERENCES from standard entity editor:
|
|
11
|
+
* - NO slug input (patterns don't have slugs)
|
|
12
|
+
* - NO patterns tab in block picker (to prevent recursive patterns)
|
|
13
|
+
* - Run as Phase 12 sub-gate before functional tests
|
|
14
|
+
*
|
|
15
|
+
* Scope:
|
|
16
|
+
* - Navigate to patterns pages (requires login)
|
|
17
|
+
* - Assert elements exist in DOM (no form submissions)
|
|
18
|
+
* - Fast execution (< 30 seconds per describe block)
|
|
19
|
+
*
|
|
20
|
+
* Test IDs:
|
|
21
|
+
* - SEL_PAT_001: Patterns List Page Selectors (5 selectors)
|
|
22
|
+
* - SEL_PAT_002: Patterns List Table Actions (4 selectors)
|
|
23
|
+
* - SEL_PAT_003: Patterns Editor Header - KEY DIFFERENCES (5 selectors)
|
|
24
|
+
* - SEL_PAT_004: Patterns Editor Block Picker - KEY DIFFERENCES (5 selectors)
|
|
25
|
+
* - SEL_PAT_005: Patterns Reports Page (4 selectors)
|
|
26
|
+
* - SEL_PAT_006: Pattern Usage Stats (3 selectors)
|
|
27
|
+
* - SEL_PAT_007: Pattern Usage Report Controls (5 selectors)
|
|
28
|
+
* - SEL_PAT_008: Pattern Usage Table (3 selectors)
|
|
29
|
+
*
|
|
30
|
+
* DEPENDENCIES:
|
|
31
|
+
* - Sample patterns must exist (from seed data)
|
|
32
|
+
* - At least one pattern must have usages (for reports tests)
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { PatternsPOM } from '../../../src/entities/PatternsPOM'
|
|
36
|
+
import { cySelector } from '../../../src/selectors'
|
|
37
|
+
import { loginAsDefaultDeveloper } from '../../../src/session-helpers'
|
|
38
|
+
|
|
39
|
+
describe('Patterns Selectors Validation', { tags: ['@ui-selectors', '@patterns', '@feat-patterns'] }, () => {
|
|
40
|
+
const patterns = PatternsPOM.create()
|
|
41
|
+
|
|
42
|
+
// ============================================
|
|
43
|
+
// SEL_PAT_001: PATTERNS LIST PAGE SELECTORS (5 selectors)
|
|
44
|
+
// ============================================
|
|
45
|
+
describe('SEL_PAT_001: Patterns List Page Selectors', { tags: '@SEL_PAT_001' }, () => {
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
loginAsDefaultDeveloper()
|
|
48
|
+
patterns.visitList()
|
|
49
|
+
patterns.waitForList()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('SEL_PAT_001_01: should find page container', { tags: '@SEL_PAT_001_01' }, () => {
|
|
53
|
+
cy.get(patterns.selectors.page).should('exist')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('SEL_PAT_001_02: should find page title', { tags: '@SEL_PAT_001_02' }, () => {
|
|
57
|
+
cy.get(patterns.selectors.title).should('exist')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('SEL_PAT_001_03: should find add button', { tags: '@SEL_PAT_001_03' }, () => {
|
|
61
|
+
cy.get(patterns.selectors.addButton).should('exist')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('SEL_PAT_001_04: should find search container', { tags: '@SEL_PAT_001_04' }, () => {
|
|
65
|
+
cy.get(patterns.selectors.searchContainer).should('exist')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('SEL_PAT_001_05: should find table container', { tags: '@SEL_PAT_001_05' }, () => {
|
|
69
|
+
cy.get(patterns.selectors.table).should('exist')
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// ============================================
|
|
74
|
+
// SEL_PAT_002: PATTERNS LIST TABLE ACTIONS (4 selectors)
|
|
75
|
+
// REQUIRES: At least one pattern in the database
|
|
76
|
+
// ============================================
|
|
77
|
+
describe('SEL_PAT_002: Patterns List Table Actions', { tags: '@SEL_PAT_002' }, () => {
|
|
78
|
+
beforeEach(() => {
|
|
79
|
+
loginAsDefaultDeveloper()
|
|
80
|
+
patterns.visitList()
|
|
81
|
+
patterns.waitForList()
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('SEL_PAT_002_01: should find row menu for first pattern', { tags: '@SEL_PAT_002_01' }, () => {
|
|
85
|
+
// Get first pattern row and find its menu
|
|
86
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
87
|
+
const dataCy = $row.attr('data-cy')
|
|
88
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
89
|
+
if (patternId) {
|
|
90
|
+
cy.get(patterns.selectors.rowMenu(patternId)).should('exist')
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('SEL_PAT_002_02: should find edit action in row menu', { tags: '@SEL_PAT_002_02' }, () => {
|
|
96
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
97
|
+
const dataCy = $row.attr('data-cy')
|
|
98
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
99
|
+
if (patternId) {
|
|
100
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
101
|
+
cy.get(patterns.selectors.rowAction('edit', patternId)).should('exist')
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it('SEL_PAT_002_03: should find delete action in row menu', { tags: '@SEL_PAT_002_03' }, () => {
|
|
107
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
108
|
+
const dataCy = $row.attr('data-cy')
|
|
109
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
110
|
+
if (patternId) {
|
|
111
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
112
|
+
cy.get(patterns.selectors.rowAction('delete', patternId)).should('exist')
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('SEL_PAT_002_04: should find usages quick action in row menu', { tags: '@SEL_PAT_002_04' }, () => {
|
|
118
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
119
|
+
const dataCy = $row.attr('data-cy')
|
|
120
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
121
|
+
if (patternId) {
|
|
122
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
123
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).should('exist')
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
// ============================================
|
|
130
|
+
// SEL_PAT_003: PATTERNS EDITOR HEADER - KEY DIFFERENCES (5 selectors)
|
|
131
|
+
// NOTE: Patterns editor does NOT have slug input (unlike pages/posts)
|
|
132
|
+
// ============================================
|
|
133
|
+
describe('SEL_PAT_003: Patterns Editor Header', { tags: '@SEL_PAT_003' }, () => {
|
|
134
|
+
beforeEach(() => {
|
|
135
|
+
loginAsDefaultDeveloper()
|
|
136
|
+
// Navigate to create a new pattern
|
|
137
|
+
cy.visit('/dashboard/patterns/create', { timeout: 60000 })
|
|
138
|
+
// Wait for editor to load using block editor selector
|
|
139
|
+
cy.get(cySelector('blockEditor.header.container'), { timeout: 15000 }).should('be.visible')
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
it('SEL_PAT_003_01: should find header container', { tags: '@SEL_PAT_003_01' }, () => {
|
|
143
|
+
cy.get(cySelector('blockEditor.header.container')).should('exist')
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('SEL_PAT_003_02: should find title input', { tags: '@SEL_PAT_003_02' }, () => {
|
|
147
|
+
cy.get(cySelector('blockEditor.header.titleInput')).should('exist')
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('SEL_PAT_003_03: should NOT have slug input (patterns-specific)', { tags: '@SEL_PAT_003_03' }, () => {
|
|
151
|
+
// KEY DIFFERENCE: Patterns do not have slugs
|
|
152
|
+
cy.get(cySelector('blockEditor.header.slugInput')).should('not.exist')
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('SEL_PAT_003_04: should find save button', { tags: '@SEL_PAT_003_04' }, () => {
|
|
156
|
+
cy.get(cySelector('blockEditor.header.saveButton')).should('exist')
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('SEL_PAT_003_05: should find view mode toggle', { tags: '@SEL_PAT_003_05' }, () => {
|
|
160
|
+
cy.get(cySelector('blockEditor.header.viewToggle')).should('exist')
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
// ============================================
|
|
165
|
+
// SEL_PAT_004: PATTERNS EDITOR BLOCK PICKER - KEY DIFFERENCES (5 selectors)
|
|
166
|
+
// NOTE: Patterns block picker does NOT have patterns tab (to prevent recursion)
|
|
167
|
+
// ============================================
|
|
168
|
+
describe('SEL_PAT_004: Patterns Editor Block Picker', { tags: '@SEL_PAT_004' }, () => {
|
|
169
|
+
beforeEach(() => {
|
|
170
|
+
loginAsDefaultDeveloper()
|
|
171
|
+
cy.visit('/dashboard/patterns/create', { timeout: 60000 })
|
|
172
|
+
cy.get(cySelector('blockEditor.header.container'), { timeout: 15000 }).should('be.visible')
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('SEL_PAT_004_01: should find block picker container', { tags: '@SEL_PAT_004_01' }, () => {
|
|
176
|
+
cy.get(cySelector('blockEditor.blockPicker.container')).should('exist')
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
it('SEL_PAT_004_02: should find blocks tab', { tags: '@SEL_PAT_004_02' }, () => {
|
|
180
|
+
cy.get(cySelector('blockEditor.blockPicker.tabBlocks')).should('exist')
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it('SEL_PAT_004_03: should NOT have patterns tab (patterns-specific)', { tags: '@SEL_PAT_004_03' }, () => {
|
|
184
|
+
// KEY DIFFERENCE: Patterns cannot contain other patterns (prevent recursion)
|
|
185
|
+
cy.get(cySelector('blockEditor.blockPicker.tabPatterns')).should('not.exist')
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
it('SEL_PAT_004_04: should find config tab', { tags: '@SEL_PAT_004_04' }, () => {
|
|
189
|
+
cy.get(cySelector('blockEditor.blockPicker.tabConfig')).should('exist')
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
it('SEL_PAT_004_05: should find search input', { tags: '@SEL_PAT_004_05' }, () => {
|
|
193
|
+
cy.get(cySelector('blockEditor.blockPicker.searchInput')).should('exist')
|
|
194
|
+
})
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
// ============================================
|
|
198
|
+
// SEL_PAT_005: PATTERNS REPORTS PAGE (4 selectors)
|
|
199
|
+
// REQUIRES: A pattern with usages for meaningful tests
|
|
200
|
+
// ============================================
|
|
201
|
+
describe('SEL_PAT_005: Patterns Reports Page', { tags: '@SEL_PAT_005' }, () => {
|
|
202
|
+
beforeEach(() => {
|
|
203
|
+
loginAsDefaultDeveloper()
|
|
204
|
+
patterns.visitList()
|
|
205
|
+
patterns.waitForList()
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it('SEL_PAT_005_01: should navigate to pattern usages and find report container', { tags: '@SEL_PAT_005_01' }, () => {
|
|
209
|
+
// Click usages action on first pattern
|
|
210
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
211
|
+
const dataCy = $row.attr('data-cy')
|
|
212
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
213
|
+
if (patternId) {
|
|
214
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
215
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
216
|
+
// Wait for page to load and find report container
|
|
217
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
218
|
+
}
|
|
219
|
+
})
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('SEL_PAT_005_02: should find back button on usages page', { tags: '@SEL_PAT_005_02' }, () => {
|
|
223
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
224
|
+
const dataCy = $row.attr('data-cy')
|
|
225
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
226
|
+
if (patternId) {
|
|
227
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
228
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
229
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
230
|
+
// Back button should exist on the page
|
|
231
|
+
cy.get(patterns.selectors.backButton).should('exist')
|
|
232
|
+
}
|
|
233
|
+
})
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
it('SEL_PAT_005_03: should find page title on usages page', { tags: '@SEL_PAT_005_03' }, () => {
|
|
237
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
238
|
+
const dataCy = $row.attr('data-cy')
|
|
239
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
240
|
+
if (patternId) {
|
|
241
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
242
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
243
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
244
|
+
cy.get(patterns.selectors.headerTitle).should('exist')
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
it('SEL_PAT_005_04: should find edit button on usages page', { tags: '@SEL_PAT_005_04' }, () => {
|
|
250
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
251
|
+
const dataCy = $row.attr('data-cy')
|
|
252
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
253
|
+
if (patternId) {
|
|
254
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
255
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
256
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
257
|
+
cy.get(patterns.selectors.editButton).should('exist')
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
})
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
// ============================================
|
|
264
|
+
// SEL_PAT_006: PATTERN USAGE STATS (3 selectors)
|
|
265
|
+
// ============================================
|
|
266
|
+
describe('SEL_PAT_006: Pattern Usage Stats', { tags: '@SEL_PAT_006' }, () => {
|
|
267
|
+
beforeEach(() => {
|
|
268
|
+
loginAsDefaultDeveloper()
|
|
269
|
+
patterns.visitList()
|
|
270
|
+
patterns.waitForList()
|
|
271
|
+
// Navigate to first pattern's usages
|
|
272
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
273
|
+
const dataCy = $row.attr('data-cy')
|
|
274
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
275
|
+
if (patternId) {
|
|
276
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
277
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
278
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
it('SEL_PAT_006_01: should find stats container', { tags: '@SEL_PAT_006_01' }, () => {
|
|
284
|
+
cy.get(patterns.patternSelectors.usageStats.container).should('exist')
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
it('SEL_PAT_006_02: should find total usage card', { tags: '@SEL_PAT_006_02' }, () => {
|
|
288
|
+
cy.get(patterns.patternSelectors.usageStats.total).should('exist')
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
it('SEL_PAT_006_03: should find usage by type cards (if usages exist)', { tags: '@SEL_PAT_006_03' }, () => {
|
|
292
|
+
// This might not exist if pattern has no usages, so check for either stats or loading
|
|
293
|
+
cy.get('body').then(($body) => {
|
|
294
|
+
if ($body.find(patterns.patternSelectors.usageStats.byType('pages')).length > 0) {
|
|
295
|
+
cy.get(patterns.patternSelectors.usageStats.byType('pages')).should('exist')
|
|
296
|
+
} else if ($body.find(patterns.patternSelectors.usageStats.byType('posts')).length > 0) {
|
|
297
|
+
cy.get(patterns.patternSelectors.usageStats.byType('posts')).should('exist')
|
|
298
|
+
} else {
|
|
299
|
+
// No usage by type cards, which is fine if pattern has no usages
|
|
300
|
+
cy.log('No usage by type cards found - pattern may have no usages')
|
|
301
|
+
}
|
|
302
|
+
})
|
|
303
|
+
})
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
// ============================================
|
|
307
|
+
// SEL_PAT_007: PATTERN USAGE REPORT CONTROLS (5 selectors)
|
|
308
|
+
// ============================================
|
|
309
|
+
describe('SEL_PAT_007: Pattern Usage Report Controls', { tags: '@SEL_PAT_007' }, () => {
|
|
310
|
+
beforeEach(() => {
|
|
311
|
+
loginAsDefaultDeveloper()
|
|
312
|
+
patterns.visitList()
|
|
313
|
+
patterns.waitForList()
|
|
314
|
+
// Navigate to first pattern's usages
|
|
315
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
316
|
+
const dataCy = $row.attr('data-cy')
|
|
317
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
318
|
+
if (patternId) {
|
|
319
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
320
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
321
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
322
|
+
}
|
|
323
|
+
})
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
it('SEL_PAT_007_01: should find report container', { tags: '@SEL_PAT_007_01' }, () => {
|
|
327
|
+
cy.get(patterns.patternSelectors.usageReport.container).should('exist')
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
it('SEL_PAT_007_02: should find filter select', { tags: '@SEL_PAT_007_02' }, () => {
|
|
331
|
+
cy.get(patterns.patternSelectors.usageReport.filterSelect).should('exist')
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
it('SEL_PAT_007_03: should find pagination container', { tags: '@SEL_PAT_007_03' }, () => {
|
|
335
|
+
cy.get(patterns.patternSelectors.usageReport.pagination).should('exist')
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
it('SEL_PAT_007_04: should find prev page button', { tags: '@SEL_PAT_007_04' }, () => {
|
|
339
|
+
cy.get(patterns.patternSelectors.usageReport.prevPage).should('exist')
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
it('SEL_PAT_007_05: should find next page button', { tags: '@SEL_PAT_007_05' }, () => {
|
|
343
|
+
cy.get(patterns.patternSelectors.usageReport.nextPage).should('exist')
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
it('SEL_PAT_007_06: should find results info', { tags: '@SEL_PAT_007_06' }, () => {
|
|
347
|
+
cy.get(patterns.patternSelectors.usageReport.resultsInfo).should('exist')
|
|
348
|
+
})
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
// ============================================
|
|
352
|
+
// SEL_PAT_008: PATTERN USAGE TABLE (3 selectors)
|
|
353
|
+
// ============================================
|
|
354
|
+
describe('SEL_PAT_008: Pattern Usage Table', { tags: '@SEL_PAT_008' }, () => {
|
|
355
|
+
beforeEach(() => {
|
|
356
|
+
loginAsDefaultDeveloper()
|
|
357
|
+
patterns.visitList()
|
|
358
|
+
patterns.waitForList()
|
|
359
|
+
// Navigate to first pattern's usages
|
|
360
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
361
|
+
const dataCy = $row.attr('data-cy')
|
|
362
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
363
|
+
if (patternId) {
|
|
364
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
365
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
366
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
367
|
+
}
|
|
368
|
+
})
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
it('SEL_PAT_008_01: should find usage table container (or empty state)', { tags: '@SEL_PAT_008_01' }, () => {
|
|
372
|
+
cy.get('body').then(($body) => {
|
|
373
|
+
// Either the table exists or the empty state
|
|
374
|
+
if ($body.find(patterns.patternSelectors.usageTable.container).length > 0) {
|
|
375
|
+
cy.get(patterns.patternSelectors.usageTable.container).should('exist')
|
|
376
|
+
} else {
|
|
377
|
+
cy.get(patterns.patternSelectors.usageTable.empty).should('exist')
|
|
378
|
+
}
|
|
379
|
+
})
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
it.skip('SEL_PAT_008_02: should find usage row (requires pattern with usages)', { tags: '@SEL_PAT_008_02' }, () => {
|
|
383
|
+
// This test requires the pattern to have actual usages
|
|
384
|
+
cy.get('[data-cy^="pattern-usage-row-"]').first().should('exist')
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
it.skip('SEL_PAT_008_03: should find view link in usage row (requires pattern with usages)', { tags: '@SEL_PAT_008_03' }, () => {
|
|
388
|
+
// This test requires the pattern to have actual usages
|
|
389
|
+
cy.get('[data-cy^="pattern-usage-view-"]').first().should('exist')
|
|
390
|
+
})
|
|
391
|
+
})
|
|
392
|
+
})
|
|
@@ -66,6 +66,11 @@ export class DashboardPOM extends BasePOM {
|
|
|
66
66
|
topnavUserLoading: cySelector('dashboard.topnav.userLoading'),
|
|
67
67
|
topnavSignin: cySelector('dashboard.topnav.signin'),
|
|
68
68
|
topnavSignup: cySelector('dashboard.topnav.signup'),
|
|
69
|
+
// Topnav settings menu
|
|
70
|
+
topnavSettingsMenuTrigger: cySelector('dashboard.topnav.settingsMenu.trigger'),
|
|
71
|
+
topnavSettingsMenuContent: cySelector('dashboard.topnav.settingsMenu.content'),
|
|
72
|
+
topnavSettingsMenuItem: (index: number) => cySelector('dashboard.topnav.settingsMenu.item', { index }),
|
|
73
|
+
topnavSettingsMenuLink: (index: number) => cySelector('dashboard.topnav.settingsMenu.link', { index }),
|
|
69
74
|
// Topnav mobile menu
|
|
70
75
|
topnavMobileMenuToggle: cySelector('dashboard.topnav.mobileMenu.toggle'),
|
|
71
76
|
topnavMobileMenuContainer: cySelector('dashboard.topnav.mobileMenu.container'),
|