Skip to content

feat(cdk/testing): add the ability to dispatch arbitrary events #20714

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/cdk/testing/protractor/protractor-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,19 @@ export class ProtractorElement implements TestElement {
async isFocused(): Promise<boolean> {
return this.element.equals(browser.driver.switchTo().activeElement());
}

async dispatchEvent(name: string): Promise<void> {
return browser.executeScript(_dispatchEvent, name, this.element);
}
}

/**
* Dispatches an event with a particular name and data to an element.
* Note that this needs to be a pure function, because it gets stringified by
* Protractor and is executed inside the browser.
*/
function _dispatchEvent(name: string, element: ElementFinder) {
const event = document.createEvent('Event');
event.initEvent(name);
element.dispatchEvent(event);
}
7 changes: 7 additions & 0 deletions src/cdk/testing/test-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ export interface TestElement {
* @breaking-change 12.0.0 To become a required method.
*/
selectOptions?(...optionIndexes: number[]): Promise<void>;

/**
* Dispatches an event with a particular name.
* @param name Name of the event to be dispatched.
* @breaking-change 12.0.0 To be a required method.
*/
dispatchEvent?(name: string): Promise<void>;
}

export interface TextOptions {
Expand Down
5 changes: 5 additions & 0 deletions src/cdk/testing/testbed/unit-test-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@ export class UnitTestElement implements TestElement {
return document.activeElement === this.element;
}

async dispatchEvent(name: string): Promise<void> {
dispatchFakeEvent(this.element, name);
await this._stabilize();
}

/**
* Dispatches a pointer event on the current element if the browser supports it.
* @param name Name of the pointer event to be dispatched.
Expand Down
9 changes: 8 additions & 1 deletion src/cdk/testing/tests/cross-environment.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,6 @@ export function crossEnvironmentSpecs(
expect(await button.matchesSelector('button:disabled')).toBe(false);
});


it('should get correct text excluding certain selectors', async () => {
const results = await harness.subcomponentAndSpecialHarnesses();
const subHarnessHost = await results[0].host();
Expand All @@ -454,6 +453,14 @@ export function crossEnvironmentSpecs(
expect(await subHarnessHost.text({exclude: 'li'})).toBe('List of test tools');
});

it('should dispatch a basic custom event', async () => {
const target = await harness.customEventBasic();

// @breaking-change 12.0.0 Remove non-null assertion once `dispatchEvent` is required.
await target.dispatchEvent!('myCustomEvent');
expect(await target.text()).toBe('Basic event: 1');
});

it('should get TestElements and ComponentHarnesses', async () => {
const results = await harness.subcomponentHarnessesAndElements();
expect(results.length).toBe(5);
Expand Down
1 change: 1 addition & 0 deletions src/cdk/testing/tests/harnesses/main-component-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export class MainComponentHarness extends ComponentHarness {
readonly deepShadow = this.locatorFor(
'test-shadow-boundary test-sub-shadow-boundary > .in-the-shadows');
readonly hoverTest = this.locatorFor('#hover-box');
readonly customEventBasic = this.locatorFor('#custom-event-basic');

private _testTools = this.locatorFor(SubComponentHarness);

Expand Down
2 changes: 1 addition & 1 deletion src/cdk/testing/tests/test-main-component.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ <h1 style="height: 100px; width: 200px;">Main Component</h1>
</select>
<div id="multi-select-value">Multi-select: {{multiSelect}}</div>
<div id="multi-select-change-counter">Change events: {{multiSelectChangeEventCount}}</div>

<div (myCustomEvent)="basicEvent = basicEvent + 1" id="custom-event-basic">Basic event: {{basicEvent}}</div>
</div>
<div class="subcomponents">
<test-sub class="test-special" title="test tools" [items]="testTools"></test-sub>
Expand Down
2 changes: 1 addition & 1 deletion src/cdk/testing/tests/test-main-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})

export class TestMainComponent implements OnDestroy {
username: string;
counter: number;
Expand All @@ -42,6 +41,7 @@ export class TestMainComponent implements OnDestroy {
singleSelectChangeEventCount = 0;
multiSelect: string[] = [];
multiSelectChangeEventCount = 0;
basicEvent = 0;
_shadowDomSupported = _supportsShadowDom();

@ViewChild('clickTestElement') clickTestElement: ElementRef<HTMLElement>;
Expand Down
1 change: 1 addition & 0 deletions tools/public_api_guard/cdk/testing.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export interface TestElement {
click(): Promise<void>;
click(location: 'center'): Promise<void>;
click(relativeX: number, relativeY: number): Promise<void>;
dispatchEvent?(name: string): Promise<void>;
focus(): Promise<void>;
getAttribute(name: string): Promise<string | null>;
getCssValue(property: string): Promise<string>;
Expand Down
1 change: 1 addition & 0 deletions tools/public_api_guard/cdk/testing/protractor.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export declare class ProtractorElement implements TestElement {
blur(): Promise<void>;
clear(): Promise<void>;
click(...args: [] | ['center'] | [number, number]): Promise<void>;
dispatchEvent(name: string): Promise<void>;
focus(): Promise<void>;
getAttribute(name: string): Promise<string | null>;
getCssValue(property: string): Promise<string>;
Expand Down
1 change: 1 addition & 0 deletions tools/public_api_guard/cdk/testing/testbed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export declare class UnitTestElement implements TestElement {
blur(): Promise<void>;
clear(): Promise<void>;
click(...args: [] | ['center'] | [number, number]): Promise<void>;
dispatchEvent(name: string): Promise<void>;
focus(): Promise<void>;
getAttribute(name: string): Promise<string | null>;
getCssValue(property: string): Promise<string>;
Expand Down