@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,367 @@
1
+ /**
2
+ * Patterns in Pages - Functional E2E Tests
3
+ *
4
+ * Tests the integration of the patterns system with the page builder:
5
+ * - Patterns tab visibility and functionality
6
+ * - Pattern insertion into pages
7
+ * - Pattern reference rendering and interaction
8
+ * - Pattern nesting prevention (patterns tab hidden when editing patterns)
9
+ *
10
+ * Sample Patterns in DB (team-nextspark-001):
11
+ * - Newsletter CTA (slug: newsletter-cta, status: published)
12
+ * - Footer Links (slug: footer-links, status: published)
13
+ * - Hero Header (slug: hero-header, status: draft)
14
+ *
15
+ * Re-execution:
16
+ * pnpm tags @patterns # Run all patterns tests
17
+ * pnpm tags @TC_PAT_001 # Run specific test
18
+ * pnpm cy:run --spec "cypress/e2e/patterns/patterns-in-pages.cy.ts"
19
+ */
20
+
21
+ import { PageBuilderPOM } from '../../src/features/PageBuilderPOM'
22
+ import { loginAsDefaultDeveloper } from '../../src/session-helpers'
23
+
24
+ const DEVELOPER_TEAM_ID = 'team-nextspark-001'
25
+
26
+ describe('Patterns in Pages - Functional Tests', {
27
+ tags: ['@patterns', '@block-editor', '@functional']
28
+ }, () => {
29
+ const pom = PageBuilderPOM.create()
30
+
31
+ beforeEach(() => {
32
+ loginAsDefaultDeveloper()
33
+ cy.window().then((win) => {
34
+ win.localStorage.setItem('activeTeamId', DEVELOPER_TEAM_ID)
35
+ })
36
+ })
37
+
38
+ // ===========================================================================
39
+ // TC_PAT_001: Can switch to Patterns tab in block picker
40
+ // ===========================================================================
41
+ describe('TC_PAT_001: Switch to Patterns Tab', { tags: '@TC_PAT_001' }, () => {
42
+ it('should display patterns tab when editing pages', { tags: '@TC_PAT_001_01' }, () => {
43
+ pom.visitCreate()
44
+ pom.waitForEditor()
45
+
46
+ // Patterns tab should be visible
47
+ cy.get('[data-cy="block-picker-tab-patterns"]')
48
+ .should('exist')
49
+ .and('be.visible')
50
+ })
51
+
52
+ it('should switch to patterns tab on click', { tags: '@TC_PAT_001_02' }, () => {
53
+ pom.visitCreate()
54
+ pom.waitForEditor()
55
+
56
+ // Click patterns tab
57
+ cy.get('[data-cy="block-picker-tab-patterns"]').click()
58
+
59
+ // Patterns search and list should appear
60
+ cy.get('[data-cy="block-picker-patterns-search"]').should('be.visible')
61
+ cy.get('[data-cy="block-picker-patterns-list"]').should('be.visible')
62
+ })
63
+
64
+ it('should switch back to blocks tab', { tags: '@TC_PAT_001_03' }, () => {
65
+ pom.visitCreate()
66
+ pom.waitForEditor()
67
+
68
+ // Switch to patterns
69
+ cy.get('[data-cy="block-picker-tab-patterns"]').click()
70
+ cy.get('[data-cy="block-picker-patterns-list"]').should('be.visible')
71
+
72
+ // Switch back to blocks
73
+ cy.get('[data-cy="block-picker-tab-blocks"]').click()
74
+ cy.get('[data-cy="block-picker-list"]').should('be.visible')
75
+ })
76
+ })
77
+
78
+ // ===========================================================================
79
+ // TC_PAT_002: Patterns tab shows sample patterns
80
+ // ===========================================================================
81
+ describe('TC_PAT_002: Display Sample Patterns', { tags: '@TC_PAT_002' }, () => {
82
+ beforeEach(() => {
83
+ pom.visitCreate()
84
+ pom.waitForEditor()
85
+ cy.get('[data-cy="block-picker-tab-patterns"]').click()
86
+ cy.wait(500) // Wait for patterns to load
87
+ })
88
+
89
+ it('should display at least one published pattern', { tags: '@TC_PAT_002_01' }, () => {
90
+ // Check that at least one pattern card exists
91
+ cy.get('[data-cy^="block-picker-pattern-card-"]')
92
+ .should('have.length.at.least', 1)
93
+ })
94
+
95
+ it('should display pattern card with all elements', { tags: '@TC_PAT_002_02' }, () => {
96
+ // Get first pattern card
97
+ cy.get('[data-cy^="block-picker-pattern-card-"]').first().within(() => {
98
+ // Check for icon, title, description, insert button
99
+ cy.get('[data-cy^="block-picker-pattern-icon-"]').should('exist')
100
+ cy.get('[data-cy^="block-picker-pattern-title-"]').should('exist').and('not.be.empty')
101
+ cy.get('[data-cy^="block-picker-pattern-desc-"]').should('exist')
102
+ cy.get('[data-cy^="block-picker-pattern-insert-"]').should('exist').and('be.visible')
103
+ })
104
+ })
105
+
106
+ it('should filter patterns using search', { tags: '@TC_PAT_002_03' }, () => {
107
+ // Get initial count
108
+ cy.get('[data-cy^="block-picker-pattern-card-"]').then(($cards) => {
109
+ const initialCount = $cards.length
110
+
111
+ // Type search term
112
+ cy.get('[data-cy="block-picker-patterns-search"]').type('Newsletter')
113
+ cy.wait(300)
114
+
115
+ // Pattern list should be filtered
116
+ cy.get('[data-cy^="block-picker-pattern-card-"]').then(($filtered) => {
117
+ // Should have fewer or equal patterns after filtering
118
+ expect($filtered.length).to.be.at.most(initialCount)
119
+
120
+ // If newsletter pattern exists, it should be visible
121
+ if ($filtered.length > 0) {
122
+ cy.get('[data-cy^="block-picker-pattern-title-"]')
123
+ .first()
124
+ .should('contain.text', 'Newsletter')
125
+ }
126
+ })
127
+ })
128
+ })
129
+
130
+ it('should clear search filter', { tags: '@TC_PAT_002_04' }, () => {
131
+ // Search for something
132
+ cy.get('[data-cy="block-picker-patterns-search"]').type('Footer')
133
+ cy.wait(300)
134
+
135
+ // Clear search
136
+ cy.get('[data-cy="block-picker-patterns-search"]').clear()
137
+ cy.wait(300)
138
+
139
+ // All published patterns should be visible again
140
+ cy.get('[data-cy^="block-picker-pattern-card-"]')
141
+ .should('have.length.at.least', 1)
142
+ })
143
+ })
144
+
145
+ // ===========================================================================
146
+ // TC_PAT_003: Can insert a pattern into a page
147
+ // ===========================================================================
148
+ describe('TC_PAT_003: Insert Pattern into Page', { tags: '@TC_PAT_003' }, () => {
149
+ it('should insert pattern when clicking insert button', { tags: '@TC_PAT_003_01' }, () => {
150
+ pom.visitCreate()
151
+ pom.waitForEditor()
152
+ pom.switchToLayoutMode()
153
+
154
+ // Switch to patterns tab
155
+ cy.get('[data-cy="block-picker-tab-patterns"]').click()
156
+ cy.wait(500)
157
+
158
+ // Click insert on first pattern
159
+ cy.get('[data-cy^="block-picker-pattern-insert-"]').first().click()
160
+
161
+ // Pattern reference should appear in layout canvas
162
+ cy.wait(1000)
163
+ cy.get('[data-cy^="sortable-block-"]').should('have.length.at.least', 1)
164
+ })
165
+
166
+ it('should show pattern reference in sortable blocks list', { tags: '@TC_PAT_003_02' }, () => {
167
+ pom.visitCreate()
168
+ pom.waitForEditor()
169
+ pom.switchToLayoutMode()
170
+
171
+ // Insert pattern
172
+ cy.get('[data-cy="block-picker-tab-patterns"]').click()
173
+ cy.wait(500)
174
+ cy.get('[data-cy^="block-picker-pattern-insert-"]').first().click()
175
+ cy.wait(1000)
176
+
177
+ // Should see pattern reference block in layout canvas
178
+ // Pattern reference should have a distinct appearance (badge, etc.)
179
+ cy.get(pom.editorSelectors.sortableBlockGeneric)
180
+ .should('have.length.at.least', 1)
181
+ })
182
+
183
+ it('should allow inserting multiple patterns', { tags: '@TC_PAT_003_03' }, () => {
184
+ pom.visitCreate()
185
+ pom.waitForEditor()
186
+ pom.switchToLayoutMode()
187
+
188
+ cy.get('[data-cy="block-picker-tab-patterns"]').click()
189
+ cy.wait(500)
190
+
191
+ // Get count of available patterns
192
+ cy.get('[data-cy^="block-picker-pattern-insert-"]').then(($buttons) => {
193
+ const patternCount = Math.min($buttons.length, 2) // Insert max 2 patterns
194
+
195
+ // Insert first pattern
196
+ cy.get('[data-cy^="block-picker-pattern-insert-"]').eq(0).click()
197
+ cy.wait(500)
198
+
199
+ if (patternCount > 1) {
200
+ // Insert second pattern if available
201
+ cy.get('[data-cy^="block-picker-pattern-insert-"]').eq(1).click()
202
+ cy.wait(500)
203
+
204
+ // Should have 2 blocks
205
+ cy.get(pom.editorSelectors.sortableBlockGeneric)
206
+ .should('have.length.at.least', 2)
207
+ }
208
+ })
209
+ })
210
+ })
211
+
212
+ // ===========================================================================
213
+ // TC_PAT_004: Pattern reference displays correctly in preview
214
+ // ===========================================================================
215
+ describe('TC_PAT_004: Pattern Reference in Preview', { tags: '@TC_PAT_004' }, () => {
216
+ beforeEach(() => {
217
+ pom.visitCreate()
218
+ pom.waitForEditor()
219
+ pom.switchToLayoutMode()
220
+
221
+ // Insert a pattern
222
+ cy.get('[data-cy="block-picker-tab-patterns"]').click()
223
+ cy.wait(500)
224
+ cy.get('[data-cy^="block-picker-pattern-insert-"]').first().click()
225
+ cy.wait(1000)
226
+
227
+ // Switch to preview mode
228
+ pom.switchToPreviewMode()
229
+ cy.wait(500)
230
+ })
231
+
232
+ it('should render pattern reference container in preview', { tags: '@TC_PAT_004_01' }, () => {
233
+ // Pattern reference should be visible
234
+ cy.get('[data-cy^="pattern-reference-"]')
235
+ .should('exist')
236
+ .and('be.visible')
237
+ })
238
+
239
+ it('should display pattern reference badge', { tags: '@TC_PAT_004_02' }, () => {
240
+ // Badge should indicate this is a pattern reference
241
+ cy.get('[data-cy^="pattern-reference-badge-"]')
242
+ .should('exist')
243
+ })
244
+
245
+ it('should show pattern reference edit link', { tags: '@TC_PAT_004_03' }, () => {
246
+ // Edit link should allow navigating to pattern editor
247
+ cy.get('[data-cy^="pattern-reference-edit-link-"]')
248
+ .should('exist')
249
+ .and('be.visible')
250
+ })
251
+
252
+ it('should show remove button for pattern reference', { tags: '@TC_PAT_004_04' }, () => {
253
+ cy.get('[data-cy^="pattern-reference-remove-"]')
254
+ .should('exist')
255
+ })
256
+
257
+ it('should show locked state when pattern reference is selected', { tags: '@TC_PAT_004_05' }, () => {
258
+ // Click on pattern reference
259
+ cy.get('[data-cy^="pattern-reference-"]').first().click()
260
+ cy.wait(500)
261
+
262
+ // Locked indicator should appear
263
+ cy.get('[data-cy^="pattern-reference-locked-"]')
264
+ .should('exist')
265
+ })
266
+ })
267
+
268
+ // ===========================================================================
269
+ // TC_PAT_005: Can remove pattern reference from page
270
+ // ===========================================================================
271
+ describe('TC_PAT_005: Remove Pattern Reference', { tags: '@TC_PAT_005' }, () => {
272
+ it('should remove pattern reference when clicking remove button', { tags: '@TC_PAT_005_01' }, () => {
273
+ pom.visitCreate()
274
+ pom.waitForEditor()
275
+ pom.switchToLayoutMode()
276
+
277
+ // Insert pattern
278
+ cy.get('[data-cy="block-picker-tab-patterns"]').click()
279
+ cy.wait(500)
280
+ cy.get('[data-cy^="block-picker-pattern-insert-"]').first().click()
281
+ cy.wait(1000)
282
+
283
+ // Get initial count
284
+ cy.get(pom.editorSelectors.sortableBlockGeneric).then(($blocks) => {
285
+ const initialCount = $blocks.length
286
+
287
+ // Switch to preview to access remove button
288
+ pom.switchToPreviewMode()
289
+ cy.wait(500)
290
+
291
+ // Click remove button
292
+ cy.get('[data-cy^="pattern-reference-remove-"]').first().click()
293
+ cy.wait(500)
294
+
295
+ // Switch back to layout mode to verify
296
+ pom.switchToLayoutMode()
297
+ cy.wait(500)
298
+
299
+ // Block count should decrease
300
+ cy.get(pom.editorSelectors.sortableBlockGeneric).should('have.length', initialCount - 1)
301
+ })
302
+ })
303
+
304
+ it('should remove pattern reference from layout mode', { tags: '@TC_PAT_005_02' }, () => {
305
+ pom.visitCreate()
306
+ pom.waitForEditor()
307
+ pom.switchToLayoutMode()
308
+
309
+ // Insert pattern
310
+ cy.get('[data-cy="block-picker-tab-patterns"]').click()
311
+ cy.wait(500)
312
+ cy.get('[data-cy^="block-picker-pattern-insert-"]').first().click()
313
+ cy.wait(1000)
314
+
315
+ // In layout mode, use standard block remove button
316
+ cy.get(pom.editorSelectors.sortableBlockGeneric).first()
317
+ .invoke('attr', 'data-cy')
318
+ .then((dataCy) => {
319
+ const blockId = dataCy?.replace('sortable-block-', '') || ''
320
+ cy.get(pom.editorSelectors.removeBlock(blockId)).click()
321
+ cy.wait(500)
322
+
323
+ // Block should be removed
324
+ cy.get(pom.editorSelectors.sortableBlockGeneric).should('have.length', 0)
325
+ })
326
+ })
327
+ })
328
+
329
+ // ===========================================================================
330
+ // TC_PAT_006: Patterns tab is NOT shown when editing patterns entity
331
+ // ===========================================================================
332
+ describe('TC_PAT_006: Prevent Pattern Nesting', { tags: '@TC_PAT_006' }, () => {
333
+ it('should NOT show patterns tab when editing a pattern', { tags: '@TC_PAT_006_01' }, () => {
334
+ // Visit the patterns entity create page
335
+ cy.visit('/dashboard/patterns/create')
336
+ cy.wait(1000)
337
+
338
+ // Wait for editor to load
339
+ cy.get(pom.editorSelectors.container, { timeout: 15000 }).should('be.visible')
340
+
341
+ // Patterns tab should NOT exist (to prevent nesting patterns inside patterns)
342
+ cy.get('[data-cy="block-picker-tab-patterns"]').should('not.exist')
343
+ })
344
+
345
+ it('should only show blocks and config tabs when editing patterns', { tags: '@TC_PAT_006_02' }, () => {
346
+ cy.visit('/dashboard/patterns/create')
347
+ cy.wait(1000)
348
+ cy.get(pom.editorSelectors.container, { timeout: 15000 }).should('be.visible')
349
+
350
+ // Only Blocks and Config tabs should be visible
351
+ cy.get('[data-cy="block-picker-tab-blocks"]').should('exist').and('be.visible')
352
+ cy.get('[data-cy="block-picker-tab-config"]').should('exist').and('be.visible')
353
+ cy.get('[data-cy="block-picker-tab-patterns"]').should('not.exist')
354
+ })
355
+
356
+ it('should show patterns tab when editing pages (control test)', { tags: '@TC_PAT_006_03' }, () => {
357
+ // Visit pages create (should show patterns tab)
358
+ pom.visitCreate()
359
+ pom.waitForEditor()
360
+
361
+ // All three tabs should be visible
362
+ cy.get('[data-cy="block-picker-tab-blocks"]').should('exist').and('be.visible')
363
+ cy.get('[data-cy="block-picker-tab-patterns"]').should('exist').and('be.visible')
364
+ cy.get('[data-cy="block-picker-tab-config"]').should('exist').and('be.visible')
365
+ })
366
+ })
367
+ })
@@ -3,6 +3,15 @@
3
3
  "_warning": "AUTO-GENERATED by build-registry.mjs - DO NOT EDIT MANUALLY",
4
4
  "_theme": "default",
5
5
  "entities": {
6
+ "patterns": {
7
+ "slug": "patterns",
8
+ "singular": "pattern",
9
+ "plural": "Patterns",
10
+ "tableName": "patterns",
11
+ "fields": [],
12
+ "filters": [],
13
+ "source": "core"
14
+ },
6
15
  "customers": {
7
16
  "slug": "customers",
8
17
  "singular": "customer",