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

Support for array matchers, similar like the some method, but for use with expect #512

Open
dietergeerts opened this issue Aug 6, 2021 · 9 comments

Comments

@dietergeerts
Copy link

This would be awesome, so that we don't need to apply multiple transformations and calculations, and having no good error feedback when the expect fails.

@christian-bromann
Copy link
Member

@dietergeerts can you provide an example?

@dietergeerts
Copy link
Author

I have written the following helper:

export function areNotSelected(elements: ReturnType<typeof browser['$$']>) {
  return elements.every(async (element) => !(await element.isSelected()))
}

And used it like:

Then(/^I see that neither region options are selected$/, async () => {
  const noneSelected = await areNotSelected(authLoginRegionSelect.options)
  await expect(noneSelected).toBe(true)
})

So basically, the methods that work on a single element, like isSelected, I would like to see a version that works on an array of elements, so I don't need to write my own helper methods, because with my own helpers, I don't have nice error messages from the test framework. (I could extend expect myself, but I think they can fit really nicely in this package as others can use this too, so first going for this route)

@christian-bromann
Copy link
Member

How do you think these matchers should be named?

@dietergeerts
Copy link
Author

🤔 , when we compare with isSelected for a single element, which is toBeSelected, we could have:

  • toBeAllSelected (toBeEverySelected doesn't sound that natural to me, though in util libraries like Lodash, this is what's used a lot for checking if a list of items all match)
  • toBeSomeSelected

Because webdriver-io itself doesn't have functions for getting the selection state of all elements, we could also expose such helpers like areAllSelected/areEverySelected and areSomeSelected, because sometimes you want to check that without actually asserting it.

I don't have too much experience with webdriver-io, so I might be missing things, not seeing existing ways of doing this easily, but also not knowing all (edge-)cases that can happen with element arrays. I've used protractor for years, and it's the first project I'm really using webdriver-io for end-2-end testing now.

@christian-bromann
Copy link
Member

How about we modify matchers such as toBeSelected to detect if the provided object is an array of elements and if so the matcher checks if all elements are selected. That would be easily applicable to toBeExisting, toBeDisplayed etc., for example:

// checks if a single element is selected
expect($('#singleElem')).toBeSelected()
// checks if all elements are selected
expect($$('.manyElems')).toBeSelected()

To enable the other use case of checking if just some are selected we could use a partial parameter to the matcher. This parameter would be ignored if used on a single element, e.g.:

// this would be the same as "expect($('#singleElem')).toBeSelected()"
expect($('#singleElem')).toBeSelected({partial: true})
// checks if at least one element is selected
expect($$('.manyElems')).toBeSelected({partial: true})

This way we can re-use existing matchers and don't bloat the API. What do you think?

@dietergeerts
Copy link
Author

This way we can re-use existing matchers and don't bloat the API

It wouldn't be bloat, unless you think of bloat as just more matchers. Imho, it's better to have more matchers if they make things more clear than having less matchers where there can be confusion in what they can handle. toBeSelected could work for an array of elements, but does that mean all/every or some of them? Of course, some things can be re-used internally, but to the outside, it will be better to have more matchers to be clearer. Your IDE will also help you better, because when writing a test, you know if you have an array of elements or just one element, and thus you can start typing toBeAll and you'll see what's possible for an array of elements where all needs to be whatever the check is.

I understand that this can be seen as "taste", but from experience, I have seen that having clear functions(/matchers in this case), where there is only 1 thing they do with 1 way to call them, is the best way to go for everyone, as they are very clear. This is also what Functional Programming is partly about. So whatever you want to choose, this is my preference and experience.

@christian-bromann
Copy link
Member

@webdriverio/project-committers and @mgrybyk any suggestions?

@erwinheitzman
Copy link
Member

I agree with Christian that having a single and easy to understand API makes more sense here.

Imagine that we would allow you to retrieve the text of all elements.
You wouldn't want getAllText but rather getText.
This way the user knows the API and does not have to think about it.

@dietergeerts
Copy link
Author

I agree with Christian that having a single and easy to understand API makes more sense here.

Imagine that we would allow you to retrieve the text of all elements. You wouldn't want getAllText but rather getText. This way the user knows the API and does not have to think about it.

I agree too, but sometimes you have something in-between. toBeSelected could work with single element and an array of elements, as that is the same as "all" of these elemetens are selected. But when you want to check that only some are selected, so at least 1, then you need something else, and that's what I'm asking for here, as then the error message will be specific too, which makes it easier to understand etc....

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

No branches or pull requests

3 participants