@nextsparkjs/theme-crm 0.1.0-beta.19 → 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.
Files changed (70) hide show
  1. package/package.json +2 -2
  2. package/tests/cypress/e2e/api/activities/activities-crud.cy.ts +686 -0
  3. package/tests/cypress/e2e/api/campaigns/campaigns-crud.cy.ts +592 -0
  4. package/tests/cypress/e2e/api/companies/companies-crud.cy.ts +682 -0
  5. package/tests/cypress/e2e/api/contacts/contacts-crud.cy.ts +668 -0
  6. package/tests/cypress/e2e/api/leads/leads-crud.cy.ts +648 -0
  7. package/tests/cypress/e2e/api/notes/notes-crud.cy.ts +424 -0
  8. package/tests/cypress/e2e/api/opportunities/opportunities-crud.cy.ts +865 -0
  9. package/tests/cypress/e2e/api/pipelines/pipelines-crud.cy.ts +545 -0
  10. package/tests/cypress/e2e/api/products/products-crud.cy.ts +447 -0
  11. package/tests/cypress/e2e/ui/activities/activities-admin.cy.ts +268 -0
  12. package/tests/cypress/e2e/ui/activities/activities-member.cy.ts +257 -0
  13. package/tests/cypress/e2e/ui/activities/activities-owner.cy.ts +268 -0
  14. package/tests/cypress/e2e/ui/companies/companies-admin.cy.ts +188 -0
  15. package/tests/cypress/e2e/ui/companies/companies-member.cy.ts +166 -0
  16. package/tests/cypress/e2e/ui/companies/companies-owner.cy.ts +189 -0
  17. package/tests/cypress/e2e/ui/contacts/contacts-admin.cy.ts +252 -0
  18. package/tests/cypress/e2e/ui/contacts/contacts-member.cy.ts +224 -0
  19. package/tests/cypress/e2e/ui/contacts/contacts-owner.cy.ts +236 -0
  20. package/tests/cypress/e2e/ui/leads/leads-admin.cy.ts +286 -0
  21. package/tests/cypress/e2e/ui/leads/leads-member.cy.ts +193 -0
  22. package/tests/cypress/e2e/ui/leads/leads-owner.cy.ts +210 -0
  23. package/tests/cypress/e2e/ui/opportunities/opportunities-admin.cy.ts +197 -0
  24. package/tests/cypress/e2e/ui/opportunities/opportunities-member.cy.ts +229 -0
  25. package/tests/cypress/e2e/ui/opportunities/opportunities-owner.cy.ts +196 -0
  26. package/tests/cypress/e2e/ui/pipelines/pipelines-admin.cy.ts +320 -0
  27. package/tests/cypress/e2e/ui/pipelines/pipelines-member.cy.ts +262 -0
  28. package/tests/cypress/e2e/ui/pipelines/pipelines-owner.cy.ts +282 -0
  29. package/tests/cypress/fixtures/blocks.json +9 -0
  30. package/tests/cypress/fixtures/entities.json +240 -0
  31. package/tests/cypress/src/components/CRMDataTable.js +223 -0
  32. package/tests/cypress/src/components/CRMMobileNav.js +138 -0
  33. package/tests/cypress/src/components/CRMSidebar.js +145 -0
  34. package/tests/cypress/src/components/CRMTopBar.js +194 -0
  35. package/tests/cypress/src/components/DealCard.js +197 -0
  36. package/tests/cypress/src/components/EntityDetail.ts +290 -0
  37. package/tests/cypress/src/components/EntityForm.ts +357 -0
  38. package/tests/cypress/src/components/EntityList.ts +360 -0
  39. package/tests/cypress/src/components/PipelineKanban.js +204 -0
  40. package/tests/cypress/src/components/StageColumn.js +196 -0
  41. package/tests/cypress/src/components/index.js +13 -0
  42. package/tests/cypress/src/components/index.ts +22 -0
  43. package/tests/cypress/src/controllers/ActivityAPIController.ts +113 -0
  44. package/tests/cypress/src/controllers/BaseAPIController.ts +307 -0
  45. package/tests/cypress/src/controllers/CampaignAPIController.ts +114 -0
  46. package/tests/cypress/src/controllers/CompanyAPIController.ts +112 -0
  47. package/tests/cypress/src/controllers/ContactAPIController.ts +104 -0
  48. package/tests/cypress/src/controllers/LeadAPIController.ts +96 -0
  49. package/tests/cypress/src/controllers/NoteAPIController.ts +130 -0
  50. package/tests/cypress/src/controllers/OpportunityAPIController.ts +134 -0
  51. package/tests/cypress/src/controllers/PipelineAPIController.ts +116 -0
  52. package/tests/cypress/src/controllers/ProductAPIController.ts +113 -0
  53. package/tests/cypress/src/controllers/index.ts +35 -0
  54. package/tests/cypress/src/entities/ActivitiesPOM.ts +130 -0
  55. package/tests/cypress/src/entities/CompaniesPOM.ts +117 -0
  56. package/tests/cypress/src/entities/ContactsPOM.ts +117 -0
  57. package/tests/cypress/src/entities/LeadsPOM.ts +129 -0
  58. package/tests/cypress/src/entities/OpportunitiesPOM.ts +178 -0
  59. package/tests/cypress/src/entities/PipelinesPOM.ts +341 -0
  60. package/tests/cypress/src/entities/index.ts +31 -0
  61. package/tests/cypress/src/forms/OpportunityForm.js +316 -0
  62. package/tests/cypress/src/forms/PipelineForm.js +243 -0
  63. package/tests/cypress/src/forms/index.js +8 -0
  64. package/tests/cypress/src/index.js +22 -0
  65. package/tests/cypress/src/index.ts +68 -0
  66. package/tests/cypress/src/selectors.ts +50 -0
  67. package/tests/cypress/src/session-helpers.ts +94 -0
  68. package/tests/cypress/support/e2e.ts +89 -0
  69. package/tests/cypress.config.ts +165 -0
  70. package/tests/tsconfig.json +15 -0
@@ -0,0 +1,268 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /**
4
+ * Activities 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 { ActivitiesPOM } from '../../../src/entities/ActivitiesPOM'
11
+ import { loginAsCrmOwner } from '../../../src/session-helpers'
12
+
13
+ describe('Activities CRUD - Owner Role (Full Access)', () => {
14
+ const activities = new ActivitiesPOM()
15
+
16
+ beforeEach(() => {
17
+ loginAsCrmOwner()
18
+ cy.visit('/dashboard/activities')
19
+ activities.list.validatePageVisible()
20
+ })
21
+
22
+ describe('CREATE - Owner can create activities', () => {
23
+ it('OWNER_ACTIV_CREATE_001: should create new call activity', () => {
24
+ const timestamp = Date.now()
25
+ const subject = `Owner 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('OWNER_ACTIV_CREATE_002: should create meeting activity with all fields', () => {
42
+ const timestamp = Date.now()
43
+ const subject = `Owner Meeting ${timestamp}`
44
+
45
+ activities.list.clickCreate()
46
+ activities.form.validateFormVisible()
47
+
48
+ activities.fillActivityForm({
49
+ type: 'meeting',
50
+ subject,
51
+ description: 'Team sync 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('OWNER_ACTIV_CREATE_003: should create email activity', () => {
61
+ const timestamp = Date.now()
62
+ const subject = `Owner 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('OWNER_ACTIV_CREATE_004: should create task activity', () => {
79
+ const timestamp = Date.now()
80
+ const subject = `Owner Task ${timestamp}`
81
+
82
+ activities.list.clickCreate()
83
+ activities.form.validateFormVisible()
84
+
85
+ activities.fillActivityForm({
86
+ type: 'task',
87
+ subject,
88
+ description: 'Prepare report'
89
+ })
90
+
91
+ activities.submitForm()
92
+
93
+ cy.url().should('include', '/dashboard/activities')
94
+ cy.contains(subject).should('be.visible')
95
+ })
96
+
97
+ it('OWNER_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('OWNER_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 - Owner can read activities', () => {
123
+ it('OWNER_ACTIV_READ_001: should view activity list', () => {
124
+ activities.list.validatePageVisible()
125
+ activities.list.validateTableVisible()
126
+ })
127
+
128
+ it('OWNER_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('OWNER_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 - Owner can update activities', () => {
145
+ it('OWNER_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 = `Owner 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('OWNER_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('OWNER_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 - Owner can delete activities', () => {
207
+ it('OWNER_ACTIV_DELETE_001: should delete activity successfully', () => {
208
+ const timestamp = Date.now()
209
+ const subject = `Owner 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('OWNER_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 - Owner role capabilities', () => {
248
+ it('OWNER_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('OWNER_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,188 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /**
4
+ * Companies 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 { CompaniesPOM } from '../../../src/entities/CompaniesPOM'
11
+ import { loginAsCrmAdmin } from '../../../src/session-helpers'
12
+
13
+ describe('Companies CRUD - Admin Role (Full Access)', () => {
14
+ const companies = new CompaniesPOM()
15
+
16
+ beforeEach(() => {
17
+ loginAsCrmAdmin()
18
+ cy.visit('/dashboard/companies')
19
+ companies.list.validatePageVisible()
20
+ })
21
+
22
+ describe('CREATE - Admin can create companies', () => {
23
+ it('ADMIN_COMPANY_CREATE_001: should create new company with required fields', () => {
24
+ const timestamp = Date.now()
25
+ const companyName = `Admin Test Company ${timestamp}`
26
+
27
+ companies.list.clickCreate()
28
+ companies.form.validateFormVisible()
29
+
30
+ companies.fillCompanyForm({
31
+ name: companyName,
32
+ industry: 'retail'
33
+ })
34
+
35
+ companies.submitForm()
36
+
37
+ cy.url().should('include', '/dashboard/companies')
38
+ cy.contains(companyName).should('be.visible')
39
+ })
40
+
41
+ it('ADMIN_COMPANY_CREATE_002: should create company with optional fields', () => {
42
+ const timestamp = Date.now()
43
+ const companyName = `Admin Full Company ${timestamp}`
44
+
45
+ companies.list.clickCreate()
46
+ companies.form.validateFormVisible()
47
+
48
+ companies.fillCompanyForm({
49
+ name: companyName,
50
+ industry: 'manufacturing',
51
+ website: 'https://admin-company.com',
52
+ phone: '+1-555-4444'
53
+ })
54
+
55
+ companies.submitForm()
56
+
57
+ cy.url().should('include', '/dashboard/companies')
58
+ cy.contains(companyName).should('be.visible')
59
+ })
60
+ })
61
+
62
+ describe('READ - Admin can read companies', () => {
63
+ it('ADMIN_COMPANY_READ_001: should view company list', () => {
64
+ companies.list.validatePageVisible()
65
+ companies.list.validateTableVisible()
66
+ })
67
+
68
+ it('ADMIN_COMPANY_READ_002: should view company details', () => {
69
+ cy.get(companies.list.selectors.rowGeneric).then($rows => {
70
+ if ($rows.length > 0) {
71
+ companies.list.clickRowByIndex(0)
72
+ cy.url().should('match', /\/dashboard\/companies\/[a-z0-9-]+/)
73
+ }
74
+ })
75
+ })
76
+
77
+ it('ADMIN_COMPANY_READ_003: should search companies', () => {
78
+ companies.list.search('test')
79
+ cy.wait(500)
80
+ companies.list.clearSearch()
81
+ })
82
+ })
83
+
84
+ describe('UPDATE - Admin can update companies', () => {
85
+ it('ADMIN_COMPANY_UPDATE_001: should edit company', () => {
86
+ cy.get(companies.list.selectors.rowGeneric).then($rows => {
87
+ if ($rows.length > 0) {
88
+ companies.list.clickRowByIndex(0)
89
+
90
+ cy.url().then(url => {
91
+ const companyId = url.split('/').pop()
92
+ companies.form.visitEdit(companyId!)
93
+ companies.form.validateFormVisible()
94
+
95
+ const updatedName = `Admin Updated Company ${Date.now()}`
96
+ companies.form.typeInField('name', updatedName)
97
+
98
+ companies.submitForm()
99
+
100
+ cy.url().should('include', '/dashboard/companies')
101
+ cy.contains(updatedName).should('be.visible')
102
+ })
103
+ }
104
+ })
105
+ })
106
+
107
+ it('ADMIN_COMPANY_UPDATE_002: should update company contact information', () => {
108
+ cy.get(companies.list.selectors.rowGeneric).then($rows => {
109
+ if ($rows.length > 0) {
110
+ companies.list.clickRowByIndex(0)
111
+
112
+ cy.url().then(url => {
113
+ const companyId = url.split('/').pop()
114
+ companies.form.visitEdit(companyId!)
115
+ companies.form.validateFormVisible()
116
+
117
+ const timestamp = Date.now()
118
+ companies.form.typeInField('phone', `+1-555-${timestamp % 10000}`)
119
+
120
+ companies.submitForm()
121
+
122
+ cy.url().should('include', '/dashboard/companies')
123
+ })
124
+ }
125
+ })
126
+ })
127
+
128
+ it('ADMIN_COMPANY_UPDATE_003: should cancel update without saving', () => {
129
+ cy.get(companies.list.selectors.rowGeneric).then($rows => {
130
+ if ($rows.length > 0) {
131
+ companies.list.clickRowByIndex(0)
132
+
133
+ cy.url().then(url => {
134
+ const companyId = url.split('/').pop()
135
+ companies.form.visitEdit(companyId!)
136
+ companies.form.validateFormVisible()
137
+
138
+ companies.form.typeInField('name', 'ShouldNotSave')
139
+
140
+ companies.form.cancel()
141
+ cy.url().should('not.include', '/edit')
142
+ })
143
+ }
144
+ })
145
+ })
146
+ })
147
+
148
+ describe('DELETE - Admin can delete companies', () => {
149
+ it('ADMIN_COMPANY_DELETE_001: should delete company successfully', () => {
150
+ const timestamp = Date.now()
151
+ const companyName = `Admin Delete Test ${timestamp}`
152
+
153
+ companies.list.clickCreate()
154
+ companies.fillCompanyForm({
155
+ name: companyName,
156
+ industry: 'education'
157
+ })
158
+ companies.submitForm()
159
+
160
+ cy.contains(companyName).should('be.visible')
161
+
162
+ companies.list.search(companyName)
163
+
164
+ cy.get(companies.list.selectors.rowGeneric).first().within(() => {
165
+ cy.get('[data-cy*="delete"]').click()
166
+ })
167
+
168
+ companies.list.confirmDelete()
169
+
170
+ cy.wait(1000)
171
+ companies.list.search(companyName)
172
+ cy.get(companies.list.selectors.emptyState).should('be.visible')
173
+ })
174
+
175
+ it('ADMIN_COMPANY_DELETE_002: should cancel deletion', () => {
176
+ cy.get(companies.list.selectors.rowGeneric).then($rows => {
177
+ if ($rows.length > 0) {
178
+ cy.get(companies.list.selectors.rowGeneric).first().within(() => {
179
+ cy.get('[data-cy*="delete"]').click()
180
+ })
181
+
182
+ companies.list.cancelDelete()
183
+ companies.list.validateTableVisible()
184
+ }
185
+ })
186
+ })
187
+ })
188
+ })
@@ -0,0 +1,166 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /**
4
+ * Companies CRUD - Member Role (Restricted: Read Only)
5
+ *
6
+ * Uses CRM theme-specific POMs with Entity Testing Convention.
7
+ * Selectors follow the pattern: {slug}-{component}-{detail}
8
+ */
9
+
10
+ import { CompaniesPOM } from '../../../src/entities/CompaniesPOM'
11
+ import { loginAsCrmMember } from '../../../src/session-helpers'
12
+
13
+ describe('Companies CRUD - Member Role (Restricted: Read Only)', () => {
14
+ const companies = new CompaniesPOM()
15
+
16
+ beforeEach(() => {
17
+ loginAsCrmMember()
18
+ cy.visit('/dashboard/companies')
19
+ companies.list.validatePageVisible()
20
+ })
21
+
22
+ describe('READ - Member CAN view companies', () => {
23
+ it('MEMBER_COMPANY_READ_001: should view company list', () => {
24
+ companies.list.validatePageVisible()
25
+ companies.list.validateTableVisible()
26
+ })
27
+
28
+ it('MEMBER_COMPANY_READ_002: should view company details', () => {
29
+ cy.get(companies.list.selectors.rowGeneric).then($rows => {
30
+ if ($rows.length > 0) {
31
+ companies.list.clickRowByIndex(0)
32
+ cy.url().should('match', /\/dashboard\/companies\/[a-z0-9-]+/)
33
+ }
34
+ })
35
+ })
36
+
37
+ it('MEMBER_COMPANY_READ_003: should search companies', () => {
38
+ companies.list.search('test')
39
+ cy.wait(500)
40
+ companies.list.clearSearch()
41
+ })
42
+ })
43
+
44
+ describe('CREATE - Member CANNOT create companies', () => {
45
+ it('MEMBER_COMPANY_CREATE_001: create button should be hidden', () => {
46
+ cy.get(companies.list.selectors.createButton).should('not.exist')
47
+ })
48
+
49
+ it('MEMBER_COMPANY_CREATE_002: should not be able to access create form via UI', () => {
50
+ // Verify no visible way to access create form
51
+ cy.get('[data-cy*="create"], [data-cy*="add"]').should('not.exist')
52
+ })
53
+
54
+ it('MEMBER_COMPANY_CREATE_003: direct navigation to create form should be blocked', () => {
55
+ cy.visit('/dashboard/companies/create', { failOnStatusCode: false })
56
+
57
+ // Should either redirect or show access denied
58
+ cy.url().then(url => {
59
+ if (url.includes('/dashboard/companies/create')) {
60
+ // If still on create page, should show error
61
+ cy.get('body').should('not.contain', companies.form.selectors.form)
62
+ } else {
63
+ // Should redirect away from create page
64
+ cy.url().should('not.include', '/create')
65
+ }
66
+ })
67
+ })
68
+ })
69
+
70
+ describe('UPDATE - Member CANNOT update companies', () => {
71
+ it('MEMBER_COMPANY_UPDATE_001: edit buttons should be hidden', () => {
72
+ cy.get('[data-cy*="edit"]').should('not.exist')
73
+ })
74
+
75
+ it('MEMBER_COMPANY_UPDATE_002: should not see edit action in company list', () => {
76
+ cy.get(companies.list.selectors.rowGeneric).then($rows => {
77
+ if ($rows.length > 0) {
78
+ cy.get(companies.list.selectors.rowGeneric).first().within(() => {
79
+ cy.get('[data-cy*="edit"]').should('not.exist')
80
+ })
81
+ }
82
+ })
83
+ })
84
+
85
+ it('MEMBER_COMPANY_UPDATE_003: should not see edit action in detail view', () => {
86
+ cy.get(companies.list.selectors.rowGeneric).then($rows => {
87
+ if ($rows.length > 0) {
88
+ companies.list.clickRowByIndex(0)
89
+ cy.url().should('match', /\/dashboard\/companies\/[a-z0-9-]+/)
90
+
91
+ cy.get('[data-cy*="edit"]').should('not.exist')
92
+ }
93
+ })
94
+ })
95
+ })
96
+
97
+ describe('DELETE - Member CANNOT delete companies', () => {
98
+ it('MEMBER_COMPANY_DELETE_001: delete buttons should be hidden', () => {
99
+ cy.get('[data-cy*="delete"]').should('not.exist')
100
+ })
101
+
102
+ it('MEMBER_COMPANY_DELETE_002: should not see delete action in company list', () => {
103
+ cy.get(companies.list.selectors.rowGeneric).then($rows => {
104
+ if ($rows.length > 0) {
105
+ cy.get(companies.list.selectors.rowGeneric).first().within(() => {
106
+ cy.get('[data-cy*="delete"]').should('not.exist')
107
+ })
108
+ }
109
+ })
110
+ })
111
+
112
+ it('MEMBER_COMPANY_DELETE_003: should not see delete action in detail view', () => {
113
+ cy.get(companies.list.selectors.rowGeneric).then($rows => {
114
+ if ($rows.length > 0) {
115
+ companies.list.clickRowByIndex(0)
116
+ cy.url().should('match', /\/dashboard\/companies\/[a-z0-9-]+/)
117
+
118
+ cy.get('[data-cy*="delete"]').should('not.exist')
119
+ }
120
+ })
121
+ })
122
+
123
+ it('MEMBER_COMPANY_DELETE_004: should NOT delete company via API', () => {
124
+ cy.get(companies.list.selectors.rowGeneric).then($rows => {
125
+ if ($rows.length > 0) {
126
+ cy.get(companies.list.selectors.rowGeneric).first().invoke('attr', 'data-cy').then(dataCy => {
127
+ if (dataCy) {
128
+ const companyId = dataCy.replace('companies-row-', '')
129
+
130
+ cy.request({
131
+ method: 'DELETE',
132
+ url: `/api/v1/companies/${companyId}`,
133
+ failOnStatusCode: false,
134
+ }).then(response => {
135
+ expect(response.status).to.be.oneOf([401, 403, 404])
136
+ })
137
+ }
138
+ })
139
+ }
140
+ })
141
+ })
142
+ })
143
+
144
+ describe('PERMISSIONS - Member role capabilities', () => {
145
+ it('MEMBER_COMPANY_PERMISSIONS_001: should have read-only access', () => {
146
+ companies.list.validatePageVisible()
147
+
148
+ // Check for no create button
149
+ cy.get(companies.list.selectors.createButton).should('not.exist')
150
+
151
+ // Check for no edit/delete buttons
152
+ cy.get('[data-cy*="edit"]').should('not.exist')
153
+ cy.get('[data-cy*="delete"]').should('not.exist')
154
+ })
155
+
156
+ it('MEMBER_COMPANY_PERMISSIONS_002: should see all organization companies', () => {
157
+ companies.list.validatePageVisible()
158
+
159
+ cy.get(companies.list.selectors.rowGeneric).then($rows => {
160
+ if ($rows.length > 0) {
161
+ cy.get(companies.list.selectors.rowGeneric).should('have.length.at.least', 1)
162
+ }
163
+ })
164
+ })
165
+ })
166
+ })