diff --git a/README.md b/README.md
index bd2394b..c2bacce 100644
--- a/README.md
+++ b/README.md
@@ -82,6 +82,7 @@ clear to read and to maintain.
- [`toHaveRole`](#tohaverole)
- [`toHaveErrorMessage`](#tohaveerrormessage)
- [`toBePressed`](#tobepressed)
+ - [`toBePartiallyPressed`](#tobepartiallypressed)
- [Deprecated matchers](#deprecated-matchers)
- [`toBeEmpty`](#tobeempty)
- [`toBeInTheDOM`](#tobeinthedom)
@@ -1347,6 +1348,44 @@ screen.getByRole('button', {name: 'Pressed span'}).toBePressed()
screen.getByRole('button', {name: 'Released span'}).not.toBePressed()
```
+
+
+### `toBePartiallyPressed`
+
+This allows to check whether given element is partially
+[pressed](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-pressed).
+
+It accepts elements with explicit or implicit `button` role and valid
+`aria-pressed` attribute of `mixed`.
+
+```typescript
+toBePressed()
+```
+
+#### Examples
+
+```html
+
+
+Partially pressed span
+```
+
+##### Using DOM Testing Library
+
+```javascript
+screen.getByRole('button', {name: 'Partially pressed'}).toBePartiallyPressed()
+screen
+ .getByRole('button', {name: 'Partially pressed input button'})
+ .toBePartiallyPressed()
+screen
+ .getByRole('button', {name: 'Partially pressed span'})
+ .toBePartiallyPressed()
+```
+
## Deprecated matchers
### `toBeEmpty`
diff --git a/src/__tests__/to-be-partially-pressed.js b/src/__tests__/to-be-partially-pressed.js
new file mode 100644
index 0000000..da6e7fe
--- /dev/null
+++ b/src/__tests__/to-be-partially-pressed.js
@@ -0,0 +1,111 @@
+import {render} from './helpers/test-utils'
+
+describe('.toBePartiallyPressed', () => {
+ test('handles button element', () => {
+ const {queryByTestId} = render(`
+
+
+
+
+ `)
+
+ expect(queryByTestId('button-partially-pressed')).toBePartiallyPressed()
+ expect(queryByTestId('button-not-pressed')).not.toBePartiallyPressed()
+ expect(queryByTestId('button-pressed')).not.toBePartiallyPressed()
+ expect(queryByTestId('button')).not.toBePartiallyPressed()
+ })
+
+ test('handles element with role="button"', () => {
+ const {queryByTestId} = render(`
+
+
+
+
+ `)
+
+ expect(queryByTestId('button-partially-pressed')).toBePartiallyPressed()
+ expect(queryByTestId('button-not-pressed')).not.toBePartiallyPressed()
+ expect(queryByTestId('button-pressed')).not.toBePartiallyPressed()
+ expect(queryByTestId('button')).not.toBePartiallyPressed()
+ })
+
+ test('handles input with button type', () => {
+ const {queryByTestId} = render(`
+
+
+
+
+ `)
+
+ expect(queryByTestId('button-partially-pressed')).toBePartiallyPressed()
+ expect(queryByTestId('button-not-pressed')).not.toBePartiallyPressed()
+ expect(queryByTestId('button-pressed')).not.toBePartiallyPressed()
+ expect(queryByTestId('button')).not.toBePartiallyPressed()
+ })
+
+ test('throw an error when pressable element is not partially pressed but expected to be', () => {
+ const {queryByTestId} = render(`
+
+ `)
+
+ expect(() => expect(queryByTestId('button')).toBePartiallyPressed())
+ .toThrowErrorMatchingInlineSnapshot(`
+ expect(>element>).toBePartiallyPressed()>
+
+ Expected element to have:
+ aria-pressed="mixed">
+ Received:
+ aria-pressed="true">
+ `)
+ })
+
+ test('throw an error when pressable element is partially pressed but expected not to be', () => {
+ const {queryByTestId} = render(`
+
+ `)
+
+ expect(() => expect(queryByTestId('button')).not.toBePartiallyPressed())
+ .toThrowErrorMatchingInlineSnapshot(`
+ expect(>element>).not.toBePartiallyPressed()>
+
+ Expected element not to have:
+ aria-pressed="mixed">
+ Received:
+ aria-pressed="mixed">
+ `)
+ })
+
+ test('throw an error when pressable element has invalid aria-pressed attribute', () => {
+ const {queryByTestId} = render(`
+
+ `)
+
+ expect(() =>
+ expect(queryByTestId('button')).toBePartiallyPressed(),
+ ).toThrowErrorMatchingInlineSnapshot(
+ `Only button or input with type="button" or element with role="button" and a valid aria-pressed attribute can be used with .toBePartiallyPressed()`,
+ )
+ })
+
+ test('throws when element is not a button', () => {
+ const {queryByTestId} = render(`
+
+ `)
+
+ expect(() =>
+ expect(queryByTestId('div')).toBePartiallyPressed(),
+ ).toThrowErrorMatchingInlineSnapshot(
+ `Only button or input with type="button" or element with role="button" and a valid aria-pressed attribute can be used with .toBePartiallyPressed()`,
+ )
+ })
+
+ test('throws when element do not have aria-pressed attribute', () => {
+ const {queryByTestId} = render(``)
+
+ expect(() =>
+ expect(queryByTestId('span')).toBePartiallyPressed(),
+ ).toThrowErrorMatchingInlineSnapshot(
+ `Only button or input with type="button" or element with role="button" and a valid aria-pressed attribute can be used with .toBePartiallyPressed()`,
+ )
+ })
+})
diff --git a/src/matchers.js b/src/matchers.js
index 9f5a72d..e121edb 100644
--- a/src/matchers.js
+++ b/src/matchers.js
@@ -26,3 +26,4 @@ export {toHaveDescription} from './to-have-description'
export {toHaveErrorMessage} from './to-have-errormessage'
export {toHaveSelection} from './to-have-selection'
export {toBePressed} from './to-be-pressed'
+export {toBePartiallyPressed} from './to-be-partially-pressed'
diff --git a/src/to-be-partially-pressed.js b/src/to-be-partially-pressed.js
new file mode 100644
index 0000000..d6b545f
--- /dev/null
+++ b/src/to-be-partially-pressed.js
@@ -0,0 +1,54 @@
+import {checkHtmlElement, getMessage} from './utils'
+
+export function toBePartiallyPressed(element) {
+ checkHtmlElement(element, toBePartiallyPressed, this)
+
+ const roles = (element.getAttribute('role') || '')
+ .split(' ')
+ .map(role => role.trim())
+
+ const isButton =
+ element.tagName.toLowerCase() === 'button' ||
+ (element.tagName.toLowerCase() === 'input' && element.type === 'button') ||
+ roles.includes('button')
+
+ const pressedAttribute = element.getAttribute('aria-pressed')
+
+ const isValidAriaElement =
+ pressedAttribute === 'true' ||
+ pressedAttribute === 'false' ||
+ pressedAttribute === 'mixed'
+
+ if (!isButton || !isValidAriaElement) {
+ return {
+ pass: false,
+ message: () =>
+ `Only button or input with type="button" or element with role="button" and a valid aria-pressed attribute can be used with .toBePartiallyPressed()`,
+ }
+ }
+
+ const isPartiallyPressed = pressedAttribute === 'mixed'
+
+ return {
+ pass: isButton && isPartiallyPressed,
+
+ message: () => {
+ const to = this.isNot ? 'not to' : 'to'
+
+ const matcher = this.utils.matcherHint(
+ `${this.isNot ? '.not' : ''}.toBePartiallyPressed`,
+ 'element',
+ '',
+ )
+
+ return getMessage(
+ this,
+ matcher,
+ `Expected element ${to} have`,
+ `aria-pressed="mixed"`,
+ `Received`,
+ `aria-pressed="${pressedAttribute}"`,
+ )
+ },
+ }
+}
diff --git a/types/matchers.d.ts b/types/matchers.d.ts
index b7c7e6a..34fdaff 100755
--- a/types/matchers.d.ts
+++ b/types/matchers.d.ts
@@ -763,10 +763,10 @@ declare namespace matchers {
toHaveSelection(selection?: string): R
/*
* @description
- * 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 has been [pressed](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-pressed)
*
- * It accepts elements with explicit or implicit `button` role and valid `aria-pressed`
- * attribute of `"true"` or `"false"`.
+ * It accepts elements with explicit or implicit `button` role and valid `aria-pressed`
+ * attribute of `"true"` or `"false"`.
*
* @example
*
@@ -774,16 +774,16 @@ declare namespace matchers {
*
*
*
- *
+ *
* Pressed span
* Released span
*
* screen.getByRole('button', { name: 'Pressed' }).toBePressed();
* screen.getByRole('button', { name: 'Released' }).not.toBePressed();
- *
+ *
* screen.getByRole('button', { name: 'Pressed input button' }).toBePressed();
* screen.getByRole('button', { name: 'Released input button' }).not.toBePressed();
- *
+ *
* screen.getByRole('button', { name: 'Pressed span' }).toBePressed();
* screen.getByRole('button', { name: 'Released span' }).not.toBePressed();
*
@@ -791,6 +791,25 @@ declare namespace matchers {
* [testing-library/jest-dom#tobepressed](https://github.com/testing-library/jest-dom#tobepressed)
*/
toBePressed(): R
+ /*
+ * @description
+ * This allows to check whether given element has been [partially pressed](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-pressed)
+ *
+ * It accepts elements with explicit or implicit `button` role and valid `aria-pressed` of `"mixed"`.
+ *
+ * @example
+ *
+ *
+ * Partially pressed span
+ *
+ * screen.getByRole('button', { name: 'Partially Pressed' }).toBePartiallyPressed();
+ * screen.getByRole('button', { name: 'Partially pressed input button' }).toBePartiallyPressed();
+ * screen.getByRole('button', { name: 'Partially pressed span' }).toBePartiallyPressed();
+ *
+ * @See
+ * [testing-library/jest-dom#tobepartiallypressed](https://github.com/testing-library/jest-dom#tobepartiallypressed)
+ */
+ toBePartiallyPressed(): R
}
}