Skip to content

feat(cdk-experimental/testing): Bring in component harness #16089

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 8 commits into from
Jun 5, 2019

Conversation

mmalerba
Copy link
Contributor

@mmalerba mmalerba commented May 22, 2019

This is the initial PR bringing in the the ComponentHarness from google3. Huge thanks to @qiyigg and @vikerman for getting this started, and to all who contributed to the code in google3.

Main files

  • cdk-experimental/testing/component-harness.ts contains classes and interfaces that define the test-environment-independent component harness

    • ComponentHarness the base class for all harnesses
    • TestElement an interface used by the ComponentHarness to interface with the DOM
    • Locator an interface used by the ComponentHarness to find TestElements
  • cdk-experimental/testing/testbed.ts contains implementation specific to Angular's TestBed

    • TestBed compatible implementations of TestElement and Locator
    • load method used to create instances of ComponentHarness that are compatible with TestBed
    • Depends on @angular/core/testing
  • cdk-experimental/testing/protractor.ts contains implementation specific to Protractor.

    • Protractor compatible implementations of TestElement and Locator
    • load method used to create instances of ComponentHarness that are compatible with TestBed
    • Depends on protractor and selenium-webdriver
  • cdk-experimental/testing/tests/* contains tests for the component harness framework, including definitions for a couple simple components and corresponding harnesses to be used in the tests

Future work

  • Have the harness know it's component's root selector
  • Add convenience method for checking CSS classes
  • Fix protractor implementation of focs/blur
  • Add ability for testbed implementation to detect fakeAsync tests
  • Refactor names and structure of some of the objects (e.g. load)
  • Consider what other actions might need to be added to TestElement (e.g. tap)
  • The current allowNull behavior seems confusing, consider revising it
  • Consider separating methods for sending key presses and typing input
  • Consider moving protractor and testbed implementations to their own tertiary entry points

@mmalerba mmalerba requested a review from devversion as a code owner May 22, 2019 17:13
@mmalerba mmalerba added the cla: yes PR author has agreed to Google's Contributor License Agreement label May 22, 2019
@Splaktar Splaktar self-requested a review May 23, 2019 17:53
* Search all matched test elements under current root by css selector.
* @param css Selector of the test elements.
*/
findAll(css: string): Promise<TestElement[]>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we call these querySelector and querySelectorAll since it's what people are familiar with?

This comment was marked as resolved.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the Locator methods to querySelector/querySelectorAll, it is a little bit different though because it returns a Promise. The methods of the same name on ComponentHarness are even more different because they return () => Promise. I've left them as find/findAll for now, but open to renaming those as well

return toPromise<string>(this.element.getCssValue(property));
}

async hover(): Promise<void> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would we handle this if the consumer was running the test against a touch screen device?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it would be an issue necessarily. Protractor must have some way to handle mouseMove on touch devices already, even if its to just do nothing. It would make sense to add a tap action as well. I can do that in a follow-up PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK Protractor simulates real user input at the OS level so I'm not sure how it work. My main concern with hover was for unit tests and it should be a bit easier to simulate it there though.

await this._stabilize();
}

async getCssValue(property: string): Promise<string> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be flaky between browsers, because some of the normalize things like color values. IIRC Edge or IE return all colors in RGBA, regardless of the format the color was set in.

Copy link
Contributor Author

@mmalerba mmalerba May 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can add normalization logic here as we encounter things that need it. In the mean time, the harness author can always normalize on their end if needed.

Also what do you think about the name of this method? Should I change it to getComputedStyle?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel strongly about the name. We could call it getPropertyValue which corresponds to the method on the CSSStyleDeclaration that gets returned from getComputedStyle.

this.element instanceof HTMLTextAreaElement)) {
throw new Error('Attempting to clear an invalid element');
}
this.element.focus();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving focus here might a bit risky since it's not what would necessarily happen to a real user. E.g. an input "clear" button won't move focus into the input.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that true? in Chrome with an <input type="search"> pressing the button also focuses.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant if it's a custom clear button, rather than the native browser one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, in that case the particular component that implements the clear button can choose to expose a clear method in its harness API that clicks the custom button instead. This class is meant to be an implementation of the interface harness authors use to write their harnesses.

await this._stabilize();
(this.element as HTMLElement).focus();
const e = this.element as HTMLInputElement;
for (const key of keys) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this logic come from somewhere? It would be good to reference back to it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that I'm aware of, but Yi is the original author

@mmalerba mmalerba force-pushed the harness branch 4 times, most recently from f97a374 to 2e31b2d Compare June 3, 2019 18:25
@mmalerba mmalerba added target: patch This PR is targeted for the next patch release pr: merge safe labels Jun 3, 2019
@mmalerba
Copy link
Contributor Author

mmalerba commented Jun 3, 2019

@jelbourn @crisbeto I've addressed all of the comments above, left some of them unresolved for further dicsussion

@mmalerba mmalerba force-pushed the harness branch 2 times, most recently from 0a679f2 to 0914d84 Compare June 3, 2019 23:02
mmalerba and others added 7 commits June 5, 2019 08:33
Co-Authored-By: Yi Qi <qiyi@google.com>
Co-Authored-By: Rado Kirov <radokirov@google.com>
Co-Authored-By: Thomas Shafer <tshafer@google.com>
Co-Authored-By: Caitlin Mott <caitlinmott@google.com>
Co-Authored-By: Craig Nishina <cnishina@google.com>
Copy link
Member

@crisbeto crisbeto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a couple of nits, but aside from those it LGTM.

* Search all matched test elements under current root by CSS selector.
* @param selector The CSS selector of the test elements.
*/
querySelectorAll(selector: string): Promise<TestElement[]>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should querySelectorAll accept options as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm planning to address this when I make some API changes in the next PR. I think this is currently implemented like this because allowNull doesn't really make sense for querySelectorAll

Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I'm good iterating on API/naming in follow-up PRs

@mmalerba mmalerba added the action: merge The PR is ready for merge by the caretaker label Jun 5, 2019
@josephperrott josephperrott merged commit 7baac27 into angular:master Jun 5, 2019
josephperrott pushed a commit that referenced this pull request Jun 10, 2019
Co-Authored-By: Yi Qi <qiyi@google.com>
Co-Authored-By: Rado Kirov <radokirov@google.com>
Co-Authored-By: Thomas Shafer <tshafer@google.com>
Co-Authored-By: Caitlin Mott <caitlinmott@google.com>
Co-Authored-By: Craig Nishina <cnishina@google.com>
RudolfFrederiksen pushed a commit to RudolfFrederiksen/material2 that referenced this pull request Jun 21, 2019
…16089)

Co-Authored-By: Yi Qi <qiyi@google.com>
Co-Authored-By: Rado Kirov <radokirov@google.com>
Co-Authored-By: Thomas Shafer <tshafer@google.com>
Co-Authored-By: Caitlin Mott <caitlinmott@google.com>
Co-Authored-By: Craig Nishina <cnishina@google.com>
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 10, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes PR author has agreed to Google's Contributor License Agreement target: patch This PR is targeted for the next patch release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants