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

Update docs with guides on using matchers #902

Merged
merged 14 commits into from
Apr 7, 2021
Merged

Update docs with guides on using matchers #902

merged 14 commits into from
Apr 7, 2021

Conversation

minkimcello
Copy link
Contributor

@minkimcello minkimcello commented Mar 13, 2021

Motivation

To update our docs with guides on how to use matchers. Resolves #824.

Approach

Here is the new Assertions and Matchers page, but I also had to make several changes to the previous Locators, Filters, and Actions page so please read through both pages.

TODOs

  • Should applyMatcher() be included in the guides? In discussing how one can write their own matchers, I show how including() is implemented and provide a greaterThan() example neither of which use applyMatcher().
  • Need to add a sneak peak example for matchers in the quick start page. Later?
  • Not scoped to this PR but should mention that Add HTML and FormField to the builtin interactor list. #845 is on my TODOs list after this PR is finished.

@changeset-bot
Copy link

changeset-bot bot commented Mar 13, 2021

⚠️ No Changeset found

Latest commit: 2d8872c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Mar 13, 2021

The preview packages of this pull request have been published.
Click on the following packages for instructions on how to install them:

@bigtest/cli

Install using the following command:

$ npm install @bigtest/cli@mk_matchers

Or update your package.json file:

{
  "@bigtest/cli": "mk_matchers"
}

@bigtest/interactor

Install using the following command:

$ npm install @bigtest/interactor@mk_matchers

Or update your package.json file:

{
  "@bigtest/interactor": "mk_matchers"
}

@bigtest/server

Install using the following command:

$ npm install @bigtest/server@mk_matchers

Or update your package.json file:

{
  "@bigtest/server": "mk_matchers"
}

bigtest-sample

Install using the following command:

$ npm install bigtest-sample@mk_matchers

Or update your package.json file:

{
  "bigtest-sample": "mk_matchers"
}

Generated by 🚫 dangerJS against 2d8872c

@minkimcello minkimcello requested review from jenweber and cowboyd March 13, 2021 03:59
@cowboyd
Copy link
Member

cowboyd commented Mar 15, 2021

Should applyMatcher() be included in the guides? In discussing how one can write their own matchers, I show how including() is implemented and provide a greaterThan() example neither of which use applyMatcher().

applyMatcher is a private API, and so our docs shouldn't talk about it.

Copy link
Contributor

@jorgelainfiesta jorgelainfiesta left a comment

Choose a reason for hiding this comment

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

Great work Min! I added some thoughts that come to mind

@minkimcello
Copy link
Contributor Author

@cowboyd I'm trying to find an appropriate place in the Quick Start to include a matchers sneak peak but it feels to me that page goes over the big picture and matchers is more a micro feature.

If we were to include it somehow, I could sneak them into either the sign button should be absent example or into the airline example. But, including it into either of those examples would require us to address it saying "hey, this is a matcher. read more about it [here](link)" but since we haven't introduced any other concepts yet at that point I think that's jumping the gun a little.

We could add a sentence in the Continue learning about Interactors section to include Assertions and Matchers but since we're considering reorganizing our content (issue #907), I think we can put it off until then.

@minkimcello minkimcello marked this pull request as ready for review March 23, 2021 14:57
Copy link
Contributor

@jorgelainfiesta jorgelainfiesta left a comment

Choose a reason for hiding this comment

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

Awesome work y'all! it's looking great!! I left two questions/comments for your consideration. Thanks!

Link('Google').has({
href: or(
'https://google.com',
'https://twitter.com'
Copy link
Contributor

Choose a reason for hiding this comment

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

Just for the sake of making the example more realistic, maybe the second option could be https://google.ca or another domain (which makes me wonder, can or take an arbitrary amount of parameters?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can change up the example however you'd like. Any specific reason for https://google.ca?

or can take more than two arguments:

These next three matchers: and(), or(), and not() are different from the first two matchers in that they can take multiple arguments and the arguments can be either a value or another matcher.

Copy link
Contributor

Choose a reason for hiding this comment

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

No reason, just that a link to Google probably has a google href. How about this:

Link('Google').has({ 
  href: or(
    'https://google.com',
    'https://google.co.uk',
    'https://google.es'
...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh I see what you're saying. We're straying off into an unrealistic example. However, I do like that the two are very different and it makes it easier to get the message across. If anybody is skimming through the docs, they might not notice the difference between .com and .ca.

So when we take this example:

Link('Google').has({
  href: or(
    'https://google.com',
    'https://twitter.com'
  )
})

It's very clear without any context that or() is a conditional that only needs one condition to return true. The reader doesn't even need to remember the HTML layout to understand the example:

<a href="https://google.com">Google</a>
<a href="https://twitter.com">Twitter</a>

Whereas with:

Link('Google').has({
  href: or(
    'https://google.com',
    'https://google.co.uk'
  )
})

The reader might go "why not?" It's a silly example but matchers are used in complex situations. Because interactors are already so intuitive that the need for matchers would, I assume, be in special cases. Meaning I think it's appropriate to show unrealistic examples as long as it helps the readers understand how they work in the quickest way possible.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I like the example showing 3 TLDs. I think when there are three, it's easier to spot the difference. The other reason I like it is that I would not think to pass more than 2 parameters into this, and so it's teaching something useful about the API without introducing any new concepts/commentary.

This example is an opportunity to show off Frontside instead of google, potentially:

https://frontside.com/
https://www.frontside.com/

Copy link
Contributor Author

@minkimcello minkimcello Apr 6, 2021

Choose a reason for hiding this comment

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

@jorgelainfiesta For the or() matcher we just need to illustrate that one false statement can still make a test pass because it's an either-or situation.

Link('Frontside').has({
  href: or(
    'frontside',
    'frontside',
    'frontside'
  )
})

☝️ isn't as clear as:

Link('Frontside').has({
  href: or(
    'frontside',
    'not-frontside'
  )
})

Was the point I was trying to make.

And also do we actually add the different TLDs into the HTML example?

<a href="https://frontside.com">Frontside</a>
<a href="https://www.frontside.com">Frontside</a>
<a href="https://www.frontside.io">Frontside</a>

Because with only those three links, it's hard to discuss not() - was the other argument I was making.

I suppose we could do frontside and google (just one of each) and still use the or example with three different TLDs. 🤷‍♂️

Copy link
Collaborator

Choose a reason for hiding this comment

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

I was thinking that the HTML example could shoot show a single link, and the “or” matcher includes three different URLs. International TLDs is a more realistic example than frontside urls, but the frontside URLs get the job done too. I think either example works here.

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 still think the non-realistic example drives the point better of how or() is used than using google.ca and google.co.uk.

Because if I was reading this, I'll be thinking, "why not just use href: including('google')? what are the benefits of using or()?". And in what real life scenario do we need to ensure that it's just one of the three of all the TLDs? It would make sense to use not() if we wanted to specify that it should not be google.ca.

So by doing or('google.com', 'twitter.com'), I think we all know how silly the example is but we get the point much faster.

But anyway, I changed it. You can see the commit here. I didn't switch one of the links to Frontside yet because people will already be on the frontside website when they're reading this guide, and putting our Frontside link next to Google's might give off an inaccurate impression of how we perceive ourselves.

Copy link
Contributor

@jorgelainfiesta jorgelainfiesta Apr 7, 2021

Choose a reason for hiding this comment

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

Ah gotcha, I see your point. Indeed including would've been a better choice indeed. What is the use of or then? I can't think of a use case but I guess there are plenty?

For me, reading incoherent examples is confusing. I'm like "why would they do that?"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The only real use case I saw was where someone wants to assert for a Button that may or may not be visible but still available in the DOM:

Button({ visibility: or(true, false) }).is(whatever);

So we could change all the examples for and, or, and not so it uses a button instead but that boolean for visibility really only applies to or so there's a lot of switching back and forth in the examples even if we use the same Button.

Like you mentioned below, let's just brush this off for now and update it later.


To create your own matcher without the use of any of the preexisting ones, you will need to create a function that returns a `{ match(), format() }` object.

The `match()` function is where you place all of the matcher logic. It takes one argument, `actual`, which represents the values from the interactors. Here's how the `including()` matcher is implemented:
Copy link
Member

Choose a reason for hiding this comment

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

Can we be more specific. Instead of "the values from the interactors", actual will be the value of the locator or filter

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The match() function is where you place all of the matcher logic. It takes one argument, actual, which will be the value of the locator or filter.

☝️ is this okay?

We pondered over this very sentence. The reasoning behind why I said "values" instead of being more specific is that in the context of creating your own matchers it doesn't make a difference whether "actual" is going to be a locator or filter value.

Copy link
Contributor Author

@minkimcello minkimcello Apr 1, 2021

Choose a reason for hiding this comment

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

@cowboyd I'm going to assume the thumbs up are for the explanation for why I went with just "values". I'll resolve this for now?

Copy link
Member

@cowboyd cowboyd left a comment

Choose a reason for hiding this comment

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

matchers are mentioned in the assertion section, but they can also be used anywhere you would pass a locator or a filter. That includes for finding. Do we emphasize this enough? I seem to recall an todo item to tease matchers in the section on filters and locators.

@minkimcello
Copy link
Contributor Author

minkimcello commented Mar 25, 2021

@cowboyd

I seem to recall an todo item to tease matchers in the section on filters and locators.

I believe we discussed including it in the quick start. I've pointed it out in the comment above.

I also skimmed through the Locators, Filters, and Actions page to see where we might be able to include matchers. But the examples we use are simple and the use cases for matchers are for not-simple scenarios. If we had to include matchers, it would either be "Why would you write a test that way?" or we would need to divert to a completely different example. I'll ask Jen what she thinks.

@jenweber
Copy link
Collaborator

jenweber commented Apr 1, 2021

Regarding this last comment, I think putting matchers in their own file is the way to go here. Then you can show using matchers for assertions and other things, without trying to introduce the other concepts at the same time. Someone should already know what filters, assertions, etc. are.

Copy link
Contributor

@jorgelainfiesta jorgelainfiesta 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 already! I'd ship it

@minkimcello minkimcello merged commit fc65a68 into v0 Apr 7, 2021
@minkimcello minkimcello deleted the mk/matchers branch April 7, 2021 13:19
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.

Update guides to show using matchers
4 participants