如何在测试 Web 组件时使用 Cypress 通过 <slot> 进行查询
How To Query Through <slot> Using Cypress While Testing Web Components
经过多年的端到端测试全局 DOM 测试,我发现测试使用插槽的 Web 组件即使不是不可能,也是非常困难的。在我解释这个问题之前,我想说我不能改变生成的标记来改进它们的现状。
<wc-1 attributes-etc="">
<wc-2 attributes-etc="">
<slot>
<wc-3 attributes-etc="">
<slot>
...eventually get to an input...
<input type="text" name="firstName" />
有大量来自某种表单生成器的嵌套 Web 组件,并且还使用了大量插槽。 web components有属性但是slots没有,所以我用web component名称来查询。
document.querSelector('wc-1')
.shadowRoot.querySelector('wc-2')
.shadowRoot.querySelector('slot')
// Yields <slot>...</slot>
到目前为止一切正常,Cypress 有一个我使用的 .shadow()
命令,但我在这里仅使用 devtools 进行测试以查看插槽具有的所有属性。
document.querSelector('wc-1')
.shadowRoot.querySelector('wc-2')
.shadowRoot.querySelector('slot')
.shadowRoot
// Yields "null".
// I don't know how to get to the .lightDOM? of wc-2?
我尝试的任何 属性 最终都为 null 或返回值中有 0 个元素。使用其他前端工具和全局DOM,我总是可以在一个命令中cy.get('div[data-testid="the-nested-element-i-want"]').type('important words')
。
所以我的主要问题是:一旦 Web 组件开始堆积,人们如何测试这些东西?或者不这样做,只在 isolation/unit 测试中测试 Web 组件,因为很难查询嵌套影子 DOMs?
主要目标是最终获得 cy.get('input[name"firstName"]').type('John')
的表单输入。在我的示例中,有人可以给我链式 docuement.querySelector()
命令以到达 <wc-3>
吗?
您的 <slot>
中将没有 DOM 内容,因为没有 DOM 内容 已移动 到插槽中。
光DOM 内容在插槽中 反射,但 保持 不可见! 光线DOM.
(这就是为什么你也 )
来自文档:
, .
' ; .
所以要测试某些东西是否在 "in" 插槽
- 您需要检查 lightDOM 元素的
slot=?
属性
- 并仔细检查
<slot name=? >
是否确实存在于 shadowDOM 中
反之亦然
或钩入 slotchange
事件,但那不是测试
伪代码:
反之亦然;可能包含错误..它的伪代码..
function processDOMnode( node ){
if (node.shadowRoot){
// query shadowDOM
let slotnames = [...node.shadowRoot.querySelectorAll("slot")].map(s=>s.name);
// query lightDOM
slotnames.forEach( name =>{
let content = node.querySelectorAll(`[slot="${name}"]`);
console.log( "slot:" , name , "content:" , content );
});
// maybe do something with slotnames in lightDOM that do NOT exist in shadowDOM
// dive deeper
this.shadowRooot.children.forEach(shadownode => processDOMnode(shadownode));
}
}
答案涉及assignedNodes()
:https://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement/assignedNodes
The assignedNodes() property of the HTMLSlotElement interface returns a sequence of the nodes assigned to this slot...
我使用它与 assignedElements()
没有区别。因此,您所要做的就是在查询到您需要的插槽后使用该方法。对于我的例子,答案是:
const wc-3 = document.querySelector('wc-1').shadowRoot
.querySelector('wc-2').shadowRoot
.querySelector('slot').assignedNodes()
.map((el) => el.shadowRoot)[0]
然后你可以继续沿着链向下...我知道我只有一个未命名的插槽,所以这就是我从返回的 .map()
.
中获取它的原因
此问答为我指明正确方向的支持:
经过多年的端到端测试全局 DOM 测试,我发现测试使用插槽的 Web 组件即使不是不可能,也是非常困难的。在我解释这个问题之前,我想说我不能改变生成的标记来改进它们的现状。
<wc-1 attributes-etc="">
<wc-2 attributes-etc="">
<slot>
<wc-3 attributes-etc="">
<slot>
...eventually get to an input...
<input type="text" name="firstName" />
有大量来自某种表单生成器的嵌套 Web 组件,并且还使用了大量插槽。 web components有属性但是slots没有,所以我用web component名称来查询。
document.querSelector('wc-1')
.shadowRoot.querySelector('wc-2')
.shadowRoot.querySelector('slot')
// Yields <slot>...</slot>
到目前为止一切正常,Cypress 有一个我使用的 .shadow()
命令,但我在这里仅使用 devtools 进行测试以查看插槽具有的所有属性。
document.querSelector('wc-1')
.shadowRoot.querySelector('wc-2')
.shadowRoot.querySelector('slot')
.shadowRoot
// Yields "null".
// I don't know how to get to the .lightDOM? of wc-2?
我尝试的任何 属性 最终都为 null 或返回值中有 0 个元素。使用其他前端工具和全局DOM,我总是可以在一个命令中cy.get('div[data-testid="the-nested-element-i-want"]').type('important words')
。
所以我的主要问题是:一旦 Web 组件开始堆积,人们如何测试这些东西?或者不这样做,只在 isolation/unit 测试中测试 Web 组件,因为很难查询嵌套影子 DOMs?
主要目标是最终获得 cy.get('input[name"firstName"]').type('John')
的表单输入。在我的示例中,有人可以给我链式 docuement.querySelector()
命令以到达 <wc-3>
吗?
您的 <slot>
中将没有 DOM 内容,因为没有 DOM 内容 已移动 到插槽中。
光DOM 内容在插槽中 反射,但 保持 不可见! 光线DOM.
(这就是为什么你也
来自文档:
, . ' ; .
所以要测试某些东西是否在 "in" 插槽
- 您需要检查 lightDOM 元素的
slot=?
属性 - 并仔细检查
<slot name=? >
是否确实存在于 shadowDOM 中
反之亦然
或钩入 slotchange
事件,但那不是测试
伪代码:
反之亦然;可能包含错误..它的伪代码..
function processDOMnode( node ){
if (node.shadowRoot){
// query shadowDOM
let slotnames = [...node.shadowRoot.querySelectorAll("slot")].map(s=>s.name);
// query lightDOM
slotnames.forEach( name =>{
let content = node.querySelectorAll(`[slot="${name}"]`);
console.log( "slot:" , name , "content:" , content );
});
// maybe do something with slotnames in lightDOM that do NOT exist in shadowDOM
// dive deeper
this.shadowRooot.children.forEach(shadownode => processDOMnode(shadownode));
}
}
答案涉及assignedNodes()
:https://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement/assignedNodes
The assignedNodes() property of the HTMLSlotElement interface returns a sequence of the nodes assigned to this slot...
我使用它与 assignedElements()
没有区别。因此,您所要做的就是在查询到您需要的插槽后使用该方法。对于我的例子,答案是:
const wc-3 = document.querySelector('wc-1').shadowRoot
.querySelector('wc-2').shadowRoot
.querySelector('slot').assignedNodes()
.map((el) => el.shadowRoot)[0]
然后你可以继续沿着链向下...我知道我只有一个未命名的插槽,所以这就是我从返回的 .map()
.
此问答为我指明正确方向的支持: