@nextsparkjs/theme-crm 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/api/activities/activities-crud.cy.ts +686 -0
- package/tests/cypress/e2e/api/campaigns/campaigns-crud.cy.ts +592 -0
- package/tests/cypress/e2e/api/companies/companies-crud.cy.ts +682 -0
- package/tests/cypress/e2e/api/contacts/contacts-crud.cy.ts +668 -0
- package/tests/cypress/e2e/api/leads/leads-crud.cy.ts +648 -0
- package/tests/cypress/e2e/api/notes/notes-crud.cy.ts +424 -0
- package/tests/cypress/e2e/api/opportunities/opportunities-crud.cy.ts +865 -0
- package/tests/cypress/e2e/api/pipelines/pipelines-crud.cy.ts +545 -0
- package/tests/cypress/e2e/api/products/products-crud.cy.ts +447 -0
- package/tests/cypress/e2e/ui/activities/activities-admin.cy.ts +268 -0
- package/tests/cypress/e2e/ui/activities/activities-member.cy.ts +257 -0
- package/tests/cypress/e2e/ui/activities/activities-owner.cy.ts +268 -0
- package/tests/cypress/e2e/ui/companies/companies-admin.cy.ts +188 -0
- package/tests/cypress/e2e/ui/companies/companies-member.cy.ts +166 -0
- package/tests/cypress/e2e/ui/companies/companies-owner.cy.ts +189 -0
- package/tests/cypress/e2e/ui/contacts/contacts-admin.cy.ts +252 -0
- package/tests/cypress/e2e/ui/contacts/contacts-member.cy.ts +224 -0
- package/tests/cypress/e2e/ui/contacts/contacts-owner.cy.ts +236 -0
- package/tests/cypress/e2e/ui/leads/leads-admin.cy.ts +286 -0
- package/tests/cypress/e2e/ui/leads/leads-member.cy.ts +193 -0
- package/tests/cypress/e2e/ui/leads/leads-owner.cy.ts +210 -0
- package/tests/cypress/e2e/ui/opportunities/opportunities-admin.cy.ts +197 -0
- package/tests/cypress/e2e/ui/opportunities/opportunities-member.cy.ts +229 -0
- package/tests/cypress/e2e/ui/opportunities/opportunities-owner.cy.ts +196 -0
- package/tests/cypress/e2e/ui/pipelines/pipelines-admin.cy.ts +320 -0
- package/tests/cypress/e2e/ui/pipelines/pipelines-member.cy.ts +262 -0
- package/tests/cypress/e2e/ui/pipelines/pipelines-owner.cy.ts +282 -0
- package/tests/cypress/fixtures/blocks.json +9 -0
- package/tests/cypress/fixtures/entities.json +240 -0
- package/tests/cypress/src/components/CRMDataTable.js +223 -0
- package/tests/cypress/src/components/CRMMobileNav.js +138 -0
- package/tests/cypress/src/components/CRMSidebar.js +145 -0
- package/tests/cypress/src/components/CRMTopBar.js +194 -0
- package/tests/cypress/src/components/DealCard.js +197 -0
- package/tests/cypress/src/components/EntityDetail.ts +290 -0
- package/tests/cypress/src/components/EntityForm.ts +357 -0
- package/tests/cypress/src/components/EntityList.ts +360 -0
- package/tests/cypress/src/components/PipelineKanban.js +204 -0
- package/tests/cypress/src/components/StageColumn.js +196 -0
- package/tests/cypress/src/components/index.js +13 -0
- package/tests/cypress/src/components/index.ts +22 -0
- package/tests/cypress/src/controllers/ActivityAPIController.ts +113 -0
- package/tests/cypress/src/controllers/BaseAPIController.ts +307 -0
- package/tests/cypress/src/controllers/CampaignAPIController.ts +114 -0
- package/tests/cypress/src/controllers/CompanyAPIController.ts +112 -0
- package/tests/cypress/src/controllers/ContactAPIController.ts +104 -0
- package/tests/cypress/src/controllers/LeadAPIController.ts +96 -0
- package/tests/cypress/src/controllers/NoteAPIController.ts +130 -0
- package/tests/cypress/src/controllers/OpportunityAPIController.ts +134 -0
- package/tests/cypress/src/controllers/PipelineAPIController.ts +116 -0
- package/tests/cypress/src/controllers/ProductAPIController.ts +113 -0
- package/tests/cypress/src/controllers/index.ts +35 -0
- package/tests/cypress/src/entities/ActivitiesPOM.ts +130 -0
- package/tests/cypress/src/entities/CompaniesPOM.ts +117 -0
- package/tests/cypress/src/entities/ContactsPOM.ts +117 -0
- package/tests/cypress/src/entities/LeadsPOM.ts +129 -0
- package/tests/cypress/src/entities/OpportunitiesPOM.ts +178 -0
- package/tests/cypress/src/entities/PipelinesPOM.ts +341 -0
- package/tests/cypress/src/entities/index.ts +31 -0
- package/tests/cypress/src/forms/OpportunityForm.js +316 -0
- package/tests/cypress/src/forms/PipelineForm.js +243 -0
- package/tests/cypress/src/forms/index.js +8 -0
- package/tests/cypress/src/index.js +22 -0
- package/tests/cypress/src/index.ts +68 -0
- package/tests/cypress/src/selectors.ts +50 -0
- package/tests/cypress/src/session-helpers.ts +94 -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,262 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pipelines - Member Role (Read Only Access)
|
|
5
|
+
*
|
|
6
|
+
* Uses CRM theme-specific POMs with Entity Testing Convention.
|
|
7
|
+
* Selectors follow the pattern: {slug}-{component}-{detail}
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { PipelinesPOM } from '../../../src/entities/PipelinesPOM'
|
|
11
|
+
import { loginAsCrmMember } from '../../../src/session-helpers'
|
|
12
|
+
|
|
13
|
+
describe('Pipelines - Member Role (Read Only Access)', () => {
|
|
14
|
+
const pipelines = new PipelinesPOM()
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
loginAsCrmMember()
|
|
18
|
+
cy.visit('/dashboard/pipelines')
|
|
19
|
+
pipelines.list.validatePageVisible()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// ==================== READ ONLY ====================
|
|
23
|
+
describe('READ Pipeline (Allowed)', () => {
|
|
24
|
+
it('MEMBER_PIPE_READ_001: Should display pipelines list', () => {
|
|
25
|
+
pipelines.list.validatePageVisible()
|
|
26
|
+
pipelines.list.validateTableVisible()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('MEMBER_PIPE_READ_002: Should search and filter pipelines', () => {
|
|
30
|
+
pipelines.list.search('Sales')
|
|
31
|
+
cy.wait(500)
|
|
32
|
+
pipelines.list.clearSearch()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('MEMBER_PIPE_READ_003: Should view pipeline details (Kanban)', () => {
|
|
36
|
+
pipelines.list.clickRowByIndex(0)
|
|
37
|
+
cy.url().should('match', /\/pipelines\/[a-zA-Z0-9-]+$/)
|
|
38
|
+
pipelines.validateKanbanVisible()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('MEMBER_PIPE_READ_004: Should paginate through pipelines', () => {
|
|
42
|
+
pipelines.list.validatePageVisible()
|
|
43
|
+
|
|
44
|
+
cy.get(pipelines.list.selectors.pagination).then($pagination => {
|
|
45
|
+
if ($pagination.length > 0) {
|
|
46
|
+
pipelines.list.nextPage()
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('MEMBER_PIPE_READ_005: Should view pipelines created by other users', () => {
|
|
52
|
+
// Member should see owner and admin created pipelines
|
|
53
|
+
pipelines.list.validateTableVisible()
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('MEMBER_PIPE_READ_006: Should view pipeline stages in Kanban', () => {
|
|
57
|
+
pipelines.list.clickRowByIndex(0)
|
|
58
|
+
pipelines.validateKanbanVisible()
|
|
59
|
+
cy.get('[data-cy^="stage-column-"]').should('have.length.at.least', 1)
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// ==================== CREATE NOT ALLOWED ====================
|
|
64
|
+
describe('CREATE Pipeline (Denied)', () => {
|
|
65
|
+
it('MEMBER_PIPE_CREATE_001: Should not see create button', () => {
|
|
66
|
+
// Verify create button doesn't exist or is disabled
|
|
67
|
+
cy.get(pipelines.list.selectors.createButton).should('not.exist')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('MEMBER_PIPE_CREATE_002: Should not be able to navigate to create form via URL', () => {
|
|
71
|
+
// Try to access create form directly
|
|
72
|
+
cy.visit('/dashboard/pipelines/create', { failOnStatusCode: false })
|
|
73
|
+
|
|
74
|
+
// Should redirect or show error
|
|
75
|
+
cy.url().then(url => {
|
|
76
|
+
if (url.includes('/create')) {
|
|
77
|
+
// If on create page, should show permission error
|
|
78
|
+
cy.contains(/unauthorized|access denied|permission denied|forbidden/i).should('exist')
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('MEMBER_PIPE_CREATE_003: Should show permission error on create attempt via API', () => {
|
|
84
|
+
cy.request({
|
|
85
|
+
method: 'POST',
|
|
86
|
+
url: '/api/v1/pipelines',
|
|
87
|
+
failOnStatusCode: false,
|
|
88
|
+
headers: {
|
|
89
|
+
'Content-Type': 'application/json'
|
|
90
|
+
},
|
|
91
|
+
body: {
|
|
92
|
+
name: 'Unauthorized Pipeline',
|
|
93
|
+
stages: [{ id: '1', name: 'Test', order: 1, color: '#3b82f6' }]
|
|
94
|
+
}
|
|
95
|
+
}).then(response => {
|
|
96
|
+
expect(response.status).to.be.oneOf([401, 403])
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
// ==================== UPDATE NOT ALLOWED ====================
|
|
102
|
+
describe('UPDATE Pipeline (Denied)', () => {
|
|
103
|
+
it('MEMBER_PIPE_UPDATE_001: Should not see edit button in list', () => {
|
|
104
|
+
// Navigate to a pipeline
|
|
105
|
+
pipelines.list.clickRowByIndex(0)
|
|
106
|
+
pipelines.validateKanbanVisible()
|
|
107
|
+
|
|
108
|
+
// Check if edit button exists in Kanban header
|
|
109
|
+
cy.get('[data-cy*="edit-btn"]').should('not.exist')
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('MEMBER_PIPE_UPDATE_002: Should not be able to navigate to edit form via URL', () => {
|
|
113
|
+
// Get first pipeline ID
|
|
114
|
+
pipelines.list.clickRowByIndex(0)
|
|
115
|
+
|
|
116
|
+
cy.url().then(url => {
|
|
117
|
+
const pipelineId = url.split('/').pop()
|
|
118
|
+
|
|
119
|
+
// Try to access edit form directly
|
|
120
|
+
cy.visit(`/dashboard/pipelines/${pipelineId}/edit`, { failOnStatusCode: false })
|
|
121
|
+
|
|
122
|
+
cy.url().then(editUrl => {
|
|
123
|
+
if (editUrl.includes('/edit')) {
|
|
124
|
+
cy.contains(/unauthorized|access denied|permission denied|forbidden/i).should('exist')
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('MEMBER_PIPE_UPDATE_003: Should show permission error on update attempt via API', () => {
|
|
131
|
+
cy.request({
|
|
132
|
+
method: 'PATCH',
|
|
133
|
+
url: '/api/v1/pipelines/test-id',
|
|
134
|
+
failOnStatusCode: false,
|
|
135
|
+
headers: {
|
|
136
|
+
'Content-Type': 'application/json'
|
|
137
|
+
},
|
|
138
|
+
body: {
|
|
139
|
+
name: 'Unauthorized Update'
|
|
140
|
+
}
|
|
141
|
+
}).then(response => {
|
|
142
|
+
expect(response.status).to.be.oneOf([401, 403, 404])
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
// ==================== DELETE NOT ALLOWED ====================
|
|
148
|
+
describe('DELETE Pipeline (Denied)', () => {
|
|
149
|
+
it('MEMBER_PIPE_DELETE_001: Should not see delete button', () => {
|
|
150
|
+
pipelines.list.validateTableVisible()
|
|
151
|
+
|
|
152
|
+
// Verify delete actions don't exist in rows
|
|
153
|
+
cy.get(pipelines.list.selectors.rowGeneric).first().within(() => {
|
|
154
|
+
cy.get('[data-cy*="delete"]').should('not.exist')
|
|
155
|
+
})
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
it('MEMBER_PIPE_DELETE_002: Should not see bulk delete controls', () => {
|
|
159
|
+
// Verify bulk select checkboxes don't allow deletion
|
|
160
|
+
cy.get(pipelines.list.selectors.bulkActions).should('not.exist')
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it('MEMBER_PIPE_DELETE_003: Should show permission error on delete attempt via API', () => {
|
|
164
|
+
cy.request({
|
|
165
|
+
method: 'DELETE',
|
|
166
|
+
url: '/api/v1/pipelines/test-id',
|
|
167
|
+
failOnStatusCode: false
|
|
168
|
+
}).then(response => {
|
|
169
|
+
expect(response.status).to.be.oneOf([401, 403, 404])
|
|
170
|
+
})
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
// ==================== PERMISSION BOUNDARIES ====================
|
|
175
|
+
describe('Permission Boundaries', () => {
|
|
176
|
+
it('MEMBER_PIPE_PERM_001: Should only have view access in Kanban', () => {
|
|
177
|
+
pipelines.list.clickRowByIndex(0)
|
|
178
|
+
pipelines.validateKanbanVisible()
|
|
179
|
+
|
|
180
|
+
// Should not see edit/delete buttons
|
|
181
|
+
cy.get('[data-cy*="edit-btn"]').should('not.exist')
|
|
182
|
+
cy.get('[data-cy*="delete-btn"]').should('not.exist')
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('MEMBER_PIPE_PERM_002: Should be able to view deals in Kanban', () => {
|
|
186
|
+
pipelines.list.clickRowByIndex(0)
|
|
187
|
+
pipelines.validateKanbanVisible()
|
|
188
|
+
|
|
189
|
+
// Should see deal cards (if any exist)
|
|
190
|
+
cy.get(pipelines.kanbanSelectors.boardContainer).should('be.visible')
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it('MEMBER_PIPE_PERM_003: Should not be able to add deals', () => {
|
|
194
|
+
pipelines.list.clickRowByIndex(0)
|
|
195
|
+
pipelines.validateKanbanVisible()
|
|
196
|
+
|
|
197
|
+
// Add deal button should not exist for members
|
|
198
|
+
cy.get(pipelines.kanbanSelectors.addDealButton).should('not.exist')
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
it('MEMBER_PIPE_PERM_004: Should maintain read-only state during navigation', () => {
|
|
202
|
+
// Check list page
|
|
203
|
+
cy.get(pipelines.list.selectors.createButton).should('not.exist')
|
|
204
|
+
|
|
205
|
+
// Navigate to Kanban
|
|
206
|
+
pipelines.list.clickRowByIndex(0)
|
|
207
|
+
pipelines.validateKanbanVisible()
|
|
208
|
+
|
|
209
|
+
// Navigate back
|
|
210
|
+
cy.visit('/dashboard/pipelines')
|
|
211
|
+
pipelines.list.validatePageVisible()
|
|
212
|
+
|
|
213
|
+
// Still read-only
|
|
214
|
+
cy.get(pipelines.list.selectors.createButton).should('not.exist')
|
|
215
|
+
})
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
// ==================== KANBAN VIEW (Read Only) ====================
|
|
219
|
+
describe('KANBAN View (Read Only)', () => {
|
|
220
|
+
it('MEMBER_PIPE_KANBAN_001: Should display Kanban board', () => {
|
|
221
|
+
pipelines.list.clickRowByIndex(0)
|
|
222
|
+
pipelines.validateKanbanVisible()
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
it('MEMBER_PIPE_KANBAN_002: Should display stats cards', () => {
|
|
226
|
+
pipelines.list.clickRowByIndex(0)
|
|
227
|
+
pipelines.validateStatsVisible()
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
it('MEMBER_PIPE_KANBAN_003: Should display stage columns', () => {
|
|
231
|
+
pipelines.list.clickRowByIndex(0)
|
|
232
|
+
cy.get(pipelines.kanbanSelectors.boardContainer).should('be.visible')
|
|
233
|
+
cy.get('[data-cy^="stage-column-"]').should('have.length.at.least', 1)
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
it('MEMBER_PIPE_KANBAN_004: Should not be able to drag deals', () => {
|
|
237
|
+
pipelines.list.clickRowByIndex(0)
|
|
238
|
+
pipelines.validateKanbanVisible()
|
|
239
|
+
|
|
240
|
+
// Deal cards should not be draggable for members
|
|
241
|
+
cy.get('[data-cy^="deal-card-"]').first().then($card => {
|
|
242
|
+
if ($card.length > 0) {
|
|
243
|
+
// Try dragging - should not work or card should not have draggable attribute
|
|
244
|
+
expect($card.attr('draggable')).to.not.equal('true')
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
it('MEMBER_PIPE_KANBAN_005: Should be able to click deal cards to view details', () => {
|
|
250
|
+
pipelines.list.clickRowByIndex(0)
|
|
251
|
+
pipelines.validateKanbanVisible()
|
|
252
|
+
|
|
253
|
+
// If deal cards exist, clicking should navigate to deal detail
|
|
254
|
+
cy.get('[data-cy^="deal-card-"]').then($cards => {
|
|
255
|
+
if ($cards.length > 0) {
|
|
256
|
+
cy.wrap($cards.first()).click()
|
|
257
|
+
cy.url().should('include', '/opportunities/')
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
})
|
|
261
|
+
})
|
|
262
|
+
})
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pipelines CRUD - Owner Role (Full Access)
|
|
5
|
+
*
|
|
6
|
+
* Uses CRM theme-specific POMs with Entity Testing Convention.
|
|
7
|
+
* Selectors follow the pattern: {slug}-{component}-{detail}
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { PipelinesPOM } from '../../../src/entities/PipelinesPOM'
|
|
11
|
+
import { loginAsCrmOwner } from '../../../src/session-helpers'
|
|
12
|
+
|
|
13
|
+
describe('Pipelines CRUD - Owner Role (Full Access)', () => {
|
|
14
|
+
const pipelines = new PipelinesPOM()
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
loginAsCrmOwner()
|
|
18
|
+
cy.visit('/dashboard/pipelines')
|
|
19
|
+
pipelines.list.validatePageVisible()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// ==================== CREATE ====================
|
|
23
|
+
describe('CREATE Pipeline', () => {
|
|
24
|
+
it('OWNER_PIPE_CREATE_001: Should create new pipeline with required fields', () => {
|
|
25
|
+
pipelines.list.clickCreate()
|
|
26
|
+
pipelines.validateFormVisible()
|
|
27
|
+
|
|
28
|
+
pipelines.fillPipelineForm({
|
|
29
|
+
name: 'Sales Pipeline 2025'
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
pipelines.submitPipelineForm()
|
|
33
|
+
cy.url().should('include', '/pipelines')
|
|
34
|
+
pipelines.list.validatePageVisible()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('OWNER_PIPE_CREATE_002: Should create pipeline with multiple stages', () => {
|
|
38
|
+
pipelines.list.clickCreate()
|
|
39
|
+
pipelines.validateFormVisible()
|
|
40
|
+
|
|
41
|
+
pipelines.fillPipelineForm({
|
|
42
|
+
name: 'Complex Sales Pipeline'
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
pipelines.validateStagesRepeaterVisible()
|
|
46
|
+
|
|
47
|
+
// Modify default stages
|
|
48
|
+
pipelines.fillStageByIndex(0, { name: 'Lead', probability: 10 })
|
|
49
|
+
pipelines.fillStageByIndex(1, { name: 'Qualified', probability: 25 })
|
|
50
|
+
pipelines.fillStageByIndex(2, { name: 'Proposal', probability: 50 })
|
|
51
|
+
pipelines.fillStageByIndex(3, { name: 'Negotiation', probability: 75 })
|
|
52
|
+
pipelines.fillStageByIndex(4, { name: 'Closed Won', probability: 100 })
|
|
53
|
+
|
|
54
|
+
pipelines.submitPipelineForm()
|
|
55
|
+
cy.url().should('include', '/pipelines')
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('OWNER_PIPE_CREATE_003: Should create pipeline with optional fields', () => {
|
|
59
|
+
pipelines.list.clickCreate()
|
|
60
|
+
pipelines.validateFormVisible()
|
|
61
|
+
|
|
62
|
+
pipelines.fillPipelineForm({
|
|
63
|
+
name: 'Default Support Pipeline',
|
|
64
|
+
description: 'Pipeline for customer support tickets'
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
pipelines.submitPipelineForm()
|
|
68
|
+
cy.url().should('include', '/pipelines')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('OWNER_PIPE_CREATE_004: Should show validation error for empty name', () => {
|
|
72
|
+
pipelines.list.clickCreate()
|
|
73
|
+
pipelines.validateFormVisible()
|
|
74
|
+
|
|
75
|
+
// Submit without filling name
|
|
76
|
+
pipelines.submitPipelineForm()
|
|
77
|
+
|
|
78
|
+
// Should stay on create page
|
|
79
|
+
cy.url().should('include', '/create')
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('OWNER_PIPE_CREATE_005: Should cancel pipeline creation', () => {
|
|
83
|
+
pipelines.list.clickCreate()
|
|
84
|
+
pipelines.validateFormVisible()
|
|
85
|
+
|
|
86
|
+
pipelines.fillPipelineForm({
|
|
87
|
+
name: 'Cancel Test Pipeline'
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
pipelines.cancelPipelineForm()
|
|
91
|
+
pipelines.list.validatePageVisible()
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// ==================== READ ====================
|
|
96
|
+
describe('READ Pipeline', () => {
|
|
97
|
+
it('OWNER_PIPE_READ_001: Should display pipelines list', () => {
|
|
98
|
+
pipelines.list.validatePageVisible()
|
|
99
|
+
pipelines.list.validateTableVisible()
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('OWNER_PIPE_READ_002: Should search and filter pipelines', () => {
|
|
103
|
+
pipelines.list.search('Sales')
|
|
104
|
+
cy.wait(500)
|
|
105
|
+
pipelines.list.clearSearch()
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('OWNER_PIPE_READ_003: Should view pipeline details (Kanban)', () => {
|
|
109
|
+
pipelines.list.clickRowByIndex(0)
|
|
110
|
+
cy.url().should('match', /\/pipelines\/[a-zA-Z0-9-]+$/)
|
|
111
|
+
pipelines.validateKanbanVisible()
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('OWNER_PIPE_READ_004: Should paginate through pipelines', () => {
|
|
115
|
+
pipelines.list.validatePageVisible()
|
|
116
|
+
|
|
117
|
+
cy.get(pipelines.list.selectors.pagination).then($pagination => {
|
|
118
|
+
if ($pagination.length > 0) {
|
|
119
|
+
pipelines.list.nextPage()
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
// ==================== UPDATE ====================
|
|
126
|
+
describe('UPDATE Pipeline', () => {
|
|
127
|
+
it('OWNER_PIPE_UPDATE_001: Should update pipeline name', () => {
|
|
128
|
+
pipelines.list.clickRowByIndex(0)
|
|
129
|
+
pipelines.validateKanbanVisible()
|
|
130
|
+
|
|
131
|
+
cy.url().then(url => {
|
|
132
|
+
const pipelineId = url.split('/').pop()
|
|
133
|
+
pipelines.visitEdit(pipelineId!)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
pipelines.validateFormVisible()
|
|
137
|
+
cy.get(pipelines.formSelectors.nameInput).clear().type('Sales Pipeline 2025 Updated')
|
|
138
|
+
|
|
139
|
+
pipelines.submitPipelineForm()
|
|
140
|
+
cy.url().should('include', '/pipelines')
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('OWNER_PIPE_UPDATE_002: Should update pipeline stages', () => {
|
|
144
|
+
pipelines.list.clickRowByIndex(0)
|
|
145
|
+
|
|
146
|
+
cy.url().then(url => {
|
|
147
|
+
const pipelineId = url.split('/').pop()
|
|
148
|
+
pipelines.visitEdit(pipelineId!)
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
pipelines.validateFormVisible()
|
|
152
|
+
pipelines.validateStagesRepeaterVisible()
|
|
153
|
+
|
|
154
|
+
// Add a new stage
|
|
155
|
+
pipelines.addStage()
|
|
156
|
+
|
|
157
|
+
cy.get(pipelines.stagesSelectors.list)
|
|
158
|
+
.find('[data-cy^="stages-repeater-item-"]')
|
|
159
|
+
.last()
|
|
160
|
+
.within(() => {
|
|
161
|
+
cy.get('input[data-cy^="stages-repeater-name-"]').type('Closed Lost')
|
|
162
|
+
cy.get('input[data-cy^="stages-repeater-probability-"]').clear().type('0')
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
pipelines.submitPipelineForm()
|
|
166
|
+
cy.url().should('include', '/pipelines')
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('OWNER_PIPE_UPDATE_003: Should update optional fields', () => {
|
|
170
|
+
pipelines.list.clickRowByIndex(0)
|
|
171
|
+
|
|
172
|
+
cy.url().then(url => {
|
|
173
|
+
const pipelineId = url.split('/').pop()
|
|
174
|
+
pipelines.visitEdit(pipelineId!)
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
pipelines.validateFormVisible()
|
|
178
|
+
|
|
179
|
+
cy.get(pipelines.formSelectors.descriptionInput)
|
|
180
|
+
.clear()
|
|
181
|
+
.type('Updated pipeline description')
|
|
182
|
+
|
|
183
|
+
pipelines.submitPipelineForm()
|
|
184
|
+
cy.url().should('include', '/pipelines')
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
it('OWNER_PIPE_UPDATE_004: Should cancel update without saving', () => {
|
|
188
|
+
pipelines.list.clickRowByIndex(0)
|
|
189
|
+
|
|
190
|
+
cy.url().then(url => {
|
|
191
|
+
const pipelineId = url.split('/').pop()
|
|
192
|
+
pipelines.visitEdit(pipelineId!)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
pipelines.validateFormVisible()
|
|
196
|
+
cy.get(pipelines.formSelectors.nameInput).clear().type('Should Not Be Saved')
|
|
197
|
+
|
|
198
|
+
pipelines.cancelPipelineForm()
|
|
199
|
+
cy.url().should('not.include', '/edit')
|
|
200
|
+
})
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
// ==================== DELETE ====================
|
|
204
|
+
describe('DELETE Pipeline', () => {
|
|
205
|
+
it('OWNER_PIPE_DELETE_001: Should delete pipeline', () => {
|
|
206
|
+
// Create a pipeline to delete
|
|
207
|
+
pipelines.list.clickCreate()
|
|
208
|
+
pipelines.validateFormVisible()
|
|
209
|
+
|
|
210
|
+
pipelines.fillPipelineForm({
|
|
211
|
+
name: 'Pipeline To Delete'
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
pipelines.submitPipelineForm()
|
|
215
|
+
cy.url().should('include', '/pipelines')
|
|
216
|
+
|
|
217
|
+
// Delete it
|
|
218
|
+
pipelines.list.validatePageVisible()
|
|
219
|
+
pipelines.list.search('Pipeline To Delete')
|
|
220
|
+
|
|
221
|
+
cy.get(pipelines.list.selectors.rowGeneric).first().within(() => {
|
|
222
|
+
cy.get('[data-cy*="delete"]').click()
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
pipelines.list.confirmDelete()
|
|
226
|
+
|
|
227
|
+
// Verify deleted
|
|
228
|
+
pipelines.list.search('Pipeline To Delete')
|
|
229
|
+
cy.get(pipelines.list.selectors.emptyState).should('be.visible')
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it('OWNER_PIPE_DELETE_002: Should cancel deletion', () => {
|
|
233
|
+
pipelines.list.search('Sales')
|
|
234
|
+
|
|
235
|
+
cy.get(pipelines.list.selectors.rowGeneric).first().then($row => {
|
|
236
|
+
cy.wrap($row).within(() => {
|
|
237
|
+
cy.get('[data-cy*="delete"]').click()
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
pipelines.list.cancelDelete()
|
|
242
|
+
pipelines.list.validateTableVisible()
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
it('OWNER_PIPE_DELETE_003: Should handle bulk delete', () => {
|
|
246
|
+
pipelines.list.selectAll()
|
|
247
|
+
pipelines.list.validateBulkActionsVisible()
|
|
248
|
+
})
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
// ==================== KANBAN BOARD ====================
|
|
252
|
+
describe('KANBAN Board', () => {
|
|
253
|
+
it('OWNER_PIPE_KANBAN_001: Should display Kanban board on pipeline detail', () => {
|
|
254
|
+
pipelines.list.clickRowByIndex(0)
|
|
255
|
+
pipelines.validateKanbanVisible()
|
|
256
|
+
pipelines.validateStatsVisible()
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it('OWNER_PIPE_KANBAN_002: Should display pipeline header with name', () => {
|
|
260
|
+
pipelines.list.clickRowByIndex(0)
|
|
261
|
+
cy.get(pipelines.kanbanSelectors.header).should('be.visible')
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
it('OWNER_PIPE_KANBAN_003: Should display stats cards', () => {
|
|
265
|
+
pipelines.list.clickRowByIndex(0)
|
|
266
|
+
pipelines.validateStatsVisible()
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
it('OWNER_PIPE_KANBAN_004: Should display stage columns', () => {
|
|
270
|
+
pipelines.list.clickRowByIndex(0)
|
|
271
|
+
cy.get(pipelines.kanbanSelectors.boardContainer).should('be.visible')
|
|
272
|
+
cy.get('[data-cy^="stage-column-"]').should('have.length.at.least', 1)
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
it('OWNER_PIPE_KANBAN_005: Should click add deal button', () => {
|
|
276
|
+
pipelines.list.clickRowByIndex(0)
|
|
277
|
+
pipelines.validateKanbanVisible()
|
|
278
|
+
pipelines.clickAddDeal()
|
|
279
|
+
cy.url().should('include', 'opportunities')
|
|
280
|
+
})
|
|
281
|
+
})
|
|
282
|
+
})
|