Skip to content

feat: add toBePressed matcher (#203) #658

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

kretajak
Copy link

What:

New toBePressed matcher is added

Why:

Closes #203

Checklist:

  • Documentation
  • Tests
  • Updated Type Definitions
  • Ready to be merged

In my opinion this PR could be followed by another one which would add support for checking aria-pressed="mixed". Maybe toBePartiallyPressed? It would follow the same approach as splitter toBeChecked and toBePartiallyChecked into two separate matchers.

@kretajak
Copy link
Author

kretajak commented Feb 21, 2025

Hi, may I ask for reviews?

@kretajak
Copy link
Author

kretajak commented Aug 9, 2025

Hi @gnapse, can I kindly ask for a review?

Copy link
Member

@gnapse gnapse left a comment

Choose a reason for hiding this comment

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

Thanks for making this contribution. It is good stuff. Though there are a couple of things that need to be improved.

(the comments marked as "nit-pick" are not fundamental to be changed, but other ones are)

README.md Outdated

### `toBePressed`

This allows to check whether given element has been [pressed](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-pressed).
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
This allows to check whether given element has been [pressed](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-pressed).
This allows to check whether given element is [pressed](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-pressed).

Copy link
Author

Choose a reason for hiding this comment

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

Fixed. ✅

Comment on lines 78 to 88
test('throws when element do not have aria-pressed attribute', () => {
const {queryByTestId} = render(`<span data-testid="span" />`)

expect(() =>
expect(queryByTestId('span')).toBePressed(),
).toThrowErrorMatchingInlineSnapshot(
`Only button or input with type="button" or element with role="button" and a valid aria-pressed attribute can be used with .toBePressed()`,
)
})
Copy link
Member

Choose a reason for hiding this comment

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

This test perhaps should be titled "throws an error when element is not a button" because that's the real reason for this use case to fail.

To illustrate, it should fail even if you pass the aria-pressed attribute. So maybe also modify the test to show that:

Suggested change
test('throws when element do not have aria-pressed attribute', () => {
const {queryByTestId} = render(`<span data-testid="span" />`)
expect(() =>
expect(queryByTestId('span')).toBePressed(),
).toThrowErrorMatchingInlineSnapshot(
`Only button or input with type="button" or element with role="button" and a valid aria-pressed attribute can be used with .toBePressed()`,
)
})
test('throws an error when element is not a button', () => {
const {queryByTestId} = render(`<span data-testid="span" aria-pressed="true" />`)
expect(() =>
expect(queryByTestId('span')).toBePressed(),
).toThrowErrorMatchingInlineSnapshot(
`Only button or input with type="button" or element with role="button" and a valid aria-pressed attribute can be used with .toBePressed()`,
)
})

Copy link
Author

Choose a reason for hiding this comment

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

Fixed. ✅

Comment on lines 16 to 21

if (ariaPressed === 'true' || ariaPressed === 'false') {
return true
}

return false
Copy link
Member

Choose a reason for hiding this comment

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

nit-pick:

Suggested change
if (ariaPressed === 'true' || ariaPressed === 'false') {
return true
}
return false
return ariaPressed === 'true' || ariaPressed === 'false'

Copy link
Author

Choose a reason for hiding this comment

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

Fixed. ✅

Comment on lines 6 to 12
const isButton = () => {
return (
element.tagName.toLowerCase() === 'button' ||
element.getAttribute('role') === 'button' ||
(element.tagName.toLowerCase() === 'input' && element.type === 'button')
)
}
Copy link
Member

Choose a reason for hiding this comment

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

This is mostly it but misses an edge case. An element can have more than one role via the role attribute (ref).

You could soften the condition on the role attribute to check that it includes the button role:

-element.getAttribute('role') === 'button' ||
+element.getAttribute('role')?.split(/\s/)?.includes('button') ||

Though ideally we should do this via the helper functions found in the to-have-role.js source file. Unfortunately, those are internal to the module. They'd have to be moved to a new module role-helpers.js and used from there in that matcher, and in this new matcher.

Copy link
Author

Choose a reason for hiding this comment

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

Playwright has logic of const roles = (element.getAttribute('role') || '').split(' ').map(role => role.trim());. Seems more readable to me.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, that works.

Copy link
Author

Choose a reason for hiding this comment

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

Fixed. ✅

}

return {
pass: isButton() && isPressed(),
Copy link
Member

Choose a reason for hiding this comment

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

nit-pick:

I am not sure why you chose to make these (isButton, isPressed, isValidAriaElement) to be functions. They could simply be variables instead. You compute the value once and store it.

Not a big deal, but just curious.

Copy link
Author

Choose a reason for hiding this comment

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

I was a bit following convention from the other files. I changed that as per your request. ✅

@kretajak kretajak force-pushed the feat/add-to-be-pressed-matcher branch from 5a89af4 to 2662e5d Compare August 12, 2025 19:11
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.

Support for matching pressed state of toggle buttons
2 participants