@nextsparkjs/theme-default 0.1.0-beta.49 → 0.1.0-beta.51

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.
@@ -0,0 +1,329 @@
1
+ /**
2
+ * PatternsPOM - Page Object Model for Patterns entity
3
+ *
4
+ * Extends DashboardEntityPOM for standard CRUD operations on patterns.
5
+ * Includes pattern-specific methods for:
6
+ * - Usage report interactions
7
+ * - Delete dialog with usage checking
8
+ * - Placeholder handling in block editor
9
+ *
10
+ * @example
11
+ * // List operations
12
+ * PatternsPOM.create()
13
+ * .visitList()
14
+ * .waitForList()
15
+ * .search('Hero Section')
16
+ *
17
+ * // View pattern usage
18
+ * PatternsPOM.create()
19
+ * .visitDetailWithApiWait(patternId)
20
+ * .assertUsageStatsLoaded()
21
+ *
22
+ * // Delete with usage warning (from list)
23
+ * PatternsPOM.create()
24
+ * .visitList()
25
+ * .openDeleteDialogFromList(patternId)
26
+ * .assertUsageWarningVisible()
27
+ * .confirmPatternDelete()
28
+ */
29
+
30
+ import { DashboardEntityPOM } from '../core/DashboardEntityPOM'
31
+ import { cySelector } from '../selectors'
32
+ import entitiesConfig from '../../fixtures/entities.json'
33
+
34
+ export class PatternsPOM extends DashboardEntityPOM {
35
+ constructor() {
36
+ super(entitiesConfig.entities.patterns.slug)
37
+ }
38
+
39
+ // ============================================
40
+ // FACTORY METHOD
41
+ // ============================================
42
+
43
+ static create(): PatternsPOM {
44
+ return new PatternsPOM()
45
+ }
46
+
47
+ // ============================================
48
+ // PATTERN-SPECIFIC SELECTORS
49
+ // ============================================
50
+
51
+ get patternSelectors() {
52
+ return {
53
+ // Usage Table
54
+ usageTable: {
55
+ container: cySelector('patterns.usageTable.container'),
56
+ loading: cySelector('patterns.usageTable.loading'),
57
+ empty: cySelector('patterns.usageTable.empty'),
58
+ row: (id: string) => cySelector('patterns.usageTable.row', { id }),
59
+ viewLink: (id: string) => cySelector('patterns.usageTable.viewLink', { id }),
60
+ },
61
+ // Usage Stats
62
+ usageStats: {
63
+ container: cySelector('patterns.usageStats.container'),
64
+ loading: cySelector('patterns.usageStats.loading'),
65
+ total: cySelector('patterns.usageStats.total'),
66
+ byType: (entityType: string) => cySelector('patterns.usageStats.byType', { entityType }),
67
+ },
68
+ // Usage Report
69
+ usageReport: {
70
+ container: cySelector('patterns.usageReport.container'),
71
+ error: cySelector('patterns.usageReport.error'),
72
+ filters: cySelector('patterns.usageReport.filters'),
73
+ filterSelect: cySelector('patterns.usageReport.filterSelect'),
74
+ pagination: cySelector('patterns.usageReport.pagination'),
75
+ prevPage: cySelector('patterns.usageReport.prevPage'),
76
+ nextPage: cySelector('patterns.usageReport.nextPage'),
77
+ resultsInfo: cySelector('patterns.usageReport.resultsInfo'),
78
+ },
79
+ // Delete Dialog
80
+ deleteDialog: {
81
+ trigger: cySelector('patterns.deleteDialog.trigger'),
82
+ container: cySelector('patterns.deleteDialog.container'),
83
+ loading: cySelector('patterns.deleteDialog.loading'),
84
+ error: cySelector('patterns.deleteDialog.error'),
85
+ warning: cySelector('patterns.deleteDialog.warning'),
86
+ usageList: cySelector('patterns.deleteDialog.usageList'),
87
+ noUsage: cySelector('patterns.deleteDialog.noUsage'),
88
+ cancel: cySelector('patterns.deleteDialog.cancel'),
89
+ confirm: cySelector('patterns.deleteDialog.confirm'),
90
+ },
91
+ // Deleted Pattern Placeholder
92
+ placeholder: {
93
+ container: cySelector('patterns.placeholder.container'),
94
+ removeBtn: cySelector('patterns.placeholder.removeBtn'),
95
+ },
96
+ }
97
+ }
98
+
99
+ // ============================================
100
+ // USAGE REPORT METHODS
101
+ // ============================================
102
+
103
+ /**
104
+ * Assert usage stats container is visible and loaded
105
+ */
106
+ assertUsageStatsLoaded(): this {
107
+ cy.get(this.patternSelectors.usageStats.container).should('be.visible')
108
+ cy.get(this.patternSelectors.usageStats.loading).should('not.exist')
109
+ return this
110
+ }
111
+
112
+ /**
113
+ * Assert usage table is visible and loaded
114
+ */
115
+ assertUsageTableLoaded(): this {
116
+ cy.get(this.patternSelectors.usageTable.container).should('be.visible')
117
+ cy.get(this.patternSelectors.usageTable.loading).should('not.exist')
118
+ return this
119
+ }
120
+
121
+ /**
122
+ * Assert usage report shows empty state
123
+ */
124
+ assertUsageTableEmpty(): this {
125
+ cy.get(this.patternSelectors.usageTable.empty).should('be.visible')
126
+ return this
127
+ }
128
+
129
+ /**
130
+ * Assert total usage count
131
+ */
132
+ assertTotalUsageCount(expectedCount: number): this {
133
+ cy.get(this.patternSelectors.usageStats.total)
134
+ .should('contain.text', expectedCount.toString())
135
+ return this
136
+ }
137
+
138
+ /**
139
+ * Filter usage by entity type
140
+ */
141
+ filterUsageByType(entityType: string): this {
142
+ cy.get(this.patternSelectors.usageReport.filterSelect).click()
143
+ cy.get(`[data-value="${entityType}"]`).click()
144
+ return this
145
+ }
146
+
147
+ /**
148
+ * Navigate to next page of usage results
149
+ */
150
+ goToNextUsagePage(): this {
151
+ cy.get(this.patternSelectors.usageReport.nextPage).click()
152
+ return this
153
+ }
154
+
155
+ /**
156
+ * Navigate to previous page of usage results
157
+ */
158
+ goToPrevUsagePage(): this {
159
+ cy.get(this.patternSelectors.usageReport.prevPage).click()
160
+ return this
161
+ }
162
+
163
+ /**
164
+ * Click view link for a specific usage row
165
+ */
166
+ clickUsageViewLink(usageId: string): this {
167
+ cy.get(this.patternSelectors.usageTable.viewLink(usageId)).click()
168
+ return this
169
+ }
170
+
171
+ // ============================================
172
+ // DELETE DIALOG METHODS
173
+ // ============================================
174
+
175
+ /**
176
+ * Open the delete dialog for a pattern from the list dropdown menu
177
+ * @param id - The pattern ID to delete
178
+ */
179
+ openDeleteDialogFromList(id: string): this {
180
+ // Click on the dropdown menu first
181
+ cy.get(this.selectors.rowMenu(id)).click()
182
+ // Then click the delete action
183
+ cy.get(this.selectors.rowAction('delete', id)).click()
184
+ // Wait for dialog to be visible
185
+ cy.get(this.patternSelectors.deleteDialog.container).should('be.visible')
186
+ return this
187
+ }
188
+
189
+ /**
190
+ * Open the delete dialog using the standalone trigger (if present)
191
+ * @deprecated Use openDeleteDialogFromList() for list-based deletion
192
+ */
193
+ openDeleteDialog(): this {
194
+ cy.get(this.patternSelectors.deleteDialog.trigger).click()
195
+ cy.get(this.patternSelectors.deleteDialog.container).should('be.visible')
196
+ return this
197
+ }
198
+
199
+ /**
200
+ * Wait for usage check to complete in delete dialog
201
+ */
202
+ waitForUsageCheck(): this {
203
+ cy.get(this.patternSelectors.deleteDialog.loading).should('not.exist')
204
+ return this
205
+ }
206
+
207
+ /**
208
+ * Assert the delete dialog shows usage warning
209
+ */
210
+ assertUsageWarningVisible(): this {
211
+ cy.get(this.patternSelectors.deleteDialog.warning).should('be.visible')
212
+ return this
213
+ }
214
+
215
+ /**
216
+ * Assert the delete dialog shows no usage message
217
+ */
218
+ assertNoUsageVisible(): this {
219
+ cy.get(this.patternSelectors.deleteDialog.noUsage).should('be.visible')
220
+ return this
221
+ }
222
+
223
+ /**
224
+ * Assert the delete dialog shows error
225
+ */
226
+ assertDeleteDialogError(): this {
227
+ cy.get(this.patternSelectors.deleteDialog.error).should('be.visible')
228
+ return this
229
+ }
230
+
231
+ /**
232
+ * Confirm deletion in the delete dialog
233
+ */
234
+ confirmPatternDelete(): this {
235
+ cy.get(this.patternSelectors.deleteDialog.confirm).click()
236
+ return this
237
+ }
238
+
239
+ /**
240
+ * Cancel deletion in the delete dialog
241
+ */
242
+ cancelPatternDelete(): this {
243
+ cy.get(this.patternSelectors.deleteDialog.cancel).click()
244
+ return this
245
+ }
246
+
247
+ /**
248
+ * Delete pattern from list with API wait
249
+ * Handles the full flow: open dialog from dropdown, wait for usage check, confirm
250
+ * @param id - The pattern ID to delete
251
+ */
252
+ deletePatternFromListWithApiWait(id: string): this {
253
+ this.openDeleteDialogFromList(id)
254
+ this.waitForUsageCheck()
255
+ this.api.interceptDelete()
256
+ this.confirmPatternDelete()
257
+ this.api.waitForDelete()
258
+ return this
259
+ }
260
+
261
+ /**
262
+ * Delete pattern with API wait (using standalone trigger)
263
+ * @deprecated Use deletePatternFromListWithApiWait() for list-based deletion
264
+ */
265
+ deletePatternWithApiWait(): this {
266
+ this.openDeleteDialog()
267
+ this.waitForUsageCheck()
268
+ this.api.interceptDelete()
269
+ this.confirmPatternDelete()
270
+ this.api.waitForDelete()
271
+ return this
272
+ }
273
+
274
+ // ============================================
275
+ // PLACEHOLDER METHODS (Block Editor context)
276
+ // ============================================
277
+
278
+ /**
279
+ * Assert deleted pattern placeholder is visible
280
+ */
281
+ assertPlaceholderVisible(): this {
282
+ cy.get(this.patternSelectors.placeholder.container).should('be.visible')
283
+ return this
284
+ }
285
+
286
+ /**
287
+ * Click remove button on deleted pattern placeholder
288
+ */
289
+ clickPlaceholderRemove(): this {
290
+ cy.get(this.patternSelectors.placeholder.removeBtn).click()
291
+ return this
292
+ }
293
+
294
+ // ============================================
295
+ // WORKFLOW METHODS
296
+ // ============================================
297
+
298
+ /**
299
+ * Create a new pattern (navigates to create page)
300
+ */
301
+ navigateToCreate(): this {
302
+ this.clickAdd()
303
+ return this
304
+ }
305
+
306
+ /**
307
+ * Navigate to edit a pattern
308
+ */
309
+ navigateToEdit(id: string): this {
310
+ this.clickRowAction('edit', id)
311
+ return this
312
+ }
313
+
314
+ /**
315
+ * Assert pattern appears in list
316
+ */
317
+ assertPatternInList(title: string): this {
318
+ return this.assertInList(title)
319
+ }
320
+
321
+ /**
322
+ * Assert pattern does not appear in list
323
+ */
324
+ assertPatternNotInList(title: string): this {
325
+ return this.assertNotInList(title)
326
+ }
327
+ }
328
+
329
+ export default PatternsPOM
@@ -6,9 +6,11 @@
6
6
  * - CustomersPOM: Customers CRUD operations
7
7
  * - PostsPOM: Posts list operations (use PostEditorPOM for editing)
8
8
  * - PagesPOM: Pages list operations (use PageBuilderPOM for editing)
9
+ * - PatternsPOM: Patterns CRUD operations with usage tracking
9
10
  */
10
11
 
11
12
  export { TasksPOM, type TaskFormData } from './TasksPOM'
12
13
  export { CustomersPOM, type CustomerFormData } from './CustomersPOM'
13
14
  export { PostsPOM, type PostListFilters } from './PostsPOM'
14
15
  export { PagesPOM, type PageListFilters } from './PagesPOM'
16
+ export { PatternsPOM } from './PatternsPOM'