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

feat: add toBeVisible matcher #73

Merged
merged 11 commits into from
Oct 20, 2022

Conversation

fluiddot
Copy link
Contributor

@fluiddot fluiddot commented Jan 24, 2022

What:

Add toBeVisible matcher following a similar logic as the jest-dom matcher (reference).

Why:

This matcher provides a useful way to verify that a queried element is actually visible.

How:

The matcher has been introduced based on the implementation of other matchers and trying to reproduce a similar logic as the jest-dom matcher (reference), but taking into account the React Native nuances.

Checklist:

  • Documentation added to the
    docs
  • Typescript definitions updated
  • Tests
  • Ready to be merged

Copy link

@dcalhoun dcalhoun 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! This matcher would be quite useful. I left a few comments to consider.

README.md Outdated Show resolved Hide resolved
src/__tests__/to-be-visible.js Outdated Show resolved Hide resolved
src/to-be-visible.js Outdated Show resolved Hide resolved
@fluiddot fluiddot force-pushed the feat/to-be-visible branch 5 times, most recently from e7afe06 to 17eaad4 Compare January 25, 2022 10:26
@fluiddot fluiddot marked this pull request as ready for review January 25, 2022 10:28
@fluiddot
Copy link
Contributor Author

Great work! This matcher would be quite useful. I left a few comments to consider.

Thank you very much @dcalhoun for taking a look at this PR 🙇.

Following your comments and suggestions, I've applied some updates to the changes. At this point, the PR can be considered as ready to be reviewed in order to include the new toBeVisible matcher.

@fluiddot
Copy link
Contributor Author

Looks like most of the unit tests are failing with the following error:

TypeError: _interopRequireDefault is not a function

However, I managed to reproduce the same issue by running the tests in the main branch, so not sure whether these changes might be the cause 🤔 .

@dcalhoun
Copy link

@mdjastrzebski @thymikee would either of you be willing to review this work please? Totally understand if you do not have time currently. Just wanted to check in. Thanks! 🙇🏻

@GuglielmoFelici
Copy link

Hi all! Any update on this? Would be quite useful 🙌

@mdjastrzebski
Copy link
Collaborator

I will try to work on that next week

@Norfeldt
Copy link

Norfeldt commented Aug 15, 2022

I will try to work on that next week

Don't know if this would be of any help @mdjastrzebski . I'm using this:

expect.extend({
  // should be replacable once this PR gets merged https://github.com/testing-library/jest-native/pull/73
  toHaveZeroOpacity(element) {
    let pass = element.props.style?.opacity === 0
    let parent = element.parent
    while (parent && pass === false) {
      if (parent.props.style?.opacity === 0) pass = true
      parent = parent?.parent
    }

    return {
      message: () => 'expected element to be hidden',
      pass,
    }
  },
})

import { render } from '@testing-library/react-native'
import * as React from 'react'
import { View, Text } from 'react-native'

describe('extended `expect` methods', () => {
  describe('.toHaveZeroOpacity', () => {
    it('should pass when element is has zero opacity', () => {
      const utils = render(<View style={{ opacity: 0 }} testID="TestId__VIEW" />)
      expect(utils.getByTestId('TestId__VIEW')).toHaveZeroOpacity()
    })

    it('should NOT pass when element is has non-zero opacity', () => {
      const utils = render(<View style={{ opacity: 0.001 }} testID="TestId__VIEW" />)
      expect(utils.getByTestId('TestId__VIEW')).not.toHaveZeroOpacity()
    })

    it('should pass when some parent element is has zero opacity', () => {
      const utils = render(
        <View style={{ opacity: 0 }}>
          <View>
            <Text>invisible</Text>
          </View>
        </View>
      )
      expect(utils.getByText(/invisible/i)).toHaveZeroOpacity()
    })

    it('should pass when NO parent elements has zero opacity', () => {
      const utils = render(
        <View>
          <View>
            <Text>invisible</Text>
          </View>
        </View>
      )
      expect(utils.getByText(/invisible/i)).not.toHaveZeroOpacity()
    })
  })
})

Copy link
Collaborator

@mdjastrzebski mdjastrzebski left a comment

Choose a reason for hiding this comment

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

@fluiddot, @dcalhoun I've added some comments regarding sharing logic with a related PR in RNTL. We also removed ramda in the mean time so pls update your imports.

README.md Outdated Show resolved Hide resolved
README.md Show resolved Hide resolved
}

function isAttributeVisible(element) {
return element.type !== 'Modal' || element.props.visible !== false;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Directly checking modal type looks kinda hacky, maybe we could check some accessiblity props here: accessibilityElementsHidden, etc

Copy link

Choose a reason for hiding this comment

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

does it support bottom sheet from gorhom ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hard to say without checking, depends on how well that library supports accessibility props. I think we should first concentrate on supporting built-in components, e.g. built-in Modal from RN, and handle the external libraries afterwards on a case-by-case basis, as in some cases the proper place to support them will be here, but in other case it might be by submitting the PR to the library authors to improve their accessibility support.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@fluiddot I wonder how Modal actually performs hidding of its children when visibility=false. Instead of relying on querying the element for type and visible prop, we could check the underlying code. Maybe it just does not render the children at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Instead of relying on querying the element for type and visible prop, we could check the underlying code. Maybe it just does not render the children at all.

@mdjastrzebski I checked when testing that Modal component doesn't actually render children, so this matcher will throw an exception when using it for children elements of a not visible modal.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Directly checking modal type looks kinda hacky, maybe we could check some accessiblity props here: accessibilityElementsHidden, etc

@mdjastrzebski good point. To be honest, I added the modal type check as a special case, since it's likely that we want to check the visibility of a modal using this matcher. In any case, I'm open to reconsider this condition in favor of a better approach or even not including it.

Regarding the accessibility props, I went ahead and updated the matcher to also check them in this commit, similar to the logic of isInaccessible function.

@tomwaitforitmy
Copy link

I would be very happy to use this! 👍

@mdjastrzebski
Copy link
Collaborator

@fluiddot Do you have capacity to work on updating this PR?

@dcalhoun, @Norfeldt & others: maybe you are willing to take over this.

re isInaccessible function/respectAccessiblity option from RNTL: it seems that to toBeVisible from Jest DOM has slightly different logic than isInaccessible from DTL, as it e.g. takes into account opacity: 0. So this matcher should not sole rely on isInaccessible.

@fluiddot
Copy link
Contributor Author

@fluiddot Do you have capacity to work on updating this PR?

Hey @mdjastrzebski, my apologies for not being very active in the PR. I'd like to resume the work on this and review the feedback as soon as possible, but my bandwidth nowadays is usually low. If someone is willing to take over this, please feel to do it. Otherwise, I'll try to make some progress in the next weeks.

import { render } from '@testing-library/react-native';

describe('.toBeVisible', () => {
test.each([
Copy link
Collaborator

Choose a reason for hiding this comment

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

Github/link seems to be complaining about missing key prop, Could you refactor these tests to be regular. not .each tests for readability.

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 fixed this issue when migrating the test file to TypeScript in this commit.


function isStyleVisible(element) {
const style = element.props.style || {};
const { display = 'flex', opacity = 1 } = Array.isArray(style) ? mergeAll(style) : style;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use StyleSheet.flatten to calculate flat style object.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch, I've applied this suggestion in this commit.


function isStyleVisible(element) {
const style = element.props.style || {};
const { display = 'flex', opacity = 1 } = Array.isArray(style) ? mergeAll(style) : style;
Copy link
Collaborator

Choose a reason for hiding this comment

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

No need for default values, if we later compare them to known values.

Suggested change
const { display = 'flex', opacity = 1 } = Array.isArray(style) ? mergeAll(style) : style;
const { display, opacity } = Array.isArray(style) ? mergeAll(style) : style;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, I've applied this suggestion in this commit.

@mdjastrzebski
Copy link
Collaborator

@fluiddot Overall the current implementation looks solid. I think it's sensible approach to base it on Jest DOM matcher code with some tweaks to adjust for different props in RN than in Web.

# Conflicts:
#	extend-expect.d.ts
#	src/extend-expect.ts
@mdjastrzebski
Copy link
Collaborator

@fluiddot would you be able to rebase the code and migrate it to typescript as the current codebase uses it now.

@fluiddot
Copy link
Contributor Author

@fluiddot would you be able to rebase the code and migrate it to typescript as the current codebase uses it now.

@mdjastrzebski 😅 Sorry for the long delay on addressing the comments of the PR and migrating the changes to TypeScript. After the recent changes I pushed, the PR should be ready for another review. Let me know if there's anything else I can contribute with in order to conclude the feature. Thank you very much for the help 🙇 .

@codecov
Copy link

codecov bot commented Oct 18, 2022

Codecov Report

Merging #73 (7267da4) into main (beaf547) will not change coverage.
The diff coverage is 100.00%.

@@            Coverage Diff            @@
##              main       #73   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            8         9    +1     
  Lines          151       175   +24     
  Branches        47        57   +10     
=========================================
+ Hits           151       175   +24     
Flag Coverage Δ
node-14 100.00% <100.00%> (ø)
node-16 100.00% <100.00%> (ø)
node-18 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/extend-expect.ts 100.00% <ø> (ø)
src/to-be-visible.ts 100.00% <100.00%> (ø)

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

README.md Outdated Show resolved Hide resolved
@mdjastrzebski
Copy link
Collaborator

@fluiddot looks pretty solid. I think the code is ready, I've added some tweak to code comments. Pls fix code coverage back to 100%. It should be a matter of adding a single test probably.

fluiddot and others added 2 commits October 20, 2022 20:28
Co-authored-by: Maciej Jastrzebski <[email protected]>
@fluiddot
Copy link
Contributor Author

@fluiddot looks pretty solid. I think the code is ready, I've added some tweak to code comments. Pls fix code coverage back to 100%. It should be a matter of adding a single test probably.

Thanks for the review @mdjastrzebski 🙇. I've just applied your suggestions and typo fixes. I'll take a look at the code coverage and try to add another test to provide 100% 👍.

@fluiddot
Copy link
Contributor Author

@fluiddot looks pretty solid. I think the code is ready, I've added some tweak to code comments. Pls fix code coverage back to 100%. It should be a matter of adding a single test probably.

Thanks for the review @mdjastrzebski 🙇. I've just applied your suggestions and typo fixes. I'll take a look at the code coverage and try to add another test to provide 100% 👍.

I added a new test for checking that the matcher throws an error when the expectation is not matched. With this, the coverage should go back to 100% 🎊.

Copy link
Collaborator

@mdjastrzebski mdjastrzebski left a comment

Choose a reason for hiding this comment

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

Looks good! Happy to finally merge it :-) Thank you @fluiddot for this contribution!

@mdjastrzebski mdjastrzebski merged commit 1b65ce3 into testing-library:main Oct 20, 2022
@github-actions
Copy link

🎉 This PR is included in version 5.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@fluiddot fluiddot deleted the feat/to-be-visible branch October 20, 2022 20:28
@fluiddot
Copy link
Contributor Author

Looks good! Happy to finally merge it :-) Thank you @fluiddot for this contribution!

Thank you so much @mdjastrzebski for the review and help of this contribution 🙇! Happy to know that it's finally merged 😃!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants