Skip to content
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

Add docs about decision around, and alternatives to, testID #35

Merged
merged 2 commits into from Jul 11, 2018

Conversation

lemonmade
Copy link
Member

Does what it says on the tin. I wanted to get this down into words so people understand why we are mostly opposed to the use of this attribute, provide some historical context for why we have so many in the existing Web app, and give people alternatives for the common patterns I have seen.

cc/ @Shopify/web-foundation

Copy link
Contributor

@TzviPM TzviPM left a comment

Choose a reason for hiding this comment

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

looks great. Should we also mention the issue of tracking (trekkie, etc.) that seemingly prompted us to move away from testIDs?

it('includes the children in the markup', () => {
const children = <div>Contents</div>;
const card = mount(<Card>{children}</Card>);
expect(card).toContainReact(children);
Copy link
Contributor

Choose a reason for hiding this comment

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

TIL ❤️


To make this approach even easier, our [`enzyme-utilities` package](https://github.com/Shopify/quilt/tree/master/packages/enzyme-utilities) provides a `findById` utility function.

* If neither of the above apply, filter the set of matched components based on the properties that are unique to them. If no properties are unique, fall back to the index of the item in the matched set.
Copy link
Contributor

Choose a reason for hiding this comment

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

this wording is a bit confusing to me. To confirm, if you can't make it into a separate component, and a unique ID doesn't make sense, then simply find all instances of the component and filter them by some other unique thing like text or a prop. If there are no unique attributes that make sense, then locate the item by its index (ex. the second modal)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, that is exactly correct (text is always a prop of the component, but I wanted to try to not tie this entire section just to React)

@@ -0,0 +1,49 @@
# We do not use test IDs in tests
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe just We do not use test IDs ?

@loic-d
Copy link

loic-d commented Jul 10, 2018

We ran into this problem with our DiscountSummary component that renders different summary lines to describe discount characteristics to merchants. However, based on the type of discount, the outputted markup for a given line will be different. We used testID to clearly identify which part of the JSX was rendered.

I think that removing testID would have forced us to maybe split our component in sub-components per summary lines, or just assert that the text at a given line index was correct. At the end of the day, we just want to know if the UI matches the UX spec, but don't really care how we got there.

The proposed changes make sense 👍 but we will definitely have to do some refactoring in multiple places to respect this new best practice.

it('includes the children in the markup', () => {
const children = <div>Contents</div>;
const card = mount(<Card>{children}</Card>);
expect(card).toContainReact(children);
Copy link

Choose a reason for hiding this comment

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

Really nice, didn't know you could do that.

@rox163
Copy link

rox163 commented Jul 10, 2018

Love it! Simple yet in-depth explanation of a really important practice.

Copy link
Contributor

@cartogram cartogram left a comment

Choose a reason for hiding this comment

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

👏

* Markup that has an important effect on the visual output of a component, but which have no other defining characteristics (for example, an element on which we apply a particular class name or inline styles).
* A child component that is rendered multiple times, where the developer wishes to easily disambiguate between the instances (for example, a component that renders multiple `Modal`s from Polaris React).

We would like to avoid test IDs for handling the cases above, as make it easy to reach into your component in ways that unnecessarily lock down the implementation. You can typically avoid test IDs by using one of the following strategies:
Copy link
Contributor

Choose a reason for hiding this comment

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

as make it easy => as they make it easy


## Description

Developers sometimes feel the need to add "hooks" that allow their tests to easily find parts of the component subtree and assert details about those subtrees in tests. In the React ecosystem, this is a key recommendation of an alternative to Enzyme (our preferred React testing library), [`react-testing-library`/ `dom-testing-library`](https://github.com/kentcdodds/dom-testing-library/blob/master/README.md#faq).
Copy link
Contributor

Choose a reason for hiding this comment

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

That second sentence is distracting and does not really add anything.

In building the initial version of Shopify Web, we took several steps to encourage and facilitate the use of test IDs:

* A [babel plugin](https://github.com/lemonmade/babel-plugin-react-test-id) to remove the unnecessary attribute in production
* Allowing the `testID` prop implicitly with TypeScript and adding a `findByTestId` utility to Shopify Web
Copy link
Contributor

Choose a reason for hiding this comment

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

This is 2 separate bullets, but its fine.

* A [babel plugin](https://github.com/lemonmade/babel-plugin-react-test-id) to remove the unnecessary attribute in production
* Allowing the `testID` prop implicitly with TypeScript and adding a `findByTestId` utility to Shopify Web

These were originally introduced to facilitate differentiation between the same React component rendered multiple times within a tree (specifically, to target multiple `TextField` components rendered by a card in the product section of the admin). No analysis of alternatives was performed at the time. The cases in which this attribute was used expanded and, as of July 10, 2018, it is used 280 times in the Web codebase.
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think you need the part in parens. And maybe Web should be Shopify Web to match when it is mentioned above.


## Decision

`testID` provides some benefits that have made it attractive to developers working in the Web stack:
Copy link
Contributor

Choose a reason for hiding this comment

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

Web => Shopify Web

* You must prevent console warnings that React prints by default complaining about an unexpected `testID` prop on DOM elements
* You must be sure to include our custom Babel plugin to strip the attribute in production builds

Additionally, in reviewing the use of `testID` in Web, we found that the ways it were used were better addressed using other strategies. We have detailed common patterns we found (along with alternative strategies to `testID`) in our [testing best practices](../Best%20practices/Testing.md#test-ids), but in summary, we found that `testID` was used to:
Copy link
Contributor

Choose a reason for hiding this comment

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

Web => Shopify Web (or change them all to just Web). I don't have a preference other than that it is consistent.

@lemonmade lemonmade merged commit 9885149 into master Jul 11, 2018
@lemonmade lemonmade deleted the test-id branch July 11, 2018 13:09
BPScott pushed a commit that referenced this pull request Mar 25, 2020
Update changelog for release 5.1.0
BPScott added a commit that referenced this pull request Mar 25, 2020
Use full module name for presets
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants