@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 +3 -3
- package/tests/cypress/e2e/ui/boards/boards-owner.cy.ts +349 -0
- package/tests/cypress/e2e/ui/cards/cards-modal.cy.ts +369 -0
- package/tests/cypress/e2e/ui/kanban/kanban-cards.cy.ts +280 -0
- package/tests/cypress/e2e/ui/kanban/kanban-columns.cy.ts +243 -0
- package/tests/cypress/fixtures/blocks.json +9 -0
- package/tests/cypress/fixtures/entities.json +60 -0
- package/tests/cypress/src/components/BoardsPOM.ts +353 -0
- package/tests/cypress/src/components/CardsPOM.ts +383 -0
- package/tests/cypress/src/components/KanbanPOM.ts +399 -0
- package/tests/cypress/src/components/index.ts +9 -0
- package/tests/cypress/src/controllers/BoardsAPIController.js +302 -0
- package/tests/cypress/src/controllers/CardsAPIController.js +406 -0
- package/tests/cypress/src/controllers/ListsAPIController.js +299 -0
- package/tests/cypress/src/index.ts +25 -0
- package/tests/cypress/src/selectors.ts +50 -0
- package/tests/cypress/src/session-helpers.ts +105 -0
- package/tests/cypress/support/e2e.ts +89 -0
- package/tests/cypress.config.ts +165 -0
- package/tests/jest/__mocks__/jose.js +22 -0
- package/tests/jest/__mocks__/next-server.js +56 -0
- package/tests/jest/jest.config.cjs +127 -0
- package/tests/jest/setup.ts +170 -0
- package/tests/tsconfig.json +15 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Card Detail Modal - Owner Role Tests
|
|
5
|
+
*
|
|
6
|
+
* Tests for the card detail modal functionality.
|
|
7
|
+
* All selectors follow the pattern: cards-modal-{detail}
|
|
8
|
+
*
|
|
9
|
+
* @see test/cypress/src/classes/themes/productivity/components/CardsPOM.ts
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { CardsPOM } from '../../../src/components/CardsPOM'
|
|
13
|
+
import { KanbanPOM } from '../../../src/components/KanbanPOM'
|
|
14
|
+
import { BoardsPOM } from '../../../src/components/BoardsPOM'
|
|
15
|
+
import { loginAsProductivityOwner } from '../../../src/session-helpers'
|
|
16
|
+
|
|
17
|
+
describe('Card Detail Modal - Owner Role', () => {
|
|
18
|
+
let testBoardId: string
|
|
19
|
+
let testColumnId: string
|
|
20
|
+
|
|
21
|
+
before(() => {
|
|
22
|
+
// Create a board and column for all modal tests
|
|
23
|
+
loginAsProductivityOwner()
|
|
24
|
+
BoardsPOM.visitList()
|
|
25
|
+
BoardsPOM.waitForListLoad()
|
|
26
|
+
|
|
27
|
+
const timestamp = Date.now()
|
|
28
|
+
const boardName = `Modal Test Board ${timestamp}`
|
|
29
|
+
|
|
30
|
+
BoardsPOM.clickCreate()
|
|
31
|
+
BoardsPOM.waitForFormLoad()
|
|
32
|
+
BoardsPOM.fillName(boardName)
|
|
33
|
+
BoardsPOM.submitForm()
|
|
34
|
+
|
|
35
|
+
// Extract board ID from URL
|
|
36
|
+
cy.url().then((url) => {
|
|
37
|
+
const match = url.match(/\/boards\/([a-z0-9_-]+)/)
|
|
38
|
+
if (match) {
|
|
39
|
+
testBoardId = match[1]
|
|
40
|
+
|
|
41
|
+
// Create a test column
|
|
42
|
+
KanbanPOM.waitForBoardLoad()
|
|
43
|
+
KanbanPOM.createColumn(`Modal Test Column ${timestamp}`)
|
|
44
|
+
cy.wait(500)
|
|
45
|
+
|
|
46
|
+
// Get column ID
|
|
47
|
+
cy.get('[data-cy^="lists-column-"]').first().then(($column) => {
|
|
48
|
+
const dataCy = $column.attr('data-cy')
|
|
49
|
+
if (dataCy) {
|
|
50
|
+
testColumnId = dataCy.replace('lists-column-', '')
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
loginAsProductivityOwner()
|
|
59
|
+
cy.then(() => {
|
|
60
|
+
KanbanPOM.visitBoard(testBoardId)
|
|
61
|
+
KanbanPOM.waitForBoardLoad()
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
after(() => {
|
|
66
|
+
// Cleanup: Delete the test board
|
|
67
|
+
loginAsProductivityOwner()
|
|
68
|
+
cy.then(() => {
|
|
69
|
+
if (testBoardId) {
|
|
70
|
+
BoardsPOM.visitEdit(testBoardId)
|
|
71
|
+
BoardsPOM.waitForFormLoad()
|
|
72
|
+
BoardsPOM.confirmDelete()
|
|
73
|
+
BoardsPOM.deleteFromEdit()
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
describe('MODAL - Open and close', () => {
|
|
79
|
+
it('CARDS_MODAL_001: should open modal when clicking card', () => {
|
|
80
|
+
const timestamp = Date.now()
|
|
81
|
+
const cardTitle = `Modal Open Test ${timestamp}`
|
|
82
|
+
|
|
83
|
+
cy.then(() => {
|
|
84
|
+
// Create a card
|
|
85
|
+
KanbanPOM.createCard(testColumnId, cardTitle)
|
|
86
|
+
cy.wait(500)
|
|
87
|
+
|
|
88
|
+
// Click card to open modal
|
|
89
|
+
cy.contains('[data-cy^="cards-item-"]', cardTitle).click()
|
|
90
|
+
|
|
91
|
+
// Modal should be visible
|
|
92
|
+
CardsPOM.validateModalVisible()
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
cy.log('✅ Modal opens on card click')
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('CARDS_MODAL_002: should close modal with cancel button', () => {
|
|
99
|
+
const timestamp = Date.now()
|
|
100
|
+
const cardTitle = `Modal Cancel Test ${timestamp}`
|
|
101
|
+
|
|
102
|
+
cy.then(() => {
|
|
103
|
+
// Create a card
|
|
104
|
+
KanbanPOM.createCard(testColumnId, cardTitle)
|
|
105
|
+
cy.wait(500)
|
|
106
|
+
|
|
107
|
+
// Open modal
|
|
108
|
+
cy.contains('[data-cy^="cards-item-"]', cardTitle).click()
|
|
109
|
+
CardsPOM.waitForModal()
|
|
110
|
+
|
|
111
|
+
// Close with cancel button
|
|
112
|
+
CardsPOM.clickCancel()
|
|
113
|
+
|
|
114
|
+
// Modal should be closed
|
|
115
|
+
CardsPOM.validateModalNotVisible()
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
cy.log('✅ Modal closes with cancel button')
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('CARDS_MODAL_003: should close modal with Escape key (when no changes)', () => {
|
|
122
|
+
const timestamp = Date.now()
|
|
123
|
+
const cardTitle = `Modal Escape Test ${timestamp}`
|
|
124
|
+
|
|
125
|
+
cy.then(() => {
|
|
126
|
+
// Create a card
|
|
127
|
+
KanbanPOM.createCard(testColumnId, cardTitle)
|
|
128
|
+
cy.wait(500)
|
|
129
|
+
|
|
130
|
+
// Open modal
|
|
131
|
+
cy.contains('[data-cy^="cards-item-"]', cardTitle).click()
|
|
132
|
+
CardsPOM.waitForModal()
|
|
133
|
+
|
|
134
|
+
// Close with Escape key
|
|
135
|
+
CardsPOM.closeModalWithEscape()
|
|
136
|
+
|
|
137
|
+
// Modal should be closed
|
|
138
|
+
CardsPOM.validateModalNotVisible()
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
cy.log('✅ Modal closes with Escape key')
|
|
142
|
+
})
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
describe('MODAL - View card details', () => {
|
|
146
|
+
it('CARDS_MODAL_004: should display card title', () => {
|
|
147
|
+
const timestamp = Date.now()
|
|
148
|
+
const cardTitle = `View Title Test ${timestamp}`
|
|
149
|
+
|
|
150
|
+
cy.then(() => {
|
|
151
|
+
// Create a card
|
|
152
|
+
KanbanPOM.createCard(testColumnId, cardTitle)
|
|
153
|
+
cy.wait(500)
|
|
154
|
+
|
|
155
|
+
// Open modal
|
|
156
|
+
cy.contains('[data-cy^="cards-item-"]', cardTitle).click()
|
|
157
|
+
CardsPOM.waitForModal()
|
|
158
|
+
|
|
159
|
+
// Title should match
|
|
160
|
+
CardsPOM.assertTitle(cardTitle)
|
|
161
|
+
|
|
162
|
+
// Close modal
|
|
163
|
+
CardsPOM.clickCancel()
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
cy.log('✅ Modal displays card title correctly')
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('CARDS_MODAL_005: should display all form fields', () => {
|
|
170
|
+
const timestamp = Date.now()
|
|
171
|
+
const cardTitle = `Fields Test ${timestamp}`
|
|
172
|
+
|
|
173
|
+
cy.then(() => {
|
|
174
|
+
// Create a card
|
|
175
|
+
KanbanPOM.createCard(testColumnId, cardTitle)
|
|
176
|
+
cy.wait(500)
|
|
177
|
+
|
|
178
|
+
// Open modal
|
|
179
|
+
cy.contains('[data-cy^="cards-item-"]', cardTitle).click()
|
|
180
|
+
CardsPOM.waitForModal()
|
|
181
|
+
|
|
182
|
+
// Verify all fields are present
|
|
183
|
+
cy.get(CardsPOM.selectors.title).should('be.visible')
|
|
184
|
+
cy.get(CardsPOM.selectors.description).should('be.visible')
|
|
185
|
+
cy.get(CardsPOM.selectors.priority).should('be.visible')
|
|
186
|
+
cy.get(CardsPOM.selectors.dueDate).should('be.visible')
|
|
187
|
+
|
|
188
|
+
// Close modal
|
|
189
|
+
CardsPOM.clickCancel()
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
cy.log('✅ Modal displays all form fields')
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
describe('MODAL - Edit card fields', () => {
|
|
197
|
+
it('CARDS_MODAL_006: should update card title', () => {
|
|
198
|
+
const timestamp = Date.now()
|
|
199
|
+
const originalTitle = `Original ${timestamp}`
|
|
200
|
+
const updatedTitle = `Updated ${timestamp}`
|
|
201
|
+
|
|
202
|
+
cy.then(() => {
|
|
203
|
+
// Create a card
|
|
204
|
+
KanbanPOM.createCard(testColumnId, originalTitle)
|
|
205
|
+
cy.wait(500)
|
|
206
|
+
|
|
207
|
+
// Open modal
|
|
208
|
+
cy.contains('[data-cy^="cards-item-"]', originalTitle).click()
|
|
209
|
+
CardsPOM.waitForModal()
|
|
210
|
+
|
|
211
|
+
// Update title
|
|
212
|
+
CardsPOM.fillTitle(updatedTitle)
|
|
213
|
+
|
|
214
|
+
// Save
|
|
215
|
+
CardsPOM.clickSave()
|
|
216
|
+
|
|
217
|
+
// Wait for save
|
|
218
|
+
cy.wait(500)
|
|
219
|
+
|
|
220
|
+
// Verify update
|
|
221
|
+
cy.contains(updatedTitle).should('be.visible')
|
|
222
|
+
cy.contains(originalTitle).should('not.exist')
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
cy.log('✅ Card title updated successfully')
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
it('CARDS_MODAL_007: should update card description', () => {
|
|
229
|
+
const timestamp = Date.now()
|
|
230
|
+
const cardTitle = `Description Test ${timestamp}`
|
|
231
|
+
const description = `This is a test description ${timestamp}`
|
|
232
|
+
|
|
233
|
+
cy.then(() => {
|
|
234
|
+
// Create a card
|
|
235
|
+
KanbanPOM.createCard(testColumnId, cardTitle)
|
|
236
|
+
cy.wait(500)
|
|
237
|
+
|
|
238
|
+
// Open modal
|
|
239
|
+
cy.contains('[data-cy^="cards-item-"]', cardTitle).click()
|
|
240
|
+
CardsPOM.waitForModal()
|
|
241
|
+
|
|
242
|
+
// Update description
|
|
243
|
+
CardsPOM.fillDescription(description)
|
|
244
|
+
|
|
245
|
+
// Save
|
|
246
|
+
CardsPOM.clickSave()
|
|
247
|
+
|
|
248
|
+
// Wait and reopen to verify
|
|
249
|
+
cy.wait(500)
|
|
250
|
+
cy.contains('[data-cy^="cards-item-"]', cardTitle).click()
|
|
251
|
+
CardsPOM.waitForModal()
|
|
252
|
+
|
|
253
|
+
// Verify description
|
|
254
|
+
CardsPOM.assertDescription(description)
|
|
255
|
+
|
|
256
|
+
CardsPOM.clickCancel()
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
cy.log('✅ Card description updated successfully')
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it('CARDS_MODAL_008: should update card priority', () => {
|
|
263
|
+
const timestamp = Date.now()
|
|
264
|
+
const cardTitle = `Priority Test ${timestamp}`
|
|
265
|
+
|
|
266
|
+
cy.then(() => {
|
|
267
|
+
// Create a card
|
|
268
|
+
KanbanPOM.createCard(testColumnId, cardTitle)
|
|
269
|
+
cy.wait(500)
|
|
270
|
+
|
|
271
|
+
// Open modal
|
|
272
|
+
cy.contains('[data-cy^="cards-item-"]', cardTitle).click()
|
|
273
|
+
CardsPOM.waitForModal()
|
|
274
|
+
|
|
275
|
+
// Select priority
|
|
276
|
+
CardsPOM.selectPriority('high')
|
|
277
|
+
|
|
278
|
+
// Save
|
|
279
|
+
CardsPOM.clickSave()
|
|
280
|
+
|
|
281
|
+
// Wait and verify
|
|
282
|
+
cy.wait(500)
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
cy.log('✅ Card priority updated successfully')
|
|
286
|
+
})
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
describe('MODAL - Delete card', () => {
|
|
290
|
+
it('CARDS_MODAL_009: should delete card from modal', () => {
|
|
291
|
+
const timestamp = Date.now()
|
|
292
|
+
const cardTitle = `Delete Modal Test ${timestamp}`
|
|
293
|
+
|
|
294
|
+
cy.then(() => {
|
|
295
|
+
// Create a card
|
|
296
|
+
KanbanPOM.createCard(testColumnId, cardTitle)
|
|
297
|
+
cy.wait(500)
|
|
298
|
+
|
|
299
|
+
// Open modal
|
|
300
|
+
cy.contains('[data-cy^="cards-item-"]', cardTitle).click()
|
|
301
|
+
CardsPOM.waitForModal()
|
|
302
|
+
|
|
303
|
+
// Set up confirmation handler
|
|
304
|
+
cy.on('window:confirm', () => true)
|
|
305
|
+
|
|
306
|
+
// Delete
|
|
307
|
+
CardsPOM.clickDelete()
|
|
308
|
+
|
|
309
|
+
// Wait for deletion
|
|
310
|
+
cy.wait(500)
|
|
311
|
+
|
|
312
|
+
// Verify deletion
|
|
313
|
+
cy.contains(cardTitle).should('not.exist')
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
cy.log('✅ Card deleted from modal successfully')
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
it('CARDS_MODAL_010: should show delete button for owner', () => {
|
|
320
|
+
const timestamp = Date.now()
|
|
321
|
+
const cardTitle = `Delete Button Test ${timestamp}`
|
|
322
|
+
|
|
323
|
+
cy.then(() => {
|
|
324
|
+
// Create a card
|
|
325
|
+
KanbanPOM.createCard(testColumnId, cardTitle)
|
|
326
|
+
cy.wait(500)
|
|
327
|
+
|
|
328
|
+
// Open modal
|
|
329
|
+
cy.contains('[data-cy^="cards-item-"]', cardTitle).click()
|
|
330
|
+
CardsPOM.waitForModal()
|
|
331
|
+
|
|
332
|
+
// Delete button should be visible for owner
|
|
333
|
+
CardsPOM.assertDeleteVisible()
|
|
334
|
+
|
|
335
|
+
CardsPOM.clickCancel()
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
cy.log('✅ Delete button visible for owner')
|
|
339
|
+
})
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
describe('MODAL - Unsaved changes', () => {
|
|
343
|
+
it('CARDS_MODAL_011: should show unsaved changes indicator', () => {
|
|
344
|
+
const timestamp = Date.now()
|
|
345
|
+
const cardTitle = `Unsaved Test ${timestamp}`
|
|
346
|
+
|
|
347
|
+
cy.then(() => {
|
|
348
|
+
// Create a card
|
|
349
|
+
KanbanPOM.createCard(testColumnId, cardTitle)
|
|
350
|
+
cy.wait(500)
|
|
351
|
+
|
|
352
|
+
// Open modal
|
|
353
|
+
cy.contains('[data-cy^="cards-item-"]', cardTitle).click()
|
|
354
|
+
CardsPOM.waitForModal()
|
|
355
|
+
|
|
356
|
+
// Make a change
|
|
357
|
+
CardsPOM.fillTitle(`${cardTitle} Modified`)
|
|
358
|
+
|
|
359
|
+
// Should show unsaved changes indicator
|
|
360
|
+
CardsPOM.assertUnsavedChanges()
|
|
361
|
+
|
|
362
|
+
// Cancel without saving
|
|
363
|
+
CardsPOM.clickCancel()
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
cy.log('✅ Unsaved changes indicator works')
|
|
367
|
+
})
|
|
368
|
+
})
|
|
369
|
+
})
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Kanban Cards - Owner Role Tests
|
|
5
|
+
*
|
|
6
|
+
* Tests for managing cards within Kanban columns.
|
|
7
|
+
* All selectors follow the pattern: cards-{component}-{detail}
|
|
8
|
+
*
|
|
9
|
+
* @see test/cypress/src/classes/themes/productivity/components/KanbanPOM.ts
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { KanbanPOM } from '../../../src/components/KanbanPOM'
|
|
13
|
+
import { BoardsPOM } from '../../../src/components/BoardsPOM'
|
|
14
|
+
import { loginAsProductivityOwner } from '../../../src/session-helpers'
|
|
15
|
+
|
|
16
|
+
describe('Kanban Cards - Owner Role', () => {
|
|
17
|
+
let testBoardId: string
|
|
18
|
+
let testColumnId: string
|
|
19
|
+
|
|
20
|
+
before(() => {
|
|
21
|
+
// Create a board and column for all card tests
|
|
22
|
+
loginAsProductivityOwner()
|
|
23
|
+
BoardsPOM.visitList()
|
|
24
|
+
BoardsPOM.waitForListLoad()
|
|
25
|
+
|
|
26
|
+
const timestamp = Date.now()
|
|
27
|
+
const boardName = `Cards Test Board ${timestamp}`
|
|
28
|
+
|
|
29
|
+
BoardsPOM.clickCreate()
|
|
30
|
+
BoardsPOM.waitForFormLoad()
|
|
31
|
+
BoardsPOM.fillName(boardName)
|
|
32
|
+
BoardsPOM.submitForm()
|
|
33
|
+
|
|
34
|
+
// Extract board ID from URL
|
|
35
|
+
cy.url().then((url) => {
|
|
36
|
+
const match = url.match(/\/boards\/([a-z0-9_-]+)/)
|
|
37
|
+
if (match) {
|
|
38
|
+
testBoardId = match[1]
|
|
39
|
+
|
|
40
|
+
// Create a test column
|
|
41
|
+
KanbanPOM.waitForBoardLoad()
|
|
42
|
+
KanbanPOM.createColumn(`Test Column ${timestamp}`)
|
|
43
|
+
cy.wait(500)
|
|
44
|
+
|
|
45
|
+
// Get column ID
|
|
46
|
+
cy.get('[data-cy^="lists-column-"]').first().then(($column) => {
|
|
47
|
+
const dataCy = $column.attr('data-cy')
|
|
48
|
+
if (dataCy) {
|
|
49
|
+
testColumnId = dataCy.replace('lists-column-', '')
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
beforeEach(() => {
|
|
57
|
+
loginAsProductivityOwner()
|
|
58
|
+
cy.then(() => {
|
|
59
|
+
KanbanPOM.visitBoard(testBoardId)
|
|
60
|
+
KanbanPOM.waitForBoardLoad()
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
after(() => {
|
|
65
|
+
// Cleanup: Delete the test board
|
|
66
|
+
loginAsProductivityOwner()
|
|
67
|
+
cy.then(() => {
|
|
68
|
+
if (testBoardId) {
|
|
69
|
+
BoardsPOM.visitEdit(testBoardId)
|
|
70
|
+
BoardsPOM.waitForFormLoad()
|
|
71
|
+
BoardsPOM.confirmDelete()
|
|
72
|
+
BoardsPOM.deleteFromEdit()
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
describe('CREATE - Add new cards', () => {
|
|
78
|
+
it('KANBAN_CARDS_CREATE_001: should add a new card to column', () => {
|
|
79
|
+
const timestamp = Date.now()
|
|
80
|
+
const cardTitle = `New Card ${timestamp}`
|
|
81
|
+
|
|
82
|
+
cy.then(() => {
|
|
83
|
+
// Click add card button in the column
|
|
84
|
+
KanbanPOM.clickAddCard(testColumnId)
|
|
85
|
+
|
|
86
|
+
// Fill card title
|
|
87
|
+
KanbanPOM.fillCardTitle(testColumnId, cardTitle)
|
|
88
|
+
|
|
89
|
+
// Submit
|
|
90
|
+
KanbanPOM.submitAddCard(testColumnId)
|
|
91
|
+
|
|
92
|
+
// Wait for card creation
|
|
93
|
+
cy.wait(500)
|
|
94
|
+
|
|
95
|
+
// Verify card was created
|
|
96
|
+
cy.contains(cardTitle).should('be.visible')
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
cy.log('✅ Created new card successfully')
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('KANBAN_CARDS_CREATE_002: should create multiple cards in a column', () => {
|
|
103
|
+
const timestamp = Date.now()
|
|
104
|
+
const cards = ['Task 1', 'Task 2', 'Task 3'].map((name) => `${name} ${timestamp}`)
|
|
105
|
+
|
|
106
|
+
cy.then(() => {
|
|
107
|
+
// Create each card
|
|
108
|
+
cards.forEach((cardTitle) => {
|
|
109
|
+
KanbanPOM.clickAddCard(testColumnId)
|
|
110
|
+
KanbanPOM.fillCardTitle(testColumnId, cardTitle)
|
|
111
|
+
KanbanPOM.submitAddCard(testColumnId)
|
|
112
|
+
cy.wait(500)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
// Verify all cards exist
|
|
116
|
+
cards.forEach((cardTitle) => {
|
|
117
|
+
cy.contains(cardTitle).should('be.visible')
|
|
118
|
+
})
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
cy.log('✅ Created multiple cards successfully')
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('KANBAN_CARDS_CREATE_003: should cancel card creation with Escape', () => {
|
|
125
|
+
const timestamp = Date.now()
|
|
126
|
+
const cardTitle = `Cancelled Card ${timestamp}`
|
|
127
|
+
|
|
128
|
+
cy.then(() => {
|
|
129
|
+
// Click add card button
|
|
130
|
+
KanbanPOM.clickAddCard(testColumnId)
|
|
131
|
+
|
|
132
|
+
// Fill card title
|
|
133
|
+
KanbanPOM.fillCardTitle(testColumnId, cardTitle)
|
|
134
|
+
|
|
135
|
+
// Press Escape to cancel
|
|
136
|
+
cy.get(KanbanPOM.selectors.cardFieldTitle(testColumnId)).type('{esc}')
|
|
137
|
+
|
|
138
|
+
// Wait a moment
|
|
139
|
+
cy.wait(500)
|
|
140
|
+
|
|
141
|
+
// Card should not exist
|
|
142
|
+
cy.contains(cardTitle).should('not.exist')
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
cy.log('✅ Card creation cancelled successfully')
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
it('KANBAN_CARDS_CREATE_004: should create card with Enter key', () => {
|
|
149
|
+
const timestamp = Date.now()
|
|
150
|
+
const cardTitle = `Enter Card ${timestamp}`
|
|
151
|
+
|
|
152
|
+
cy.then(() => {
|
|
153
|
+
// Click add card button
|
|
154
|
+
KanbanPOM.clickAddCard(testColumnId)
|
|
155
|
+
|
|
156
|
+
// Fill card title and press Enter
|
|
157
|
+
cy.get(KanbanPOM.selectors.cardFieldTitle(testColumnId)).type(`${cardTitle}{enter}`)
|
|
158
|
+
|
|
159
|
+
// Wait for card creation
|
|
160
|
+
cy.wait(500)
|
|
161
|
+
|
|
162
|
+
// Verify card was created
|
|
163
|
+
cy.contains(cardTitle).should('be.visible')
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
cy.log('✅ Created card with Enter key successfully')
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
describe('READ - View cards', () => {
|
|
171
|
+
it('KANBAN_CARDS_READ_001: should display cards in column', () => {
|
|
172
|
+
// Create a test card first
|
|
173
|
+
const timestamp = Date.now()
|
|
174
|
+
const cardTitle = `Read Test Card ${timestamp}`
|
|
175
|
+
|
|
176
|
+
cy.then(() => {
|
|
177
|
+
KanbanPOM.createCard(testColumnId, cardTitle)
|
|
178
|
+
cy.wait(500)
|
|
179
|
+
|
|
180
|
+
// Verify card is visible
|
|
181
|
+
cy.contains(cardTitle).should('be.visible')
|
|
182
|
+
|
|
183
|
+
// Verify card has proper data-cy attribute
|
|
184
|
+
cy.get('[data-cy^="cards-item-"]').should('have.length.at.least', 1)
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
cy.log('✅ Cards display correctly in column')
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
it('KANBAN_CARDS_READ_002: should click card to open modal', () => {
|
|
191
|
+
// Create a test card first
|
|
192
|
+
const timestamp = Date.now()
|
|
193
|
+
const cardTitle = `Click Test Card ${timestamp}`
|
|
194
|
+
|
|
195
|
+
cy.then(() => {
|
|
196
|
+
KanbanPOM.createCard(testColumnId, cardTitle)
|
|
197
|
+
cy.wait(500)
|
|
198
|
+
|
|
199
|
+
// Get the card and click it
|
|
200
|
+
cy.contains('[data-cy^="cards-item-"]', cardTitle).click()
|
|
201
|
+
|
|
202
|
+
// Modal should open
|
|
203
|
+
cy.get('[data-cy="cards-modal"]').should('be.visible')
|
|
204
|
+
|
|
205
|
+
// Close modal
|
|
206
|
+
cy.get('[data-cy="cards-modal-cancel"]').click()
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
cy.log('✅ Card click opens modal')
|
|
210
|
+
})
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
describe('UPDATE - Modify cards via modal', () => {
|
|
214
|
+
it('KANBAN_CARDS_UPDATE_001: should update card title', () => {
|
|
215
|
+
const timestamp = Date.now()
|
|
216
|
+
const originalTitle = `Original Title ${timestamp}`
|
|
217
|
+
const updatedTitle = `Updated Title ${timestamp}`
|
|
218
|
+
|
|
219
|
+
cy.then(() => {
|
|
220
|
+
// Create a card
|
|
221
|
+
KanbanPOM.createCard(testColumnId, originalTitle)
|
|
222
|
+
cy.wait(500)
|
|
223
|
+
|
|
224
|
+
// Click card to open modal
|
|
225
|
+
cy.contains('[data-cy^="cards-item-"]', originalTitle).click()
|
|
226
|
+
|
|
227
|
+
// Wait for modal
|
|
228
|
+
cy.get('[data-cy="cards-modal"]').should('be.visible')
|
|
229
|
+
|
|
230
|
+
// Update title
|
|
231
|
+
cy.get('[data-cy="cards-modal-title"]').clear().type(updatedTitle)
|
|
232
|
+
|
|
233
|
+
// Save
|
|
234
|
+
cy.get('[data-cy="cards-modal-save"]').click()
|
|
235
|
+
|
|
236
|
+
// Wait for save
|
|
237
|
+
cy.wait(500)
|
|
238
|
+
|
|
239
|
+
// Verify title updated
|
|
240
|
+
cy.contains(updatedTitle).should('be.visible')
|
|
241
|
+
cy.contains(originalTitle).should('not.exist')
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
cy.log('✅ Card title updated successfully')
|
|
245
|
+
})
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
describe('DELETE - Remove cards', () => {
|
|
249
|
+
it('KANBAN_CARDS_DELETE_001: should delete card from modal', () => {
|
|
250
|
+
const timestamp = Date.now()
|
|
251
|
+
const cardTitle = `Delete Test Card ${timestamp}`
|
|
252
|
+
|
|
253
|
+
cy.then(() => {
|
|
254
|
+
// Create a card
|
|
255
|
+
KanbanPOM.createCard(testColumnId, cardTitle)
|
|
256
|
+
cy.wait(500)
|
|
257
|
+
|
|
258
|
+
// Click card to open modal
|
|
259
|
+
cy.contains('[data-cy^="cards-item-"]', cardTitle).click()
|
|
260
|
+
|
|
261
|
+
// Wait for modal
|
|
262
|
+
cy.get('[data-cy="cards-modal"]').should('be.visible')
|
|
263
|
+
|
|
264
|
+
// Set up confirmation handler
|
|
265
|
+
cy.on('window:confirm', () => true)
|
|
266
|
+
|
|
267
|
+
// Click delete
|
|
268
|
+
cy.get('[data-cy="cards-modal-delete"]').click()
|
|
269
|
+
|
|
270
|
+
// Wait for deletion
|
|
271
|
+
cy.wait(500)
|
|
272
|
+
|
|
273
|
+
// Verify card is gone
|
|
274
|
+
cy.contains(cardTitle).should('not.exist')
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
cy.log('✅ Card deleted successfully')
|
|
278
|
+
})
|
|
279
|
+
})
|
|
280
|
+
})
|