-
#715
78cecbe
Thanks @renovate! -aria-query
was updated to5.3.0
. This update provides updated alignment with the ARIA spec, and will affect Testing Library queries andgetAccessibilityTree
results. -
#715
78cecbe
Thanks @renovate! - We are now using@testing-library/jest-dom@6
. We now support all of the jest-dom matchers, except for the deprecated ones.toHaveErrorMessage
was deprecated, usetoHaveAccessibleErrorMessage
insteadtoHaveRole
was added
-
#732
29b8671
Thanks @calebeby! - Allow returning non-serializable values fromwaitFor
-
#754
6f8ba78
Thanks @renovate! - Updatepuppeteer
tov22
. The Puppeteer changelog is available here -
#728
76f1862
Thanks @calebeby! - Re-export devices frompuppeteer.KnownDevices
instead of deprecatedpuppeteer.devices
-
#748
6d757ef
Thanks @calebeby! - Reimplement windows supportLong ago, Pleasantest worked on Windows, but without regular testing it gradually diverged. This release adds proper Windows support back and adds automated testing for it.
-
#684
53fe380
Thanks @renovate! - Update@testing-library/dom
tov9
.Breaking changes:
ByRole
now only allows string as a role. Theexact
,trim
,collapseWhitespace
, andnormalizer
options are no longer supported for role queries.
-
#681
f00efad
Thanks @calebeby! - Drop support for node 14 and 19 -
#686
563cd06
Thanks @renovate! - Update Puppeteer fromv18
tov20
. Thepuppeteer
changelog is available here.
-
#631
f124a5a
Thanks @calebeby! - [bugfix] Don't override<head>
when usingutils.injectHTML
This was a bug introduced in
3.0.0
. This change fixes that behavior to match what is documented. The documented behavior is thatinjectHTML
replaces the content of the body only. The behavior introduced in3.0.0
also resets the<head>
to the default; that was unintended behavior that is now removed.
- #561
b565e0b
Thanks @calebeby! - Normalize whitespace in element accessible names ingetAccessibilityTree
. Markup with elements which have an accessible name that includes irregular whitespace, like non-breaking spaces, will now have a different output forgetAccessibilityTree
snapshots. Previously, the whitespace was included, now, whitespace is replaced with a single space.
-
#535
dc6f81c
Thanks @calebeby! - Values exported fromrunJS
are now available in Node.For example:
test( 'receiving exported values from runJS', withBrowser(async ({ utils }) => { // Each export is available in the returned object. // Each export is wrapped in a JSHandle, meaning that it points to an in-browser object const { focusTarget, favoriteNumber } = await utils.runJS(` export const focusTarget = document.activeElement export const favoriteNumber = 20 `); // Serializable JSHandles can be unwrapped using JSONValue: console.log(await favoriteNumber.jsonValue()); // Logs "20" // A JSHandle<Element>, or ElementHandle is not serializable // But we can pass it back into the browser to use it (it will be unwrapped in the browser): await utils.runJS( ` // The import.meta.pleasantestArgs context object receives the parameters passed in below const [focusTarget] = import.meta.pleasantestArgs; console.log(focusTarget) // Logs the element in the browser `, // Passing the JSHandle in here passes it into the browser (unwrapped) in import.meta.pleasantestArgs [focusTarget], ); }), );
We've also introduced a utility function to make it easier to call
JSHandle
s that point to functions,makeCallableJSHandle
. This function takes aJSHandle<Function>
and returns a node function that calls the corresponding browser function, passing along the parameters, and returning the return value wrapped inPromise<JSHandle<T>>
:// new import: import { makeCallableJSHandle } from 'pleasantest'; test( 'calling functions with makeCallableJSHandle', withBrowser(async ({ utils }) => { const { displayFavoriteNumber } = await utils.runJS(` export const displayFavoriteNumber = (number) => { document.querySelector('.output').innerHTML = "Favorite number is: " + number } `); // displayFavoriteNumber is a JSHandle<Function> // (a pointer to a function in the browser) // so we cannot call it directly, so we wrap it in a node function first: const displayFavoriteNumberNode = makeCallableJSHandle( displayFavoriteNumber, ); // Note the added `await`. // Even though the original function was not async, the wrapped function is. // This is needed because the wrapped function needs to asynchronously communicate with the browser. await displayFavoriteNumberNode(42); }), );
For TypeScript users,
runJS
now accepts a new optional type parameter, to specify the exported types of the in-browser module that is passed in. The default value for this parameter isRecord<string, unknown>
(an object with string properties and unknown values). Note that this type does not includeJSHandles
, those are wrapped in the return type fromrunJS
automatically.Using the first example, the optional type would be:
test( 'receiving exported values from runJS', withBrowser(async ({ utils }) => { const { focusTarget, favoriteNumber } = await utils.runJS<{ focusTarget: Element; favoriteNumber: number; }>(` export const focusTarget = document.activeElement export const favoriteNumber = 20 `); }), );
Now
focusTarget
automatically has the typeJSHandle<Element>
andfavoriteNumber
automatically has the typeJSHandle<number>
. Without passing in the type parameter torunJS
, their types would both beJSHandle<unknown>
.
-
#541
39085ac
Thanks @calebeby! -injectHTML
now executes script tags in the injected markup by default. This can be disabled by passing theexecuteScriptTags: false
option as the second parameter.For example, the script tag is now executed by default:
await utils.injectHTML( "<script>document.querySelector('div').textContent = 'changed'</script>", );
But by passing
executeScriptTags: false
, we can disable execution:await utils.injectHTML( "<script>document.querySelector('div').textContent = 'changed'</script>", { executeScriptTags: false }, );
-
#535
dc6f81c
Thanks @calebeby! - The way thatrunJS
receives parameters in the browser has changed. Now, parameters are available asimport.meta.pleasantestArgs
instead of through an automatically-called default export.For example, code that used to work like this:
test( 'old version of runJS parameters', withBrowser(async ({ utils }) => { // Pass a variable from node to the browser const url = isDev ? 'dev.example.com' : 'prod.example.com'; await utils.runJS( ` // Parameters get passed into the default-export function, which is called automatically export default (url) => { console.log(url) } `, // array of parameters passed here [url], ); }), );
Now should be written like this:
test( 'new version of runJS parameters', withBrowser(async ({ utils }) => { // Pass a variable from node to the browser const url = isDev ? 'dev.example.com' : 'prod.example.com'; await utils.runJS( ` // Parameters get passed as an array into this context variable, and we can destructure them const [url] = import.meta.pleasantestArgs console.log(url) // If we added a default exported function here, it would no longer be automatically called. `, // array of parameters passed here [url], ); }), );
This is a breaking change, because the previous mechanism for receiving parameters no longer works, and functions that are
default export
s from runJS are no longer called automatically.
- #557
7bb10e0
Thanks @calebeby! - Update@testing-library/dom
to8.17.1
and@testing-library/jest-dom
to5.16.5
-
#494
730300e
Thanks @calebeby! - New assertion:expect(page).toPassAxeTests()
This assertion is based on the
jest-puppeteer-axe
package. (That package already works with Pleasantest, our new feature just formats error messages a little differently)It allows you to pass a page to be checked with the axe accessibility linter.
test( 'Axe tests', withBrowser(async ({ utils, page }) => { await utils.injectHTML(` <h1>Some html</h1> `); await expect(page).toPassAxeTests(); }), );
-
#459
d36f234
Thanks @renovate! - Update dependency@testing-library/dom
tov8.13.0
.This adds support to filtering
ByRole
queries by description:// Select by accessible role and description await screen.getByRole('button', { description: /^items in the trash will be/i, });
-
#345
847cbd8
Thanks @calebeby! - Normalize whitespace ingetAccessibilityTree
Now anytime there is contiguous whitespace in text strings it is collapsed into a single space. This matches the behavior of browser accessibility trees.
This is a breaking change because it changes the
getAccessibilityTree
output, and may break your snapshots. Update your snapshots with Jest and review the changes.
- #446
1eaa648
Thanks @calebeby! - Use document.title as fallback implicit accessible name for html root element in accessibility tree snapshots
-
#445
5fa4103
Thanks @calebeby! - Add heading levels togetAccessibilityTree
. The heading levels are computed from the corresponding element number in<h1>
-<h6>
, or from thearia-level
role.In the accessibility tree snapshot, it looks like this:
heading "Name of Heading" (level=2)
This is a breaking change because it will cause existing accessibility tree snapshots to fail which contain headings. Update the snapshots to make them pass again.
-
#451
eb364cc
Thanks @calebeby! - Addedaria-expanded
support togetAccessibilityTree
and fix handling for<details>
/<summary>
Now, elements which have the
aria-expanded
attribute will represent the state of that attribute in accessibility tree snapshots.<details>
/<summary>
elements will represent their expanded state in the tree as well.Also, for collapsed
<details>
/<summary>
elements, the hidden content is now hidden in the accessibility tree, to match screen reader behavior.
- #248
abe22a6
Thanks @gerardo-rodriguez! - Enforce minimum target size when callinguser.click()
, per WCAG Success Criterion 2.5.5 Target Size guideline.
-
#403
6ceb029
Thanks @calebeby! - ExposeaccessibilityTreeSnapshotSerializer
. This is the snapshot serializer that Pleasantest configures Jest to use to format accessibility tree snapshots. It was enabled by default in previous versions, and it still is, just now it is also exposed as an export so you can pass the snapshot serializer to other tools, likesnapshot-diff
.Here's an example of using this:
This part you'd put in your test setup file (configured in Jest's
setupFilesAfterEnv
):import snapshotDiff from 'snapshot-diff'; expect.addSnapshotSerializer(snapshotDiff.getSnapshotDiffSerializer()); snapshotDiff.setSerializers([ { test: accessibilityTreeSnapshotSerializer.test, // @ts-ignore print: (value) => accessibilityTreeSnapshotSerializer.serialize(value), diffOptions: () => ({ expand: true }), }, ]);
Then in your tests:
const beforeSnap = await getAccessibilityTree(element); // ... interact with the DOM const afterSnap = await getAccessibilityTree(element); expect(snapshotDiff(beforeSnap, afterSnap)).toMatchInlineSnapshot(` Snapshot Diff: - First value + Second value region "Summary" heading "Summary" text "Summary" list listitem text "Items:" - text "2" + text "5" link "Checkout" text "Checkout" `);
The diff provided by snapshotDiff automatically highlights the differences between the snapshots, to make it clear to the test reader what changed in the page accessibility structure as the interactions happened.
- #412
33ddf04
Thanks @calebeby! - Ignore HTML comments ingetAccessibilityTree
output (potentially breaking bugfix)
-
#391
55a7d42
Thanks @renovate! - Updatedom-accessibility-api
to 0.5.11<input type="number" />
now maps to rolespinbutton
(wastextbox
before).This is technically a breaking change for users which depended on the incorrect behavior of
getAccessibilityTree
withinput[type="number"]
previously mapping totextbox
.
-
#344
d7bbae3
Thanks @calebeby! - Allow passingpage
instead of anElementHandle
togetAccessibilityTree
.If
page
is passed, the accessibility tree will be of the roothtml
element.
-
#314
542f3f9
Thanks @calebeby! - Improve printing of HTML elements in error messages- Printed HTML now is syntax-highlighted
- Adjacent whitespace is collapsed in places where the browser would collapse it
-
#265
2b92fbc
Thanks @renovate! - Update@testing-library/dom
tov8.11.1
Read their release notes for all the versions between 8.1.0 and 8.11.1 to see the full changes.
Notably, we have added the ability for TypeScript users to optionally specify an element type as a type parameter for DTL queries:
import { withBrowser } from 'pleasantest'; test( 'changelog example', withBrowser(async ({ screen }) => { // ElementHandle<HTMLButtonElement> const button = await screen.getByRole<HTMLButtonElement>(/button/); // ElementHandle<HTMLButtonElement>[] const buttons = await screen.getAllByRole<HTMLButtonElement>(/button/); }), );
The return type is automatically determined based on the specified element type. Since Pleasantest DTL queries return
ElementHandle
s, the return type will be wrapped withPromise<ElementHandle<...>>
. For queries which return arrays of elements, the singular version of the element type is accepted as the type parameter, and the return type will automatically be wrapped withPromise<Array<ElementHandle<...>>>
.
- #236
67a222f
Thanks @calebeby! - Add accessibility snapshots feature:getAccessibilityTree
. This feature can be used to ensure that changes to the accessibility structure of your applications are intentional and correct.
- #327
dfc9620
Thanks @calebeby! - Add suggestion to error message when transformation plugin is missing for unrecognized file extensions
- #290
e9808b5
Thanks @calebeby! - Fix regression in stack frames handling when callinguser.*
andscreen.*
methods.
- #234
bf53e31
Thanks @gerardo-rodriguez! - Allow functions to be passed to runJS
- #219
f0ee064
Thanks @calebeby! - Improve node_modules resolver (now it is able to resolve multiple package versions and it supports pnpm)
- #190
9fb149d
Thanks @calebeby! - Improve error message output for resolution errors and syntax errors/transform errors
-
#186
33691ba
Thanks @calebeby! - Release 1.0There are no breaking changes, we are just bumping the version to 1.0, so from now going forwards, we'll be following post-1.0 semver.
- #104
69fd00b
Thanks @renovate! - Remove toHaveDescription, toBeInTheDOM, and toBeEmpty (they are deprecated by jest-dom)
- #104
69fd00b
Thanks @renovate! - Add toHaveAccessibleDescription and toHaveAccessibleName from jest-dom matchers
- #143
0ba7584
Thanks @calebeby! - Improve CJS interop with packages that can't be statically analyzed
- #128
c074d3d
Thanks @calebeby! - Enable JSX parsing/transpilation for .js, .mjs, .cjs files (not just .jsx)
- #115
b4eb08d
Thanks @calebeby! - Replace vite-based module server with wmr-based custom module server (This is probably a breaking change - minor bump is only because pre-1.0)
-
#86
35be60a
Thanks @renovate! - Update puppeteer to v10.0.0Chromium version is now 92.0.4512.0 (r884014)
7705216
Thanks @calebeby! - Update@testing-library/dom
tov7.31.2
. This change fixes some issues with label associations.
- #78
55b75f9
Thanks @calebeby! - Handle errors thrown by browser launcher instead of silently hanging
-
#61
be9eef7
Thanks @calebeby! - Update puppeteer to v9.1.1Chromium version is now 91.0.4469.0 (r869685)
-
4e0335c
#58 Thanks @calebeby! - Implementuser.clear()
Additionally, the default delay between keypresses in
user.type
has been decreased to 1ms.
31cc1a9
#55 Thanks @calebeby! - ExportJSHandle
andElementHandle
types from puppeteer. Now if you want to use those types you can import them directly from pleasantest.
ae4a89a
#53 Thanks @calebeby! - Bundle types for@testing-library/dom
so people don't have to install@testing-library/dom
(closes #50)
064e5b4
#48 Thanks @calebeby! - - Add user.type method- Add actionability checks: visible and attached
-
beb1914
#43 Thanks @calebeby! - Provide a helpful message if the user forgets to useawait
.For example, if a user forgets to use
await
in the jest-dom assertion:test( 'example', withBrowser(async ({ screen, utils }) => { await utils.injectHTML('<button>Hi</button>'); const button = await screen.getByText(/hi/i); expect(button).toBeVisible(); }), );
Then a useful error message is produced:
Cannot execute assertion toBeVisible after test finishes. Did you forget to await? 103 | await utils.injectHTML('<button>Hi</button>'); 104 | const button = await screen.getByText(/hi/i); > 105 | expect(button).toBeVisible(); | ^ 106 | }), 107 | ); 108 |
This is also handled for utility functions, user methods, and Testing Library queries.
-
732fbff
#45 Thanks @calebeby! - Now it is possible to pass variables to the browser in runJS:import { withBrowser } from 'pleasantest'; test( 'runJS example with argument', withBrowser(async ({ utils, screen }) => { // element is an ElementHandle (pointer to an element in the browser) const element = await screen.getByText(/button/i); // we can pass element into runJS and the default exported function can access it as an Element await utils.runJS( ` export default (element) => console.log(element); `, [element], ); }), );