Skip to content

Commit 7c84e27

Browse files
Maggie DongSkCQ
authored andcommitted
Add point-links puppeteer test.
Bug: b/457471965 Change-Id: I8a19fab710ae2041c310173f33df082e075b5d44 Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/1117223 Reviewed-by: Anri Sidorov <[email protected]> Commit-Queue: Maggie Dong <[email protected]>
1 parent 20d0b63 commit 7c84e27

File tree

8 files changed

+160
-24
lines changed

8 files changed

+160
-24
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,11 @@
11
export const DEFAULT_VIEWPORT = { width: 600, height: 600 };
2+
3+
/**
4+
* Common timeouts and intervals used in PointLinksSkPO.
5+
*/
6+
export const POLLING_CONSTANT = {
7+
TIMEOUT_MS: 30000,
8+
INTERVAL_MS: 100,
9+
};
10+
11+
export const CLIPBOARD_READ_TIMEOUT_MS = 5000; // 5 second timeout

perf/modules/point-links-sk/BUILD.bazel

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
load("//infra-sk:index.bzl", "karma_test", "sk_demo_page_server", "sk_element", "sk_element_puppeteer_test", "sk_page")
1+
load("//infra-sk:index.bzl", "karma_test", "sk_demo_page_server", "sk_element", "sk_element_puppeteer_test", "sk_page", "ts_library")
22

33
sk_demo_page_server(
44
name = "demo_page_server",
@@ -37,13 +37,27 @@ sk_page(
3737
ts_entry_point = "point-links-sk-demo.ts",
3838
)
3939

40+
ts_library(
41+
name = "point-links-sk_po_ts_lib",
42+
srcs = ["point-links-sk_po.ts"],
43+
visibility = ["//visibility:public"],
44+
deps = [
45+
"//infra-sk/modules/page_object:page_object_element_ts_lib",
46+
"//infra-sk/modules/page_object:page_object_ts_lib",
47+
"//perf/modules/common:puppeteer-test-util_ts_lib",
48+
],
49+
)
50+
4051
sk_element_puppeteer_test(
4152
name = "point-links-sk_puppeteer_test",
4253
src = "point-links-sk_puppeteer_test.ts",
4354
sk_demo_page_server = ":demo_page_server",
4455
deps = [
56+
":point-links-sk_po_ts_lib",
4557
"//:node_modules/@types/chai",
4658
"//:node_modules/chai",
59+
"//:node_modules/puppeteer",
60+
"//perf/modules/common:puppeteer-test-util_ts_lib",
4761
"//puppeteer-tests:util_ts_lib",
4862
],
4963
)

perf/modules/point-links-sk/point-links-sk-demo.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
<body class="body-sk">
1010
<h1>point-links-sk</h1>
1111
<point-links-sk id="different-commits"></point-links-sk>
12-
<point-links-sk id="same-commits"></point-links-sk>
1312

1413
<h2>Events</h2>
1514
<pre id=events></pre>
15+
16+
<button id="copy-links">Click Links</button>
1617
</body>
1718
</html>

perf/modules/point-links-sk/point-links-sk-demo.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,21 @@ fetchMock.post('/_/details/?results=false', (_url, request) => {
3535
}
3636
});
3737

38+
const returnLinks = {
39+
buildKey: 'https://v8/builder/build1',
40+
traceKey: 'https://traceViewer/trace',
41+
};
42+
43+
fetchMock.post('/_/links/', {
44+
version: 1,
45+
links: returnLinks,
46+
});
47+
48+
// Expose fetchMock globally and ensure it intercepts fetch calls.
49+
// This is crucial for Puppeteer tests where fetchMock needs to be active on the page.
50+
(window as any).fetchMock = fetchMock;
51+
3852
window.customElements.whenDefined('point-links-sk').then(() => {
3953
const links1 = document.getElementById('different-commits') as PointLinksSk;
40-
const links2 = document.getElementById('same-commits') as PointLinksSk;
4154
links1.load(CommitNumber(12), CommitNumber(11), 'foo', ['V8 Git Hash'], ['Build Page'], []);
42-
links2.load(CommitNumber(10), CommitNumber(11), 'foo', ['V8 Git Hash'], ['Build Page'], []);
4355
});

perf/modules/point-links-sk/point-links-sk.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ export class PointLinksSk extends ElementSk {
119119
return html` <li>
120120
<span id="tooltip-key">${keyText}</span>
121121
<span id="tooltip-text"> ${link.startsWith('http') ? htmlUrl : link} </span>
122-
<md-icon-button @click=${() => this.copyToClipboard(link)}>
123-
<md-icon id="copy-icon">content_copy</md-icon>
124-
</md-icon-button>
122+
<md-outlined-icon-button id="copy-link-button" @click=${() => this.copyToClipboard(link)}>
123+
<md-icon id="copy-icon" .icon=${'content_copy'}></md-icon>
124+
</md-outlined-icon-button>
125125
</li>`;
126126
};
127127
const htmlPromises = keys.map(getHtml);
@@ -247,7 +247,7 @@ export class PointLinksSk extends ElementSk {
247247
// Reuse the existing links
248248
this.displayUrls = existingLink.displayUrls || {};
249249
this.displayTexts = existingLink.displayTexts || {};
250-
this.renderPointLinks();
250+
await this.renderPointLinks();
251251
return Promise.resolve(commitLinks);
252252
}
253253
}
@@ -328,7 +328,7 @@ export class PointLinksSk extends ElementSk {
328328

329329
this.displayTexts = displayTexts;
330330
this.displayUrls = displayUrls;
331-
this.renderPointLinks();
331+
await this.renderPointLinks();
332332

333333
// Before adding a new commit link, check if it already exists in the array.
334334
// This should not be necessary, but it is a safeguard due to async calls.
@@ -352,11 +352,11 @@ export class PointLinksSk extends ElementSk {
352352
}
353353

354354
/** Clear Point Links */
355-
reset(): void {
355+
async reset(): Promise<void> {
356356
this.commitPosition = null;
357357
this.displayUrls = {};
358358
this.displayTexts = {};
359-
this.renderPointLinks();
359+
await this.renderPointLinks();
360360
}
361361

362362
render(): void {
@@ -454,7 +454,7 @@ export class PointLinksSk extends ElementSk {
454454
const json = await jsonOrThrow(resp);
455455
const format = json as ingest.Format;
456456
response = format.links!;
457-
// Currently in fuchsia json response, the key-value pair is not "Build Log": "url".
457+
// Currently in fuchsia json response. The key-value pair is not "Build Log": "url".
458458
// For example, the key-value format for fuchsia instance is:
459459
// Test stdio: '[Build Log](https://ci.chromium.org/b/8719307892946930401)'
460460
if (format.links && format.links![this.fuchsiaBuildLogKey]) {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { PageObject } from '../../../infra-sk/modules/page_object/page_object';
2+
import { PageObjectElementList } from '../../../infra-sk/modules/page_object/page_object_element';
3+
import { POLLING_CONSTANT } from '../common/puppeteer-test-util';
4+
5+
export class PointLinksSkPO extends PageObject {
6+
get copyButtons(): PageObjectElementList {
7+
return this.bySelectorAll('md-outlined-icon-button');
8+
}
9+
10+
async clickCopyButton(index: number): Promise<void> {
11+
const copyButton = this.copyButtons.item(index);
12+
13+
await (await copyButton).click();
14+
}
15+
16+
private async poll(
17+
checkFn: () => Promise<boolean>,
18+
message: string,
19+
timeout = POLLING_CONSTANT.TIMEOUT_MS,
20+
interval = POLLING_CONSTANT.INTERVAL_MS
21+
): Promise<void> {
22+
const startTime = Date.now();
23+
while (Date.now() - startTime < timeout) {
24+
if (await checkFn()) {
25+
return;
26+
}
27+
await new Promise((resolve) => setTimeout(resolve, interval));
28+
}
29+
throw new Error(`Timeout: ${message}`);
30+
}
31+
}
Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,95 @@
11
import { expect } from 'chai';
22
import { loadCachedTestBed, takeScreenshot, TestBed } from '../../../puppeteer-tests/util';
3+
import { PointLinksSkPO } from './point-links-sk_po';
4+
import { ElementHandle } from 'puppeteer';
5+
import { CLIPBOARD_READ_TIMEOUT_MS } from '../common/puppeteer-test-util';
36

47
describe('point-links-sk', () => {
58
let testBed: TestBed;
9+
let pointLinksSk: ElementHandle;
10+
let pointLinksSkPO: PointLinksSkPO;
11+
612
before(async () => {
713
testBed = await loadCachedTestBed();
814
});
915

1016
beforeEach(async () => {
1117
await testBed.page.goto(testBed.baseUrl);
12-
await testBed.page.setViewport({ width: 400, height: 550 });
18+
await testBed.page.setViewport({ width: 800, height: 550 });
19+
20+
pointLinksSk = (await testBed.page.$('point-links-sk'))!;
21+
pointLinksSkPO = new PointLinksSkPO(pointLinksSk);
22+
23+
// Set displayUrls and displayTexts directly for the component.
24+
await pointLinksSk.evaluate(
25+
async (el: any, displayUrls, displayTexts) => {
26+
// Made async
27+
el.displayUrls = displayUrls;
28+
el.displayTexts = displayTexts;
29+
await el.renderPointLinks();
30+
},
31+
{
32+
V8: 'https://chromium.googlesource.com/v8/v8/+log/f052b8c4db1f08d1f8275351c047854e6ff1805f..47f420e89ec1b33dacc048d93e0317ab7fec43dd?n=1000',
33+
},
34+
{
35+
V8: 'f052b8c4 - 47f420e8',
36+
}
37+
);
38+
});
39+
40+
afterEach(async () => {
41+
// No request interception or dynamic loading to clean up.
1342
});
1443

1544
it('should render the demo page (smoke test)', async () => {
16-
expect(await testBed.page.$$('point-links-sk')).to.have.length(2);
45+
expect(await testBed.page.$$('point-links-sk')).to.have.length(1);
46+
});
47+
48+
it('shows the default view', async () => {
49+
await takeScreenshot(testBed.page, 'perf', 'point-links-sk');
1750
});
1851

19-
describe('screenshots', () => {
20-
it('shows the default view', async () => {
21-
await takeScreenshot(testBed.page, 'perf', 'point-links-sk');
52+
it('copies link to clipboard', async () => {
53+
await testBed.page
54+
.browserContext()
55+
.overridePermissions(testBed.baseUrl, ['clipboard-read', 'clipboard-write']);
56+
57+
// Wait for the component to render the links.
58+
await testBed.page.waitForSelector('md-outlined-icon-button', { visible: true });
59+
await pointLinksSkPO.clickCopyButton(0);
60+
61+
let clipboardText = '';
62+
const startTime = Date.now();
63+
// set 5 second timeout
64+
while (Date.now() - startTime < CLIPBOARD_READ_TIMEOUT_MS) {
65+
clipboardText = await testBed.page.evaluate(() => navigator.clipboard.readText());
66+
if (clipboardText) {
67+
break;
68+
}
69+
await new Promise((r) => setTimeout(r, 100));
70+
}
71+
expect(clipboardText).to.not.null;
72+
await takeScreenshot(testBed.page, 'point-links', 'point-links-sk');
73+
});
74+
75+
it('should display the correct key and link text', async () => {
76+
await testBed.page.waitForSelector('md-outlined-icon-button', { visible: true });
77+
78+
const keyText = await testBed.page.evaluate(() => {
79+
const keySpan = document
80+
.querySelector('point-links-sk')
81+
?.shadowRoot?.querySelector('#tooltip-key');
82+
return keySpan ? keySpan.textContent?.trim() : '';
83+
});
84+
const linkText = await testBed.page.evaluate(() => {
85+
const linkSpan = document
86+
.querySelector('point-links-sk')
87+
?.shadowRoot?.querySelector('#tooltip-text a');
88+
return linkSpan ? linkSpan.textContent?.trim() : '';
2289
});
90+
91+
expect(keyText).to.not.null;
92+
expect(linkText).to.not.null;
93+
await takeScreenshot(testBed.page, 'point-links', 'point-links-sk');
2394
});
2495
});

perf/modules/point-links-sk/point-links-sk_test.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ describe('point-links-sk', () => {
1010
const newInstance = setUpElementUnderTest<PointLinksSk>('point-links-sk');
1111

1212
let element: PointLinksSk;
13-
beforeEach(() => {});
13+
beforeEach(() => {
14+
element = newInstance();
15+
fetchMock.reset();
16+
});
1417

1518
describe('Load links for a commit.', () => {
1619
const commitLinks: CommitLinks = {
@@ -23,12 +26,6 @@ describe('point-links-sk', () => {
2326
key4: 'Commit Link',
2427
},
2528
};
26-
27-
beforeEach(() => {
28-
element = newInstance();
29-
fetchMock.reset();
30-
});
31-
3229
it('With no eligible links.', () => {
3330
const currentCommitId = CommitNumber(4);
3431
const prevCommitId = CommitNumber(3);

0 commit comments

Comments
 (0)