Skip to content

Commit 71b5dcc

Browse files
authored
Introduce page objects (#168)
1 parent 92410ab commit 71b5dcc

22 files changed

Lines changed: 1301 additions & 1083 deletions

File tree

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { type Locator, type Page } from "@playwright/test";
2+
3+
export class CommonPage {
4+
reportTitleLocator: Locator;
5+
6+
toggleLayoutButtonLocator: Locator;
7+
splitLayoutLocator: Locator;
8+
singleLayoutLocator: Locator;
9+
10+
envPickerLocator: Locator;
11+
envPickerButtonLocator: Locator;
12+
13+
constructor(readonly page: Page) {
14+
this.reportTitleLocator = page.getByTestId("report-title");
15+
16+
this.toggleLayoutButtonLocator = page.getByTestId("toggle-layout-button");
17+
this.splitLayoutLocator = page.getByTestId("split-layout");
18+
this.singleLayoutLocator = page.getByTestId("base-layout");
19+
20+
this.envPickerLocator = page.getByTestId("environment-picker");
21+
this.envPickerButtonLocator = page.getByTestId("environment-picker-button");
22+
}
23+
24+
async toggleLayout() {
25+
await this.toggleLayoutButtonLocator.click();
26+
}
27+
28+
async selectEnv(env: string) {
29+
await this.envPickerButtonLocator.click();
30+
await this.envPickerLocator.getByText(env).click();
31+
}
32+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { type Locator, type Page } from "@playwright/test";
2+
3+
export class TestResultPage {
4+
titleLocator: Locator;
5+
fullnameLocator: Locator;
6+
fullnameCopyLocator: Locator;
7+
8+
statusPassedLocator: Locator;
9+
statusFailedLocator: Locator;
10+
statusSkippedLocator: Locator;
11+
statusBrokenLocator: Locator;
12+
statusUnknownLocator: Locator;
13+
14+
navPrevLocator: Locator;
15+
navNextLocator: Locator;
16+
navCurrentLocator: Locator;
17+
18+
errorMessageLocator: Locator;
19+
errorTraceLocator: Locator;
20+
errorDiffButtonLocator: Locator;
21+
errorDiffLocator: Locator;
22+
23+
tabLocator: Locator;
24+
25+
envItemLocator: Locator;
26+
27+
constructor(readonly page: Page) {
28+
this.titleLocator = page.getByTestId("test-result-info-title");
29+
this.fullnameLocator = page.getByTestId("test-result-fullname");
30+
this.fullnameCopyLocator = page.getByTestId("test-result-fullname-copy");
31+
32+
this.statusPassedLocator = page.getByTestId("test-result-status-passed");
33+
this.statusFailedLocator = page.getByTestId("test-result-status-failed");
34+
this.statusSkippedLocator = page.getByTestId("test-result-status-skipped");
35+
this.statusBrokenLocator = page.getByTestId("test-result-status-broken");
36+
this.statusUnknownLocator = page.getByTestId("test-result-status-unknown");
37+
38+
this.navPrevLocator = page.getByTestId("test-result-nav-prev");
39+
this.navNextLocator = page.getByTestId("test-result-nav-next");
40+
this.navCurrentLocator = page.getByTestId("test-result-nav-current");
41+
42+
this.errorMessageLocator = page.getByTestId("test-result-error-message");
43+
this.errorTraceLocator = page.getByTestId("test-result-error-trace");
44+
this.errorDiffButtonLocator = page.getByTestId("test-result-diff-button");
45+
this.errorDiffLocator = page.getByTestId("test-result-diff");
46+
47+
this.tabLocator = page.getByTestId("test-result-tab");
48+
49+
this.envItemLocator = page.getByTestId("test-result-env-item");
50+
}
51+
52+
get envTabLocator() {
53+
return this.tabById("environments");
54+
}
55+
56+
tabById(id: string) {
57+
return this.page.getByTestId(`test-result-tab-${id}`);
58+
}
59+
60+
async clickNextTestResult() {
61+
await this.navNextLocator.click();
62+
}
63+
64+
async clickPrevTestResult() {
65+
await this.navPrevLocator.click();
66+
}
67+
68+
async copyFullname() {
69+
await this.fullnameCopyLocator.click();
70+
}
71+
}
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
import { type Locator, type Page } from "@playwright/test";
2+
import { randomNumber } from "../../utils/index.js";
3+
4+
export class TreePage {
5+
leafLocator: Locator;
6+
7+
leafStatusPassedLocator: Locator;
8+
leafStatusFailedLocator: Locator;
9+
leafStatusSkippedLocator: Locator;
10+
leafStatusBrokenLocator: Locator;
11+
leafStatusUnknownLocator: Locator;
12+
13+
sectionsLocator: Locator;
14+
searchLocator: Locator;
15+
searchClearLocator: Locator;
16+
17+
metadataTotalLocator: Locator;
18+
metadataRetriesLocator: Locator;
19+
metadataFlakyLocator: Locator;
20+
metadataPassedLocator: Locator;
21+
metadataFailedLocator: Locator;
22+
metadataSkippedLocator: Locator;
23+
metadataBrokenLocator: Locator;
24+
metadataUnknownLocator: Locator;
25+
26+
envSectionButtonLocator: Locator;
27+
envSectionContentLocator: Locator;
28+
29+
filtersButtonLocator: Locator;
30+
filtersMenuLocator: Locator;
31+
32+
retryFilterLocator: Locator;
33+
flakyFilterLocator: Locator;
34+
35+
constructor(readonly page: Page) {
36+
this.leafLocator = page.getByTestId("tree-leaf");
37+
38+
this.leafStatusPassedLocator = page.getByTestId("tree-leaf-status-passed");
39+
this.leafStatusFailedLocator = page.getByTestId("tree-leaf-status-failed");
40+
this.leafStatusSkippedLocator = page.getByTestId("tree-leaf-status-skipped");
41+
this.leafStatusBrokenLocator = page.getByTestId("tree-leaf-status-broken");
42+
this.leafStatusUnknownLocator = page.getByTestId("tree-leaf-status-unknown");
43+
44+
this.sectionsLocator = page.getByTestId("tree-section");
45+
this.searchLocator = page.getByTestId("search-input");
46+
this.searchClearLocator = page.getByTestId("clear-button");
47+
48+
this.metadataTotalLocator = page.getByTestId("metadata-item-total");
49+
this.metadataRetriesLocator = page.getByTestId("metadata-item-retries");
50+
this.metadataFlakyLocator = page.getByTestId("metadata-item-flaky");
51+
this.metadataPassedLocator = page.getByTestId("metadata-item-passed");
52+
this.metadataFailedLocator = page.getByTestId("metadata-item-failed");
53+
this.metadataBrokenLocator = page.getByTestId("metadata-item-broken");
54+
this.metadataSkippedLocator = page.getByTestId("metadata-item-skipped");
55+
this.metadataUnknownLocator = page.getByTestId("metadata-item-unknown");
56+
57+
this.envSectionContentLocator = page.getByTestId("tree-section-env-content");
58+
this.envSectionButtonLocator = page.getByTestId("tree-section-env-button");
59+
60+
this.filtersButtonLocator = page.getByTestId("filters-button");
61+
this.filtersMenuLocator = page.getByTestId("filters-menu");
62+
63+
this.retryFilterLocator = page.getByTestId("retry-filter");
64+
this.flakyFilterLocator = page.getByTestId("flaky-filter");
65+
}
66+
67+
getNthLeafLocator(n: number) {
68+
return this.leafLocator.nth(n);
69+
}
70+
71+
getNthLeafTitleLocator(n: number) {
72+
return this.getNthLeafLocator(n).getByTestId("tree-leaf-title");
73+
}
74+
75+
getNthLeafOrderLocator(n: number) {
76+
return this.getNthLeafLocator(n).getByTestId("tree-leaf-order");
77+
}
78+
79+
getNthLeafPassedStatusLocator(n: number) {
80+
return this.getNthLeafLocator(n).getByTestId("tree-leaf-status-passed");
81+
}
82+
83+
getNthLeafFailedStatusLocator(n: number) {
84+
return this.getNthLeafLocator(n).getByTestId("tree-leaf-status-failed");
85+
}
86+
87+
getNthLeafSkippedStatusLocator(n: number) {
88+
return this.getNthLeafLocator(n).getByTestId("tree-leaf-status-skipped");
89+
}
90+
91+
getNthLeafBrokenStatusLocator(n: number) {
92+
return this.getNthLeafLocator(n).getByTestId("tree-leaf-status-broken");
93+
}
94+
95+
getNthLeafUnknownStatusLocator(n: number) {
96+
return this.getNthLeafLocator(n).getByTestId("tree-leaf-status-unknown");
97+
}
98+
99+
getNthSectionLocator(n: number) {
100+
return this.sectionsLocator.nth(n);
101+
}
102+
103+
getNthSectionTitleLocator(n: number) {
104+
return this.getNthSectionLocator(n).getByTestId("tree-section-title");
105+
}
106+
107+
getLeafByTitle(title: string) {
108+
return this.leafLocator.filter({
109+
has: this.page.getByText(title, { exact: true }),
110+
});
111+
}
112+
113+
async getMetadataValue(
114+
metadata: "total" | "retries" | "flaky" | "passed" | "failed" | "skipped" | "broken" | "unknown" = "total",
115+
) {
116+
let baseLocator: Locator;
117+
118+
switch (metadata) {
119+
case "total":
120+
baseLocator = this.metadataTotalLocator;
121+
break;
122+
case "retries":
123+
baseLocator = this.metadataRetriesLocator;
124+
break;
125+
case "flaky":
126+
baseLocator = this.metadataFlakyLocator;
127+
break;
128+
case "passed":
129+
baseLocator = this.metadataPassedLocator;
130+
break;
131+
case "failed":
132+
baseLocator = this.metadataFailedLocator;
133+
break;
134+
case "skipped":
135+
baseLocator = this.metadataSkippedLocator;
136+
break;
137+
case "broken":
138+
baseLocator = this.metadataBrokenLocator;
139+
break;
140+
case "unknown":
141+
baseLocator = this.metadataUnknownLocator;
142+
break;
143+
default:
144+
throw new Error(`Unknown metadata: ${metadata as string}`);
145+
}
146+
147+
try {
148+
return (await baseLocator.getByTestId("metadata-value").innerText({ timeout: 1000 })).trim();
149+
} catch (err) {
150+
return undefined;
151+
}
152+
}
153+
154+
async getMetadataValues() {
155+
return {
156+
total: await this.getMetadataValue("total"),
157+
retries: await this.getMetadataValue("retries"),
158+
flaky: await this.getMetadataValue("flaky"),
159+
passed: await this.getMetadataValue("passed"),
160+
failed: await this.getMetadataValue("failed"),
161+
skipped: await this.getMetadataValue("skipped"),
162+
broken: await this.getMetadataValue("broken"),
163+
unknown: await this.getMetadataValue("unknown"),
164+
};
165+
}
166+
167+
async clickNthLeaf(n: number) {
168+
await this.leafLocator.nth(n).click();
169+
}
170+
171+
async clickRandomLeaf() {
172+
// wait before any leaf appear
173+
await this.leafLocator.nth(0).waitFor({ state: "visible" });
174+
175+
const leavesCount = await this.leafLocator.count();
176+
177+
if (leavesCount === 0) {
178+
throw new Error("No leaves found");
179+
}
180+
181+
await this.leafLocator.nth(randomNumber(0, leavesCount - 1)).click();
182+
}
183+
184+
async toggleNthSection(n: number) {
185+
await this.sectionsLocator.nth(n).getByTestId("tree-arrow").click();
186+
}
187+
188+
async clickTreeTab(tab: string) {
189+
await this.page.getByTestId(`tab-${tab}`).click();
190+
}
191+
192+
async searchTree(text: string) {
193+
await this.searchLocator.fill(text);
194+
}
195+
196+
async searchClear() {
197+
await this.searchClearLocator.click();
198+
}
199+
200+
async openFilterMenu() {
201+
await this.filtersButtonLocator.click();
202+
await this.filtersMenuLocator.waitFor({ state: "visible" });
203+
}
204+
205+
async closeFilterMenu() {
206+
await this.filtersMenuLocator.waitFor({ state: "visible" });
207+
await this.filtersButtonLocator.click();
208+
await this.filtersMenuLocator.waitFor({ state: "hidden" });
209+
}
210+
211+
async toggleRetryFilter() {
212+
await this.openFilterMenu();
213+
await this.retryFilterLocator.click();
214+
await this.closeFilterMenu();
215+
}
216+
217+
async toggleFlakyFilter() {
218+
await this.openFilterMenu();
219+
await this.flakyFilterLocator.click();
220+
await this.closeFilterMenu();
221+
}
222+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from "./Tree.js";
2+
export * from "./TestResult.js";
3+
export * from "./Common.js";

0 commit comments

Comments
 (0)