【问题标题】:How to test slotted elements in web components with jest in javascript (no Framework)如何在 javascript 中使用 jest 测试 Web 组件中的插槽元素(无框架)
【发布时间】:2021-11-18 11:23:12
【问题描述】:

我想在我的一个自定义组件中测试插槽的内容。 如果我在 html 文件中使用我的组件并在浏览器中打开它,一切都会按预期工作。但是,如果我想用 jest 自动化我的测试,它会失败。下面是一个输出形式 jest 的最小工作示例:


placeholder.js:

const template = document.createElement("template");
template.innerHTML = `
    <p>
        <slot></slot>
    </p>
`;


class Placeholder extends HTMLElement {
    constructor() {
        super();

        this.attachShadow({ mode: "open" });
        this.shadowRoot.appendChild(template.content.cloneNode(true));
    }

    get name() {
        return this.shadowRoot.querySelector("slot").innerText;
    }
}

window.customElements.define("place-holder", Placeholder);

export default Placeholder;

placeholder.test.js:

import Placeholder from "../src/placeholder.js";

describe("name is 'Lorem Ipsum'", () => {
    let ph;
    
    beforeAll(() => {
        ph = new Placeholder();
        const textNode = document.createTextNode("Lorem Ipsum");
        ph.appendChild(textNode);
    });

    test("if the name is 'Lorem Ipsum'", () => {
        expect(ph.name).toBe("Lorem Ipsum");
    });
});

输出:

name is 'Lorem Ipsum' › if the name is 'Lorem Ipsum'

expect(received).toBe(expected) // Object.is equality

Expected: "Lorem Ipsum"
Received: undefined

  11 |
  12 |     test("if the name is 'Lorem Ipsum'", () => {
> 13 |         expect(ph.name).toBe("Lorem Ipsum");
     |                         ^
  14 |     });
  15 | });

  at Object.<anonymous> (test/placeholder.test.js:13:25)
  at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:333:13)
  at runJest (node_modules/@jest/core/build/runJest.js:387:19)
  at _run10000 (node_modules/@jest/core/build/cli/index.js:408:7)
  at runCLI (node_modules/@jest/core/build/cli/index.js:261:3)

如您所见,jest 以某种方式无法获取开槽文本并返回undefined。我该如何解决这个问题?

【问题讨论】:

    标签: javascript jestjs web-component shadow-dom native-web-component


    【解决方案1】:

    文本节点不会成为&lt;slot&gt; 元素内部的一部分。它只是文本节点的包装器。要获取放置在插槽内的节点,您必须使用HTMLSlotElement.assignedNodes() 方法。

    HTMLSlotElement 接口的assignedNodes() 方法返回分配给该槽的节点序列。

    这样,您将获得一个驻留在插槽中的节点数组。添加的文本节点将在此数组中。

    我已经修改了您的 name getter 以从分配的节点数组中取出第一个节点并返回该节点的 textContent 值。

    const template = document.createElement("template");
    template.innerHTML = `
      <p>
        <slot></slot>
      </p>
    `;
    
    
    class Placeholder extends HTMLElement {
      constructor() {
        super();
    
        this.attachShadow({
          mode: "open"
        });
        
        this.shadowRoot.appendChild(template.content.cloneNode(true));
      }
      
      get name() {
        const slot = this.shadowRoot.querySelector("slot");
        const [name] = slot.assignedNodes();
        
        if (!name) {
          return ''
        }
        
        return name.textContent
      }
      
      connectedCallback() {
        console.log(this.name)
      }
    }
    
    window.customElements.define("place-holder", Placeholder);
    &lt;place-holder&gt;Hello&lt;/place-holder&gt;

    旁注:每当您在模板的插槽内添加文本作为占位符时,&lt;slot&gt; 元素将具有 innerText

    class ExampleElement extends HTMLElement {
      constructor() {
        super();
        
        this.attachShadow({ mode: "open" });
        this.shadowRoot.innerHTML = `
          <slot>Placeholder text</slot>
        `;
      }
      
      get placeholder() {
        const slot = this.shadowRoot.querySelector('slot');
        return slot.innerText;
      }
      
      connectedCallback() {
        console.log(this.placeholder)
      }
    }
    
    customElements.define('example-element', ExampleElement);
    &lt;example-element&gt;&lt;/example-element&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-07
      • 1970-01-01
      • 1970-01-01
      • 2019-11-21
      • 2020-07-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-20
      相关资源
      最近更新 更多