如何在 javascript 中使用 jest 测试 Web 组件中的开槽元素(无框架)
How to test slotted elements in web components with jest in javascript (no Framework)
我想测试我的一个自定义组件中插槽的内容。
如果我在 html 文件中使用我的组件并在浏览器中打开它,一切都会按预期进行。但是,如果我想开玩笑地自动化我的测试,它就会失败。下面是一个最小的工作示例,输出形式为 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 以某种方式无法获取开槽文本和 returns undefined
。我该如何解决这个问题?
文本节点不会成为 <slot>
元素内部的一部分。它只是文本节点的包装器。要获取放置在插槽内的节点,您必须使用 HTMLSlotElement.assignedNodes()
方法。
The assignedNodes() method of the HTMLSlotElement interface returns a sequence of the nodes assigned to this slot.
有了这个,你就得到了一个驻留在插槽中的节点数组。添加的文本节点将在此数组中。
我修改了你的 name
getter 以从分配的节点数组中获取第一个节点和 return 节点的 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);
<place-holder>Hello</place-holder>
旁注:只要您在模板中的槽内添加文本作为占位符,<slot>
元素就会有一个 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);
<example-element></example-element>
我想测试我的一个自定义组件中插槽的内容。 如果我在 html 文件中使用我的组件并在浏览器中打开它,一切都会按预期进行。但是,如果我想开玩笑地自动化我的测试,它就会失败。下面是一个最小的工作示例,输出形式为 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 以某种方式无法获取开槽文本和 returns undefined
。我该如何解决这个问题?
文本节点不会成为 <slot>
元素内部的一部分。它只是文本节点的包装器。要获取放置在插槽内的节点,您必须使用 HTMLSlotElement.assignedNodes()
方法。
The assignedNodes() method of the HTMLSlotElement interface returns a sequence of the nodes assigned to this slot.
有了这个,你就得到了一个驻留在插槽中的节点数组。添加的文本节点将在此数组中。
我修改了你的 name
getter 以从分配的节点数组中获取第一个节点和 return 节点的 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);
<place-holder>Hello</place-holder>
旁注:只要您在模板中的槽内添加文本作为占位符,<slot>
元素就会有一个 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);
<example-element></example-element>