@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.
- package/api/ai/chat/stream/route.ts +4 -1
- package/api/ai/orchestrator/route.ts +10 -3
- package/api/ai/single-agent/route.ts +10 -3
- package/api/ai/usage/route.ts +4 -1
- package/blocks/text-content/component.tsx +10 -8
- package/config/dashboard.config.ts +14 -0
- package/config/permissions.config.ts +11 -0
- package/messages/en/admin.json +12 -1
- package/messages/es/admin.json +12 -1
- package/migrations/093_pages_sample_data.sql +7 -7
- package/migrations/098_patterns_sample_data.sql +234 -0
- package/package.json +3 -3
- package/tests/cypress/e2e/_utils/selectors/block-editor.bdd.md +127 -3
- package/tests/cypress/e2e/_utils/selectors/block-editor.cy.ts +124 -0
- package/tests/cypress/e2e/ai/chat-api.cy.ts +50 -38
- package/tests/cypress/e2e/api/_core/security/security-headers.cy.ts +601 -0
- package/tests/cypress/e2e/patterns/patterns-in-pages.cy.ts +367 -0
- package/tests/cypress/fixtures/entities.json +9 -0
- package/tests/cypress/src/entities/PatternsPOM.ts +329 -0
- package/tests/cypress/src/entities/index.ts +2 -0
|
@@ -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'
|