@agnos-ui/page-objects 0.3.1 → 0.4.0-next.1

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/.eslintrc.json ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": ["../.eslintrc.json"]
3
+ }
@@ -0,0 +1,93 @@
1
+ import type {Locator} from '@playwright/test';
2
+ import {BasePO} from '@agnos-ui/base-po';
3
+
4
+ export class AccordionPO extends BasePO {
5
+ private readonly selectors = {
6
+ item: '.accordion-item',
7
+ bodyContainer: '.accordion-collapse',
8
+ body: '.accordion-body',
9
+ header: '.accordion-header',
10
+ buttons: '.accordion-button',
11
+ };
12
+ override getComponentSelector(): string {
13
+ return '.au-accordion';
14
+ }
15
+
16
+ /**
17
+ * Gets the locators of the items containing the header and the body-container inside
18
+ * the accordion
19
+ */
20
+ get locatorAccordionItems(): Locator {
21
+ return this.locatorRoot.locator(this.selectors.item);
22
+ }
23
+
24
+ /**
25
+ * Gets the locators of the item specified by the itemIndex containing the header and the body-container inside
26
+ * the accordion
27
+ */
28
+ locatorAccordionItem(itemIndex: number): Locator {
29
+ return this.locatorRoot.locator(this.selectors.item).nth(itemIndex);
30
+ }
31
+
32
+ get locatorAccordionCBodyContainers(): Locator {
33
+ return this.locatorAccordionItems.locator(this.selectors.bodyContainer);
34
+ }
35
+
36
+ locatorAccordionBodyContainer(bodyContainerIndex: number): Locator {
37
+ return this.locatorAccordionItem(bodyContainerIndex).locator(this.selectors.bodyContainer);
38
+ }
39
+
40
+ /**
41
+ * Gets the locator of the bodies of the accordion.
42
+ */
43
+ get locatorAccordionBodies(): Locator {
44
+ return this.locatorAccordionCBodyContainers.locator(this.selectors.body);
45
+ }
46
+
47
+ locatorAccordionBody(bodyIndex: number): Locator {
48
+ return this.locatorAccordionBodyContainer(bodyIndex).locator(this.selectors.body);
49
+ }
50
+
51
+ get locatorAccordionHeaders(): Locator {
52
+ return this.locatorAccordionItems.locator(this.selectors.header);
53
+ }
54
+
55
+ locatorAccordionHeader(headerIndex: number): Locator {
56
+ return this.locatorAccordionItem(headerIndex).locator(this.selectors.header);
57
+ }
58
+
59
+ /**
60
+ * Gets the locators of the buttons that handle the accordion, present in the accordion header.
61
+ * It does not get the locators of the buttons present in the body, added by the developer.
62
+ */
63
+ get locatorAccordionButtons(): Locator {
64
+ return this.locatorAccordionHeaders.locator(this.selectors.buttons);
65
+ }
66
+
67
+ locatorAccordionButton(buttonIndex: number): Locator {
68
+ return this.locatorAccordionHeader(buttonIndex).locator(this.selectors.buttons);
69
+ }
70
+
71
+ async state() {
72
+ return await this.locatorRoot.evaluate((rootNode: HTMLElement) => {
73
+ const itemsElements = [...rootNode.querySelectorAll('.accordion-item')] as HTMLDivElement[];
74
+ const items = [];
75
+ for (const item of itemsElements) {
76
+ const bodyContainer = item.querySelector('.accordion-collapse');
77
+ const button = item.querySelector('.accordion-button');
78
+ items.push({
79
+ classes: item.className.trim().split(' '),
80
+ id: item.id,
81
+ isInDOM: bodyContainer !== null ? true : false,
82
+ bodyContainerId: bodyContainer?.id,
83
+ buttonId: button?.id,
84
+ expanded: button?.getAttribute('aria-expanded'),
85
+ disabled: button?.getAttribute('aria-disabled'),
86
+ labeledBy: bodyContainer?.getAttribute('aria-labelledby'),
87
+ buttonControls: button?.getAttribute('aria-controls'),
88
+ });
89
+ }
90
+ return {rootClasses: rootNode.className.trim().split(' '), items: items};
91
+ });
92
+ }
93
+ }
@@ -0,0 +1,34 @@
1
+ import {BasePO} from '@agnos-ui/base-po';
2
+ import type {Locator} from '@playwright/test';
3
+
4
+ export const alertSelectors = {
5
+ rootComponent: '.alert',
6
+ body: '.alert-body',
7
+ closeButton: '.btn-close',
8
+ };
9
+
10
+ export class AlertPO extends BasePO {
11
+ selectors = structuredClone(alertSelectors);
12
+
13
+ override getComponentSelector(): string {
14
+ return this.selectors.rootComponent;
15
+ }
16
+
17
+ get locatorCloseButton(): Locator {
18
+ return this.locatorRoot.locator(this.selectors.closeButton);
19
+ }
20
+
21
+ async state() {
22
+ return this.locatorRoot.evaluate((rootNode: HTMLElement, selectors) => {
23
+ // normalize body content to remove non-printable characters such as line breaks
24
+ // as different browsers represent innerText in their own manner
25
+ const body = rootNode.querySelector<HTMLDivElement>(selectors.body)?.innerText?.replace(/[^\x20-\x7E]/g, '');
26
+ const closeButton = rootNode.querySelector<HTMLButtonElement>(selectors.closeButton)?.getAttribute('aria-label');
27
+ return {
28
+ rootClasses: rootNode.className.trim().split(' ').sort(),
29
+ body,
30
+ closeButton,
31
+ };
32
+ }, this.selectors);
33
+ }
34
+ }
package/lib/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ export * from './modal.po';
2
+ export * from './pagination.po';
3
+ export * from './rating.po';
4
+ export * from './select.po';
5
+ export * from './alert.po';
6
+ export * from './accordion.po';
7
+ export * from './progressbar.po';
8
+ export * from './slider.po';
9
+ export * from './toast.po';
@@ -0,0 +1,63 @@
1
+ import type {Locator} from '@playwright/test';
2
+ import {BasePO} from '@agnos-ui/base-po';
3
+
4
+ export const modalSelectors = {
5
+ // TODO: should we use bootstrap-independent classes starting with au- ?
6
+ rootComponent: '.modal',
7
+ closeButton: '.btn-close',
8
+ backdrop: "xpath=./preceding-sibling::div[contains(@class,'modal-backdrop')]",
9
+ header: '.modal-header',
10
+ title: '.modal-title',
11
+ body: '.modal-body',
12
+ footer: '.modal-footer',
13
+ };
14
+
15
+ export class ModalPO extends BasePO {
16
+ selectors = structuredClone(modalSelectors);
17
+
18
+ override getComponentSelector(): string {
19
+ return this.selectors.rootComponent;
20
+ }
21
+
22
+ get locatorHeader(): Locator {
23
+ return this.locatorRoot.locator(this.selectors.header);
24
+ }
25
+
26
+ get locatorTitle(): Locator {
27
+ return this.locatorHeader.locator(this.selectors.title);
28
+ }
29
+
30
+ get locatorBody(): Locator {
31
+ return this.locatorRoot.locator(this.selectors.body);
32
+ }
33
+
34
+ get locatorFooter(): Locator {
35
+ return this.locatorRoot.locator(this.selectors.footer);
36
+ }
37
+
38
+ get locatorCloseButton(): Locator {
39
+ return this.locatorRoot.locator(this.selectors.closeButton);
40
+ }
41
+
42
+ get locatorBackdrop(): Locator {
43
+ return this.locatorRoot.locator(this.selectors.backdrop);
44
+ }
45
+
46
+ async state() {
47
+ return this.locatorRoot.evaluate(async (rootNode: HTMLElement, selectors) => {
48
+ const closeButton = rootNode.querySelector<HTMLButtonElement>(selectors.closeButton)?.getAttribute('aria-label');
49
+ const header = rootNode.querySelector<HTMLDivElement>(selectors.header)?.innerText?.trim();
50
+ const title = rootNode.querySelector<HTMLDivElement>(selectors.title)?.innerText?.trim();
51
+ const body = rootNode.querySelector<HTMLDivElement>(selectors.body)?.innerText?.trim();
52
+ const footer = rootNode.querySelector<HTMLDivElement>(selectors.footer)?.innerText?.trim();
53
+ return {
54
+ rootClasses: rootNode.className.trim().split(' ').sort(),
55
+ header,
56
+ title,
57
+ body,
58
+ footer,
59
+ closeButton,
60
+ };
61
+ }, this.selectors);
62
+ }
63
+ }
@@ -0,0 +1,157 @@
1
+ import type {Locator} from '@playwright/test';
2
+ import {BasePO} from '@agnos-ui/base-po';
3
+
4
+ /** Pagination navigation buttons hrefs */
5
+ export interface HrefsNavigation {
6
+ first?: string;
7
+ previous?: string;
8
+ next?: string;
9
+ last?: string;
10
+ }
11
+
12
+ /** Pagination page object */
13
+ export interface PaginationPOState {
14
+ rootClasses: string[];
15
+ disabled: string | null;
16
+ pages: string[];
17
+ hrefs: string[];
18
+ hrefsNavigation?: HrefsNavigation;
19
+ isFirstDisabled?: boolean;
20
+ isPreviousDisabled?: boolean;
21
+ isNextDisabled?: boolean;
22
+ isLastDisabled?: boolean;
23
+ }
24
+
25
+ export const paginationSelectors = {
26
+ rootComponent: '.au-pagination',
27
+ activePage: '.active',
28
+ previousPage: '.au-previous',
29
+ nextPage: '.au-next',
30
+ firstPage: '.au-first',
31
+ lastPage: '.au-last',
32
+ pages: '.au-page',
33
+ ellipses: '.au-ellipsis',
34
+ };
35
+
36
+ export class PaginationPO extends BasePO {
37
+ selectors = structuredClone(paginationSelectors);
38
+
39
+ // TODO should we add this in the list of selector ?
40
+ // Depend on the setSelectors usage...
41
+ override getComponentSelector(): string {
42
+ return this.selectors.rootComponent;
43
+ }
44
+
45
+ /**
46
+ * Gets the locator of the button is the current page in the pagination component.
47
+ */
48
+ get locatorActivePage(): Locator {
49
+ return this.locatorRoot.locator(this.selectors.activePage);
50
+ }
51
+
52
+ /**
53
+ * Gets the locator of the button that once clicked moves to the previous page in the pagination component.
54
+ */
55
+ get locatorPreviousButton(): Locator {
56
+ return this.locatorRoot.locator(this.selectors.previousPage);
57
+ }
58
+
59
+ /**
60
+ * Gets the locator of the button that once clicked moves to the next page in the pagination component.
61
+ */
62
+ get locatorNextButton(): Locator {
63
+ return this.locatorRoot.locator(this.selectors.nextPage);
64
+ }
65
+
66
+ /**
67
+ * Gets the locator of the button that once clicked moves to the first page in the pagination component.
68
+ */
69
+ get locatorFirstButton(): Locator {
70
+ return this.locatorRoot.locator(this.selectors.firstPage);
71
+ }
72
+
73
+ /**
74
+ * Gets the locator of the button that once clicked moves to the last page in the pagination component.
75
+ */
76
+ get locatorLastButton(): Locator {
77
+ return this.locatorRoot.locator(this.selectors.lastPage);
78
+ }
79
+
80
+ /**
81
+ * Gets the locators of the pages
82
+ */
83
+ get locatorPages(): Locator {
84
+ return this.locatorRoot.locator(this.selectors.pages);
85
+ }
86
+
87
+ /**
88
+ * Gets the locator of a page button in the pagination component given his position.
89
+ * @param pageNumber - The number of the page in the pagination object.
90
+ */
91
+ locatorNthPage(pageNumber: number): Locator {
92
+ return this.locatorRoot.locator(this.selectors.pages).nth(pageNumber - 1);
93
+ }
94
+
95
+ /**
96
+ * Gets the locator of a page button in the pagination component given a string.
97
+ * @param pageString - The string of the page in the pagination object.
98
+ */
99
+ locatorPage(pageString: string): Locator {
100
+ return this.locatorRoot.locator(this.selectors.pages, {hasText: pageString});
101
+ }
102
+
103
+ get locatorEllipses(): Locator {
104
+ return this.locatorRoot.locator(this.selectors.ellipses);
105
+ }
106
+
107
+ async state() {
108
+ return this.locatorRoot.evaluate((rootNode: HTMLElement) => {
109
+ const returnState: PaginationPOState = {rootClasses: [], disabled: null, pages: [], hrefs: []};
110
+ const pagesElements = [...rootNode.querySelectorAll('.au-page')] as HTMLLinkElement[];
111
+ const pages = [];
112
+ const hrefs = [];
113
+ const hrefsNavigation: HrefsNavigation = {};
114
+ const getHref = (elem: Element | null) => elem?.getAttribute('href');
115
+ const firstElem = rootNode.querySelector('a.au-first');
116
+ const previousElem = rootNode.querySelector('a.au-previous');
117
+ const nextElem = rootNode.querySelector('a.au-next');
118
+ const lastElem = rootNode.querySelector('a.au-last');
119
+ firstElem && (hrefsNavigation.first = getHref(firstElem)!);
120
+ previousElem && (hrefsNavigation.previous = getHref(previousElem)!);
121
+ nextElem && (hrefsNavigation.next = getHref(nextElem)!);
122
+ lastElem && (hrefsNavigation.last = getHref(lastElem)!);
123
+
124
+ for (const element of pagesElements) {
125
+ hrefs.push(element.getAttribute('href') || '');
126
+ pages.push((element.textContent || '').trim());
127
+ }
128
+ const pagesDisabledElements = [...rootNode.querySelectorAll('a.au-page[aria-disabled]')] as HTMLLinkElement[];
129
+ returnState['pages'] = pages;
130
+ returnState['hrefs'] = hrefs;
131
+ returnState['hrefsNavigation'] = hrefsNavigation;
132
+ returnState['rootClasses'] = rootNode.className.trim().split(' ');
133
+ returnState['disabled'] = pagesDisabledElements.length === pagesElements.length ? 'true' : null;
134
+ if (rootNode.querySelector('a.au-previous[aria-disabled]')) {
135
+ returnState['isPreviousDisabled'] = true;
136
+ } else if (previousElem) {
137
+ returnState['isPreviousDisabled'] = false;
138
+ }
139
+ if (rootNode.querySelector('a.au-next[aria-disabled]')) {
140
+ returnState['isNextDisabled'] = true;
141
+ } else if (nextElem) {
142
+ returnState['isNextDisabled'] = false;
143
+ }
144
+ if (rootNode.querySelector('a.au-first[aria-disabled]')) {
145
+ returnState['isFirstDisabled'] = true;
146
+ } else if (firstElem) {
147
+ returnState['isFirstDisabled'] = false;
148
+ }
149
+ if (rootNode.querySelector('a.au-last[aria-disabled]')) {
150
+ returnState['isLastDisabled'] = true;
151
+ } else if (lastElem) {
152
+ returnState['isLastDisabled'] = false;
153
+ }
154
+ return returnState;
155
+ });
156
+ }
157
+ }
@@ -0,0 +1,53 @@
1
+ import {BasePO} from '@agnos-ui/base-po';
2
+ import type {Locator} from '@playwright/test';
3
+
4
+ export const progressbarSelectors = {
5
+ rootComponent: '[role="progressbar"]',
6
+ outerBar: '.progress',
7
+ innerBar: '.progress-bar',
8
+ };
9
+
10
+ export interface State {
11
+ ariaLabel: string | null;
12
+ ariaValueNow: string | null;
13
+ ariaValueMin: string | null;
14
+ ariaValueMax: string | null;
15
+ ariaValueText: string | null;
16
+ label: string | null | undefined;
17
+ innerClasses: string[];
18
+ outerHeight: string | undefined;
19
+ innerWidth: string | undefined;
20
+ }
21
+
22
+ export class ProgressbarPO extends BasePO {
23
+ selectors = structuredClone(progressbarSelectors);
24
+
25
+ override getComponentSelector(): string {
26
+ return this.selectors.rootComponent;
27
+ }
28
+
29
+ get locatorOuterBar(): Locator {
30
+ return this.locatorRoot.locator(this.selectors.outerBar);
31
+ }
32
+ get locatorInnerBar(): Locator {
33
+ return this.locatorRoot.locator(this.selectors.innerBar);
34
+ }
35
+
36
+ async state(): Promise<State> {
37
+ return this.locatorRoot.evaluate((rootNode: HTMLElement) => {
38
+ const innerBar = rootNode.querySelector('.progress-bar');
39
+ const outerBar = rootNode.querySelector('.progress');
40
+ return {
41
+ ariaLabel: rootNode.getAttribute('aria-label'),
42
+ ariaValueNow: rootNode.getAttribute('aria-valuenow'),
43
+ ariaValueMin: rootNode.getAttribute('aria-valuemin'),
44
+ ariaValueMax: rootNode.getAttribute('aria-valuemax'),
45
+ ariaValueText: rootNode.getAttribute('aria-valuetext'),
46
+ label: innerBar?.textContent?.trim(),
47
+ innerClasses: innerBar?.className?.trim()?.split(' ')?.sort() ?? [],
48
+ outerHeight: (outerBar as HTMLElement | undefined)?.style?.height,
49
+ innerWidth: (innerBar as HTMLElement | undefined)?.style?.width,
50
+ };
51
+ });
52
+ }
53
+ }
@@ -0,0 +1,46 @@
1
+ import {BasePO} from '@agnos-ui/base-po';
2
+
3
+ export const ratingSelectors = {
4
+ rootComponent: '.au-rating',
5
+ star: '.au-rating-star',
6
+ };
7
+
8
+ // TODO add selector list
9
+ export class RatingPO extends BasePO {
10
+ selectors = structuredClone(ratingSelectors);
11
+
12
+ override getComponentSelector(): string {
13
+ return this.selectors.rootComponent;
14
+ }
15
+
16
+ /**
17
+ * Get the main title locator of the feature page
18
+ */
19
+ locatorStar(index: number) {
20
+ return this.locatorRoot.locator(this.selectors.star).nth(index);
21
+ }
22
+
23
+ async state() {
24
+ return await this.locatorRoot.evaluate((rootNode: HTMLElement, selectors) => {
25
+ const starsElements = [...rootNode.querySelectorAll(selectors.star)] as HTMLSpanElement[];
26
+ const stars = [];
27
+ const classes = [];
28
+ for (const element of starsElements) {
29
+ stars.push((element.textContent || '').trim());
30
+ classes.push(element.className.split(' '));
31
+ }
32
+
33
+ return {
34
+ rootClasses: rootNode.className.trim().split(' ').sort(),
35
+ value: rootNode.getAttribute('aria-valuenow'),
36
+ min: rootNode.getAttribute('aria-valuemin'),
37
+ max: rootNode.getAttribute('aria-valuemax'),
38
+ text: rootNode.getAttribute('aria-valuetext'),
39
+ disabled: rootNode.getAttribute('aria-disabled'),
40
+ readonly: rootNode.getAttribute('aria-readonly'),
41
+ stars,
42
+ classes,
43
+ };
44
+ }, this.selectors);
45
+ }
46
+ }
@@ -0,0 +1,94 @@
1
+ import {BasePO} from '@agnos-ui/base-po';
2
+
3
+ export const selectSelectors = {
4
+ rootComponent: '.au-select',
5
+ // TODO add selector list
6
+ };
7
+
8
+ export class SelectPO extends BasePO {
9
+ selectors = structuredClone(selectSelectors);
10
+
11
+ override getComponentSelector(): string {
12
+ return this.selectors.rootComponent;
13
+ }
14
+
15
+ /**
16
+ * Get the main title locator of the feature page
17
+ */
18
+ get locatorInput() {
19
+ return this.locatorRoot.locator('input[type="text"]').nth(0);
20
+ }
21
+
22
+ /**
23
+ * Menu container
24
+ */
25
+ get locatorMenu() {
26
+ return this.locatorRoot.locator('.dropdown-menu');
27
+ }
28
+
29
+ /**
30
+ * Return the first menu item locator including the text
31
+ */
32
+ get locatorMenuItems() {
33
+ return this.locatorMenu.locator('.au-select-item');
34
+ }
35
+
36
+ /**
37
+ * Return the first menu item locator including the text
38
+ */
39
+ locatorMenuItem(text: string) {
40
+ return this.locatorMenu.getByText(text).nth(0);
41
+ }
42
+
43
+ /**
44
+ * Bages container
45
+ */
46
+ get locatorBadges() {
47
+ return this.locatorRoot.locator('div.au-select-badge');
48
+ }
49
+
50
+ /**
51
+ * Return the first badge locator including the text
52
+ */
53
+ locatorBadgeItem(text: string) {
54
+ return this.locatorBadges.filter({hasText: text}).nth(0);
55
+ }
56
+
57
+ async state() {
58
+ return await this.locatorRoot.evaluate((rootNode: HTMLElement) => {
59
+ const badgesContainer = rootNode.querySelector('div[role="combobox"]');
60
+ const input: HTMLInputElement = rootNode.querySelector('input[type="text"]')!;
61
+
62
+ const badges = [];
63
+ if (badgesContainer) {
64
+ const badgeElements = badgesContainer.querySelectorAll('div.au-select-badge');
65
+ for (const badgeElement of badgeElements) {
66
+ badges.push(badgeElement?.textContent?.trim());
67
+ }
68
+ }
69
+
70
+ const menuElement = rootNode.querySelector('ul.dropdown-menu');
71
+ const isOpen = menuElement != null;
72
+ const list: Array<string | undefined> = [];
73
+ const checked: Array<string | undefined> = [];
74
+ if (menuElement != null) {
75
+ const lis = menuElement.querySelectorAll('li.dropdown-item');
76
+ for (const li of lis) {
77
+ const text = li.textContent?.trim();
78
+ list.push(text);
79
+ if (li.classList.contains('selected')) {
80
+ checked.push(text);
81
+ }
82
+ }
83
+ }
84
+
85
+ return {
86
+ text: input.value,
87
+ badges,
88
+ isOpen,
89
+ list,
90
+ checked,
91
+ };
92
+ });
93
+ }
94
+ }
@@ -0,0 +1,73 @@
1
+ import {BasePO} from '@agnos-ui/base-po';
2
+ import type {Locator} from '@playwright/test';
3
+
4
+ export const sliderSelectors = {
5
+ rootComponent: '.au-slider',
6
+ clickableArea: '.au-slider-clickable-area',
7
+ handle: '.au-slider-handle',
8
+ minLabelHorizontal: '.au-slider-label-min',
9
+ maxLabelHorizontal: '.au-slider-label-max',
10
+ minLabelVertical: '.au-slider-label-vertical-min',
11
+ maxLabelVertical: '.au-slider-label-vertical-max',
12
+ valueLabel: '.au-slider-label-now',
13
+ progress: '.au-slider-progress',
14
+ };
15
+
16
+ export class SliderPO extends BasePO {
17
+ selectors = structuredClone(sliderSelectors);
18
+
19
+ override getComponentSelector(): string {
20
+ return this.selectors.rootComponent;
21
+ }
22
+
23
+ get locatorHandle(): Locator {
24
+ return this.locatorRoot.locator(this.selectors.handle);
25
+ }
26
+
27
+ get locatorMinLabelHorizontal(): Locator {
28
+ return this.locatorRoot.locator(this.selectors.minLabelHorizontal);
29
+ }
30
+
31
+ get locatorMaxLabelHorizontal(): Locator {
32
+ return this.locatorRoot.locator(this.selectors.maxLabelHorizontal);
33
+ }
34
+
35
+ get locatorMinLabelVertical(): Locator {
36
+ return this.locatorRoot.locator(this.selectors.minLabelVertical);
37
+ }
38
+
39
+ get locatorMaxLabelVertical(): Locator {
40
+ return this.locatorRoot.locator(this.selectors.maxLabelVertical);
41
+ }
42
+
43
+ get locatorProgress(): Locator {
44
+ return this.locatorRoot.locator(this.selectors.progress);
45
+ }
46
+
47
+ get locatorValueLabel(): Locator {
48
+ return this.locatorRoot.locator(this.selectors.valueLabel);
49
+ }
50
+
51
+ async sliderHandleState() {
52
+ return this.locatorRoot.locator(this.selectors.handle).evaluateAll((rootNode: HTMLElement[]) => {
53
+ return rootNode.map((rn) => {
54
+ return {
55
+ style: rn.getAttribute('style'),
56
+ value: rn.getAttribute('aria-valuenow'),
57
+ min: rn.getAttribute('aria-valuemin'),
58
+ max: rn.getAttribute('aria-valuemax'),
59
+ disabled: rn.getAttribute('aria-disabled'),
60
+ readonly: rn.getAttribute('aria-readonly'),
61
+ ariaLabel: rn.getAttribute('aria-label'),
62
+ ariaValueText: rn.getAttribute('aria-valuetext'),
63
+ };
64
+ });
65
+ });
66
+ }
67
+
68
+ async sliderProgressState() {
69
+ return this.locatorRoot.locator(this.selectors.progress).evaluateAll((rootNode: HTMLElement[]) => {
70
+ return rootNode.map((rn) => rn.getAttribute('style'));
71
+ });
72
+ }
73
+ }
@@ -0,0 +1,35 @@
1
+ import type {Locator} from '@playwright/test';
2
+ import {BasePO} from '@agnos-ui/base-po';
3
+
4
+ export const toastSelectors = {
5
+ rootComponent: '.toast',
6
+ closeButton: '.btn-close',
7
+ header: '.toast-header',
8
+ body: '.toast-body',
9
+ };
10
+
11
+ export class ToastPO extends BasePO {
12
+ selectors = structuredClone(toastSelectors);
13
+
14
+ override getComponentSelector(): string {
15
+ return this.selectors.rootComponent;
16
+ }
17
+
18
+ get locatorCloseButton(): Locator {
19
+ return this.locatorRoot.locator(this.selectors.closeButton);
20
+ }
21
+
22
+ async state() {
23
+ return await this.locatorRoot.evaluate((rootNode: HTMLElement, selectors) => {
24
+ const body = rootNode.querySelector<HTMLDivElement>(selectors.body)?.innerText;
25
+ const header = rootNode.querySelector<HTMLDivElement>(selectors.header)?.innerText;
26
+ const closeButton = rootNode.querySelector<HTMLButtonElement>(selectors.closeButton)?.getAttribute('aria-label');
27
+ return {
28
+ rootClasses: rootNode.className.trim().split(' ').sort(),
29
+ body,
30
+ header,
31
+ closeButton,
32
+ };
33
+ }, this.selectors);
34
+ }
35
+ }