Skip to content

Commit 34ddc99

Browse files
committed
feat(paginator): add test harness
Sets up a test harness for `mat-paginator`.
1 parent 527f1b5 commit 34ddc99

File tree

11 files changed

+360
-1
lines changed

11 files changed

+360
-1
lines changed

src/material/config.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ entryPoints = [
3030
"menu",
3131
"menu/testing",
3232
"paginator",
33+
"paginator/testing",
3334
"progress-bar",
3435
"progress-bar/testing",
3536
"progress-spinner",

src/material/paginator/paginator.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
</mat-select>
2121
</mat-form-field>
2222

23-
<div *ngIf="_displayedPageSizeOptions.length <= 1">{{pageSize}}</div>
23+
<div
24+
class="mat-paginator-page-size-value"
25+
*ngIf="_displayedPageSizeOptions.length <= 1">{{pageSize}}</div>
2426
</div>
2527

2628
<div class="mat-paginator-range-actions">
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package(default_visibility = ["//visibility:public"])
2+
3+
load("//tools:defaults.bzl", "ng_test_library", "ng_web_test_suite", "ts_library")
4+
5+
ts_library(
6+
name = "testing",
7+
srcs = glob(
8+
["**/*.ts"],
9+
exclude = ["**/*.spec.ts"],
10+
),
11+
module_name = "@angular/material/paginator/testing",
12+
deps = [
13+
"//src/cdk/coercion",
14+
"//src/cdk/testing",
15+
"//src/material/select/testing",
16+
],
17+
)
18+
19+
filegroup(
20+
name = "source-files",
21+
srcs = glob(["**/*.ts"]),
22+
)
23+
24+
ng_test_library(
25+
name = "harness_tests_lib",
26+
srcs = ["shared.spec.ts"],
27+
deps = [
28+
":testing",
29+
"//src/cdk/testing",
30+
"//src/cdk/testing/private",
31+
"//src/cdk/testing/testbed",
32+
"//src/material/paginator",
33+
"@npm//@angular/platform-browser",
34+
],
35+
)
36+
37+
ng_test_library(
38+
name = "unit_tests_lib",
39+
srcs = glob(
40+
["**/*.spec.ts"],
41+
exclude = ["shared.spec.ts"],
42+
),
43+
deps = [
44+
":harness_tests_lib",
45+
":testing",
46+
"//src/material/paginator",
47+
],
48+
)
49+
50+
ng_web_test_suite(
51+
name = "unit_tests",
52+
deps = [":unit_tests_lib"],
53+
)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
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 * from './public-api';
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+
import {BaseHarnessFilters} from '@angular/cdk/testing';
10+
11+
/** A set of criteria that can be used to filter a list of `MatPaginatorHarness` instances. */
12+
export interface PaginatorHarnessFilters extends BaseHarnessFilters {
13+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import {MatPaginatorModule} from '@angular/material/paginator';
2+
import {runHarnessTests} from './shared.spec';
3+
import {MatPaginatorHarness} from './paginator-harness';
4+
5+
describe('Non-MDC-based MatPaginatorHarness', () => {
6+
runHarnessTests(MatPaginatorModule, MatPaginatorHarness);
7+
});
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
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 {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
10+
import {MatSelectHarness} from '@angular/material/select/testing';
11+
import {coerceNumberProperty} from '@angular/cdk/coercion';
12+
import {PaginatorHarnessFilters} from './paginator-harness-filters';
13+
14+
15+
/** Harness for interacting with a standard mat-paginator in tests. */
16+
export class MatPaginatorHarness extends ComponentHarness {
17+
/** Selector used to find paginator instances. */
18+
static hostSelector = '.mat-paginator';
19+
private _nextButton = this.locatorFor('.mat-paginator-navigation-next');
20+
private _previousButton = this.locatorFor('.mat-paginator-navigation-previous');
21+
private _firstPageButton = this.locatorForOptional('.mat-paginator-navigation-first');
22+
private _lastPageButton = this.locatorForOptional('.mat-paginator-navigation-last');
23+
private _select = this.locatorForOptional(MatSelectHarness.with({
24+
ancestor: '.mat-paginator-page-size'
25+
}));
26+
private _pageSizeFallback = this.locatorFor('.mat-paginator-page-size-value');
27+
private _rangeLabel = this.locatorFor('.mat-paginator-range-label');
28+
29+
/**
30+
* Gets a `HarnessPredicate` that can be used to search for a `MatPaginatorHarness` that meets
31+
* certain criteria.
32+
* @param options Options for filtering which paginator instances are considered a match.
33+
* @return a `HarnessPredicate` configured with the given options.
34+
*/
35+
static with(options: PaginatorHarnessFilters = {}): HarnessPredicate<MatPaginatorHarness> {
36+
return new HarnessPredicate(MatPaginatorHarness, options);
37+
}
38+
39+
/** Goes to the next page in the paginator. */
40+
async goToNextPage(): Promise<void> {
41+
return (await this._nextButton()).click();
42+
}
43+
44+
/** Goes to the previous page in the paginator. */
45+
async goToPreviousPage(): Promise<void> {
46+
return (await this._previousButton()).click();
47+
}
48+
49+
/** Goes to the first page in the paginator. */
50+
async goToFirstPage(): Promise<void> {
51+
const button = await this._firstPageButton();
52+
53+
// The first page button isn't enabled by default so we need to check for it.
54+
if (!button) {
55+
throw Error('Could not find first page button inside paginator. ' +
56+
'Make sure that `showFirstLastButtons` is enabled.');
57+
}
58+
59+
return button.click();
60+
}
61+
62+
/** Goes to the last page in the paginator. */
63+
async goToLastPage(): Promise<void> {
64+
const button = await this._lastPageButton();
65+
66+
// The last page button isn't enabled by default so we need to check for it.
67+
if (!button) {
68+
throw Error('Could not find last page button inside paginator. ' +
69+
'Make sure that `showFirstLastButtons` is enabled.');
70+
}
71+
72+
return button.click();
73+
}
74+
75+
/**
76+
* Sets the page size of the paginator.
77+
* @param size Page size that should be select.
78+
*/
79+
async setPageSize(size: number): Promise<void> {
80+
const select = await this._select();
81+
82+
// The select is only available if the `pageSizeOptions` are
83+
// set to an array with more than one item.
84+
if (!select) {
85+
throw Error('Cannot find page size selector in paginator. ' +
86+
'Make sure that the `pageSizeOptions` have been configured.');
87+
}
88+
89+
return select.clickOptions({text: `${size}`});
90+
}
91+
92+
/** Gets the page size of the paginator. */
93+
async getPageSize(): Promise<number> {
94+
const select = await this._select();
95+
const value = select ? select.getValueText() : (await this._pageSizeFallback()).text();
96+
return coerceNumberProperty(await value);
97+
}
98+
99+
/** Gets the text of the range labe of the paginator. */
100+
async getRangeLabel(): Promise<string> {
101+
return (await this._rangeLabel()).text();
102+
}
103+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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 * from './paginator-harness';
10+
export * from './paginator-harness-filters';
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import {HarnessLoader} from '@angular/cdk/testing';
2+
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
3+
import {Component, ViewChild} from '@angular/core';
4+
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
5+
import {ComponentFixture, TestBed} from '@angular/core/testing';
6+
import {MatPaginatorModule, PageEvent, MatPaginator} from '@angular/material/paginator';
7+
import {MatPaginatorHarness} from './paginator-harness';
8+
import {expectAsyncError} from '@angular/cdk/testing/private';
9+
10+
/** Shared tests to run on both the original and MDC-based paginator. */
11+
export function runHarnessTests(
12+
paginatorModule: typeof MatPaginatorModule, paginatorHarness: typeof MatPaginatorHarness) {
13+
let fixture: ComponentFixture<PaginatorHarnessTest>;
14+
let loader: HarnessLoader;
15+
let instance: PaginatorHarnessTest;
16+
17+
beforeEach(async () => {
18+
await TestBed.configureTestingModule({
19+
imports: [paginatorModule, NoopAnimationsModule],
20+
declarations: [PaginatorHarnessTest],
21+
}).compileComponents();
22+
23+
fixture = TestBed.createComponent(PaginatorHarnessTest);
24+
fixture.detectChanges();
25+
loader = TestbedHarnessEnvironment.loader(fixture);
26+
instance = fixture.componentInstance;
27+
});
28+
29+
it('should load all paginator harnesses', async () => {
30+
const paginators = await loader.getAllHarnesses(paginatorHarness);
31+
expect(paginators.length).toBe(1);
32+
});
33+
34+
it('should be able to go to the next page', async () => {
35+
const paginator = await loader.getHarness(paginatorHarness);
36+
37+
expect(instance.pageIndex).toBe(0);
38+
await paginator.goToNextPage();
39+
expect(instance.pageIndex).toBe(1);
40+
});
41+
42+
it('should be able to go to the previous page', async () => {
43+
const paginator = await loader.getHarness(paginatorHarness);
44+
45+
instance.pageIndex = 5;
46+
fixture.detectChanges();
47+
48+
await paginator.goToPreviousPage();
49+
expect(instance.pageIndex).toBe(4);
50+
});
51+
52+
it('should be able to go to the first page', async () => {
53+
const paginator = await loader.getHarness(paginatorHarness);
54+
55+
instance.pageIndex = 5;
56+
fixture.detectChanges();
57+
58+
await paginator.goToFirstPage();
59+
expect(instance.pageIndex).toBe(0);
60+
});
61+
62+
it('should be able to go to the last page', async () => {
63+
const paginator = await loader.getHarness(paginatorHarness);
64+
65+
expect(instance.pageIndex).toBe(0);
66+
await paginator.goToLastPage();
67+
expect(instance.pageIndex).toBe(49);
68+
});
69+
70+
it('should be able to set the page size', async () => {
71+
const paginator = await loader.getHarness(paginatorHarness);
72+
73+
expect(instance.pageSize).toBe(10);
74+
await paginator.setPageSize(25);
75+
expect(instance.pageSize).toBe(25);
76+
});
77+
78+
it('should be able to get the page size', async () => {
79+
const paginator = await loader.getHarness(paginatorHarness);
80+
expect(await paginator.getPageSize()).toBe(10);
81+
});
82+
83+
it('should be able to get the range label', async () => {
84+
const paginator = await loader.getHarness(paginatorHarness);
85+
expect(await paginator.getRangeLabel()).toBe('1 – 10 of 500');
86+
});
87+
88+
it('should throw an error if the first page button is not available', async () => {
89+
const paginator = await loader.getHarness(paginatorHarness);
90+
91+
instance.showFirstLastButtons = false;
92+
fixture.detectChanges();
93+
94+
await expectAsyncError(() => paginator.goToFirstPage(),
95+
/Error: Could not find first page button inside paginator/);
96+
});
97+
98+
it('should throw an error if the last page button is not available', async () => {
99+
const paginator = await loader.getHarness(paginatorHarness);
100+
101+
instance.showFirstLastButtons = false;
102+
fixture.detectChanges();
103+
104+
await expectAsyncError(() => paginator.goToLastPage(),
105+
/Error: Could not find last page button inside paginator/);
106+
});
107+
108+
it('should throw an error if the page size selector is not available', async () => {
109+
const paginator = await loader.getHarness(paginatorHarness);
110+
111+
instance.pageSizeOptions = [];
112+
fixture.detectChanges();
113+
114+
await expectAsyncError(() => paginator.setPageSize(10),
115+
/Error: Cannot find page size selector in paginator/);
116+
});
117+
}
118+
119+
@Component({
120+
template: `
121+
<mat-paginator
122+
(page)="handlePageEvent($event)"
123+
[length]="length"
124+
[pageSize]="pageSize"
125+
[showFirstLastButtons]="showFirstLastButtons"
126+
[pageSizeOptions]="pageSizeOptions"
127+
[pageIndex]="pageIndex">
128+
</mat-paginator>
129+
`
130+
})
131+
class PaginatorHarnessTest {
132+
@ViewChild(MatPaginator) paginator: MatPaginator;
133+
length = 500;
134+
pageSize = 10;
135+
pageIndex = 0;
136+
pageSizeOptions = [5, 10, 25];
137+
showFirstLastButtons = true;
138+
139+
handlePageEvent(event: PageEvent) {
140+
this.length = event.length;
141+
this.pageSize = event.pageSize;
142+
this.pageIndex = event.pageIndex;
143+
}
144+
}
145+

test/karma-system-config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ System.config({
136136
'@angular/material/menu/testing': 'dist/packages/material/menu/testing/index.js',
137137
'@angular/material/menu/testing/shared.spec': 'dist/packages/material/menu/testing/shared.spec.js',
138138
'@angular/material/paginator': 'dist/packages/material/paginator/index.js',
139+
'@angular/material/paginator/testing': 'dist/packages/material/paginator/testing/index.js',
140+
'@angular/material/paginator/testing/shared.spec': 'dist/packages/material/paginator/testing/shared.spec.js',
139141
'@angular/material/progress-bar': 'dist/packages/material/progress-bar/index.js',
140142
'@angular/material/progress-bar/testing': 'dist/packages/material/progress-bar/testing/index.js',
141143
'@angular/material/progress-bar/testing/shared.spec': 'dist/packages/material/progress-bar/testing/shared.spec.js',
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export declare class MatPaginatorHarness extends ComponentHarness {
2+
getPageSize(): Promise<number>;
3+
getRangeLabel(): Promise<string>;
4+
goToFirstPage(): Promise<void>;
5+
goToLastPage(): Promise<void>;
6+
goToNextPage(): Promise<void>;
7+
goToPreviousPage(): Promise<void>;
8+
setPageSize(size: number): Promise<void>;
9+
static hostSelector: string;
10+
static with(options?: PaginatorHarnessFilters): HarnessPredicate<MatPaginatorHarness>;
11+
}
12+
13+
export interface PaginatorHarnessFilters extends BaseHarnessFilters {
14+
}

0 commit comments

Comments
 (0)