Skip to content

Commit 6cbd4d1

Browse files
committed
fix(harness-benchmarks): lots of small changes
1 parent 4dc2d68 commit 6cbd4d1

File tree

7 files changed

+119
-124
lines changed

7 files changed

+119
-124
lines changed

test/benchmarks/material/button-harness/BUILD.bazel

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,9 @@ package(default_visibility = ["//visibility:public"])
66
# These are two separate files that provide the same tidy interface for running a performance
77
# benchmark.
88
#
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.
9+
# The testbed and protractor tests use different methods for measuring time. Since Karma does not
10+
# patch console.time, the results are not pushed back from the page to the Karma server. Instead
11+
# we use performance.now() to measure performance.
1712

1813
ts_library(
1914
name = "constants",
@@ -38,7 +33,7 @@ ts_library(
3833
# ProtractorHarnessEnvironment
3934

4035
component_benchmark(
41-
name = "benchmark",
36+
name = "e2e_benchmark",
4237
driver = ":protractor.perf-spec.ts",
4338
driver_deps = [
4439
":constants",
@@ -63,7 +58,7 @@ component_benchmark(
6358
# TestbedHarnessEnvironment
6459

6560
ng_test_library(
66-
name = "unit-test-lib",
61+
name = "unit_tests_lib",
6762
srcs = ["testbed.perf-spec.ts"],
6863
deps = [
6964
":constants",
@@ -77,6 +72,6 @@ ng_test_library(
7772
)
7873

7974
ng_web_test_suite(
80-
name = "unit-tests",
81-
deps = [":unit-test-lib"],
75+
name = "unit_benchmark_tests",
76+
deps = [":unit_tests_lib"],
8277
)

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
import {Component, NgModule, ViewEncapsulation} from '@angular/core';
1010
import {BrowserModule} from '@angular/platform-browser';
1111
import {MatButtonModule} from '@angular/material/button';
12+
<<<<<<< HEAD
13+
<<<<<<< HEAD
1214
import {NUM_BUTTONS} from './constants';
1315

1416
/** component: mat-button-harness-test */
17+
<<<<<<< HEAD
1518

1619
@Component({
1720
selector: 'app-root',
@@ -23,6 +26,30 @@ import {NUM_BUTTONS} from './constants';
2326
})
2427
export class ButtonHarnessTest {
2528
vals = Array.from({ length: NUM_BUTTONS }, (_, i) => i);
29+
=======
30+
=======
31+
import {NUM_BUTTONS} from './constants';
32+
>>>>>>> 72a4ae020 (fixup! test(button-harness): add performance tests for buttons using the protractor harness env)
33+
34+
/** component: mat-raised-button-harness-test */
35+
=======
36+
>>>>>>> bf160e8de (fixup! test(button-harness): add performance tests for buttons using the protractor harness env)
37+
38+
@Component({
39+
selector: 'app-root',
40+
template: `
41+
<button *ngFor="let val of vals" mat-button> {{ val }} </button>
42+
`,
43+
encapsulation: ViewEncapsulation.None,
44+
styleUrls: ['//src/material/core/theming/prebuilt/indigo-pink.css'],
45+
})
46+
export class ButtonHarnessTest {
47+
<<<<<<< HEAD
48+
vals = Array.from({ length: 100 }, (_, i) => i);
49+
>>>>>>> e2db57750 (test(button-harness): add performance tests for buttons using the protractor harness env)
50+
=======
51+
vals = Array.from({ length: NUM_BUTTONS }, (_, i) => i);
52+
>>>>>>> 72a4ae020 (fixup! test(button-harness): add performance tests for buttons using the protractor harness env)
2653
}
2754

2855
@NgModule({

test/benchmarks/material/button-harness/constants.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
10+
/**
11+
* Benchpress gives us fine-grained metrics on browser interactions. In some cases, we want to
12+
* just get a whole measurement of how long the entire interaction took.
13+
*/
914
export const USE_BENCHPRESS = false;
10-
export const NUM_BUTTONS = 5;
11-
export const FIRST_BUTTON = '0';
15+
16+
export const NUM_BUTTONS = 25;
1217
export const MIDDLE_BUTTON = `${Math.floor(NUM_BUTTONS / 2)}`;
13-
export const LAST_BUTTON = `${NUM_BUTTONS - 1}`;

test/benchmarks/material/button-harness/protractor-benchmark-utilities.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {USE_BENCHPRESS} from './constants';
1515
* @param id A unique identifier.
1616
* @param callback A function whose performance will be recorded.
1717
*/
18-
export async function benchmark(id: string, callback: Function) {
18+
export async function benchmark(id: string, callback: () => Promise<unknown>) {
1919
if (USE_BENCHPRESS) {
2020
await benchmarkWithBenchpress(id, callback);
2121
} else {
@@ -24,12 +24,9 @@ export async function benchmark(id: string, callback: Function) {
2424
}
2525

2626
/**
27-
* A simple wrapper for runBenchmark ... which is a wrapper for benchpress.
28-
*
29-
* @param id
30-
* @param callback
27+
* A simple wrapper for runBenchmark which is a wrapper for benchpress.
3128
*/
32-
async function benchmarkWithBenchpress(id: string, callback: Function) {
29+
async function benchmarkWithBenchpress(id: string, callback: () => Promise<unknown>) {
3330
await runBenchmark({
3431
id,
3532
url: '',
@@ -40,12 +37,9 @@ async function benchmarkWithBenchpress(id: string, callback: Function) {
4037
}
4138

4239
/**
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
40+
* Measures the time it takes to invoke the given function and prints the duration to the console.
4741
*/
48-
async function benchmarkWithConsoleAPI(id: string, callback: Function) {
42+
async function benchmarkWithConsoleAPI(id: string, callback: () => Promise<unknown>, runs = 5) {
4943
console.time(id);
5044
await callback();
5145
console.timeEnd(id);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const FIRST_BUTTON = '0';
1717
const MIDDLE_BUTTON = `${Math.floor(NUM_BUTTONS / 2)}`;
1818
const LAST_BUTTON = `${NUM_BUTTONS - 1}`;
1919

20-
describe('performance baseline for the protractor harness', () => {
20+
describe('baseline tests for interacting with the page through Protractor directly', () => {
2121
beforeEach(async () => {
2222
await browser.get('');
2323
});
@@ -54,7 +54,7 @@ describe('performance baseline for the protractor harness', () => {
5454
});
5555
});
5656

57-
describe('performance tests for the protractor harness', () => {
57+
describe('performance tests for the protractor button harness', () => {
5858
let loader: HarnessLoader;
5959

6060
beforeEach(async () => {

test/benchmarks/material/button-harness/testbed-benchmark-utilities.ts

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,19 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

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) {
9+
/**
10+
* Measures the time it takes to invoke the given function and prints the duration to the console.
11+
* @param id A unique identifier for the callback being measured.
12+
* @param callback A function whose performance will be recorded.
13+
* @param runs The number of times to run the callback.
14+
*/
15+
export async function benchmark(id: string, callback: () => Promise<unknown>, runs = 5) {
16+
// Currently karma does not send the logs from console.time to the server so console.time will
17+
// not show. As an alternative, we use performance.now()
1618
const t0 = performance.now();
17-
await callback();
19+
for (let i = 0; i < runs; i++) {
20+
await callback();
21+
}
1822
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;
23+
console.warn(`${id}: ${((t1 - t0) / runs).toFixed(2)}ms (avg over ${runs} runs)`);
3224
}

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

Lines changed: 58 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,16 @@ import {Component} from '@angular/core';
1212
import {ComponentFixture, TestBed} from '@angular/core/testing';
1313
import {MatButtonModule} from '@angular/material/button';
1414
import {MatButtonHarness} from '@angular/material/button/testing/button-harness';
15-
import {benchmark, getButtonWithText} from './testbed-benchmark-utilities';
16-
import {FIRST_BUTTON, MIDDLE_BUTTON, NUM_BUTTONS, LAST_BUTTON} from './constants';
15+
import {MIDDLE_BUTTON, NUM_BUTTONS} from './constants';
16+
import {benchmark} from './testbed-benchmark-utilities';
1717

18-
describe('performance baseline for the testbed harness', () => {
18+
describe('performance for the testbed harness environment', () => {
1919
let fixture: ComponentFixture<ButtonHarnessTest>;
20+
let loader: HarnessLoader;
21+
22+
beforeAll(() => {
23+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 36000000;
24+
});
2025

2126
beforeEach(async () => {
2227
await TestBed.configureTestingModule({
@@ -26,103 +31,81 @@ describe('performance baseline for the testbed harness', () => {
2631

2732
fixture = TestBed.createComponent(ButtonHarnessTest);
2833
fixture.detectChanges();
34+
loader = TestbedHarnessEnvironment.loader(fixture);
2935
});
3036

31-
it('(baseline) should retrieve all of the buttons', async () => {
32-
await benchmark('(baseline) get every button', async () => {
33-
document.querySelectorAll('button');
34-
});
35-
});
36-
37-
it('(baseline) should click the first button', async () => {
38-
await benchmark('(baseline) click first button', async () => {
39-
const button = getButtonWithText(FIRST_BUTTON);
40-
button.click();
37+
describe('(baseline)', () => {
38+
it('should find a button', async () => {
39+
await benchmark('(baseline) find a button', async () => {
40+
document.querySelector('button');
41+
});
4142
});
42-
});
4343

44-
it('(baseline) should click the middle button', async () => {
45-
await benchmark('(baseline) click middle button', async () => {
46-
const button = getButtonWithText(MIDDLE_BUTTON);
47-
button.click();
44+
it('should find all buttons', async () => {
45+
await benchmark('(baseline) find all buttons', async () => {
46+
document.querySelectorAll('button');
47+
});
4848
});
49-
});
5049

51-
it('(baseline) should click the last button', async () => {
52-
await benchmark('(baseline) click last button', async () => {
53-
const button = getButtonWithText(LAST_BUTTON);
54-
button.click();
50+
it('should find a button via text filter', async () => {
51+
await benchmark('(baseline) find a button via text filter', async () => {
52+
return Array.from(document.querySelectorAll('button'))
53+
.filter(b => b.innerText === MIDDLE_BUTTON);
54+
});
5555
});
56-
});
5756

58-
it('(baseline) should click all of the buttons', async () => {
59-
await benchmark('(baseline) click every button', async () => {
60-
const buttons = document.getElementsByTagName('button');
61-
for (let i = 0; i < buttons.length; i++) {
62-
const button = buttons[i];
57+
it('should click a button', async () => {
58+
const button = document.querySelector('button')!;
59+
await benchmark('(baseline) click a button', async () => {
6360
button.click();
64-
}
61+
fixture.detectChanges();
62+
});
6563
});
66-
});
67-
});
6864

69-
describe('performance tests for the testbed harness', () => {
70-
let fixture: ComponentFixture<ButtonHarnessTest>;
71-
let loader: HarnessLoader;
72-
73-
beforeEach(async () => {
74-
await TestBed.configureTestingModule({
75-
imports: [MatButtonModule],
76-
declarations: [ButtonHarnessTest],
77-
}).compileComponents();
78-
79-
fixture = TestBed.createComponent(ButtonHarnessTest);
80-
fixture.detectChanges();
81-
loader = TestbedHarnessEnvironment.loader(fixture);
65+
it('should click all buttons', async () => {
66+
const buttons = Array.prototype.slice.call(document.querySelectorAll('button'));
67+
await benchmark('(baseline) click all buttons', async () => {
68+
buttons.forEach(button => button.click());
69+
fixture.detectChanges();
70+
});
71+
});
8272
});
8373

84-
it('should retrieve all of the buttons', async () => {
85-
await benchmark('get every button', async () => {
86-
await loader.getAllHarnesses(MatButtonHarness);
74+
describe('(with harness)', () => {
75+
it('should find a button', async () => {
76+
await benchmark('(with harness) find a button', async () => {
77+
await loader.getHarness(MatButtonHarness);
78+
});
8779
});
88-
});
8980

90-
it('should click the first button', async () => {
91-
await benchmark('click first button', async () => {
92-
const button = await loader.getHarness(MatButtonHarness.with({text: FIRST_BUTTON}));
93-
await button.click();
81+
it('should find all buttons', async () => {
82+
await benchmark('(with harness) find all buttons', async () => {
83+
await loader.getAllHarnesses(MatButtonHarness);
84+
});
9485
});
95-
});
9686

97-
it('should click the middle button', async () => {
98-
await benchmark('click middle button', async () => {
99-
const button = await loader.getHarness(MatButtonHarness.with({text: MIDDLE_BUTTON}));
100-
await button.click();
87+
it('should find a button via text filter', async () => {
88+
await benchmark('(with harness) find a button via text filter', async () => {
89+
await loader.getAllHarnesses(MatButtonHarness.with({text: MIDDLE_BUTTON}));
90+
});
10191
});
102-
});
10392

104-
it('should click the last button', async () => {
105-
await benchmark('click last button', async () => {
106-
const button = await loader.getHarness(MatButtonHarness.with({text: LAST_BUTTON}));
107-
await button.click();
93+
it('should click a button', async () => {
94+
const button = await loader.getHarness(MatButtonHarness);
95+
await benchmark('(with harness) click a button', async () => {
96+
await button.click();
97+
});
10898
});
109-
});
11099

111-
it('should click all of the buttons', async () => {
112-
await benchmark('click every button', async () => {
100+
it('should click all buttons', async () => {
113101
const buttons = await loader.getAllHarnesses(MatButtonHarness);
114-
for (let i = 0; i < buttons.length; i++) {
115-
const button = buttons[i];
116-
await button.click();
117-
}
102+
await benchmark('(with harness) click all buttons', async () => {
103+
await Promise.all(buttons.map(button => button.click()));
104+
});
118105
});
119106
});
120107

121-
// To see the benchmarks for this test, uncomment the it test below.
122-
//
123-
// I don't know how to force karma_web_test to show logs in the console so we are using this as
124-
// a solution for now.
125-
// it('should fail intentionally', () => expect(1).toBe(2));
108+
it('should fail intentionally so performance numbers are logged', fail);
126109
});
127110

128111
@Component({

0 commit comments

Comments
 (0)