@nextsparkjs/theme-crm 0.1.0-beta.18 → 0.1.0-beta.20
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 +2 -2
- 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/tsconfig.json +15 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Opportunities 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 { OpportunitiesPOM } from '../../../src/entities/OpportunitiesPOM'
|
|
11
|
+
import { loginAsCrmOwner } from '../../../src/session-helpers'
|
|
12
|
+
|
|
13
|
+
describe('Opportunities CRUD - Owner Role (Full Access)', () => {
|
|
14
|
+
const opportunities = new OpportunitiesPOM()
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
loginAsCrmOwner()
|
|
18
|
+
cy.visit('/dashboard/opportunities')
|
|
19
|
+
opportunities.list.validatePageVisible()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
describe('CREATE - Owner can create opportunities', () => {
|
|
23
|
+
it('OWNER_OPPO_CREATE_001: should create new opportunity with required fields', () => {
|
|
24
|
+
const timestamp = Date.now()
|
|
25
|
+
const opportunityName = `Test Opportunity ${timestamp}`
|
|
26
|
+
|
|
27
|
+
opportunities.list.clickCreate()
|
|
28
|
+
opportunities.form.validateFormVisible()
|
|
29
|
+
|
|
30
|
+
opportunities.fillOpportunityForm({
|
|
31
|
+
name: opportunityName,
|
|
32
|
+
amount: '50000'
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
opportunities.submitForm()
|
|
36
|
+
|
|
37
|
+
cy.url().should('include', '/dashboard/opportunities')
|
|
38
|
+
cy.contains(opportunityName).should('be.visible')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('OWNER_OPPO_CREATE_002: should create opportunity with all fields', () => {
|
|
42
|
+
const timestamp = Date.now()
|
|
43
|
+
const opportunityName = `Complete Opportunity ${timestamp}`
|
|
44
|
+
|
|
45
|
+
opportunities.list.clickCreate()
|
|
46
|
+
opportunities.form.validateFormVisible()
|
|
47
|
+
|
|
48
|
+
opportunities.fillOpportunityForm({
|
|
49
|
+
name: opportunityName,
|
|
50
|
+
amount: '75000',
|
|
51
|
+
probability: '60'
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
opportunities.submitForm()
|
|
55
|
+
|
|
56
|
+
cy.url().should('include', '/dashboard/opportunities')
|
|
57
|
+
cy.contains(opportunityName).should('be.visible')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('OWNER_OPPO_CREATE_003: should validate required fields', () => {
|
|
61
|
+
opportunities.list.clickCreate()
|
|
62
|
+
opportunities.form.validateFormVisible()
|
|
63
|
+
|
|
64
|
+
// Try to submit without filling required fields
|
|
65
|
+
opportunities.submitForm()
|
|
66
|
+
|
|
67
|
+
// Should remain on form page due to validation errors
|
|
68
|
+
opportunities.form.validateFormVisible()
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
describe('READ - Owner can read opportunities', () => {
|
|
73
|
+
it('OWNER_OPPO_READ_001: should view opportunity list', () => {
|
|
74
|
+
opportunities.list.validatePageVisible()
|
|
75
|
+
opportunities.list.validateTableVisible()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('OWNER_OPPO_READ_002: should view opportunity details', () => {
|
|
79
|
+
cy.get(opportunities.list.selectors.rowGeneric).then($rows => {
|
|
80
|
+
if ($rows.length > 0) {
|
|
81
|
+
opportunities.list.clickRowByIndex(0)
|
|
82
|
+
cy.url().should('match', /\/dashboard\/opportunities\/[a-z0-9-]+/)
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('OWNER_OPPO_READ_003: should search opportunities', () => {
|
|
88
|
+
opportunities.list.search('test')
|
|
89
|
+
cy.wait(500)
|
|
90
|
+
opportunities.list.clearSearch()
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('UPDATE - Owner can update opportunities', () => {
|
|
95
|
+
it('OWNER_OPPO_UPDATE_001: should edit opportunity name', () => {
|
|
96
|
+
cy.get(opportunities.list.selectors.rowGeneric).then($rows => {
|
|
97
|
+
if ($rows.length > 0) {
|
|
98
|
+
opportunities.list.clickRowByIndex(0)
|
|
99
|
+
|
|
100
|
+
cy.url().then(url => {
|
|
101
|
+
const opportunityId = url.split('/').pop()
|
|
102
|
+
opportunities.form.visitEdit(opportunityId!)
|
|
103
|
+
opportunities.form.validateFormVisible()
|
|
104
|
+
|
|
105
|
+
const updatedName = `Updated Opportunity ${Date.now()}`
|
|
106
|
+
opportunities.form.typeInField('name', updatedName)
|
|
107
|
+
|
|
108
|
+
opportunities.submitForm()
|
|
109
|
+
|
|
110
|
+
cy.url().should('include', '/dashboard/opportunities')
|
|
111
|
+
cy.contains(updatedName).should('be.visible')
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('OWNER_OPPO_UPDATE_002: should update opportunity value', () => {
|
|
118
|
+
cy.get(opportunities.list.selectors.rowGeneric).then($rows => {
|
|
119
|
+
if ($rows.length > 0) {
|
|
120
|
+
opportunities.list.clickRowByIndex(0)
|
|
121
|
+
|
|
122
|
+
cy.url().then(url => {
|
|
123
|
+
const opportunityId = url.split('/').pop()
|
|
124
|
+
opportunities.form.visitEdit(opportunityId!)
|
|
125
|
+
opportunities.form.validateFormVisible()
|
|
126
|
+
|
|
127
|
+
opportunities.form.typeInField('amount', '100000')
|
|
128
|
+
|
|
129
|
+
opportunities.submitForm()
|
|
130
|
+
cy.url().should('include', '/dashboard/opportunities')
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('OWNER_OPPO_UPDATE_003: should cancel update without saving', () => {
|
|
137
|
+
cy.get(opportunities.list.selectors.rowGeneric).then($rows => {
|
|
138
|
+
if ($rows.length > 0) {
|
|
139
|
+
opportunities.list.clickRowByIndex(0)
|
|
140
|
+
|
|
141
|
+
cy.url().then(url => {
|
|
142
|
+
const opportunityId = url.split('/').pop()
|
|
143
|
+
opportunities.form.visitEdit(opportunityId!)
|
|
144
|
+
opportunities.form.validateFormVisible()
|
|
145
|
+
|
|
146
|
+
opportunities.form.typeInField('name', 'ShouldNotSave')
|
|
147
|
+
|
|
148
|
+
opportunities.form.cancel()
|
|
149
|
+
cy.url().should('not.include', '/edit')
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
})
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
describe('DELETE - Owner can delete opportunities', () => {
|
|
157
|
+
it('OWNER_OPPO_DELETE_001: should delete opportunity successfully', () => {
|
|
158
|
+
const timestamp = Date.now()
|
|
159
|
+
const opportunityName = `Delete Test ${timestamp}`
|
|
160
|
+
|
|
161
|
+
opportunities.list.clickCreate()
|
|
162
|
+
opportunities.fillOpportunityForm({
|
|
163
|
+
name: opportunityName,
|
|
164
|
+
amount: '25000'
|
|
165
|
+
})
|
|
166
|
+
opportunities.submitForm()
|
|
167
|
+
|
|
168
|
+
cy.contains(opportunityName).should('be.visible')
|
|
169
|
+
|
|
170
|
+
opportunities.list.search(opportunityName)
|
|
171
|
+
|
|
172
|
+
cy.get(opportunities.list.selectors.rowGeneric).first().within(() => {
|
|
173
|
+
cy.get('[data-cy*="delete"]').click()
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
opportunities.list.confirmDelete()
|
|
177
|
+
|
|
178
|
+
cy.wait(1000)
|
|
179
|
+
opportunities.list.search(opportunityName)
|
|
180
|
+
cy.get(opportunities.list.selectors.emptyState).should('be.visible')
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it('OWNER_OPPO_DELETE_002: should cancel deletion', () => {
|
|
184
|
+
cy.get(opportunities.list.selectors.rowGeneric).then($rows => {
|
|
185
|
+
if ($rows.length > 0) {
|
|
186
|
+
cy.get(opportunities.list.selectors.rowGeneric).first().within(() => {
|
|
187
|
+
cy.get('[data-cy*="delete"]').click()
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
opportunities.list.cancelDelete()
|
|
191
|
+
opportunities.list.validateTableVisible()
|
|
192
|
+
}
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
})
|
|
196
|
+
})
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pipelines CRUD - Admin 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 { loginAsCrmAdmin } from '../../../src/session-helpers'
|
|
12
|
+
|
|
13
|
+
describe('Pipelines CRUD - Admin Role (Full Access)', () => {
|
|
14
|
+
const pipelines = new PipelinesPOM()
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
loginAsCrmAdmin()
|
|
18
|
+
cy.visit('/dashboard/pipelines')
|
|
19
|
+
pipelines.list.validatePageVisible()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// ==================== CREATE ====================
|
|
23
|
+
describe('CREATE Pipeline', () => {
|
|
24
|
+
it('ADMIN_PIPE_CREATE_001: Should create new pipeline with required fields', () => {
|
|
25
|
+
// Click create button
|
|
26
|
+
pipelines.list.clickCreate()
|
|
27
|
+
pipelines.validateFormVisible()
|
|
28
|
+
|
|
29
|
+
// Fill required fields using custom form
|
|
30
|
+
pipelines.fillPipelineForm({
|
|
31
|
+
name: 'Admin Sales Pipeline 2025'
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
// Submit form
|
|
35
|
+
pipelines.submitPipelineForm()
|
|
36
|
+
|
|
37
|
+
// Verify success - should navigate to detail or list
|
|
38
|
+
cy.url().should('include', '/pipelines')
|
|
39
|
+
pipelines.list.validatePageVisible()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('ADMIN_PIPE_CREATE_002: Should create pipeline with multiple stages', () => {
|
|
43
|
+
pipelines.list.clickCreate()
|
|
44
|
+
pipelines.validateFormVisible()
|
|
45
|
+
|
|
46
|
+
pipelines.fillPipelineForm({
|
|
47
|
+
name: 'Admin Complex Pipeline'
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// Validate stages repeater is visible
|
|
51
|
+
pipelines.validateStagesRepeaterVisible()
|
|
52
|
+
|
|
53
|
+
// Fill default stages (they should already exist)
|
|
54
|
+
pipelines.fillStageByIndex(0, { name: 'Prospect', probability: 10 })
|
|
55
|
+
pipelines.fillStageByIndex(1, { name: 'Contact Made', probability: 25 })
|
|
56
|
+
|
|
57
|
+
// Add more stages
|
|
58
|
+
pipelines.addStage()
|
|
59
|
+
pipelines.fillStageByIndex(5, { name: 'Won', probability: 100 })
|
|
60
|
+
|
|
61
|
+
pipelines.submitPipelineForm()
|
|
62
|
+
cy.url().should('include', '/pipelines')
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('ADMIN_PIPE_CREATE_003: Should create pipeline with optional fields', () => {
|
|
66
|
+
pipelines.list.clickCreate()
|
|
67
|
+
pipelines.validateFormVisible()
|
|
68
|
+
|
|
69
|
+
pipelines.fillPipelineForm({
|
|
70
|
+
name: 'Admin Default Pipeline',
|
|
71
|
+
description: 'Pipeline created by admin user'
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
pipelines.submitPipelineForm()
|
|
75
|
+
cy.url().should('include', '/pipelines')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('ADMIN_PIPE_CREATE_004: Should show validation error for empty name', () => {
|
|
79
|
+
pipelines.list.clickCreate()
|
|
80
|
+
pipelines.validateFormVisible()
|
|
81
|
+
|
|
82
|
+
// Submit without filling name
|
|
83
|
+
pipelines.submitPipelineForm()
|
|
84
|
+
|
|
85
|
+
// Should show validation error (form shouldn't submit)
|
|
86
|
+
cy.url().should('include', '/create')
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('ADMIN_PIPE_CREATE_005: Should cancel pipeline creation', () => {
|
|
90
|
+
pipelines.list.clickCreate()
|
|
91
|
+
pipelines.validateFormVisible()
|
|
92
|
+
|
|
93
|
+
pipelines.fillPipelineForm({
|
|
94
|
+
name: 'Admin Cancel Test Pipeline'
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
// Cancel instead of submit
|
|
98
|
+
pipelines.cancelPipelineForm()
|
|
99
|
+
|
|
100
|
+
// Should return to list
|
|
101
|
+
pipelines.list.validatePageVisible()
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
// ==================== READ ====================
|
|
106
|
+
describe('READ Pipeline', () => {
|
|
107
|
+
it('ADMIN_PIPE_READ_001: Should display pipelines list', () => {
|
|
108
|
+
// List should be visible from beforeEach
|
|
109
|
+
pipelines.list.validatePageVisible()
|
|
110
|
+
pipelines.list.validateTableVisible()
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
it('ADMIN_PIPE_READ_002: Should search and filter pipelines', () => {
|
|
114
|
+
// Search for specific pipeline
|
|
115
|
+
pipelines.list.search('Admin')
|
|
116
|
+
|
|
117
|
+
// Wait for search results
|
|
118
|
+
cy.wait(500)
|
|
119
|
+
|
|
120
|
+
// Clear search
|
|
121
|
+
pipelines.list.clearSearch()
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('ADMIN_PIPE_READ_003: Should view pipeline details (Kanban)', () => {
|
|
125
|
+
// Click on first row to view Kanban
|
|
126
|
+
pipelines.list.clickRowByIndex(0)
|
|
127
|
+
|
|
128
|
+
// Should navigate to detail page showing Kanban
|
|
129
|
+
cy.url().should('match', /\/pipelines\/[a-zA-Z0-9-]+$/)
|
|
130
|
+
|
|
131
|
+
// Validate Kanban board is visible
|
|
132
|
+
pipelines.validateKanbanVisible()
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('ADMIN_PIPE_READ_004: Should paginate through pipelines', () => {
|
|
136
|
+
pipelines.list.validatePageVisible()
|
|
137
|
+
|
|
138
|
+
// Check if pagination exists
|
|
139
|
+
cy.get(pipelines.list.selectors.pagination).then($pagination => {
|
|
140
|
+
if ($pagination.length > 0) {
|
|
141
|
+
pipelines.list.nextPage()
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('ADMIN_PIPE_READ_005: Should view pipelines created by other users', () => {
|
|
147
|
+
// Admin should see all pipelines
|
|
148
|
+
pipelines.list.validateTableVisible()
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
// ==================== UPDATE ====================
|
|
153
|
+
describe('UPDATE Pipeline', () => {
|
|
154
|
+
it('ADMIN_PIPE_UPDATE_001: Should update pipeline name', () => {
|
|
155
|
+
// Navigate to edit page for first pipeline
|
|
156
|
+
pipelines.list.clickRowByIndex(0)
|
|
157
|
+
pipelines.validateKanbanVisible()
|
|
158
|
+
|
|
159
|
+
// Get pipeline ID from URL and navigate to edit
|
|
160
|
+
cy.url().then(url => {
|
|
161
|
+
const pipelineId = url.split('/').pop()
|
|
162
|
+
pipelines.visitEdit(pipelineId!)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
pipelines.validateFormVisible()
|
|
166
|
+
|
|
167
|
+
// Update name
|
|
168
|
+
cy.get(pipelines.formSelectors.nameInput).clear().type('Admin Sales Pipeline Updated')
|
|
169
|
+
|
|
170
|
+
pipelines.submitPipelineForm()
|
|
171
|
+
|
|
172
|
+
// Verify success
|
|
173
|
+
cy.url().should('include', '/pipelines')
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
it('ADMIN_PIPE_UPDATE_002: Should update pipeline stages', () => {
|
|
177
|
+
// Navigate to first pipeline edit
|
|
178
|
+
pipelines.list.clickRowByIndex(0)
|
|
179
|
+
|
|
180
|
+
cy.url().then(url => {
|
|
181
|
+
const pipelineId = url.split('/').pop()
|
|
182
|
+
pipelines.visitEdit(pipelineId!)
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
pipelines.validateFormVisible()
|
|
186
|
+
pipelines.validateStagesRepeaterVisible()
|
|
187
|
+
|
|
188
|
+
// Add a new stage
|
|
189
|
+
pipelines.addStage()
|
|
190
|
+
|
|
191
|
+
// Fill the new stage
|
|
192
|
+
cy.get(pipelines.stagesSelectors.list)
|
|
193
|
+
.find('[data-cy^="stages-repeater-item-"]')
|
|
194
|
+
.last()
|
|
195
|
+
.within(() => {
|
|
196
|
+
cy.get('input[data-cy^="stages-repeater-name-"]').type('New Admin Stage')
|
|
197
|
+
cy.get('input[data-cy^="stages-repeater-probability-"]').clear().type('50')
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
pipelines.submitPipelineForm()
|
|
201
|
+
cy.url().should('include', '/pipelines')
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it('ADMIN_PIPE_UPDATE_003: Should cancel update without saving', () => {
|
|
205
|
+
pipelines.list.clickRowByIndex(0)
|
|
206
|
+
|
|
207
|
+
cy.url().then(url => {
|
|
208
|
+
const pipelineId = url.split('/').pop()
|
|
209
|
+
pipelines.visitEdit(pipelineId!)
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
pipelines.validateFormVisible()
|
|
213
|
+
|
|
214
|
+
// Make changes
|
|
215
|
+
cy.get(pipelines.formSelectors.nameInput).clear().type('Admin Should Not Save')
|
|
216
|
+
|
|
217
|
+
// Cancel instead of submit
|
|
218
|
+
pipelines.cancelPipelineForm()
|
|
219
|
+
|
|
220
|
+
// Should return to previous page
|
|
221
|
+
cy.url().should('not.include', '/edit')
|
|
222
|
+
})
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
// ==================== DELETE ====================
|
|
226
|
+
describe('DELETE Pipeline', () => {
|
|
227
|
+
it('ADMIN_PIPE_DELETE_001: Should delete pipeline from list', () => {
|
|
228
|
+
// First create a pipeline to delete
|
|
229
|
+
pipelines.list.clickCreate()
|
|
230
|
+
pipelines.validateFormVisible()
|
|
231
|
+
|
|
232
|
+
pipelines.fillPipelineForm({
|
|
233
|
+
name: 'Admin Pipeline To Delete'
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
pipelines.submitPipelineForm()
|
|
237
|
+
cy.url().should('include', '/pipelines')
|
|
238
|
+
|
|
239
|
+
// Now try to delete from list
|
|
240
|
+
pipelines.list.validatePageVisible()
|
|
241
|
+
pipelines.list.search('Admin Pipeline To Delete')
|
|
242
|
+
|
|
243
|
+
// Click delete action for the row
|
|
244
|
+
cy.get(pipelines.list.selectors.rowGeneric).first().within(() => {
|
|
245
|
+
cy.get('[data-cy*="delete"]').click()
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
// Confirm deletion
|
|
249
|
+
pipelines.list.confirmDelete()
|
|
250
|
+
|
|
251
|
+
// Verify deleted
|
|
252
|
+
pipelines.list.search('Admin Pipeline To Delete')
|
|
253
|
+
cy.get(pipelines.list.selectors.emptyState).should('be.visible')
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
it('ADMIN_PIPE_DELETE_002: Should cancel deletion', () => {
|
|
257
|
+
pipelines.list.search('Admin')
|
|
258
|
+
|
|
259
|
+
// Try to delete first item
|
|
260
|
+
cy.get(pipelines.list.selectors.rowGeneric).first().then($row => {
|
|
261
|
+
cy.wrap($row).within(() => {
|
|
262
|
+
cy.get('[data-cy*="delete"]').click()
|
|
263
|
+
})
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
// Cancel deletion
|
|
267
|
+
pipelines.list.cancelDelete()
|
|
268
|
+
|
|
269
|
+
// Verify still exists
|
|
270
|
+
pipelines.list.validateTableVisible()
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
it('ADMIN_PIPE_DELETE_003: Should handle bulk delete', () => {
|
|
274
|
+
// Select multiple items
|
|
275
|
+
pipelines.list.selectAll()
|
|
276
|
+
|
|
277
|
+
// Validate bulk actions visible
|
|
278
|
+
pipelines.list.validateBulkActionsVisible()
|
|
279
|
+
})
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
// ==================== KANBAN BOARD ====================
|
|
283
|
+
describe('KANBAN Board', () => {
|
|
284
|
+
it('ADMIN_PIPE_KANBAN_001: Should display Kanban board on pipeline detail', () => {
|
|
285
|
+
pipelines.list.clickRowByIndex(0)
|
|
286
|
+
|
|
287
|
+
pipelines.validateKanbanVisible()
|
|
288
|
+
pipelines.validateStatsVisible()
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
it('ADMIN_PIPE_KANBAN_002: Should display pipeline header with name', () => {
|
|
292
|
+
pipelines.list.clickRowByIndex(0)
|
|
293
|
+
|
|
294
|
+
cy.get(pipelines.kanbanSelectors.header).should('be.visible')
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
it('ADMIN_PIPE_KANBAN_003: Should display stats cards', () => {
|
|
298
|
+
pipelines.list.clickRowByIndex(0)
|
|
299
|
+
|
|
300
|
+
pipelines.validateStatsVisible()
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
it('ADMIN_PIPE_KANBAN_004: Should display stage columns', () => {
|
|
304
|
+
pipelines.list.clickRowByIndex(0)
|
|
305
|
+
|
|
306
|
+
cy.get(pipelines.kanbanSelectors.boardContainer).should('be.visible')
|
|
307
|
+
cy.get('[data-cy^="stage-column-"]').should('have.length.at.least', 1)
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
it('ADMIN_PIPE_KANBAN_005: Should click add deal button', () => {
|
|
311
|
+
pipelines.list.clickRowByIndex(0)
|
|
312
|
+
pipelines.validateKanbanVisible()
|
|
313
|
+
|
|
314
|
+
pipelines.clickAddDeal()
|
|
315
|
+
|
|
316
|
+
// Should navigate to opportunity create or open modal
|
|
317
|
+
cy.url().should('include', 'opportunities')
|
|
318
|
+
})
|
|
319
|
+
})
|
|
320
|
+
})
|