@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,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpportunityForm - Page Object Model Class
|
|
3
|
+
*
|
|
4
|
+
* POM for the opportunity/deal create/edit form in CRM theme.
|
|
5
|
+
* Handles opportunity form interactions and validations.
|
|
6
|
+
*/
|
|
7
|
+
export class OpportunityForm {
|
|
8
|
+
static selectors = {
|
|
9
|
+
form: '[data-cy="opportunity-form"]',
|
|
10
|
+
nameInput: '[data-cy="opportunity-field-name"] input',
|
|
11
|
+
nameField: '[data-cy="opportunity-field-name"]',
|
|
12
|
+
companySelect: '[data-cy="opportunity-field-company"]',
|
|
13
|
+
companyInput: '[data-cy="opportunity-field-company"] select',
|
|
14
|
+
contactSelect: '[data-cy="opportunity-field-contact"]',
|
|
15
|
+
contactInput: '[data-cy="opportunity-field-contact"] select',
|
|
16
|
+
pipelineSelect: '[data-cy="opportunity-field-pipeline"]',
|
|
17
|
+
pipelineInput: '[data-cy="opportunity-field-pipeline"] select',
|
|
18
|
+
stageSelect: '[data-cy="opportunity-field-stage"]',
|
|
19
|
+
stageInput: '[data-cy="opportunity-field-stage"] select',
|
|
20
|
+
amountInput: '[data-cy="opportunity-field-amount"] input',
|
|
21
|
+
amountField: '[data-cy="opportunity-field-amount"]',
|
|
22
|
+
probabilityInput: '[data-cy="opportunity-field-probability"] input',
|
|
23
|
+
probabilityField: '[data-cy="opportunity-field-probability"]',
|
|
24
|
+
expectedCloseDateInput: '[data-cy="opportunity-field-expectedCloseDate"] input',
|
|
25
|
+
expectedCloseDateField: '[data-cy="opportunity-field-expectedCloseDate"]',
|
|
26
|
+
descriptionInput: '[data-cy="opportunity-field-description"] textarea',
|
|
27
|
+
descriptionField: '[data-cy="opportunity-field-description"]',
|
|
28
|
+
ownerSelect: '[data-cy="opportunity-field-owner"]',
|
|
29
|
+
ownerInput: '[data-cy="opportunity-field-owner"] select',
|
|
30
|
+
prioritySelect: '[data-cy="opportunity-field-priority"]',
|
|
31
|
+
priorityInput: '[data-cy="opportunity-field-priority"] select',
|
|
32
|
+
submitBtn: '[data-cy="opportunity-form-submit"]',
|
|
33
|
+
cancelBtn: '[data-cy="opportunity-form-cancel"]',
|
|
34
|
+
error: '[data-cy="opportunity-form-error"]',
|
|
35
|
+
fieldError: '[class*="error"], [data-error="true"]',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Validate form is visible
|
|
40
|
+
*/
|
|
41
|
+
validateVisible() {
|
|
42
|
+
cy.get(OpportunityForm.selectors.form).should('be.visible')
|
|
43
|
+
return this
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Validate form is not visible
|
|
48
|
+
*/
|
|
49
|
+
validateNotVisible() {
|
|
50
|
+
cy.get(OpportunityForm.selectors.form).should('not.exist')
|
|
51
|
+
return this
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Fill opportunity name
|
|
56
|
+
* @param {string} name - Opportunity name
|
|
57
|
+
*/
|
|
58
|
+
fillName(name) {
|
|
59
|
+
cy.get(OpportunityForm.selectors.nameInput).clear().type(name)
|
|
60
|
+
return this
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Clear opportunity name
|
|
65
|
+
*/
|
|
66
|
+
clearName() {
|
|
67
|
+
cy.get(OpportunityForm.selectors.nameInput).clear()
|
|
68
|
+
return this
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Select company
|
|
73
|
+
* @param {string} company - Company name or ID
|
|
74
|
+
*/
|
|
75
|
+
selectCompany(company) {
|
|
76
|
+
cy.get(OpportunityForm.selectors.companyInput).select(company)
|
|
77
|
+
return this
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Select contact
|
|
82
|
+
* @param {string} contact - Contact name or ID
|
|
83
|
+
*/
|
|
84
|
+
selectContact(contact) {
|
|
85
|
+
cy.get(OpportunityForm.selectors.contactInput).select(contact)
|
|
86
|
+
return this
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Select pipeline
|
|
91
|
+
* @param {string} pipeline - Pipeline name or ID
|
|
92
|
+
*/
|
|
93
|
+
selectPipeline(pipeline) {
|
|
94
|
+
cy.get(OpportunityForm.selectors.pipelineInput).select(pipeline)
|
|
95
|
+
return this
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Select stage
|
|
100
|
+
* @param {string} stage - Stage name or ID
|
|
101
|
+
*/
|
|
102
|
+
selectStage(stage) {
|
|
103
|
+
cy.get(OpportunityForm.selectors.stageInput).select(stage)
|
|
104
|
+
return this
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Fill opportunity amount
|
|
109
|
+
* @param {string|number} amount - Opportunity amount
|
|
110
|
+
*/
|
|
111
|
+
fillAmount(amount) {
|
|
112
|
+
cy.get(OpportunityForm.selectors.amountInput).clear().type(amount.toString())
|
|
113
|
+
return this
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Clear opportunity amount
|
|
118
|
+
*/
|
|
119
|
+
clearAmount() {
|
|
120
|
+
cy.get(OpportunityForm.selectors.amountInput).clear()
|
|
121
|
+
return this
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Fill probability percentage
|
|
126
|
+
* @param {string|number} probability - Probability (0-100)
|
|
127
|
+
*/
|
|
128
|
+
fillProbability(probability) {
|
|
129
|
+
cy.get(OpportunityForm.selectors.probabilityInput).clear().type(probability.toString())
|
|
130
|
+
return this
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Clear probability
|
|
135
|
+
*/
|
|
136
|
+
clearProbability() {
|
|
137
|
+
cy.get(OpportunityForm.selectors.probabilityInput).clear()
|
|
138
|
+
return this
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Fill expected close date
|
|
143
|
+
* @param {string} date - Date in YYYY-MM-DD format
|
|
144
|
+
*/
|
|
145
|
+
fillExpectedCloseDate(date) {
|
|
146
|
+
cy.get(OpportunityForm.selectors.expectedCloseDateInput).clear().type(date)
|
|
147
|
+
return this
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Clear expected close date
|
|
152
|
+
*/
|
|
153
|
+
clearExpectedCloseDate() {
|
|
154
|
+
cy.get(OpportunityForm.selectors.expectedCloseDateInput).clear()
|
|
155
|
+
return this
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Fill opportunity description
|
|
160
|
+
* @param {string} description - Opportunity description
|
|
161
|
+
*/
|
|
162
|
+
fillDescription(description) {
|
|
163
|
+
cy.get(OpportunityForm.selectors.descriptionInput).clear().type(description)
|
|
164
|
+
return this
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Clear description
|
|
169
|
+
*/
|
|
170
|
+
clearDescription() {
|
|
171
|
+
cy.get(OpportunityForm.selectors.descriptionInput).clear()
|
|
172
|
+
return this
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Select owner
|
|
177
|
+
* @param {string} owner - Owner name or ID
|
|
178
|
+
*/
|
|
179
|
+
selectOwner(owner) {
|
|
180
|
+
cy.get(OpportunityForm.selectors.ownerInput).select(owner)
|
|
181
|
+
return this
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Select priority
|
|
186
|
+
* @param {string} priority - Priority (low, medium, high)
|
|
187
|
+
*/
|
|
188
|
+
selectPriority(priority) {
|
|
189
|
+
cy.get(OpportunityForm.selectors.priorityInput).select(priority)
|
|
190
|
+
return this
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Submit the form
|
|
195
|
+
*/
|
|
196
|
+
submit() {
|
|
197
|
+
cy.get(OpportunityForm.selectors.submitBtn).click()
|
|
198
|
+
return this
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Cancel the form
|
|
203
|
+
*/
|
|
204
|
+
cancel() {
|
|
205
|
+
cy.get(OpportunityForm.selectors.cancelBtn).click()
|
|
206
|
+
return this
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Validate submit button is enabled
|
|
211
|
+
*/
|
|
212
|
+
validateSubmitEnabled() {
|
|
213
|
+
cy.get(OpportunityForm.selectors.submitBtn).should('not.be.disabled')
|
|
214
|
+
return this
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Validate submit button is disabled
|
|
219
|
+
*/
|
|
220
|
+
validateSubmitDisabled() {
|
|
221
|
+
cy.get(OpportunityForm.selectors.submitBtn).should('be.disabled')
|
|
222
|
+
return this
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Validate form error message
|
|
227
|
+
* @param {string} message - Expected error message
|
|
228
|
+
*/
|
|
229
|
+
validateError(message) {
|
|
230
|
+
cy.get(OpportunityForm.selectors.error).should('be.visible').and('contain', message)
|
|
231
|
+
return this
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Validate no form error
|
|
236
|
+
*/
|
|
237
|
+
validateNoError() {
|
|
238
|
+
cy.get(OpportunityForm.selectors.error).should('not.exist')
|
|
239
|
+
return this
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Validate field error
|
|
244
|
+
* @param {string} fieldName - Field name
|
|
245
|
+
*/
|
|
246
|
+
validateFieldError(fieldName) {
|
|
247
|
+
const fieldSelector = OpportunityForm.selectors[`${fieldName}Field`]
|
|
248
|
+
cy.get(fieldSelector).within(() => {
|
|
249
|
+
cy.get(OpportunityForm.selectors.fieldError).should('exist')
|
|
250
|
+
})
|
|
251
|
+
return this
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Validate no field error
|
|
256
|
+
* @param {string} fieldName - Field name
|
|
257
|
+
*/
|
|
258
|
+
validateNoFieldError(fieldName) {
|
|
259
|
+
const fieldSelector = OpportunityForm.selectors[`${fieldName}Field`]
|
|
260
|
+
cy.get(fieldSelector).within(() => {
|
|
261
|
+
cy.get(OpportunityForm.selectors.fieldError).should('not.exist')
|
|
262
|
+
})
|
|
263
|
+
return this
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Validate field value
|
|
268
|
+
* @param {string} fieldName - Field name (name, amount, probability, etc.)
|
|
269
|
+
* @param {string} value - Expected value
|
|
270
|
+
*/
|
|
271
|
+
validateFieldValue(fieldName, value) {
|
|
272
|
+
const inputSelector = OpportunityForm.selectors[`${fieldName}Input`]
|
|
273
|
+
cy.get(inputSelector).should('have.value', value)
|
|
274
|
+
return this
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Fill complete opportunity form
|
|
279
|
+
* @param {Object} data - Opportunity data
|
|
280
|
+
* @param {string} data.name - Opportunity name
|
|
281
|
+
* @param {string} data.company - Company ID
|
|
282
|
+
* @param {string} data.contact - Contact ID (optional)
|
|
283
|
+
* @param {string} data.pipeline - Pipeline ID
|
|
284
|
+
* @param {string} data.stage - Stage ID
|
|
285
|
+
* @param {number} data.amount - Amount
|
|
286
|
+
* @param {number} data.probability - Probability (optional)
|
|
287
|
+
* @param {string} data.expectedCloseDate - Expected close date (optional)
|
|
288
|
+
* @param {string} data.description - Description (optional)
|
|
289
|
+
* @param {string} data.owner - Owner ID (optional)
|
|
290
|
+
* @param {string} data.priority - Priority (optional)
|
|
291
|
+
*/
|
|
292
|
+
fillForm(data) {
|
|
293
|
+
if (data.name) this.fillName(data.name)
|
|
294
|
+
if (data.company) this.selectCompany(data.company)
|
|
295
|
+
if (data.contact) this.selectContact(data.contact)
|
|
296
|
+
if (data.pipeline) this.selectPipeline(data.pipeline)
|
|
297
|
+
if (data.stage) this.selectStage(data.stage)
|
|
298
|
+
if (data.amount !== undefined) this.fillAmount(data.amount)
|
|
299
|
+
if (data.probability !== undefined) this.fillProbability(data.probability)
|
|
300
|
+
if (data.expectedCloseDate) this.fillExpectedCloseDate(data.expectedCloseDate)
|
|
301
|
+
if (data.description) this.fillDescription(data.description)
|
|
302
|
+
if (data.owner) this.selectOwner(data.owner)
|
|
303
|
+
if (data.priority) this.selectPriority(data.priority)
|
|
304
|
+
return this
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Create an opportunity (fill and submit)
|
|
309
|
+
* @param {Object} data - Opportunity data
|
|
310
|
+
*/
|
|
311
|
+
createOpportunity(data) {
|
|
312
|
+
this.fillForm(data)
|
|
313
|
+
this.submit()
|
|
314
|
+
return this
|
|
315
|
+
}
|
|
316
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PipelineForm - Page Object Model Class
|
|
3
|
+
*
|
|
4
|
+
* POM for the pipeline create/edit form in CRM theme.
|
|
5
|
+
* Handles pipeline form interactions and validations.
|
|
6
|
+
*/
|
|
7
|
+
export class PipelineForm {
|
|
8
|
+
static selectors = {
|
|
9
|
+
form: '[data-cy="pipeline-form"]',
|
|
10
|
+
nameInput: '[data-cy="pipeline-field-name"] input',
|
|
11
|
+
nameField: '[data-cy="pipeline-field-name"]',
|
|
12
|
+
typeSelect: '[data-cy="pipeline-field-type"]',
|
|
13
|
+
typeInput: '[data-cy="pipeline-field-type"] select',
|
|
14
|
+
descriptionInput: '[data-cy="pipeline-field-description"] textarea',
|
|
15
|
+
descriptionField: '[data-cy="pipeline-field-description"]',
|
|
16
|
+
isActiveCheckbox: '[data-cy="pipeline-field-isActive"] input[type="checkbox"]',
|
|
17
|
+
isActiveField: '[data-cy="pipeline-field-isActive"]',
|
|
18
|
+
submitBtn: '[data-cy="pipeline-form-submit"]',
|
|
19
|
+
cancelBtn: '[data-cy="pipeline-form-cancel"]',
|
|
20
|
+
error: '[data-cy="pipeline-form-error"]',
|
|
21
|
+
fieldError: '[class*="error"], [data-error="true"]',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Validate form is visible
|
|
26
|
+
*/
|
|
27
|
+
validateVisible() {
|
|
28
|
+
cy.get(PipelineForm.selectors.form).should('be.visible')
|
|
29
|
+
return this
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Validate form is not visible
|
|
34
|
+
*/
|
|
35
|
+
validateNotVisible() {
|
|
36
|
+
cy.get(PipelineForm.selectors.form).should('not.exist')
|
|
37
|
+
return this
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Fill pipeline name
|
|
42
|
+
* @param {string} name - Pipeline name
|
|
43
|
+
*/
|
|
44
|
+
fillName(name) {
|
|
45
|
+
cy.get(PipelineForm.selectors.nameInput).clear().type(name)
|
|
46
|
+
return this
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Clear pipeline name
|
|
51
|
+
*/
|
|
52
|
+
clearName() {
|
|
53
|
+
cy.get(PipelineForm.selectors.nameInput).clear()
|
|
54
|
+
return this
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Validate name field value
|
|
59
|
+
* @param {string} name - Expected name
|
|
60
|
+
*/
|
|
61
|
+
validateNameValue(name) {
|
|
62
|
+
cy.get(PipelineForm.selectors.nameInput).should('have.value', name)
|
|
63
|
+
return this
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Select pipeline type
|
|
68
|
+
* @param {string} type - Pipeline type (sales, marketing, support, custom)
|
|
69
|
+
*/
|
|
70
|
+
selectType(type) {
|
|
71
|
+
cy.get(PipelineForm.selectors.typeInput).select(type)
|
|
72
|
+
return this
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Validate type field value
|
|
77
|
+
* @param {string} type - Expected type
|
|
78
|
+
*/
|
|
79
|
+
validateTypeValue(type) {
|
|
80
|
+
cy.get(PipelineForm.selectors.typeInput).should('have.value', type)
|
|
81
|
+
return this
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Fill pipeline description
|
|
86
|
+
* @param {string} description - Pipeline description
|
|
87
|
+
*/
|
|
88
|
+
fillDescription(description) {
|
|
89
|
+
cy.get(PipelineForm.selectors.descriptionInput).clear().type(description)
|
|
90
|
+
return this
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Clear pipeline description
|
|
95
|
+
*/
|
|
96
|
+
clearDescription() {
|
|
97
|
+
cy.get(PipelineForm.selectors.descriptionInput).clear()
|
|
98
|
+
return this
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Validate description field value
|
|
103
|
+
* @param {string} description - Expected description
|
|
104
|
+
*/
|
|
105
|
+
validateDescriptionValue(description) {
|
|
106
|
+
cy.get(PipelineForm.selectors.descriptionInput).should('have.value', description)
|
|
107
|
+
return this
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Toggle isActive checkbox
|
|
112
|
+
*/
|
|
113
|
+
toggleIsActive() {
|
|
114
|
+
cy.get(PipelineForm.selectors.isActiveCheckbox).click()
|
|
115
|
+
return this
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Set isActive checkbox
|
|
120
|
+
* @param {boolean} active - True to check, false to uncheck
|
|
121
|
+
*/
|
|
122
|
+
setIsActive(active) {
|
|
123
|
+
cy.get(PipelineForm.selectors.isActiveCheckbox).then($checkbox => {
|
|
124
|
+
const isChecked = $checkbox.is(':checked')
|
|
125
|
+
if ((active && !isChecked) || (!active && isChecked)) {
|
|
126
|
+
cy.get(PipelineForm.selectors.isActiveCheckbox).click()
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
return this
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Validate isActive checkbox state
|
|
134
|
+
* @param {boolean} checked - Expected checked state
|
|
135
|
+
*/
|
|
136
|
+
validateIsActiveChecked(checked) {
|
|
137
|
+
if (checked) {
|
|
138
|
+
cy.get(PipelineForm.selectors.isActiveCheckbox).should('be.checked')
|
|
139
|
+
} else {
|
|
140
|
+
cy.get(PipelineForm.selectors.isActiveCheckbox).should('not.be.checked')
|
|
141
|
+
}
|
|
142
|
+
return this
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Submit the form
|
|
147
|
+
*/
|
|
148
|
+
submit() {
|
|
149
|
+
cy.get(PipelineForm.selectors.submitBtn).click()
|
|
150
|
+
return this
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Cancel the form
|
|
155
|
+
*/
|
|
156
|
+
cancel() {
|
|
157
|
+
cy.get(PipelineForm.selectors.cancelBtn).click()
|
|
158
|
+
return this
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Validate submit button is enabled
|
|
163
|
+
*/
|
|
164
|
+
validateSubmitEnabled() {
|
|
165
|
+
cy.get(PipelineForm.selectors.submitBtn).should('not.be.disabled')
|
|
166
|
+
return this
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Validate submit button is disabled
|
|
171
|
+
*/
|
|
172
|
+
validateSubmitDisabled() {
|
|
173
|
+
cy.get(PipelineForm.selectors.submitBtn).should('be.disabled')
|
|
174
|
+
return this
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Validate form error message
|
|
179
|
+
* @param {string} message - Expected error message
|
|
180
|
+
*/
|
|
181
|
+
validateError(message) {
|
|
182
|
+
cy.get(PipelineForm.selectors.error).should('be.visible').and('contain', message)
|
|
183
|
+
return this
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Validate no form error
|
|
188
|
+
*/
|
|
189
|
+
validateNoError() {
|
|
190
|
+
cy.get(PipelineForm.selectors.error).should('not.exist')
|
|
191
|
+
return this
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Validate field error
|
|
196
|
+
* @param {string} fieldName - Field name (name, type, description)
|
|
197
|
+
*/
|
|
198
|
+
validateFieldError(fieldName) {
|
|
199
|
+
const fieldSelector = PipelineForm.selectors[`${fieldName}Field`]
|
|
200
|
+
cy.get(fieldSelector).within(() => {
|
|
201
|
+
cy.get(PipelineForm.selectors.fieldError).should('exist')
|
|
202
|
+
})
|
|
203
|
+
return this
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Validate no field error
|
|
208
|
+
* @param {string} fieldName - Field name (name, type, description)
|
|
209
|
+
*/
|
|
210
|
+
validateNoFieldError(fieldName) {
|
|
211
|
+
const fieldSelector = PipelineForm.selectors[`${fieldName}Field`]
|
|
212
|
+
cy.get(fieldSelector).within(() => {
|
|
213
|
+
cy.get(PipelineForm.selectors.fieldError).should('not.exist')
|
|
214
|
+
})
|
|
215
|
+
return this
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Fill complete pipeline form
|
|
220
|
+
* @param {Object} data - Pipeline data
|
|
221
|
+
* @param {string} data.name - Pipeline name
|
|
222
|
+
* @param {string} data.type - Pipeline type
|
|
223
|
+
* @param {string} data.description - Pipeline description (optional)
|
|
224
|
+
* @param {boolean} data.isActive - Is active (optional, defaults to true)
|
|
225
|
+
*/
|
|
226
|
+
fillForm(data) {
|
|
227
|
+
if (data.name) this.fillName(data.name)
|
|
228
|
+
if (data.type) this.selectType(data.type)
|
|
229
|
+
if (data.description) this.fillDescription(data.description)
|
|
230
|
+
if (data.isActive !== undefined) this.setIsActive(data.isActive)
|
|
231
|
+
return this
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Create a pipeline (fill and submit)
|
|
236
|
+
* @param {Object} data - Pipeline data
|
|
237
|
+
*/
|
|
238
|
+
createPipeline(data) {
|
|
239
|
+
this.fillForm(data)
|
|
240
|
+
this.submit()
|
|
241
|
+
return this
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRM Theme - Main Export Index
|
|
3
|
+
*
|
|
4
|
+
* Exports all CRM theme POM classes (components and forms).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Components
|
|
8
|
+
export {
|
|
9
|
+
CRMSidebar,
|
|
10
|
+
CRMTopBar,
|
|
11
|
+
CRMMobileNav,
|
|
12
|
+
CRMDataTable,
|
|
13
|
+
PipelineKanban,
|
|
14
|
+
StageColumn,
|
|
15
|
+
DealCard,
|
|
16
|
+
} from './components/index.js'
|
|
17
|
+
|
|
18
|
+
// Forms
|
|
19
|
+
export {
|
|
20
|
+
PipelineForm,
|
|
21
|
+
OpportunityForm,
|
|
22
|
+
} from './forms/index.js'
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRM Theme - Main Export Index
|
|
3
|
+
*
|
|
4
|
+
* Exports all CRM theme POM classes:
|
|
5
|
+
* - Generic components (EntityList, EntityForm, EntityDetail)
|
|
6
|
+
* - Entity-specific POMs (PipelinesPOM, OpportunitiesPOM, etc.)
|
|
7
|
+
* - API Controllers (TypeScript ES modules)
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* import { PipelinesPOM, EntityList } from '../classes/themes/crm'
|
|
11
|
+
* import { ActivityAPIController } from '../classes/themes/crm/controllers'
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// Generic Components (Entity Testing Convention)
|
|
15
|
+
export {
|
|
16
|
+
EntityList,
|
|
17
|
+
EntityForm,
|
|
18
|
+
EntityDetail,
|
|
19
|
+
type EntityConfig,
|
|
20
|
+
type EntityDetailConfig,
|
|
21
|
+
} from './components'
|
|
22
|
+
|
|
23
|
+
// Entity-specific POMs
|
|
24
|
+
export {
|
|
25
|
+
PipelinesPOM,
|
|
26
|
+
OpportunitiesPOM,
|
|
27
|
+
LeadsPOM,
|
|
28
|
+
ContactsPOM,
|
|
29
|
+
CompaniesPOM,
|
|
30
|
+
ActivitiesPOM,
|
|
31
|
+
} from './entities'
|
|
32
|
+
|
|
33
|
+
// Session helpers
|
|
34
|
+
export {
|
|
35
|
+
loginAsCrmOwner,
|
|
36
|
+
loginAsCrmAdmin,
|
|
37
|
+
loginAsCrmMember,
|
|
38
|
+
loginAsCrmLaura,
|
|
39
|
+
CRM_USERS,
|
|
40
|
+
} from './session-helpers'
|
|
41
|
+
|
|
42
|
+
// API Controllers (TypeScript ES modules)
|
|
43
|
+
// Usage: import { ActivityAPIController } from '../classes/themes/crm/controllers'
|
|
44
|
+
//
|
|
45
|
+
// Available controllers:
|
|
46
|
+
// - BaseAPIController (abstract base class)
|
|
47
|
+
// - ActivityAPIController
|
|
48
|
+
// - LeadAPIController
|
|
49
|
+
// - ProductAPIController
|
|
50
|
+
// - PipelineAPIController
|
|
51
|
+
// - ContactAPIController
|
|
52
|
+
// - CampaignAPIController
|
|
53
|
+
// - CompanyAPIController
|
|
54
|
+
// - OpportunityAPIController
|
|
55
|
+
// - NoteAPIController
|
|
56
|
+
//
|
|
57
|
+
// All controllers extend BaseAPIController and provide:
|
|
58
|
+
// - CRUD operations (getAll, getById, create, update, delete)
|
|
59
|
+
// - createTestRecord() with retry support
|
|
60
|
+
// - validateObject() for response validation
|
|
61
|
+
// - Entity-specific methods (complete, pin, closeAsWon, etc.)
|
|
62
|
+
|
|
63
|
+
// Re-export default objects for namespace imports
|
|
64
|
+
import * as Components from './components'
|
|
65
|
+
import * as Entities from './entities'
|
|
66
|
+
import * as Controllers from './controllers'
|
|
67
|
+
|
|
68
|
+
export { Components, Entities, Controllers }
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme Selectors for Cypress Tests
|
|
3
|
+
*
|
|
4
|
+
* This file re-exports from the main selectors in lib/.
|
|
5
|
+
* The lib/selectors.ts is the source of truth, placed there so
|
|
6
|
+
* block components can import it (tests/ is excluded from TypeScript).
|
|
7
|
+
*
|
|
8
|
+
* Architecture:
|
|
9
|
+
* - Core selectors: `core/lib/test/core-selectors.ts`
|
|
10
|
+
* - Theme selectors (source): `lib/selectors.ts`
|
|
11
|
+
* - Theme selectors (tests): This file (re-exports)
|
|
12
|
+
*
|
|
13
|
+
* @example POM usage:
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { cySelector, sel, SELECTORS } from '../selectors'
|
|
16
|
+
*
|
|
17
|
+
* class MyPOM extends BasePOM {
|
|
18
|
+
* get elements() {
|
|
19
|
+
* return {
|
|
20
|
+
* loginForm: cySelector('auth.login.form'),
|
|
21
|
+
* submitButton: cySelector('auth.login.submit'),
|
|
22
|
+
* leadsList: cySelector('entities.leads.list'),
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
// Re-export everything from the lib selectors
|
|
30
|
+
export {
|
|
31
|
+
BLOCK_SELECTORS,
|
|
32
|
+
ENTITY_SELECTORS,
|
|
33
|
+
CRM_SELECTORS,
|
|
34
|
+
THEME_SELECTORS,
|
|
35
|
+
SELECTORS,
|
|
36
|
+
sel,
|
|
37
|
+
s,
|
|
38
|
+
selDev,
|
|
39
|
+
cySelector,
|
|
40
|
+
entitySelectors,
|
|
41
|
+
CORE_SELECTORS,
|
|
42
|
+
} from '../../../lib/selectors'
|
|
43
|
+
|
|
44
|
+
export type {
|
|
45
|
+
ThemeSelectorsType,
|
|
46
|
+
BlockSelectorsType,
|
|
47
|
+
EntitySelectorsType,
|
|
48
|
+
CRMSelectorsType,
|
|
49
|
+
Replacements,
|
|
50
|
+
} from '../../../lib/selectors'
|