abhinaba-ghosh / cypress-react-selector

:zap: cypress plugin to locate react elements by component, props and state
https://www.cypress.io/
MIT License
274 stars 28 forks source link

Feature request: chaining/nested `react()` selectors #20

Closed laurence-myers closed 4 years ago

laurence-myers commented 4 years ago

It'd be nice to be able to chain calls to .react(), so we can query child components the exist under found parent components.

Consider this scenario:

const ErrorMessage: React.FC<{ hasError }> = ({ hasError }) => {
  if (hasError) {
    return <p>An error occurred</p>;
  } else {
    return null;
  }
};

const FormField: React.FC<{ name: string }> = ({ name }) => {
  return (
    <div>
      <input name={props.name} />
      <ErrorMessage hasError={false}/>
    </div>
  );
};

function MyForm() {
  return (
    <form>
      <FormField name="username" />
      <FormField name="password" />
    </form>
  );
}

I'd like to query the error message for the username field.

If I have two forms on the page that have a username FormField, I would need to add some other way to distinguish them in my markup. I end up having to start with a react() call, then chaining it with JQuery selectors, which isn't foolproof and requires additional changes to the markup (e.g. adding role to the error message's p element).

I'd like to do something like this:

cy.react('MyForm').react('FormField', { name: 'username' }).react('ErrorMessage').should('not.be.visible');
abhinaba-ghosh commented 4 years ago

Hi @laurence-myers , just thinking out loud, can you try below:

cy.getReact('MyForm').getReact('FormField', { name: 'username' }).react('ErrorMessage').should('not.be.visible');

react() returns DOM Node , where getReact returns resq Node. Even of this works, I need to enhance the module as per you suggested, as that makes more sense. Just let me know, if this works.

laurence-myers commented 4 years ago

I gave that a go, but the last call to .react('ErrorMessage') just returned an array undefined values (due to #19), one for each ErrorMessage in the form, where I expected a single result.

image

abhinaba-ghosh commented 4 years ago

Okay, so let me work on #19 first. It's good that chaining still can be handled through getReact

abhinaba-ghosh commented 4 years ago

Hi @laurence-myers , just thinking out loud, can you try below:

cy.getReact('MyForm').getReact('FormField', { name: 'username' }).react('ErrorMessage').should('not.be.visible');

react() returns DOM Node , where getReact returns resq Node. Even of this works, I need to enhance the module as per you suggested, as that makes more sense. Just let me know if this works.

chaining can happen with the approach, so closing the issue.

laurence-myers commented 4 years ago

Are you sure? Sorry I wasn't clear, but the last .react('ErrorMessage') does not chain off the previous .getReact() calls; it returns all components on the page. I haven't confirmed whether chaining .getReact() works.

I would be happy to add a test to confirm this, but it could require modifying the "calculator" live demo. I wonder if it'd be worthwhile using the lib https://github.com/bahmutov/cypress-react-unit-test to allow unit testing specific scenarios.

On Wed, 17 Jun. 2020, 5:22 pm Abhinaba Ghosh, notifications@github.com wrote:

Hi @laurence-myers https://github.com/laurence-myers , just thinking out loud, can you try below:

cy.getReact('MyForm').getReact('FormField', { name: 'username' }).react('ErrorMessage').should('not.be.visible');

react() returns DOM Node , where getReact returns resq Node. Even of this works, I need to enhance the module as per you suggested, as that makes more sense. Just let me know if this works.

chaining can happen with the approach, so closing the issue.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/abhinaba-ghosh/cypress-react-selector/issues/20#issuecomment-645200229, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABQK4MAPRENDH2PCKYKQGTDRXBVKJANCNFSM4N7HSBZQ .

abhinaba-ghosh commented 4 years ago

@laurence-myers You are right. When I really started testing things in this area, getting strange results. I am working on it, will keep you posted.

abhinaba-ghosh commented 4 years ago

Hi @laurence-myers, released a new version 1.1.0

Now, you should be able to chain queries like:

cy.react('MyComponent', { name: 'Bob' })
  .react('MyAge')
  .should('have.text', '50');
cy.getReact('MyComponent', { name: 'Bob' })
  .getReact('MyAge')
  .getProps('age')
  .should('eq', '50');

Can you give a quick try and let me know if that works. I have added a few sample tests in the calculator tests

abhinaba-ghosh commented 4 years ago

I hope it solved your issue. Please feel free to re-open in case any bugs found.

maga-polito commented 4 years ago

I'm trying to recognize nested components in version 1.1.1 in this way: cy.react('MyComponent', { name: 'Bob' }) .react('MyAge') .should('have.text', '50');

and getting following error: cy.react() failed because it requires a DOM element.

The subject received was:

[]

The previous command that ran was:

cy.then()

abhinaba-ghosh commented 4 years ago

Hi @maga-polito, can you raise a separate issue with actual/similar codes.

By the way, there are some ongoing tasks going on for showing error messages nicely and retrying react fluent queries. Please keep a track on:

  1. https://github.com/abhinaba-ghosh/cypress-react-selector/issues/25
  2. https://github.com/abhinaba-ghosh/cypress-react-selector/issues/26
abhinaba-ghosh commented 4 years ago

Retry ability is available in v2.0.1 with breaking changes. Thanks.