@nextsparkjs/theme-productivity 0.1.0-beta.19 → 0.1.0-beta.24

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 CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@nextsparkjs/theme-productivity",
3
- "version": "0.1.0-beta.19",
3
+ "version": "0.1.0-beta.24",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./config/theme.config.ts",
7
7
  "requiredPlugins": [],
8
8
  "dependencies": {},
9
9
  "peerDependencies": {
10
+ "@nextsparkjs/core": "0.1.0-beta.24",
10
11
  "lucide-react": "^0.539.0",
11
12
  "next": "^15.0.0",
12
13
  "react": "^19.0.0",
13
14
  "react-dom": "^19.0.0",
14
- "zod": "^4.0.0",
15
- "@nextsparkjs/core": "0.1.0-beta.19"
15
+ "zod": "^4.0.0"
16
16
  },
17
17
  "nextspark": {
18
18
  "type": "theme",
@@ -0,0 +1,349 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /**
4
+ * Boards CRUD - Owner Role (Full Access)
5
+ *
6
+ * Tests for the productivity theme boards using the Entity Testing Convention.
7
+ * All selectors follow the pattern: {slug}-{component}-{detail}
8
+ *
9
+ * @see test/cypress/src/classes/themes/productivity/components/BoardsPOM.ts
10
+ */
11
+
12
+ import { BoardsPOM } from '../../../src/components/BoardsPOM'
13
+ import { loginAsProductivityOwner } from '../../../src/session-helpers'
14
+
15
+ describe('Boards CRUD - Owner Role (Full Access)', () => {
16
+ beforeEach(() => {
17
+ loginAsProductivityOwner()
18
+ BoardsPOM.visitList()
19
+ BoardsPOM.waitForListLoad()
20
+ })
21
+
22
+ describe('CREATE - Owner can create boards', () => {
23
+ it('OWNER_BOARDS_CREATE_001: should create new board with required fields', () => {
24
+ const timestamp = Date.now()
25
+ const name = `Test Board ${timestamp}`
26
+ const description = `Test description for board ${timestamp}`
27
+
28
+ // Click create button
29
+ BoardsPOM.clickCreate()
30
+
31
+ // Validate form is visible
32
+ BoardsPOM.waitForFormLoad()
33
+ BoardsPOM.validateFormVisible()
34
+
35
+ // Fill required board fields
36
+ BoardsPOM.fillBoardForm({
37
+ name,
38
+ description,
39
+ })
40
+
41
+ // Submit form
42
+ BoardsPOM.submitForm()
43
+
44
+ // Should redirect to the new board's kanban view
45
+ cy.url().should('match', /\/dashboard\/boards\/[a-z0-9_-]+$/)
46
+
47
+ cy.log('✅ Owner created board successfully')
48
+ })
49
+
50
+ it('OWNER_BOARDS_CREATE_002: should create board with color', () => {
51
+ const timestamp = Date.now()
52
+ const name = `Colored Board ${timestamp}`
53
+
54
+ // Click create button
55
+ BoardsPOM.clickCreate()
56
+ BoardsPOM.waitForFormLoad()
57
+
58
+ // Fill fields with color selection
59
+ BoardsPOM.fillBoardForm({
60
+ name,
61
+ color: 'purple',
62
+ })
63
+
64
+ // Submit form
65
+ BoardsPOM.submitForm()
66
+
67
+ // Should redirect to board
68
+ cy.url().should('match', /\/dashboard\/boards\/[a-z0-9_-]+$/)
69
+
70
+ cy.log('✅ Owner created board with color successfully')
71
+ })
72
+
73
+ it('OWNER_BOARDS_CREATE_003: should validate required fields', () => {
74
+ // Click create button
75
+ BoardsPOM.clickCreate()
76
+ BoardsPOM.waitForFormLoad()
77
+
78
+ // Try to submit without filling required fields
79
+ BoardsPOM.submitForm()
80
+
81
+ // Form should still be visible (validation failed)
82
+ BoardsPOM.validateFormVisible()
83
+
84
+ cy.log('✅ Form validation working correctly')
85
+ })
86
+
87
+ it('OWNER_BOARDS_CREATE_004: should cancel board creation', () => {
88
+ const timestamp = Date.now()
89
+ const name = `Cancelled Board ${timestamp}`
90
+
91
+ // Click create button
92
+ BoardsPOM.clickCreate()
93
+ BoardsPOM.waitForFormLoad()
94
+
95
+ // Fill some fields
96
+ BoardsPOM.fillName(name)
97
+
98
+ // Cancel form
99
+ BoardsPOM.cancelForm()
100
+
101
+ // Should return to list
102
+ BoardsPOM.assertOnListPage()
103
+
104
+ // Board should not exist
105
+ BoardsPOM.assertBoardNotInList(name)
106
+
107
+ cy.log('✅ Board creation cancelled successfully')
108
+ })
109
+ })
110
+
111
+ describe('READ - Owner can view boards', () => {
112
+ it('OWNER_BOARDS_READ_001: should view boards list page', () => {
113
+ // Validate list page is visible
114
+ BoardsPOM.validateListPageVisible()
115
+
116
+ cy.log('✅ Owner can view boards list')
117
+ })
118
+
119
+ it('OWNER_BOARDS_READ_002: should see create button', () => {
120
+ // Create button should be visible for owner
121
+ cy.get(BoardsPOM.selectors.createBtn).should('be.visible')
122
+
123
+ cy.log('✅ Create button is visible for owner')
124
+ })
125
+
126
+ it('OWNER_BOARDS_READ_003: should click on board to open it', () => {
127
+ // Check if there are boards
128
+ cy.get('body').then(($body) => {
129
+ const boardCards = $body.find('[data-cy^="boards-card-"]')
130
+ if (boardCards.length > 0) {
131
+ // Click on first board card
132
+ cy.get('[data-cy^="boards-card-"]').first().find('a').first().click()
133
+
134
+ // Should navigate to board view
135
+ cy.url().should('match', /\/dashboard\/boards\/[a-z0-9_-]+$/)
136
+
137
+ cy.log('✅ Owner can open board')
138
+ } else {
139
+ cy.log('⚠️ No boards available to click')
140
+ }
141
+ })
142
+ })
143
+ })
144
+
145
+ describe('UPDATE - Owner can update boards', () => {
146
+ let testBoardId: string
147
+
148
+ beforeEach(() => {
149
+ // Create a board for update tests
150
+ const timestamp = Date.now()
151
+ const name = `Update Test ${timestamp}`
152
+
153
+ BoardsPOM.clickCreate()
154
+ BoardsPOM.waitForFormLoad()
155
+ BoardsPOM.fillName(name)
156
+ BoardsPOM.submitForm()
157
+
158
+ // Get board ID from URL
159
+ cy.url().then((url) => {
160
+ const match = url.match(/\/boards\/([a-z0-9_-]+)/)
161
+ if (match) {
162
+ testBoardId = match[1]
163
+ }
164
+ })
165
+ })
166
+
167
+ it('OWNER_BOARDS_UPDATE_001: should edit board name', () => {
168
+ const updatedName = `Updated Board ${Date.now()}`
169
+
170
+ // Visit edit page
171
+ cy.url().then((url) => {
172
+ const match = url.match(/\/boards\/([a-z0-9_-]+)/)
173
+ if (match) {
174
+ const boardId = match[1]
175
+ BoardsPOM.visitEdit(boardId)
176
+ BoardsPOM.waitForFormLoad()
177
+
178
+ // Update name
179
+ BoardsPOM.fillName(updatedName)
180
+
181
+ // Submit form
182
+ BoardsPOM.submitForm()
183
+
184
+ // Should redirect to board
185
+ cy.url().should('include', `/dashboard/boards/${boardId}`)
186
+
187
+ cy.log('✅ Owner updated board name successfully')
188
+ }
189
+ })
190
+ })
191
+
192
+ it('OWNER_BOARDS_UPDATE_002: should update board description', () => {
193
+ const updatedDescription = `Updated description ${Date.now()}`
194
+
195
+ cy.url().then((url) => {
196
+ const match = url.match(/\/boards\/([a-z0-9_-]+)/)
197
+ if (match) {
198
+ const boardId = match[1]
199
+ BoardsPOM.visitEdit(boardId)
200
+ BoardsPOM.waitForFormLoad()
201
+
202
+ // Update description
203
+ BoardsPOM.fillDescription(updatedDescription)
204
+
205
+ // Submit form
206
+ BoardsPOM.submitForm()
207
+
208
+ // Should redirect to board
209
+ cy.url().should('include', `/dashboard/boards/${boardId}`)
210
+
211
+ cy.log('✅ Owner updated board description successfully')
212
+ }
213
+ })
214
+ })
215
+ })
216
+
217
+ describe('DELETE - Owner can delete boards', () => {
218
+ it('OWNER_BOARDS_DELETE_001: should delete board from edit page', () => {
219
+ // Create a board to delete
220
+ const timestamp = Date.now()
221
+ const name = `Delete Test ${timestamp}`
222
+
223
+ BoardsPOM.clickCreate()
224
+ BoardsPOM.waitForFormLoad()
225
+ BoardsPOM.fillName(name)
226
+ BoardsPOM.submitForm()
227
+
228
+ // Get board ID and go to edit page
229
+ cy.url().then((url) => {
230
+ const match = url.match(/\/boards\/([a-z0-9_-]+)/)
231
+ if (match) {
232
+ const boardId = match[1]
233
+ BoardsPOM.visitEdit(boardId)
234
+ BoardsPOM.waitForFormLoad()
235
+
236
+ // Confirm deletion
237
+ BoardsPOM.confirmDelete()
238
+
239
+ // Click delete button
240
+ BoardsPOM.deleteFromEdit()
241
+
242
+ // Should redirect to list
243
+ BoardsPOM.waitForListLoad()
244
+ BoardsPOM.assertOnListPage()
245
+
246
+ // Board should not exist
247
+ BoardsPOM.assertBoardNotInList(name)
248
+
249
+ cy.log('✅ Owner deleted board successfully')
250
+ }
251
+ })
252
+ })
253
+
254
+ it('OWNER_BOARDS_DELETE_002: should delete board from list page menu', () => {
255
+ // Create a board to delete
256
+ const timestamp = Date.now()
257
+ const name = `Delete Menu Test ${timestamp}`
258
+
259
+ BoardsPOM.clickCreate()
260
+ BoardsPOM.waitForFormLoad()
261
+ BoardsPOM.fillName(name)
262
+ BoardsPOM.submitForm()
263
+
264
+ // Go back to list
265
+ BoardsPOM.visitList()
266
+ BoardsPOM.waitForListLoad()
267
+
268
+ // Find the board and open its menu
269
+ cy.get('body').then(($body) => {
270
+ // Find the board card containing our name
271
+ cy.contains('[data-cy^="boards-card-"]', name).then(($card) => {
272
+ // Extract ID from data-cy attribute
273
+ const dataCy = $card.attr('data-cy')
274
+ if (dataCy) {
275
+ const boardId = dataCy.replace('boards-card-', '')
276
+
277
+ // Confirm deletion
278
+ BoardsPOM.confirmDelete()
279
+
280
+ // Click delete from menu
281
+ BoardsPOM.clickCardDelete(boardId)
282
+
283
+ // Board should no longer exist
284
+ cy.contains('[data-cy^="boards-card-"]', name).should('not.exist')
285
+
286
+ cy.log('✅ Owner deleted board from list menu')
287
+ }
288
+ })
289
+ })
290
+ })
291
+ })
292
+
293
+ describe('INTEGRATION - Complete board lifecycle', () => {
294
+ it('OWNER_BOARDS_LIFECYCLE_001: should perform full CRUD lifecycle', () => {
295
+ const timestamp = Date.now()
296
+ const name = `Lifecycle Board ${timestamp}`
297
+ const description = `Lifecycle test description ${timestamp}`
298
+ const updatedName = `Updated Lifecycle ${timestamp}`
299
+
300
+ // CREATE
301
+ cy.log('🔄 Step 1: Create board')
302
+ BoardsPOM.clickCreate()
303
+ BoardsPOM.waitForFormLoad()
304
+ BoardsPOM.fillBoardForm({ name, description })
305
+ BoardsPOM.submitForm()
306
+
307
+ // Get board ID
308
+ cy.url().then((url) => {
309
+ const match = url.match(/\/boards\/([a-z0-9_-]+)/)
310
+ expect(match).to.not.be.null
311
+
312
+ if (match) {
313
+ const boardId = match[1]
314
+
315
+ // READ
316
+ cy.log('🔄 Step 2: Verify board was created')
317
+ BoardsPOM.visitList()
318
+ BoardsPOM.waitForListLoad()
319
+ BoardsPOM.assertBoardInList(name)
320
+
321
+ // UPDATE
322
+ cy.log('🔄 Step 3: Update board')
323
+ BoardsPOM.visitEdit(boardId)
324
+ BoardsPOM.waitForFormLoad()
325
+ BoardsPOM.fillName(updatedName)
326
+ BoardsPOM.submitForm()
327
+
328
+ // Verify update
329
+ BoardsPOM.visitList()
330
+ BoardsPOM.waitForListLoad()
331
+ BoardsPOM.assertBoardInList(updatedName)
332
+
333
+ // DELETE
334
+ cy.log('🔄 Step 4: Delete board')
335
+ BoardsPOM.visitEdit(boardId)
336
+ BoardsPOM.waitForFormLoad()
337
+ BoardsPOM.confirmDelete()
338
+ BoardsPOM.deleteFromEdit()
339
+
340
+ // Verify deletion
341
+ BoardsPOM.waitForListLoad()
342
+ BoardsPOM.assertBoardNotInList(updatedName)
343
+
344
+ cy.log('✅ Full board lifecycle completed successfully')
345
+ }
346
+ })
347
+ })
348
+ })
349
+ })