Skip to content

Commit 4b59d4f

Browse files
committed
feat: add tab user-event
1 parent b1d0063 commit 4b59d4f

File tree

7 files changed

+79
-5
lines changed

7 files changed

+79
-5
lines changed

projects/testing-library/ng-package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,10 @@
55
"lib": {
66
"entryFile": "src/public_api.ts"
77
},
8-
"whitelistedNonPeerDependencies": ["@testing-library/dom", "@phenomnomnominal/tsquery", "tslint"]
8+
"whitelistedNonPeerDependencies": [
9+
"@testing-library/dom",
10+
"@testing-library/user-event",
11+
"@phenomnomnominal/tsquery",
12+
"tslint"
13+
]
914
}

projects/testing-library/ng-package.prod.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,10 @@
55
"lib": {
66
"entryFile": "src/public_api.ts"
77
},
8-
"whitelistedNonPeerDependencies": ["@testing-library/dom", "@phenomnomnominal/tsquery", "tslint"]
8+
"whitelistedNonPeerDependencies": [
9+
"@testing-library/dom",
10+
"@testing-library/user-event",
11+
"@phenomnomnominal/tsquery",
12+
"tslint"
13+
]
914
}

projects/testing-library/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
},
3131
"dependencies": {
3232
"@testing-library/dom": "^6.12.2",
33+
"@testing-library/user-event": "^8.1.0",
3334
"@phenomnomnominal/tsquery": "^3.0.0",
3435
"tslint": "^5.16.0"
3536
},

projects/testing-library/src/lib/testing-library.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, ElementRef, OnInit, Type, NgZone } from '@angular/core';
1+
import { Component, Type, NgZone } from '@angular/core';
22
import { ComponentFixture, TestBed } from '@angular/core/testing';
33
import { By } from '@angular/platform-browser';
44
import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations';
@@ -15,7 +15,7 @@ import {
1515
waitForElementToBeRemoved,
1616
} from '@testing-library/dom';
1717
import { RenderComponentOptions, RenderDirectiveOptions, RenderResult } from './models';
18-
import { createSelectOptions, createType } from './user-events';
18+
import { createSelectOptions, createType, tab } from './user-events';
1919

2020
@Component({ selector: 'wrapper-component', template: '' })
2121
class WrapperComponent {}
@@ -170,6 +170,7 @@ export async function render<SutType, WrapperType = SutType>(
170170
debug: (element = fixture.nativeElement) => console.log(prettyDOM(element)),
171171
type: createType(eventsWithDetectChanges),
172172
selectOptions: createSelectOptions(eventsWithDetectChanges),
173+
tab,
173174
waitForDomChange: componentWaitForDomChange,
174175
waitForElement: componentWaitForElement,
175176
waitForElementToBeRemoved: componentWaitForElementToBeRemoved,

projects/testing-library/src/lib/user-events/index.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { fireEvent } from '@testing-library/dom';
22
import { createType } from './type';
33
import { createSelectOptions } from './selectOptions';
4+
import { tab } from './tab';
45

56
export interface UserEvents {
67
/**
@@ -31,9 +32,22 @@ export interface UserEvents {
3132
* component.selectOptions(component.getByLabelText('Fruit'), ['Blueberry'. 'Grape'])
3233
*/
3334
selectOptions: ReturnType<typeof createSelectOptions>;
35+
36+
/**
37+
* @description
38+
* Fires a tab event changing the document.activeElement in the same way the browser does.
39+
*
40+
* @argument
41+
* shift: can be set to true to invert tab direction (default false)
42+
* focusTrap: a container element to restrict the tabbing within (default document)
43+
*
44+
* @example
45+
* component.tab()
46+
*/
47+
tab: typeof tab;
3448
}
3549

3650
const type = createType(fireEvent);
3751
const selectOptions = createSelectOptions(fireEvent);
3852

39-
export { createType, type, createSelectOptions, selectOptions };
53+
export { createType, type, createSelectOptions, selectOptions, tab };
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import userEvent from '@testing-library/user-event';
2+
3+
export interface ITabUserOptions {
4+
shift?: boolean;
5+
focusTrap?: Document | Element;
6+
}
7+
8+
export function tab(options?: ITabUserOptions) {
9+
return userEvent.tab(options);
10+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Component } from '@angular/core';
2+
import { render } from '../../src/public_api';
3+
4+
test('cycles through elements in document tab order', async () => {
5+
@Component({
6+
selector: 'fixture',
7+
template: `
8+
<div>
9+
<input data-testid="element" type="checkbox" />
10+
<input data-testid="element" type="radio" />
11+
<input data-testid="element" type="number" />
12+
</div>
13+
`,
14+
})
15+
class FixtureComponent {}
16+
17+
const component = await render(FixtureComponent);
18+
const [checkbox, radio, number] = component.getAllByTestId('element');
19+
20+
expect(document.body).toHaveFocus();
21+
22+
component.tab();
23+
24+
expect(checkbox).toHaveFocus();
25+
26+
component.tab();
27+
28+
expect(radio).toHaveFocus();
29+
30+
component.tab();
31+
32+
expect(number).toHaveFocus();
33+
34+
component.tab();
35+
36+
// cycle goes back to first element
37+
expect(checkbox).toHaveFocus();
38+
});

0 commit comments

Comments
 (0)