Skip to content

Commit 72a4ae0

Browse files
committed
fixup! test(button-harness): add performance tests for buttons using the protractor harness env
1 parent e2db577 commit 72a4ae0

File tree

7 files changed

+381
-61
lines changed

7 files changed

+381
-61
lines changed
Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,56 @@
11
load("@npm_angular_dev_infra_private//benchmark/component_benchmark:component_benchmark.bzl", "component_benchmark")
2-
load("//tools:defaults.bzl", "ng_e2e_test_library", "ng_test_library", "ng_web_test_suite", "ts_library")
2+
load("//tools:defaults.bzl", "ng_test_library", "ng_web_test_suite", "ts_library")
33

4-
# TODO(wagnermaciel): Update this target to provide indigo-pink in a way that doesn't require having to import it with
5-
# stylesUrls inside the components once `component_benchmark` supports asset injection.
4+
package(default_visibility = ["//visibility:public"])
5+
6+
# These are two separate files that provide the same tidy interface for running a performance
7+
# benchmark.
8+
#
9+
# I am not sure why the testbed version of the test does not log console.time to the terminal,
10+
# although I assume it has something to do with the default karma config that is generated by
11+
# karma_web_test_suite (which is wrapped by ng_web_test_suite).
12+
#
13+
# I am equally lost as to why the performance api exists for the testbed tests but not for the
14+
# protractor tests.
15+
#
16+
# If you have any idea why these things happen, please let me know - @wagnermaciel.
17+
18+
ts_library(
19+
name = "constants",
20+
srcs = [":constants.ts"],
21+
)
22+
23+
ts_library(
24+
name = "protractor-benchmark-utilities",
25+
srcs = [":protractor-benchmark-utilities.ts"],
26+
deps = [
27+
":constants",
28+
"@npm//@angular/dev-infra-private",
29+
],
30+
)
31+
32+
ts_library(
33+
name = "testbed-benchmark-utilities",
34+
srcs = [":testbed-benchmark-utilities.ts"],
35+
deps = [":constants"],
36+
)
37+
38+
# ProtractorHarnessEnvironment
639

740
component_benchmark(
841
name = "benchmark",
942
driver = ":protractor.perf-spec.ts",
1043
driver_deps = [
11-
"@npm//@angular/dev-infra-private",
44+
":constants",
45+
":protractor-benchmark-utilities",
1246
"@npm//protractor",
1347
"@npm//@types/jasmine",
1448
"//src/cdk/testing",
1549
"//src/material/button/testing",
1650
"//src/cdk/testing/protractor",
1751
],
1852
ng_deps = [
53+
":constants",
1954
"@npm//@angular/core",
2055
"@npm//@angular/platform-browser",
2156
"//src/material/button",
@@ -24,3 +59,24 @@ component_benchmark(
2459
prefix = "",
2560
styles = ["//src/material/prebuilt-themes:indigo-pink"],
2661
)
62+
63+
# TestbedHarnessEnvironment
64+
65+
ng_test_library(
66+
name = "unit-test-lib",
67+
srcs = ["testbed.perf-spec.ts"],
68+
deps = [
69+
":constants",
70+
":testbed-benchmark-utilities",
71+
"//src/material/button/testing",
72+
"//src/cdk/testing",
73+
"//src/cdk/testing/testbed",
74+
"//src/material/button",
75+
"@npm//@angular/dev-infra-private",
76+
],
77+
)
78+
79+
ng_web_test_suite(
80+
name = "unit-tests",
81+
deps = [":unit-test-lib"],
82+
)

test/benchmarks/material/button-harness/app.module.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,20 @@
99
import {Component, NgModule, ViewEncapsulation} from '@angular/core';
1010
import {BrowserModule} from '@angular/platform-browser';
1111
import {MatButtonModule} from '@angular/material/button';
12+
import {NUM_BUTTONS} from './constants';
1213

1314
/** component: mat-raised-button-harness-test */
1415

1516
@Component({
16-
selector: 'app-root',
17+
selector: 'app-root',
1718
template: `
1819
<button *ngFor="let val of vals" mat-button> {{ val }} </button>
19-
`,
20-
encapsulation: ViewEncapsulation.None,
20+
`,
21+
encapsulation: ViewEncapsulation.None,
2122
styleUrls: ['//src/material/core/theming/prebuilt/indigo-pink.css'],
2223
})
2324
export class ButtonHarnessTest {
24-
vals = Array.from({ length: 100 }, (_, i) => i);
25+
vals = Array.from({ length: NUM_BUTTONS }, (_, i) => i);
2526
}
2627

2728
@NgModule({
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
export const USE_BENCHPRESS = false;
10+
export const NUM_BUTTONS = 5;
11+
export const FIRST_BUTTON = '0';
12+
export const MIDDLE_BUTTON = `${Math.floor(NUM_BUTTONS / 2)}`;
13+
export const LAST_BUTTON = `${NUM_BUTTONS - 1}`;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {runBenchmark} from '@angular/dev-infra-private/benchmark/driver-utilities';
10+
import {USE_BENCHPRESS} from './constants';
11+
12+
/**
13+
* Records the performance of the given function.
14+
*
15+
* @param id A unique identifier.
16+
* @param callback A function whose performance will be recorded.
17+
*/
18+
export async function benchmark(id: string, callback: Function) {
19+
if (USE_BENCHPRESS) {
20+
await benchmarkWithBenchpress(id, callback);
21+
} else {
22+
await benchmarkWithConsoleAPI(id, callback);
23+
}
24+
}
25+
26+
/**
27+
* A simple wrapper for runBenchmark ... which is a wrapper for benchpress.
28+
*
29+
* @param id
30+
* @param callback
31+
*/
32+
async function benchmarkWithBenchpress(id: string, callback: Function) {
33+
await runBenchmark({
34+
id,
35+
url: '',
36+
ignoreBrowserSynchronization: true,
37+
params: [],
38+
work: async () => await callback(),
39+
});
40+
}
41+
42+
/**
43+
* Uses console.time with the given id to record the time it takes for the given callback to run.
44+
*
45+
* @param id
46+
* @param callback
47+
*/
48+
async function benchmarkWithConsoleAPI(id: string, callback: Function) {
49+
console.time(id);
50+
await callback();
51+
console.timeEnd(id);
52+
}

test/benchmarks/material/button-harness/protractor.perf-spec.ts

Lines changed: 84 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6,65 +6,96 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {HarnessLoader} from '@angular/cdk/testing';
9+
import {HarnessLoader, HarnessPredicate} from '@angular/cdk/testing';
1010
import {MatButtonHarness} from '@angular/material/button/testing/button-harness';
11-
import {runBenchmark} from '@angular/dev-infra-private/benchmark/driver-utilities';
1211
import {ProtractorHarnessEnvironment} from '@angular/cdk/testing/protractor';
12+
import {$$, element, by, browser} from 'protractor';
13+
import {benchmark} from './protractor-benchmark-utilities';
14+
import {NUM_BUTTONS} from './constants';
1315

14-
let loader: HarnessLoader;
16+
const FIRST_BUTTON = '0';
17+
const MIDDLE_BUTTON = `${Math.floor(NUM_BUTTONS / 2)}`;
18+
const LAST_BUTTON = `${NUM_BUTTONS - 1}`;
1519

16-
describe('perf test for basic protractor harness', () => {
17-
it('should load the protractor harness environment', async () => {
18-
await runBenchmark({
19-
id: 'initial-harness-load',
20-
url: '',
21-
ignoreBrowserSynchronization: true,
22-
params: [],
23-
work: () => { loader = ProtractorHarnessEnvironment.loader(); },
24-
});
25-
});
20+
describe('performance baseline for the protractor harness', () => {
21+
beforeEach(async () => {
22+
await browser.get('');
23+
});
2624

27-
it('should retrieve all of the buttons', async () => {
28-
await runBenchmark({
29-
id: 'get-first-button',
30-
url: '',
31-
ignoreBrowserSynchronization: true,
32-
params: [],
33-
setup: () => { loader = ProtractorHarnessEnvironment.loader(); },
34-
work: async () => await loader.getAllHarnesses(MatButtonHarness),
35-
});
36-
});
25+
it('(baseline) should retrieve all of the buttons', async () => {
26+
await benchmark('(baseline) get every button', async () => {
27+
await $$('.mat-button');
28+
});
29+
});
3730

38-
it('should retrieve the first button', async () => {
39-
await runBenchmark({
40-
id: 'get-first-button',
41-
url: '',
42-
ignoreBrowserSynchronization: true,
43-
params: [],
44-
setup: () => { loader = ProtractorHarnessEnvironment.loader(); },
45-
work: async () => await (await loader.getHarness(MatButtonHarness.with({text: '0'}))).click(),
46-
});
47-
});
31+
it('(baseline) should click the first button', async () => {
32+
await benchmark('(baseline) click first button', async () => {
33+
await element(by.buttonText(FIRST_BUTTON)).click();
34+
});
35+
});
4836

49-
it('should retrieve the middle button', async () => {
50-
await runBenchmark({
51-
id: 'get-middle-button',
52-
url: '',
53-
ignoreBrowserSynchronization: true,
54-
params: [],
55-
setup: () => { loader = ProtractorHarnessEnvironment.loader(); },
56-
work: async () => await (await loader.getHarness(MatButtonHarness.with({text: '49'}))).click(),
57-
});
58-
});
37+
it('(baseline) should click the middle button', async () => {
38+
await benchmark('(baseline) click middle button', async () => {
39+
await element(by.buttonText(MIDDLE_BUTTON)).click();
40+
});
41+
});
5942

60-
it('should retrieve the last button', async () => {
61-
await runBenchmark({
62-
id: 'get-last-button',
63-
url: '',
64-
ignoreBrowserSynchronization: true,
65-
params: [],
66-
setup: () => { loader = ProtractorHarnessEnvironment.loader(); },
67-
work: async () => await (await loader.getHarness(MatButtonHarness.with({text: '99'}))).click(),
68-
});
69-
});
43+
it('(baseline) should click the last button', async () => {
44+
await benchmark('(baseline) click last button', async () => {
45+
await element(by.buttonText(LAST_BUTTON)).click();
46+
});
47+
});
48+
49+
it('(baseline) should click all of the buttons', async () => {
50+
await benchmark('(baseline) click every button', async () => {
51+
const buttons = $$('.mat-button');
52+
await buttons.each(async (button) => await button!.click());
53+
});
54+
});
55+
});
56+
57+
describe('performance tests for the protractor harness', () => {
58+
let loader: HarnessLoader;
59+
60+
beforeEach(async () => {
61+
await browser.get('');
62+
loader = ProtractorHarnessEnvironment.loader();
63+
});
64+
65+
it('should retrieve all of the buttons', async () => {
66+
await benchmark('get every button', async () => {
67+
await loader.getAllHarnesses(MatButtonHarness);
68+
});
69+
});
70+
71+
it('should click the first button', async () => {
72+
await benchmark('click first button', async () => {
73+
const button = await loader.getHarness(MatButtonHarness.with({text: FIRST_BUTTON}));
74+
await button.click();
75+
});
76+
});
77+
78+
it('should click the middle button', async () => {
79+
await benchmark('click middle button', async () => {
80+
const button = await loader.getHarness(MatButtonHarness.with({text: MIDDLE_BUTTON}));
81+
await button.click();
82+
});
83+
});
84+
85+
it('should click the last button', async () => {
86+
await benchmark('click last button', async () => {
87+
const button = await loader.getHarness(MatButtonHarness.with({text: LAST_BUTTON}));
88+
await button.click();
89+
});
90+
});
91+
92+
it('should click all of the buttons', async () => {
93+
await benchmark('click every button', async () => {
94+
const buttons = await loader.getAllHarnesses(MatButtonHarness);
95+
for (let i = 0; i < buttons.length; i++) {
96+
const button = buttons[i];
97+
await button.click();
98+
}
99+
});
100+
});
70101
});
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
/**
10+
* Records the performance of the given function.
11+
*
12+
* @param id A unique identifier.
13+
* @param callback A function whose performance will be recorded.
14+
*/
15+
export async function benchmark(id: string, callback: Function) {
16+
const t0 = performance.now();
17+
await callback();
18+
const t1 = performance.now();
19+
console.warn(`${id}: ${t1 - t0}`);
20+
}
21+
22+
export function getButtonWithText(text: string): HTMLButtonElement {
23+
const xpathExpression = `//button[//span[text()=' ${text} ']]`;
24+
const xPathResult = document.evaluate(
25+
xpathExpression,
26+
document,
27+
null,
28+
XPathResult.FIRST_ORDERED_NODE_TYPE,
29+
null
30+
);
31+
return xPathResult.singleNodeValue as HTMLButtonElement;
32+
}

0 commit comments

Comments
 (0)