Ad

"Failed To Execute 'querySelector' On 'Document': 'class MyComponent Extends HTMLElement" During Karma Test

I am getting the error mentioned in this question head. I don't understand why I can't check if certain div id is available. It is quite simple check.

test:

import { MyComponent } from "../src/my-component.js";
import { TestUtils } from "./test-utils.js";

describe("simple test", () => {
  it("first test", async () => {
    const { shadowRoot } = await TestUtils.render(MyComponent);
    expect(shadowRoot.querySelector("#mydiv")).toBeTruthy();
  });
});

testUtils:

export class TestUtils {
    /**
     * Renders a given element with provided attributes
     * and returns a promise which resolves as soon as
     * rendered element becomes available.
     * @param {string} tag
     * @param {object} attributes
     * @returns {Promise<HTMLElement>}
     */
    static render(tag, attributes = {}) {
      TestUtils._renderToDocument(tag, attributes);
      return TestUtils._waitForComponentToRender(tag);
    }

    /**
     * Replaces document's body with provided element
     * including given attributes.
     * @param {string} tag
     * @param {object} attributes
     */
    static _renderToDocument(tag, attributes) {
      const htmlAttributes = TestUtils._mapObjectToHTMLAttributes(attributes);
      document.body.innerHTML = `<${tag} ${htmlAttributes}></${tag}>`;
    }

    /**
     * Converts an object to HTML string representation of attributes.
     *
     * For example: `{ foo: "bar", baz: "foo" }`
     * becomes `foo="bar" baz="foo"`
     *
     * @param {object} attributes
     * @returns {string}
     */
    static _mapObjectToHTMLAttributes(attributes) {
      return Object.entries(attributes).reduce((previous, current) => {
        return previous + ` ${current[0]}="${current[1]}"`;
      }, "");
    }

    /**
     * Returns a promise which resolves as soon as
     * requested element becomes available.
     * @param {string} tag
     * @returns {Promise<HTMLElement>}
     */
    static async _waitForComponentToRender(tag) {
      return new Promise(resolve => {
        function requestComponent() {
          const element = document.querySelector(tag);
          if (element) {
            resolve(element);
          } else {
            window.requestAnimationFrame(requestComponent);
          }
        }
        requestComponent();
      });
    }
  }

component:

const templateString = `<div id="mydiv"><p>Hello world!</p></div>`;
const template = document.createElement("template");
template.innerHTML = templateString;

export class MyComponent extends HTMLElement {
  constructor() {
    super();
    const shadowRoot = this.attachShadow({ mode: "open" });
    shadowRoot.appendChild(template.content.cloneNode(true));
  }
}
customElements.define("my-component", MyComponent);

Full logs:

> @ test C:\_d\WSs\basic-vanilla-webcomponent
> karma start

15 07 2019 18:47:18.412:INFO [karma-server]: Karma v4.2.0 server started at http://0.0.0.0:9876/
15 07 2019 18:47:18.418:INFO [launcher]: Launching browsers Chrome with concurrency unlimited
15 07 2019 18:47:18.427:INFO [launcher]: Starting browser Chrome
15 07 2019 18:47:21.648:INFO [Chrome 75.0.3770 (Windows 10.0.0)]: Connected on socket y_r0BhEr4FNUaiByAAAA with id 99414473

  simple test
    × first test
        Error: Failed to execute 'querySelector' on 'Document': 'class MyComponent extends HTMLElement {
          constructor() {
            super();
            const shadowRoot = this.attachShadow({ mode: "open" });
            shadowRoot.appendChild(template.content.cloneNode(true));
          }
        }' is not a valid selector.
        error properties: Object({ INDEX_SIZE_ERR: 1, DOMSTRING_SIZE_ERR: 2, HIERARCHY_REQUEST_ERR: 3, WRONG_DOCUMENT_ERR: 4, INVALID_CHARACTER_ERR: 5, NO_DATA_ALLOWED_ERR: 6, NO_MODIFICATION_ALLOWED_ERR: 7, NOT_FOUND_ERR: 8, NOT_SUPPORTED_ERR: 9, INUSE_ATTRIBUTE_ERR: 10, INVALID_STATE_ERR: 11, SYNTAX_ERR: 12, INVALID_MODIFICATION_ERR: 13, NAMESPACE_ERR: 14, INVALID_ACCESS_ERR: 15, VALIDATION_ERR: 16, TYPE_MISMATCH_ERR: 17, SECURITY_ERR: 18, NETWORK_ERR: 19, ABORT_ERR: 20, URL_MISMATCH_ERR: 21, QUOTA_EXCEEDED_ERR: 22, TIMEOUT_ERR: 23, INVALID_NODE_TYPE_ERR: 24, DATA_CLONE_ERR: 25, code: 12 })
            at requestComponent (test/test-utils.js:50:36)
            at test/test-utils.js:57:9
            at <Jasmine>
            at Function._waitForComponentToRender (test/test-utils.js:48:14)
            at Function.render (test/test-utils.js:12:24)
            at UserContext.<anonymous> (test/my-component.test.js:6:44)
            at <Jasmine>


Chrome 75.0.3770 (Windows 10.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.032 secs / 0.005 secs)

npm ERR! Test failed.  See above for more details.
Ad

Answer

The TestUtils.render method accepts a tag (string) as its first parameter, but in your code you're passing in MyComponent. That's the immediate reason for the error.

Try calling TestUtils.render('my-component'); (Assuming my-component is the correct tag for MyComponent).

Ad
source: stackoverflow.com
Ad