@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,268 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Activities 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 { ActivitiesPOM } from '../../../src/entities/ActivitiesPOM'
|
|
11
|
+
import { loginAsCrmAdmin } from '../../../src/session-helpers'
|
|
12
|
+
|
|
13
|
+
describe('Activities CRUD - Admin Role (Full Access)', () => {
|
|
14
|
+
const activities = new ActivitiesPOM()
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
loginAsCrmAdmin()
|
|
18
|
+
cy.visit('/dashboard/activities')
|
|
19
|
+
activities.list.validatePageVisible()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
describe('CREATE - Admin can create activities', () => {
|
|
23
|
+
it('ADMIN_ACTIV_CREATE_001: should create new call activity', () => {
|
|
24
|
+
const timestamp = Date.now()
|
|
25
|
+
const subject = `Admin Call ${timestamp}`
|
|
26
|
+
|
|
27
|
+
activities.list.clickCreate()
|
|
28
|
+
activities.form.validateFormVisible()
|
|
29
|
+
|
|
30
|
+
activities.fillActivityForm({
|
|
31
|
+
type: 'call',
|
|
32
|
+
subject
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
activities.submitForm()
|
|
36
|
+
|
|
37
|
+
cy.url().should('include', '/dashboard/activities')
|
|
38
|
+
cy.contains(subject).should('be.visible')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('ADMIN_ACTIV_CREATE_002: should create meeting activity with all fields', () => {
|
|
42
|
+
const timestamp = Date.now()
|
|
43
|
+
const subject = `Admin Meeting ${timestamp}`
|
|
44
|
+
|
|
45
|
+
activities.list.clickCreate()
|
|
46
|
+
activities.form.validateFormVisible()
|
|
47
|
+
|
|
48
|
+
activities.fillActivityForm({
|
|
49
|
+
type: 'meeting',
|
|
50
|
+
subject,
|
|
51
|
+
description: 'Q1 planning meeting'
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
activities.submitForm()
|
|
55
|
+
|
|
56
|
+
cy.url().should('include', '/dashboard/activities')
|
|
57
|
+
cy.contains(subject).should('be.visible')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('ADMIN_ACTIV_CREATE_003: should create email activity', () => {
|
|
61
|
+
const timestamp = Date.now()
|
|
62
|
+
const subject = `Admin Email ${timestamp}`
|
|
63
|
+
|
|
64
|
+
activities.list.clickCreate()
|
|
65
|
+
activities.form.validateFormVisible()
|
|
66
|
+
|
|
67
|
+
activities.fillActivityForm({
|
|
68
|
+
type: 'email',
|
|
69
|
+
subject
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
activities.submitForm()
|
|
73
|
+
|
|
74
|
+
cy.url().should('include', '/dashboard/activities')
|
|
75
|
+
cy.contains(subject).should('be.visible')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('ADMIN_ACTIV_CREATE_004: should create task activity', () => {
|
|
79
|
+
const timestamp = Date.now()
|
|
80
|
+
const subject = `Admin Task ${timestamp}`
|
|
81
|
+
|
|
82
|
+
activities.list.clickCreate()
|
|
83
|
+
activities.form.validateFormVisible()
|
|
84
|
+
|
|
85
|
+
activities.fillActivityForm({
|
|
86
|
+
type: 'task',
|
|
87
|
+
subject,
|
|
88
|
+
description: 'Review documents'
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
activities.submitForm()
|
|
92
|
+
|
|
93
|
+
cy.url().should('include', '/dashboard/activities')
|
|
94
|
+
cy.contains(subject).should('be.visible')
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('ADMIN_ACTIV_CREATE_005: should validate required fields', () => {
|
|
98
|
+
activities.list.clickCreate()
|
|
99
|
+
activities.form.validateFormVisible()
|
|
100
|
+
|
|
101
|
+
// Try to submit without filling required fields
|
|
102
|
+
activities.submitForm()
|
|
103
|
+
|
|
104
|
+
// Form should still be visible (validation failed)
|
|
105
|
+
activities.form.validateFormVisible()
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('ADMIN_ACTIV_CREATE_006: should cancel activity creation', () => {
|
|
109
|
+
activities.list.clickCreate()
|
|
110
|
+
activities.form.validateFormVisible()
|
|
111
|
+
|
|
112
|
+
activities.fillActivityForm({
|
|
113
|
+
type: 'call',
|
|
114
|
+
subject: 'Should not be created'
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
activities.form.cancel()
|
|
118
|
+
cy.url().should('not.include', '/create')
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
describe('READ - Admin can read activities', () => {
|
|
123
|
+
it('ADMIN_ACTIV_READ_001: should view activity list', () => {
|
|
124
|
+
activities.list.validatePageVisible()
|
|
125
|
+
activities.list.validateTableVisible()
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
it('ADMIN_ACTIV_READ_002: should view activity details', () => {
|
|
129
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
130
|
+
if ($rows.length > 0) {
|
|
131
|
+
activities.list.clickRowByIndex(0)
|
|
132
|
+
cy.url().should('match', /\/dashboard\/activities\/[a-z0-9-]+/)
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('ADMIN_ACTIV_READ_003: should search activities', () => {
|
|
138
|
+
activities.list.search('test')
|
|
139
|
+
cy.wait(500)
|
|
140
|
+
activities.list.clearSearch()
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
describe('UPDATE - Admin can update activities', () => {
|
|
145
|
+
it('ADMIN_ACTIV_UPDATE_001: should edit activity subject', () => {
|
|
146
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
147
|
+
if ($rows.length > 0) {
|
|
148
|
+
activities.list.clickRowByIndex(0)
|
|
149
|
+
|
|
150
|
+
cy.url().then(url => {
|
|
151
|
+
const activityId = url.split('/').pop()
|
|
152
|
+
activities.form.visitEdit(activityId!)
|
|
153
|
+
activities.form.validateFormVisible()
|
|
154
|
+
|
|
155
|
+
const updatedSubject = `Admin Updated ${Date.now()}`
|
|
156
|
+
activities.form.typeInField('subject', updatedSubject)
|
|
157
|
+
|
|
158
|
+
activities.submitForm()
|
|
159
|
+
|
|
160
|
+
cy.url().should('include', '/dashboard/activities')
|
|
161
|
+
cy.contains(updatedSubject).should('be.visible')
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
it('ADMIN_ACTIV_UPDATE_002: should update activity type', () => {
|
|
168
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
169
|
+
if ($rows.length > 0) {
|
|
170
|
+
activities.list.clickRowByIndex(0)
|
|
171
|
+
|
|
172
|
+
cy.url().then(url => {
|
|
173
|
+
const activityId = url.split('/').pop()
|
|
174
|
+
activities.form.visitEdit(activityId!)
|
|
175
|
+
activities.form.validateFormVisible()
|
|
176
|
+
|
|
177
|
+
activities.form.selectOption('type', 'meeting')
|
|
178
|
+
|
|
179
|
+
activities.submitForm()
|
|
180
|
+
cy.url().should('include', '/dashboard/activities')
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('ADMIN_ACTIV_UPDATE_003: should cancel update without saving', () => {
|
|
187
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
188
|
+
if ($rows.length > 0) {
|
|
189
|
+
activities.list.clickRowByIndex(0)
|
|
190
|
+
|
|
191
|
+
cy.url().then(url => {
|
|
192
|
+
const activityId = url.split('/').pop()
|
|
193
|
+
activities.form.visitEdit(activityId!)
|
|
194
|
+
activities.form.validateFormVisible()
|
|
195
|
+
|
|
196
|
+
activities.form.typeInField('subject', 'ShouldNotSave')
|
|
197
|
+
|
|
198
|
+
activities.form.cancel()
|
|
199
|
+
cy.url().should('not.include', '/edit')
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
})
|
|
203
|
+
})
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
describe('DELETE - Admin can delete activities', () => {
|
|
207
|
+
it('ADMIN_ACTIV_DELETE_001: should delete activity successfully', () => {
|
|
208
|
+
const timestamp = Date.now()
|
|
209
|
+
const subject = `Admin Delete Test ${timestamp}`
|
|
210
|
+
|
|
211
|
+
activities.list.clickCreate()
|
|
212
|
+
activities.fillActivityForm({
|
|
213
|
+
type: 'task',
|
|
214
|
+
subject
|
|
215
|
+
})
|
|
216
|
+
activities.submitForm()
|
|
217
|
+
|
|
218
|
+
cy.contains(subject).should('be.visible')
|
|
219
|
+
|
|
220
|
+
activities.list.search(subject)
|
|
221
|
+
|
|
222
|
+
cy.get(activities.list.selectors.rowGeneric).first().within(() => {
|
|
223
|
+
cy.get('[data-cy*="delete"]').click()
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
activities.list.confirmDelete()
|
|
227
|
+
|
|
228
|
+
cy.wait(1000)
|
|
229
|
+
activities.list.search(subject)
|
|
230
|
+
cy.get(activities.list.selectors.emptyState).should('be.visible')
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it('ADMIN_ACTIV_DELETE_002: should cancel deletion', () => {
|
|
234
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
235
|
+
if ($rows.length > 0) {
|
|
236
|
+
cy.get(activities.list.selectors.rowGeneric).first().within(() => {
|
|
237
|
+
cy.get('[data-cy*="delete"]').click()
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
activities.list.cancelDelete()
|
|
241
|
+
activities.list.validateTableVisible()
|
|
242
|
+
}
|
|
243
|
+
})
|
|
244
|
+
})
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
describe('PERMISSIONS - Admin role capabilities', () => {
|
|
248
|
+
it('ADMIN_ACTIV_PERM_001: should have full CRUD access', () => {
|
|
249
|
+
activities.list.validatePageVisible()
|
|
250
|
+
|
|
251
|
+
// Check for create button
|
|
252
|
+
cy.get(activities.list.selectors.createButton).should('be.visible')
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
it('ADMIN_ACTIV_PERM_002: should have edit access', () => {
|
|
256
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
257
|
+
if ($rows.length > 0) {
|
|
258
|
+
activities.list.clickRowByIndex(0)
|
|
259
|
+
cy.url().then(url => {
|
|
260
|
+
const activityId = url.split('/').pop()
|
|
261
|
+
activities.form.visitEdit(activityId!)
|
|
262
|
+
activities.form.validateFormVisible()
|
|
263
|
+
})
|
|
264
|
+
}
|
|
265
|
+
})
|
|
266
|
+
})
|
|
267
|
+
})
|
|
268
|
+
})
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Activities CRUD - Member Role (Read + Update Only)
|
|
5
|
+
*
|
|
6
|
+
* Uses CRM theme-specific POMs with Entity Testing Convention.
|
|
7
|
+
* Selectors follow the pattern: {slug}-{component}-{detail}
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { ActivitiesPOM } from '../../../src/entities/ActivitiesPOM'
|
|
11
|
+
import { loginAsCrmMember } from '../../../src/session-helpers'
|
|
12
|
+
|
|
13
|
+
describe('Activities CRUD - Member Role (Read + Update Only)', () => {
|
|
14
|
+
const activities = new ActivitiesPOM()
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
loginAsCrmMember()
|
|
18
|
+
cy.visit('/dashboard/activities')
|
|
19
|
+
activities.list.validatePageVisible()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
describe('READ - Member CAN view activities', () => {
|
|
23
|
+
it('MEMBER_ACTIV_READ_001: should view activity list', () => {
|
|
24
|
+
activities.list.validatePageVisible()
|
|
25
|
+
activities.list.validateTableVisible()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('MEMBER_ACTIV_READ_002: should view activity details', () => {
|
|
29
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
30
|
+
if ($rows.length > 0) {
|
|
31
|
+
activities.list.clickRowByIndex(0)
|
|
32
|
+
cy.url().should('match', /\/dashboard\/activities\/[a-z0-9-]+/)
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('MEMBER_ACTIV_READ_003: should search activities', () => {
|
|
38
|
+
activities.list.search('test')
|
|
39
|
+
cy.wait(500)
|
|
40
|
+
activities.list.clearSearch()
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('UPDATE - Member CAN edit activities', () => {
|
|
45
|
+
it('MEMBER_ACTIV_UPDATE_001: should edit existing activity', () => {
|
|
46
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
47
|
+
if ($rows.length > 0) {
|
|
48
|
+
activities.list.clickRowByIndex(0)
|
|
49
|
+
|
|
50
|
+
cy.url().then(url => {
|
|
51
|
+
const activityId = url.split('/').pop()
|
|
52
|
+
activities.form.visitEdit(activityId!)
|
|
53
|
+
activities.form.validateFormVisible()
|
|
54
|
+
|
|
55
|
+
// Verify fields are enabled (Member can edit)
|
|
56
|
+
cy.get(activities.form.selectors.field('subject')).within(() => {
|
|
57
|
+
cy.get('input, textarea').should('not.be.disabled')
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('MEMBER_ACTIV_UPDATE_002: should update activity subject', () => {
|
|
65
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
66
|
+
if ($rows.length > 0) {
|
|
67
|
+
activities.list.clickRowByIndex(0)
|
|
68
|
+
|
|
69
|
+
cy.url().then(url => {
|
|
70
|
+
const activityId = url.split('/').pop()
|
|
71
|
+
activities.form.visitEdit(activityId!)
|
|
72
|
+
activities.form.validateFormVisible()
|
|
73
|
+
|
|
74
|
+
const updatedSubject = `Member Updated ${Date.now()}`
|
|
75
|
+
activities.form.typeInField('subject', updatedSubject)
|
|
76
|
+
|
|
77
|
+
activities.submitForm()
|
|
78
|
+
cy.url().should('include', '/dashboard/activities')
|
|
79
|
+
cy.contains(updatedSubject).should('be.visible')
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('MEMBER_ACTIV_UPDATE_003: should update activity type', () => {
|
|
86
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
87
|
+
if ($rows.length > 0) {
|
|
88
|
+
activities.list.clickRowByIndex(0)
|
|
89
|
+
|
|
90
|
+
cy.url().then(url => {
|
|
91
|
+
const activityId = url.split('/').pop()
|
|
92
|
+
activities.form.visitEdit(activityId!)
|
|
93
|
+
activities.form.validateFormVisible()
|
|
94
|
+
|
|
95
|
+
activities.form.selectOption('type', 'meeting')
|
|
96
|
+
|
|
97
|
+
activities.submitForm()
|
|
98
|
+
cy.url().should('include', '/dashboard/activities')
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('MEMBER_ACTIV_UPDATE_004: should cancel update without saving', () => {
|
|
105
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
106
|
+
if ($rows.length > 0) {
|
|
107
|
+
activities.list.clickRowByIndex(0)
|
|
108
|
+
|
|
109
|
+
cy.url().then(url => {
|
|
110
|
+
const activityId = url.split('/').pop()
|
|
111
|
+
activities.form.visitEdit(activityId!)
|
|
112
|
+
activities.form.validateFormVisible()
|
|
113
|
+
|
|
114
|
+
activities.form.typeInField('subject', 'ShouldNotSave')
|
|
115
|
+
|
|
116
|
+
activities.form.cancel()
|
|
117
|
+
cy.url().should('not.include', '/edit')
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
describe('CREATE - Member CANNOT create activities', () => {
|
|
125
|
+
it('MEMBER_ACTIV_CREATE_001: create button should be hidden', () => {
|
|
126
|
+
cy.get(activities.list.selectors.createButton).should('not.exist')
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it('MEMBER_ACTIV_CREATE_002: should not be able to access create form via UI', () => {
|
|
130
|
+
// Verify no visible way to access create form
|
|
131
|
+
cy.get('[data-cy*="create"], [data-cy*="add"]').should('not.exist')
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('MEMBER_ACTIV_CREATE_003: direct navigation to create form should be blocked', () => {
|
|
135
|
+
cy.visit('/dashboard/activities/create', { failOnStatusCode: false })
|
|
136
|
+
|
|
137
|
+
// Should either redirect or show access denied
|
|
138
|
+
cy.url().then(url => {
|
|
139
|
+
if (url.includes('/dashboard/activities/create')) {
|
|
140
|
+
// If still on create page, should show error
|
|
141
|
+
cy.get('body').should('not.contain', activities.form.selectors.form)
|
|
142
|
+
} else {
|
|
143
|
+
// Should redirect away from create page
|
|
144
|
+
cy.url().should('not.include', '/create')
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
describe('DELETE - Member CANNOT delete activities', () => {
|
|
151
|
+
it('MEMBER_ACTIV_DELETE_001: delete buttons should be hidden', () => {
|
|
152
|
+
cy.get('[data-cy*="delete"]').should('not.exist')
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('MEMBER_ACTIV_DELETE_002: should not see delete action in activity list', () => {
|
|
156
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
157
|
+
if ($rows.length > 0) {
|
|
158
|
+
cy.get(activities.list.selectors.rowGeneric).first().within(() => {
|
|
159
|
+
cy.get('[data-cy*="delete"]').should('not.exist')
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('MEMBER_ACTIV_DELETE_003: should not see delete action in detail view', () => {
|
|
166
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
167
|
+
if ($rows.length > 0) {
|
|
168
|
+
activities.list.clickRowByIndex(0)
|
|
169
|
+
cy.url().should('match', /\/dashboard\/activities\/[a-z0-9-]+/)
|
|
170
|
+
|
|
171
|
+
cy.get('[data-cy*="delete"]').should('not.exist')
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
it('MEMBER_ACTIV_DELETE_004: should NOT delete activity via API', () => {
|
|
177
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
178
|
+
if ($rows.length > 0) {
|
|
179
|
+
cy.get(activities.list.selectors.rowGeneric).first().invoke('attr', 'data-cy').then(dataCy => {
|
|
180
|
+
if (dataCy) {
|
|
181
|
+
const activityId = dataCy.replace('activities-row-', '')
|
|
182
|
+
|
|
183
|
+
cy.request({
|
|
184
|
+
method: 'DELETE',
|
|
185
|
+
url: `/api/v1/activities/${activityId}`,
|
|
186
|
+
failOnStatusCode: false,
|
|
187
|
+
}).then(response => {
|
|
188
|
+
expect(response.status).to.be.oneOf([401, 403, 404])
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
describe('PERMISSIONS - Member role capabilities', () => {
|
|
198
|
+
it('MEMBER_ACTIV_PERM_001: should have read and update access only', () => {
|
|
199
|
+
activities.list.validatePageVisible()
|
|
200
|
+
|
|
201
|
+
// Check for no create button
|
|
202
|
+
cy.get(activities.list.selectors.createButton).should('not.exist')
|
|
203
|
+
|
|
204
|
+
// Check for no delete buttons
|
|
205
|
+
cy.get('[data-cy*="delete"]').should('not.exist')
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it('MEMBER_ACTIV_PERM_002: should have edit access to existing activities', () => {
|
|
209
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
210
|
+
if ($rows.length > 0) {
|
|
211
|
+
activities.list.clickRowByIndex(0)
|
|
212
|
+
cy.url().then(url => {
|
|
213
|
+
const activityId = url.split('/').pop()
|
|
214
|
+
activities.form.visitEdit(activityId!)
|
|
215
|
+
activities.form.validateFormVisible()
|
|
216
|
+
})
|
|
217
|
+
}
|
|
218
|
+
})
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it('MEMBER_ACTIV_PERM_003: should see all organization activities', () => {
|
|
222
|
+
activities.list.validatePageVisible()
|
|
223
|
+
|
|
224
|
+
cy.get(activities.list.selectors.rowGeneric).then($rows => {
|
|
225
|
+
if ($rows.length > 0) {
|
|
226
|
+
cy.get(activities.list.selectors.rowGeneric).should('have.length.at.least', 1)
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
it('MEMBER_ACTIV_PERM_004: should maintain restrictions after page refresh', () => {
|
|
232
|
+
cy.reload()
|
|
233
|
+
|
|
234
|
+
activities.list.validatePageVisible()
|
|
235
|
+
|
|
236
|
+
// Verify restrictions persist
|
|
237
|
+
cy.get(activities.list.selectors.createButton).should('not.exist')
|
|
238
|
+
cy.get('[data-cy*="delete"]').should('not.exist')
|
|
239
|
+
})
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
describe('EDGE CASES - Member Role', () => {
|
|
243
|
+
it('MEMBER_ACTIV_EDGE_001: should handle empty activity list gracefully', () => {
|
|
244
|
+
activities.list.validatePageVisible()
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it('MEMBER_ACTIV_EDGE_002: should not bypass create restriction via URL', () => {
|
|
248
|
+
cy.visit('/dashboard/activities?action=create', { failOnStatusCode: false })
|
|
249
|
+
cy.get(activities.list.selectors.createButton).should('not.exist')
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
it('MEMBER_ACTIV_EDGE_003: should not bypass delete restriction via URL', () => {
|
|
253
|
+
cy.visit('/dashboard/activities?action=delete', { failOnStatusCode: false })
|
|
254
|
+
cy.get('[data-cy*="delete"]').should('not.exist')
|
|
255
|
+
})
|
|
256
|
+
})
|
|
257
|
+
})
|