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

Throw an error if getBy* queries return anything other than one result. #202

Closed
kentcdodds opened this issue Feb 4, 2019 · 8 comments
Closed
Labels
BREAKING CHANGE This change will require a major version bump released

Comments

@kentcdodds
Copy link
Member

Describe the feature you'd like:

As a random thought, what if we throw an error if you use getBy* query and there's more than 1 element that could be returned for the given query? We already do that if there are no elements returned.

I'm not certain how I feel about it, but it seems like a good idea. I had the idea when responding to #201

As it occurs to me, one very common mistake when using CodeSandbox is people render the thing they're testing in the document as well as run tests with it. The problem is that CodeSandbox does not isolate the tests' DOM from the app's DOM, so you often wind up interacting with the element that's rendered in the app rather than the one you're testing. Sometimes it happens to work, but much of the time it doesn't. If we implemented this, then people would get an error and it may help them know why.

Suggested implementation:

Take this:

https://github.com/kentcdodds/dom-testing-library/blob/369d17e169e5c7f47688482b8f0ad8ecda2ee35f/src/query-helpers.js#L32-L36

Change it to:

function resultOrNull(queryFunction, ...args) {
  const result = queryFunction(...args)
  if (result.length === 1) return result[0]
  return null
}

Describe alternatives you've considered:

Currently we allow this:

// Given: <div>Hello</div><div>Hello2</div>
getByText(/.*hello.*/i) // what should this return?

Right now we'll get the first, but that could be undesirable and even surprising.

Teachability, Documentation, Adoption, Migration Strategy:

This would require a breaking change, some slight changes to the docs, and the error message could help with teachability. As for migration, hopefully most people only have one result already, if they don't it may be a little surprise but should hopefully be pretty easy to fix by either improving the TextMatch to only match one element, or switching to the getAllBy* version of the query and grabbing the first result.

@alexkrolick
Copy link
Collaborator

I think this is a good idea. It's definitely possible to have bugs where you select the wrong copy of some ambiguous text (for example a form title and button with the same text). This forces a more specific selector.

@alexkrolick
Copy link
Collaborator

On a related note, I think the exact opposite should be the default in Cypress Testing Library - getBy should not error, it should return an empty or null result like jQuery. Might make sense to change both if there is going to be a breaking change.

@kentcdodds
Copy link
Member Author

Yes, I think Cypress is a different animal and should probably have little wrappers that use queryAllBy* directly so it can handle the results uniquely. Would you like to open an issue there?

@kentcdodds kentcdodds added the BREAKING CHANGE This change will require a major version bump label Mar 19, 2019
kentcdodds pushed a commit that referenced this issue Mar 19, 2019
Closes #202

BREAKING CHANGE: All `getBy` and `findBy` query variants now will throw an error if more than one element is returned. If this is expected, then use `getAllBy` (or `findAllBy`) instead.
kentcdodds pushed a commit that referenced this issue Mar 20, 2019
Closes #202

BREAKING CHANGE: All `getBy` and `findBy` query variants now will throw an error if more than one element is returned. If this is expected, then use `getAllBy` (or `findAllBy`) instead.
kentcdodds pushed a commit that referenced this issue Mar 20, 2019
Closes #202

BREAKING CHANGE: All `getBy` and `findBy` query variants now will throw an error if more than one element is returned. If this is expected, then use `getAllBy` (or `findAllBy`) instead.
@szabototo89
Copy link
Contributor

I think this a great idea, but it should also be configurable in the options object:

queryByText(/some text/, { throwErrorOnMultipleMatch: false }); // by default i'd set to true 

@kentcdodds
Copy link
Member Author

Sorry, but I don't see why it should be configurable. If you think there could be more than one then use getAll*

kentcdodds pushed a commit that referenced this issue Apr 17, 2019
Closes #202

BREAKING CHANGE: All `getBy` and `findBy` query variants now will throw an error if more than one element is returned. If this is expected, then use `getAllBy` (or `findAllBy`) instead.
kentcdodds pushed a commit that referenced this issue Apr 25, 2019
Closes #202

BREAKING CHANGE: All `getBy` and `findBy` query variants now will throw an error if more than one element is returned. If this is expected, then use `getAllBy` (or `findAllBy`) instead.
kentcdodds pushed a commit that referenced this issue Apr 25, 2019
Closes #202

BREAKING CHANGE: All `getBy` and `findBy` query variants now will throw an error if more than one element is returned. If this is expected, then use `getAllBy` (or `findAllBy`) instead.
@kentcdodds
Copy link
Member Author

🎉 This issue has been resolved in version 4.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@jdhines
Copy link

jdhines commented Sep 2, 2020

I know this issue is closed already, so if I should ask this somewhere else, let me know.

For me, I used getBy precisely to return the first item of several as I often wanted to test what the first item of many is, for example to verify that the component was sorting a list as expected.

To me, I just liked being able to use getBy as a shortcut to getAllBy(...)[0]. Maybe it's wrong to prefer that since it relies on an implied understanding that getBy would only return the first item?

Since getBy now causes a test to break if more than 1 is found, perhaps a getFirstBy* is needed?

@nickmccurdy
Copy link
Member

You could always add your own utility that calls getAllBy(...args)[0]. If you think it would be useful to have in core, it would help to open a new issue so we can track votes and have a discussion about it separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BREAKING CHANGE This change will require a major version bump released
Projects
None yet
Development

No branches or pull requests

5 participants