@nextsparkjs/testing 0.1.0-beta.39
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/LICENSE +21 -0
- package/README.md +99 -0
- package/dist/helpers/index.d.ts +97 -0
- package/dist/helpers/index.js +126 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1994 -0
- package/dist/index.js.map +1 -0
- package/dist/pom/index.d.ts +473 -0
- package/dist/pom/index.js +817 -0
- package/dist/pom/index.js.map +1 -0
- package/dist/selector-factory-BivSWXbw.d.ts +123 -0
- package/dist/selectors/index.d.ts +1774 -0
- package/dist/selectors/index.js +1000 -0
- package/dist/selectors/index.js.map +1 -0
- package/dist/utils/index.d.ts +224 -0
- package/dist/utils/index.js +183 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
import { R as Replacements } from '../selector-factory-BivSWXbw.js';
|
|
2
|
+
import { ApiInterceptor } from '../helpers/index.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* BasePOMCore - Base class with common utilities for all Page Object Models
|
|
6
|
+
*
|
|
7
|
+
* This is the CORE version that provides generic methods.
|
|
8
|
+
* Themes should extend this class and implement the abstract `cySelector` method
|
|
9
|
+
* to provide theme-specific selector resolution.
|
|
10
|
+
*
|
|
11
|
+
* @example Theme extension:
|
|
12
|
+
* ```ts
|
|
13
|
+
* // theme/tests/cypress/src/core/BasePOM.ts
|
|
14
|
+
* import { BasePOMCore } from '@nextsparkjs/testing/pom'
|
|
15
|
+
* import { cySelector } from '../selectors'
|
|
16
|
+
*
|
|
17
|
+
* export abstract class BasePOM extends BasePOMCore {
|
|
18
|
+
* protected cySelector(path: string, replacements?: Record<string, string>): string {
|
|
19
|
+
* return cySelector(path, replacements)
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
declare abstract class BasePOMCore {
|
|
26
|
+
/**
|
|
27
|
+
* Abstract method - themes must implement to provide their cySelector
|
|
28
|
+
* This allows themes to use their extended THEME_SELECTORS
|
|
29
|
+
*
|
|
30
|
+
* @param path - Dot-notation path to the selector (e.g., "auth.login.form")
|
|
31
|
+
* @param replacements - Optional placeholder replacements
|
|
32
|
+
* @returns Cypress selector string like [data-cy="selector-value"]
|
|
33
|
+
*/
|
|
34
|
+
protected abstract cySelector(path: string, replacements?: Replacements): string;
|
|
35
|
+
/**
|
|
36
|
+
* Get a Cypress selector using the centralized selectors
|
|
37
|
+
* Wrapper for cySelector with a shorter name
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* this.cy('auth.login.form')
|
|
41
|
+
* // Returns: '[data-cy="login-form"]'
|
|
42
|
+
*
|
|
43
|
+
* this.cy('entities.table.row', { slug: 'tasks', id: '123' })
|
|
44
|
+
* // Returns: '[data-cy="tasks-row-123"]'
|
|
45
|
+
*/
|
|
46
|
+
protected cy(path: string, replacements?: Replacements): string;
|
|
47
|
+
/**
|
|
48
|
+
* Replaces placeholders in a selector pattern and wraps with data-cy attribute
|
|
49
|
+
*
|
|
50
|
+
* @param pattern - Selector pattern with {placeholder} syntax
|
|
51
|
+
* @param replacements - Object with placeholder values
|
|
52
|
+
* @returns Formatted data-cy selector string
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* selector('{slug}-row-{id}', { slug: 'tasks', id: '123' })
|
|
56
|
+
* // Returns: '[data-cy="tasks-row-123"]'
|
|
57
|
+
*/
|
|
58
|
+
protected selector(pattern: string, replacements?: Replacements): string;
|
|
59
|
+
/**
|
|
60
|
+
* Wrapper for cy.get with selector pattern support
|
|
61
|
+
* @param pattern - Selector pattern or direct selector
|
|
62
|
+
* @param replacements - Optional placeholder replacements
|
|
63
|
+
*/
|
|
64
|
+
protected get(pattern: string, replacements?: Replacements): Cypress.Chainable<JQuery<HTMLElement>>;
|
|
65
|
+
/**
|
|
66
|
+
* Generic wait with configurable timeout
|
|
67
|
+
* @param selector - CSS selector to wait for
|
|
68
|
+
* @param timeout - Max wait time in ms (default: 15000)
|
|
69
|
+
*/
|
|
70
|
+
protected waitFor(selector: string, timeout?: number): this;
|
|
71
|
+
/**
|
|
72
|
+
* Wait for URL to contain a specific path
|
|
73
|
+
* @param path - Path segment to check for
|
|
74
|
+
*/
|
|
75
|
+
protected waitForUrl(path: string): this;
|
|
76
|
+
/**
|
|
77
|
+
* Wait for URL to match a regex pattern
|
|
78
|
+
* @param pattern - RegExp to match against URL
|
|
79
|
+
*/
|
|
80
|
+
protected waitForUrlMatch(pattern: RegExp): this;
|
|
81
|
+
/**
|
|
82
|
+
* Visit a URL and return self for chaining
|
|
83
|
+
* @param url - URL to visit
|
|
84
|
+
*/
|
|
85
|
+
visit(url: string): this;
|
|
86
|
+
/**
|
|
87
|
+
* Wait for page to load (checks for body visible)
|
|
88
|
+
*/
|
|
89
|
+
waitForPageLoad(): this;
|
|
90
|
+
/**
|
|
91
|
+
* Get an element by selector
|
|
92
|
+
* @param selector - CSS selector
|
|
93
|
+
*/
|
|
94
|
+
getElement(selector: string): Cypress.Chainable<JQuery<HTMLElement>>;
|
|
95
|
+
/**
|
|
96
|
+
* Click on an element
|
|
97
|
+
* @param selector - CSS selector
|
|
98
|
+
*/
|
|
99
|
+
click(selector: string): this;
|
|
100
|
+
/**
|
|
101
|
+
* Type text into an input
|
|
102
|
+
* @param selector - CSS selector
|
|
103
|
+
* @param text - Text to type
|
|
104
|
+
*/
|
|
105
|
+
type(selector: string, text: string): this;
|
|
106
|
+
/**
|
|
107
|
+
* Check if element exists
|
|
108
|
+
* @param selector - CSS selector
|
|
109
|
+
*/
|
|
110
|
+
exists(selector: string): Cypress.Chainable<JQuery<HTMLElement>>;
|
|
111
|
+
/**
|
|
112
|
+
* Check if element is visible
|
|
113
|
+
* @param selector - CSS selector
|
|
114
|
+
*/
|
|
115
|
+
isVisible(selector: string): Cypress.Chainable<JQuery<HTMLElement>>;
|
|
116
|
+
/**
|
|
117
|
+
* Check if element does not exist
|
|
118
|
+
* @param selector - CSS selector
|
|
119
|
+
*/
|
|
120
|
+
notExists(selector: string): Cypress.Chainable<JQuery<HTMLElement>>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* DashboardEntityPOMCore - Base class for all entity Page Object Models
|
|
125
|
+
*
|
|
126
|
+
* Provides standard CRUD operations for dashboard entities:
|
|
127
|
+
* - Navigation (list, create, edit, detail pages)
|
|
128
|
+
* - Table interactions (search, filters, pagination, row actions)
|
|
129
|
+
* - Form operations (fill fields, submit, cancel)
|
|
130
|
+
* - API interceptor integration for deterministic waits
|
|
131
|
+
* - Bulk actions
|
|
132
|
+
* - Delete confirmation dialogs
|
|
133
|
+
*
|
|
134
|
+
* This is the CORE version. Themes should extend this class and implement
|
|
135
|
+
* the abstract `cySelector` method from BasePOMCore.
|
|
136
|
+
*
|
|
137
|
+
* @example Theme extension:
|
|
138
|
+
* ```ts
|
|
139
|
+
* // theme/tests/cypress/src/core/DashboardEntityPOM.ts
|
|
140
|
+
* import { DashboardEntityPOMCore } from '@nextsparkjs/testing/pom'
|
|
141
|
+
* import { cySelector } from '../selectors'
|
|
142
|
+
*
|
|
143
|
+
* export abstract class DashboardEntityPOM extends DashboardEntityPOMCore {
|
|
144
|
+
* protected cySelector(path: string, replacements?: Record<string, string>): string {
|
|
145
|
+
* return cySelector(path, replacements)
|
|
146
|
+
* }
|
|
147
|
+
* }
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
|
|
151
|
+
interface EntityConfig {
|
|
152
|
+
slug: string;
|
|
153
|
+
singular?: string;
|
|
154
|
+
plural?: string;
|
|
155
|
+
tableName?: string;
|
|
156
|
+
fields?: string[];
|
|
157
|
+
filters?: string[];
|
|
158
|
+
}
|
|
159
|
+
declare abstract class DashboardEntityPOMCore extends BasePOMCore {
|
|
160
|
+
protected slug: string;
|
|
161
|
+
protected entityConfig: EntityConfig;
|
|
162
|
+
protected _api: ApiInterceptor | null;
|
|
163
|
+
/**
|
|
164
|
+
* Get the entity slug (public accessor)
|
|
165
|
+
* Useful for building dynamic selectors and URLs in tests
|
|
166
|
+
*/
|
|
167
|
+
get entitySlug(): string;
|
|
168
|
+
constructor(entitySlugOrConfig: string | EntityConfig);
|
|
169
|
+
/**
|
|
170
|
+
* Get or create ApiInterceptor instance for this entity
|
|
171
|
+
*/
|
|
172
|
+
get api(): ApiInterceptor;
|
|
173
|
+
/**
|
|
174
|
+
* Setup API intercepts for all CRUD operations
|
|
175
|
+
* Call this BEFORE navigation
|
|
176
|
+
*/
|
|
177
|
+
setupApiIntercepts(): this;
|
|
178
|
+
/**
|
|
179
|
+
* Get all selectors for this entity, with placeholders replaced
|
|
180
|
+
* Uses the abstract cySelector method which themes implement
|
|
181
|
+
*/
|
|
182
|
+
get selectors(): {
|
|
183
|
+
page: string;
|
|
184
|
+
pageTitle: string;
|
|
185
|
+
tableContainer: string;
|
|
186
|
+
table: string;
|
|
187
|
+
addButton: string;
|
|
188
|
+
search: string;
|
|
189
|
+
searchContainer: string;
|
|
190
|
+
searchClear: string;
|
|
191
|
+
selectAll: string;
|
|
192
|
+
selectionCount: string;
|
|
193
|
+
row: (id: string) => string;
|
|
194
|
+
rowSelect: (id: string) => string;
|
|
195
|
+
rowMenu: (id: string) => string;
|
|
196
|
+
rowAction: (action: string, id: string) => string;
|
|
197
|
+
cell: (field: string, id: string) => string;
|
|
198
|
+
rowGeneric: string;
|
|
199
|
+
pagination: string;
|
|
200
|
+
pageSize: string;
|
|
201
|
+
pageSizeOption: (size: string) => string;
|
|
202
|
+
pageInfo: string;
|
|
203
|
+
pageFirst: string;
|
|
204
|
+
pagePrev: string;
|
|
205
|
+
pageNext: string;
|
|
206
|
+
pageLast: string;
|
|
207
|
+
viewHeader: string;
|
|
208
|
+
editHeader: string;
|
|
209
|
+
createHeader: string;
|
|
210
|
+
backButton: string;
|
|
211
|
+
editButton: string;
|
|
212
|
+
deleteButton: string;
|
|
213
|
+
copyId: string;
|
|
214
|
+
title: string;
|
|
215
|
+
deleteDialog: string;
|
|
216
|
+
deleteCancel: string;
|
|
217
|
+
deleteConfirm: string;
|
|
218
|
+
form: string;
|
|
219
|
+
field: (name: string) => string;
|
|
220
|
+
submitButton: string;
|
|
221
|
+
filter: (field: string) => string;
|
|
222
|
+
filterTrigger: (field: string) => string;
|
|
223
|
+
filterContent: (field: string) => string;
|
|
224
|
+
filterOption: (field: string, value: string) => string;
|
|
225
|
+
filterBadge: (field: string, value: string) => string;
|
|
226
|
+
filterRemoveBadge: (field: string, value: string) => string;
|
|
227
|
+
filterClearAll: (field: string) => string;
|
|
228
|
+
bulkBar: string;
|
|
229
|
+
bulkCount: string;
|
|
230
|
+
bulkSelectAll: string;
|
|
231
|
+
bulkStatus: string;
|
|
232
|
+
bulkDelete: string;
|
|
233
|
+
bulkClear: string;
|
|
234
|
+
bulkStatusDialog: string;
|
|
235
|
+
bulkStatusSelect: string;
|
|
236
|
+
bulkStatusOption: (value: string) => string;
|
|
237
|
+
bulkStatusCancel: string;
|
|
238
|
+
bulkStatusConfirm: string;
|
|
239
|
+
bulkDeleteDialog: string;
|
|
240
|
+
bulkDeleteCancel: string;
|
|
241
|
+
bulkDeleteConfirm: string;
|
|
242
|
+
confirmDialog: string;
|
|
243
|
+
confirmCancel: string;
|
|
244
|
+
confirmAction: string;
|
|
245
|
+
parentDeleteConfirm: string;
|
|
246
|
+
parentDeleteCancel: string;
|
|
247
|
+
rowActionEditGeneric: string;
|
|
248
|
+
rowActionDeleteGeneric: string;
|
|
249
|
+
detail: string;
|
|
250
|
+
};
|
|
251
|
+
/**
|
|
252
|
+
* Navigate to entity list page
|
|
253
|
+
*/
|
|
254
|
+
visitList(): this;
|
|
255
|
+
/**
|
|
256
|
+
* Navigate to create page
|
|
257
|
+
*/
|
|
258
|
+
visitCreate(): this;
|
|
259
|
+
/**
|
|
260
|
+
* Navigate to edit page for specific entity
|
|
261
|
+
*/
|
|
262
|
+
visitEdit(id: string): this;
|
|
263
|
+
/**
|
|
264
|
+
* Navigate to detail/view page for specific entity
|
|
265
|
+
*/
|
|
266
|
+
visitDetail(id: string): this;
|
|
267
|
+
/**
|
|
268
|
+
* Navigate to list and wait for API response
|
|
269
|
+
*/
|
|
270
|
+
visitListWithApiWait(): this;
|
|
271
|
+
/**
|
|
272
|
+
* Navigate to edit page and wait for form to be visible
|
|
273
|
+
*/
|
|
274
|
+
visitEditWithApiWait(id: string): this;
|
|
275
|
+
/**
|
|
276
|
+
* Navigate to detail page and wait for content
|
|
277
|
+
*/
|
|
278
|
+
visitDetailWithApiWait(id: string): this;
|
|
279
|
+
/**
|
|
280
|
+
* Wait for list page to be fully loaded
|
|
281
|
+
*/
|
|
282
|
+
waitForList(): this;
|
|
283
|
+
/**
|
|
284
|
+
* Wait for form to be visible
|
|
285
|
+
*/
|
|
286
|
+
waitForForm(): this;
|
|
287
|
+
/**
|
|
288
|
+
* Wait for detail page to be loaded
|
|
289
|
+
*/
|
|
290
|
+
waitForDetail(): this;
|
|
291
|
+
/**
|
|
292
|
+
* Click the Add/Create button
|
|
293
|
+
*/
|
|
294
|
+
clickAdd(): this;
|
|
295
|
+
/**
|
|
296
|
+
* Type in the search input
|
|
297
|
+
*/
|
|
298
|
+
search(term: string): this;
|
|
299
|
+
/**
|
|
300
|
+
* Clear the search input
|
|
301
|
+
*/
|
|
302
|
+
clearSearch(): this;
|
|
303
|
+
/**
|
|
304
|
+
* Click a specific row by ID
|
|
305
|
+
*/
|
|
306
|
+
clickRow(id: string): this;
|
|
307
|
+
/**
|
|
308
|
+
* Find and click a row containing specific text
|
|
309
|
+
*/
|
|
310
|
+
clickRowByText(text: string): this;
|
|
311
|
+
/**
|
|
312
|
+
* Select a row checkbox
|
|
313
|
+
*/
|
|
314
|
+
selectRow(id: string): this;
|
|
315
|
+
/**
|
|
316
|
+
* Open the row menu (three dots)
|
|
317
|
+
*/
|
|
318
|
+
openRowMenu(id: string): this;
|
|
319
|
+
/**
|
|
320
|
+
* Click an action in the row menu
|
|
321
|
+
*/
|
|
322
|
+
clickRowAction(action: string, id: string): this;
|
|
323
|
+
/**
|
|
324
|
+
* Open a filter dropdown
|
|
325
|
+
*/
|
|
326
|
+
openFilter(field: string): this;
|
|
327
|
+
/**
|
|
328
|
+
* Select a filter option
|
|
329
|
+
*/
|
|
330
|
+
selectFilterOption(field: string, value: string): this;
|
|
331
|
+
/**
|
|
332
|
+
* Open filter and select option (convenience method)
|
|
333
|
+
*/
|
|
334
|
+
selectFilter(field: string, value: string): this;
|
|
335
|
+
/**
|
|
336
|
+
* Remove a filter badge
|
|
337
|
+
*/
|
|
338
|
+
removeFilterBadge(field: string, value: string): this;
|
|
339
|
+
/**
|
|
340
|
+
* Clear all values for a filter
|
|
341
|
+
*/
|
|
342
|
+
clearFilter(field: string): this;
|
|
343
|
+
/**
|
|
344
|
+
* Go to next page
|
|
345
|
+
*/
|
|
346
|
+
nextPage(): this;
|
|
347
|
+
/**
|
|
348
|
+
* Go to previous page
|
|
349
|
+
*/
|
|
350
|
+
prevPage(): this;
|
|
351
|
+
/**
|
|
352
|
+
* Go to first page
|
|
353
|
+
*/
|
|
354
|
+
firstPage(): this;
|
|
355
|
+
/**
|
|
356
|
+
* Go to last page
|
|
357
|
+
*/
|
|
358
|
+
lastPage(): this;
|
|
359
|
+
/**
|
|
360
|
+
* Change page size
|
|
361
|
+
*/
|
|
362
|
+
setPageSize(size: string): this;
|
|
363
|
+
/**
|
|
364
|
+
* Fill a text input field
|
|
365
|
+
*/
|
|
366
|
+
fillTextField(name: string, value: string): this;
|
|
367
|
+
/**
|
|
368
|
+
* Fill a textarea field
|
|
369
|
+
*/
|
|
370
|
+
fillTextarea(name: string, value: string): this;
|
|
371
|
+
/**
|
|
372
|
+
* Select an option in a combobox/select field
|
|
373
|
+
*/
|
|
374
|
+
selectOption(name: string, value: string): this;
|
|
375
|
+
/**
|
|
376
|
+
* Submit the form
|
|
377
|
+
*/
|
|
378
|
+
submitForm(): this;
|
|
379
|
+
/**
|
|
380
|
+
* Click back button
|
|
381
|
+
*/
|
|
382
|
+
clickBack(): this;
|
|
383
|
+
/**
|
|
384
|
+
* Click edit button
|
|
385
|
+
*/
|
|
386
|
+
clickEdit(): this;
|
|
387
|
+
/**
|
|
388
|
+
* Click delete button
|
|
389
|
+
*/
|
|
390
|
+
clickDelete(): this;
|
|
391
|
+
/**
|
|
392
|
+
* Confirm delete in dialog
|
|
393
|
+
*/
|
|
394
|
+
confirmDelete(): this;
|
|
395
|
+
/**
|
|
396
|
+
* Cancel delete in dialog
|
|
397
|
+
*/
|
|
398
|
+
cancelDelete(): this;
|
|
399
|
+
/**
|
|
400
|
+
* Select all items using table header checkbox
|
|
401
|
+
*/
|
|
402
|
+
selectAll(): this;
|
|
403
|
+
/**
|
|
404
|
+
* Click bulk delete button
|
|
405
|
+
*/
|
|
406
|
+
bulkDelete(): this;
|
|
407
|
+
/**
|
|
408
|
+
* Confirm bulk delete
|
|
409
|
+
*/
|
|
410
|
+
confirmBulkDelete(): this;
|
|
411
|
+
/**
|
|
412
|
+
* Cancel bulk delete
|
|
413
|
+
*/
|
|
414
|
+
cancelBulkDelete(): this;
|
|
415
|
+
/**
|
|
416
|
+
* Click bulk status button
|
|
417
|
+
*/
|
|
418
|
+
bulkChangeStatus(): this;
|
|
419
|
+
/**
|
|
420
|
+
* Select status in bulk status dialog
|
|
421
|
+
*/
|
|
422
|
+
selectBulkStatus(value: string): this;
|
|
423
|
+
/**
|
|
424
|
+
* Confirm bulk status change
|
|
425
|
+
*/
|
|
426
|
+
confirmBulkStatus(): this;
|
|
427
|
+
/**
|
|
428
|
+
* Clear selection
|
|
429
|
+
*/
|
|
430
|
+
clearSelection(): this;
|
|
431
|
+
/**
|
|
432
|
+
* Assert text is visible in the list
|
|
433
|
+
*/
|
|
434
|
+
assertInList(text: string): this;
|
|
435
|
+
/**
|
|
436
|
+
* Assert text is not in the list
|
|
437
|
+
*/
|
|
438
|
+
assertNotInList(text: string): this;
|
|
439
|
+
/**
|
|
440
|
+
* Assert table is visible
|
|
441
|
+
*/
|
|
442
|
+
assertTableVisible(): this;
|
|
443
|
+
/**
|
|
444
|
+
* Assert form is visible
|
|
445
|
+
*/
|
|
446
|
+
assertFormVisible(): this;
|
|
447
|
+
/**
|
|
448
|
+
* Assert page title contains text
|
|
449
|
+
*/
|
|
450
|
+
assertPageTitle(expected: string): this;
|
|
451
|
+
/**
|
|
452
|
+
* Assert row exists
|
|
453
|
+
*/
|
|
454
|
+
assertRowExists(id: string): this;
|
|
455
|
+
/**
|
|
456
|
+
* Assert row does not exist
|
|
457
|
+
*/
|
|
458
|
+
assertRowNotExists(id: string): this;
|
|
459
|
+
/**
|
|
460
|
+
* Assert selection count
|
|
461
|
+
*/
|
|
462
|
+
assertSelectionCount(count: number): this;
|
|
463
|
+
/**
|
|
464
|
+
* Assert bulk bar is visible
|
|
465
|
+
*/
|
|
466
|
+
assertBulkBarVisible(): this;
|
|
467
|
+
/**
|
|
468
|
+
* Assert bulk bar is hidden
|
|
469
|
+
*/
|
|
470
|
+
assertBulkBarHidden(): this;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
export { BasePOMCore, DashboardEntityPOMCore, type EntityConfig };
|