Skip to content

Latest commit

 

History

History
667 lines (427 loc) · 38.2 KB

CHANGELOG.md

File metadata and controls

667 lines (427 loc) · 38.2 KB

pleasantest

5.0.0

Major Changes

  • #749 10bee94 Thanks @calebeby! - Drop support for node 16

  • #715 78cecbe Thanks @renovate! - aria-query was updated to 5.3.0. This update provides updated alignment with the ARIA spec, and will affect Testing Library queries and getAccessibilityTree 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, use toHaveAccessibleErrorMessage instead
    • toHaveRole was added

Minor Changes

Patch Changes

4.0.0

Major Changes

Minor Changes

3.1.0

Minor Changes

3.0.1

Patch Changes

  • #631 f124a5a Thanks @calebeby! - [bugfix] Don't override <head> when using utils.injectHTML

    This was a bug introduced in 3.0.0. This change fixes that behavior to match what is documented. The documented behavior is that injectHTML replaces the content of the body only. The behavior introduced in 3.0.0 also resets the <head> to the default; that was unintended behavior that is now removed.

3.0.0

Major Changes

  • #561 b565e0b Thanks @calebeby! - Normalize whitespace in element accessible names in getAccessibilityTree. Markup with elements which have an accessible name that includes irregular whitespace, like non-breaking spaces, will now have a different output for getAccessibilityTree snapshots. Previously, the whitespace was included, now, whitespace is replaced with a single space.
  • #535 dc6f81c Thanks @calebeby! - Values exported from runJS 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 JSHandles that point to functions, makeCallableJSHandle. This function takes a JSHandle<Function> and returns a node function that calls the corresponding browser function, passing along the parameters, and returning the return value wrapped in Promise<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 is Record<string, unknown> (an object with string properties and unknown values). Note that this type does not include JSHandles, those are wrapped in the return type from runJS 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 type JSHandle<Element> and favoriteNumber automatically has the type JSHandle<number>. Without passing in the type parameter to runJS, their types would both be JSHandle<unknown>.

  • #541 39085ac Thanks @calebeby! - injectHTML now executes script tags in the injected markup by default. This can be disabled by passing the executeScriptTags: 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 that runJS receives parameters in the browser has changed. Now, parameters are available as import.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 exports from runJS are no longer called automatically.

Minor Changes

  • #557 7bb10e0 Thanks @calebeby! - Update @testing-library/dom to 8.17.1 and @testing-library/jest-dom to 5.16.5

2.2.0

Minor Changes

  • #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 to v8.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,
    });

2.1.0

Minor Changes

2.0.0

Major Changes

  • #345 847cbd8 Thanks @calebeby! - Normalize whitespace in getAccessibilityTree

    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 to getAccessibilityTree. The heading levels are computed from the corresponding element number in <h1> - <h6>, or from the aria-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! - Added aria-expanded support to getAccessibilityTree 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 calling user.click(), per WCAG Success Criterion 2.5.5 Target Size guideline.

Minor Changes

1.7.0

Minor Changes

  • #403 6ceb029 Thanks @calebeby! - Expose accessibilityTreeSnapshotSerializer. 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, like snapshot-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.

Patch Changes

  • #412 33ddf04 Thanks @calebeby! - Ignore HTML comments in getAccessibilityTree output (potentially breaking bugfix)

1.6.0

Minor Changes

Patch Changes

  • #391 55a7d42 Thanks @renovate! - Update dom-accessibility-api to 0.5.11

    <input type="number" /> now maps to role spinbutton (was textbox before).

    This is technically a breaking change for users which depended on the incorrect behavior of getAccessibilityTree with input[type="number"] previously mapping to textbox.

1.5.0

Minor Changes

  • #344 d7bbae3 Thanks @calebeby! - Allow passing page instead of an ElementHandle to getAccessibilityTree.

    If page is passed, the accessibility tree will be of the root html element.

1.4.0

Minor Changes

  • #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 to v8.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 ElementHandles, the return type will be wrapped with Promise<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 with Promise<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

Patch Changes

  • #290 e9808b5 Thanks @calebeby! - Fix regression in stack frames handling when calling user.* and screen.* methods.

1.3.0

Minor Changes

1.2.0

Minor Changes

  • #219 f0ee064 Thanks @calebeby! - Improve node_modules resolver (now it is able to resolve multiple package versions and it supports pnpm)

1.1.1

Patch Changes

1.1.0

Minor Changes

  • #190 9fb149d Thanks @calebeby! - Improve error message output for resolution errors and syntax errors/transform errors

Patch Changes

1.0.0

Major Changes

  • #186 33691ba Thanks @calebeby! - Release 1.0

    There 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.

Patch Changes

0.8.0

Minor Changes

Patch Changes

0.7.0

Minor Changes

  • #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

0.6.2

Patch Changes

  • #139 1d5f16c Thanks @calebeby! - Improve error message when Promise is passed into jest-dom matcher
  • #143 0ba7584 Thanks @calebeby! - Improve CJS interop with packages that can't be statically analyzed

0.6.1

Patch Changes

  • #128 c074d3d Thanks @calebeby! - Enable JSX parsing/transpilation for .js, .mjs, .cjs files (not just .jsx)

0.6.0

Minor Changes

  • #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)

Patch Changes

0.5.0

Minor Changes

  • #86 35be60a Thanks @renovate! - Update puppeteer to v10.0.0

    Chromium version is now 92.0.4512.0 (r884014)

Patch Changes

  • 7705216 Thanks @calebeby! - Update @testing-library/dom to v7.31.2. This change fixes some issues with label associations.

0.4.1

Patch Changes

  • #78 55b75f9 Thanks @calebeby! - Handle errors thrown by browser launcher instead of silently hanging

0.4.0

Minor Changes

  • #61 be9eef7 Thanks @calebeby! - Update puppeteer to v9.1.1

    Chromium version is now 91.0.4469.0 (r869685)

Patch Changes

0.3.0

Minor Changes

  • 4e0335c #58 Thanks @calebeby! - Implement user.clear()

    Additionally, the default delay between keypresses in user.type has been decreased to 1ms.

0.2.2

Patch Changes

  • 31cc1a9 #55 Thanks @calebeby! - Export JSHandle and ElementHandle types from puppeteer. Now if you want to use those types you can import them directly from pleasantest.

0.2.1

Patch Changes

  • ae4a89a #53 Thanks @calebeby! - Bundle types for @testing-library/dom so people don't have to install @testing-library/dom (closes #50)

0.2.0

Minor Changes

  • 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 use await.

    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],
        );
      }),
    );

0.1.0

Minor Changes