Skip to content

getByRole fails with "TypeError: Cannot read property 'parentElement' of null" when using Canvas Kit React button with an icon #1010

@ahayes91

Description

@ahayes91
  • @testing-library/react version: 12.1.2
  • @workday/canvas-kit-react version "^6.3.3"
  • @workday/canvas-system-icons-web version "^2.0.6"
  • Testing Framework and version: jest 26.6.3 (but that doesn't seem to matter, this fails on the template Codesandbox too)
  • DOM Environment: default jsdom, running Codesandbox tests in Chrome Version 97.0.4692.71 (Official Build) (x86_64)

Relevant code or config:

// CanvasKitButton.js
import React from "react";
import { TertiaryButton } from "@workday/canvas-kit-react/button";
import { chevronUpSmallIcon } from "@workday/canvas-system-icons-web";

export default () => (
  <TertiaryButton
    icon={chevronUpSmallIcon}
    iconPosition="right"
    onClick={() => {}}
    size="small"
  >
    CanvasKitButton
  </TertiaryButton>
);

// CanvasKitButtonWithoutIcon.js
import React from "react";
import { TertiaryButton } from "@workday/canvas-kit-react/button";

export default () => (
  <TertiaryButton onClick={() => {}} size="small">
    CanvasKitButton
  </TertiaryButton>
);


// Test code
import "@testing-library/jest-dom/extend-expect";
import React from "react";
import { render } from "@testing-library/react";
import CanvasKitButton from "../CanvasKitButton";
import CanvasKitButtonWithoutIcon from "../CanvasKitButtonWithoutIcon";

test("This fails with TypeError", () => {
  const { getByRole } = render(<CanvasKitButton />);
  expect(getByRole("button", { name: "CanvasKitButton" })).toBeInTheDocument();
});

test("This passes", () => {
  const { getByRole } = render(<CanvasKitButtonWithoutIcon />);
  expect(getByRole("button", { name: "CanvasKitButton" })).toBeInTheDocument();
});

What you did:

When trying to use getByRole queries in my application using Canvas Kit, I found that if I had buttons on my page with icons, the getByRole queries were borking out with a very strange error: "TypeError: Cannot read property 'parentElement' of null".

When I remove the icon or mock the underlying icon library, the test passes.

I found a similar error here but no solution other than to change to a different query: https://spectrum.chat/testing-library/help-react/getbyrole-error-cannot-read-property-parentelement-of-null~0b78b6db-b99f-414e-b9ed-38990d6dd717

What happened:

Repo error:

 FAIL  src/CanvasKitButton.test.js
  ✕ This fails with TypeError (177 ms)
  ✓ This should pass (108 ms)

    TypeError: Cannot read property 'parentElement' of null

      at Array.Resolver (eval at compile (node_modules/nwsapi/src/nwsapi.js:768:17), <anonymous>:3:140)
      at match_assert (node_modules/nwsapi/src/nwsapi.js:1351:13)
      at Object._matches [as match] (node_modules/nwsapi/src/nwsapi.js:1369:16)
      at exports.matchesDontThrow (node_modules/jsdom/lib/jsdom/living/helpers/selectors.js:29:36)
      at matches (node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js:50:10)
      at node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js:35:18
          at Array.forEach (<anonymous>)
      at handleSheet (node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js:26:13)
          at Array.forEach (<anonymous>)
      at exports.forEachMatchingSheetRuleOfElement (node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js:46:11)

Codesandbox error:

Cannot read properties of null (reading 'parentElement')

TypeError: Cannot read properties of null (reading 'parentElement')
    at Array.Resolver (eval at compile (https://un6lk.csb.app/static/js/jsdom-16.3.0.min.js:236:17232), <anonymous>:3:140)
    at match_assert (https://un6lk.csb.app/static/js/jsdom-16.3.0.min.js:236:30554)
    at Object._matches [as match] (https://un6lk.csb.app/static/js/jsdom-16.3.0.min.js:236:30873)
    at exports.matchesDontThrow (https://un6lk.csb.app/static/js/jsdom-16.3.0.min.js:37:1612417)
    at matches (https://un6lk.csb.app/static/js/jsdom-16.3.0.min.js:37:1620955)
    at https://un6lk.csb.app/static/js/jsdom-16.3.0.min.js:37:1620677
    at Array.forEach (<anonymous>)
    at handleSheet (https://un6lk.csb.app/static/js/jsdom-16.3.0.min.js:37:1620484)
    at Array.forEach (<anonymous>)
    at exports.forEachMatchingSheetRuleOfElement (https://un6lk.csb.app/static/js/jsdom-16.3.0.min.js:37:1620853)
    at Window.getComputedStyle (https://un6lk.csb.app/static/js/jsdom-16.3.0.min.js:37:49816)
    at isHidden (https://un6lk.csb.app/node_modules/dom-accessibility-api/dist/accessible-name.js:66:56)
    at computeTextAlternative (https://un6lk.csb.app/node_modules/dom-accessibility-api/dist/accessible-name.js:314:13)
    at computeMiscTextAlternative (https://un6lk.csb.app/node_modules/dom-accessibility-api/dist/accessible-name.js:231:28)
    at computeTextAlternative (https://un6lk.csb.app/node_modules/dom-accessibility-api/dist/accessible-name.js:413:20)
    at computeMiscTextAlternative (https://un6lk.csb.app/node_modules/dom-accessibility-api/dist/accessible-name.js:231:28)
    at computeTextAlternative (https://un6lk.csb.app/node_modules/dom-accessibility-api/dist/accessible-name.js:413:20)
    at computeMiscTextAlternative (https://un6lk.csb.app/node_modules/dom-accessibility-api/dist/accessible-name.js:231:28)
    at computeTextAlternative (https://un6lk.csb.app/node_modules/dom-accessibility-api/dist/accessible-name.js:413:20)
    at computeMiscTextAlternative (https://un6lk.csb.app/node_modules/dom-accessibility-api/dist/accessible-name.js:231:28)
    at computeTextAlternative (https://un6lk.csb.app/node_modules/dom-accessibility-api/dist/accessible-name.js:413:20)
    at computeMiscTextAlternative (https://un6lk.csb.app/node_modules/dom-accessibility-api/dist/accessible-name.js:231:28)
    at computeTextAlternative (https://un6lk.csb.app/node_modules/dom-accessibility-api/dist/accessible-name.js:402:20)
    at computeAccessibleName (https://un6lk.csb.app/node_modules/dom-accessibility-api/dist/accessible-name.js:427:25)
    at eval (https://un6lk.csb.app/node_modules/@testing-library/dom/dist/@testing-library/dom.esm.js:1190:68)
    at Array.filter (<anonymous>)
    at queryAllByRole (https://un6lk.csb.app/node_modules/@testing-library/dom/dist/@testing-library/dom.esm.js:1186:6)
    at eval (https://un6lk.csb.app/node_modules/@testing-library/dom/dist/@testing-library/dom.esm.js:795:24)
    at eval (https://un6lk.csb.app/node_modules/@testing-library/dom/dist/@testing-library/dom.esm.js:783:24)
    at Object.eval (https://un6lk.csb.app/src/__tests__/CanvasKitButton.test.js:26:10)
    at https://codesandbox.io/static/js/3.c68bd71c0.chunk.js:1:336366
    at new Promise (<anonymous>)
    at t.callAsyncFn (https://codesandbox.io/static/js/3.c68bd71c0.chunk.js:1:336025)
    at https://codesandbox.io/static/js/7.cdfc7986d.chunk.js:1:6524
    at c (https://codesandbox.io/static/js/vendors~app~embed~sandbox~sandbox-startup.bcc15d438.chunk.js:1:3629)
    at Generator._invoke (https://codesandbox.io/static/js/vendors~app~embed~sandbox~sandbox-startup.bcc15d438.chunk.js:1:3382)
    at Generator.forEach.t.<computed> [as next] (https://codesandbox.io/static/js/vendors~app~embed~sandbox~sandbox-startup.bcc15d438.chunk.js:1:3986)
    at r (https://codesandbox.io/static/js/vendors~app~embed~sandbox~sandbox-startup.bcc15d438.chunk.js:1:206)
    at u (https://codesandbox.io/static/js/vendors~app~embed~sandbox~sandbox-startup.bcc15d438.chunk.js:1:417)
    at https://codesandbox.io/static/js/vendors~app~embed~sandbox~sandbox-startup.bcc15d438.chunk.js:1:476
    at new Promise (<anonymous>)
    at https://codesandbox.io/static/js/vendors~app~embed~sandbox~sandbox-startup.bcc15d438.chunk.js:1:357
    at https://codesandbox.io/static/js/7.cdfc7986d.chunk.js:1:6791
    at https://codesandbox.io/static/js/7.cdfc7986d.chunk.js:1:5456
    at c (https://codesandbox.io/static/js/vendors~app~embed~sandbox~sandbox-startup.bcc15d438.chunk.js:1:3629)
    at Generator._invoke (https://codesandbox.io/static/js/vendors~app~embed~sandbox~sandbox-startup.bcc15d438.chunk.js:1:3382)
    at Generator.forEach.t.<computed> [as next] (https://codesandbox.io/static/js/vendors~app~embed~sandbox~sandbox-startup.bcc15d438.chunk.js:1:3986)
    at r (https://codesandbox.io/static/js/vendors~app~embed~sandbox~sandbox-startup.bcc15d438.chunk.js:1:206)
    at u (https://codesandbox.io/static/js/vendors~app~embed~sandbox~sandbox-startup.bcc15d438.chunk.js:1:417)
    at https://codesandbox.io/static/js/vendors~app~embed~sandbox~sandbox-startup.bcc15d438.chunk.js:1:476

Reproduction:

Github repository:
https://github.com/ahayes91/canvas-kit-react-testing-library/blob/main/src/CanvasKitButton.test.js

Codesandbox
Edit react-testing-library demo (forked)

Problem description:

  • getByRole should pass regardless of whether an icon is provided on the button or not
  • Cryptic errors make it hard to debug if it's your code or the test that is wrong
  • New engineers using @testing-library/react are put off by scary errors 😂

Suggested solution:

I don't have one I'm afraid, but when I went digging into the stack trace, I changed the nswapi logging in my local node modules node_modules/jsdom/lib/jsdom/living/helpers/selectors.js file:

exports.matchesDontThrow = (elImpl, selector) => {
  const document = elImpl._ownerDocument;

  if (!document._nwsapiDontThrow) {
    document._nwsapiDontThrow = initNwsapi(elImpl);
    document._nwsapiDontThrow.configure({
      LOGERRORS: true,
      VERBOSITY: true,
      IDS_DUPES: true,
      MIXEDCASE: true
    });
  }

  return document._nwsapiDontThrow.match(selector, idlUtils.wrapperForImpl(elImpl));
};

Which gave this error when I reran the tests, which was interesting but then I found myself pretty stumped without better knowledge of the underlying libraries:

 FAIL  src/CanvasKitButton.test.js
  ✕ This fails with TypeError (77 ms)
  ✕ This should pass (39 ms)

  ● This fails with TypeError

    SyntaxError: '@namespace "http://www.w3.org/1999/xhtml";

    html' is not a valid selector

      at emit (node_modules/nwsapi/src/nwsapi.js:565:17)
      at Object._matches [as match] (node_modules/nwsapi/src/nwsapi.js:1409:9)
      at exports.matchesDontThrow (node_modules/jsdom/lib/jsdom/living/helpers/selectors.js:29:36)
      at matches (node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js:50:10)
      at node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js:35:18
          at Array.forEach (<anonymous>)
      at handleSheet (node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js:26:13)
      at exports.forEachMatchingSheetRuleOfElement (node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js:45:3)
      at getComputedStyleImplementation (node_modules/jsdom/lib/jsdom/browser/Window.js:802:5)
      at isHidden (node_modules/dom-accessibility-api/sources/accessible-name-and-description.ts:84:16)

  ● This should pass

    SyntaxError: '@namespace "http://www.w3.org/1999/xhtml";

    html' is not a valid selector

      at emit (node_modules/nwsapi/src/nwsapi.js:565:17)
      at Object._matches [as match] (node_modules/nwsapi/src/nwsapi.js:1409:9)
      at exports.matchesDontThrow (node_modules/jsdom/lib/jsdom/living/helpers/selectors.js:29:36)
      at matches (node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js:50:10)
      at node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js:35:18
          at Array.forEach (<anonymous>)
      at handleSheet (node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js:26:13)
      at exports.forEachMatchingSheetRuleOfElement (node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js:45:3)
      at getComputedStyleImplementation (node_modules/jsdom/lib/jsdom/browser/Window.js:802:5)
      at isHidden (node_modules/dom-accessibility-api/sources/accessible-name-and-description.ts:84:16)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions