Polymer.js Web 组件测试器未能找到本地 DOM 元素
Polymer.js Web Component Tester Failing to Find Local DOM Element
这是我的 属性 声明:
properties: {
size: {
type: String,
value: ''
},
sizeName: {
type: String,
value: ''
}
}
我的CSS:
<style>
:root {
--width: 20px;
--height: 20px;
--border-color: black;
--font-size: 16px;
}
:host {
display: inline-block;
box-sizing: border-box;
height: var(--height);
width: var(--width);
}
#icon {
position: relative;
display: block;
width: var(--width);
height: var(--height);
border-radius: 50%;
border: 1px solid var(--border-color);
font-size: var(--font-size);
@apply(--size-icon);
}
#icon:before {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
content: '?';
text-align: center;
@apply(--size-icon--before);
}
#icon.small:before {content: 's';}
#icon.medium:before {content: 'm';}
#icon.large:before {content: 'l';}
#name {
font-size: var(--font-size);
@apply(--size-name);
}
.hidden {
display: none;
}
</style>
我有一个测试夹具如下:
<test-fixture id="hasWrongSize">
<template>
<size-icon size="asdf"></size-icon>
</template>
<template>
<size-icon size=""></size-icon>
</template>
</test-fixture>
测试套件如下:
suite('when no icon size or incorrect icon size is provided', function() {
var el;
setup(function() {
el = fixture('hasWrongSize');
});
test('when the "size" property is incorrect the inner html equals "?"', function(done) {
flush(function() {
var domEl = Polymer.dom(el.root).querySelector('#icon:before');
expect(domEl.innerHTML).to.equal('?');
done();
});
});
});
自定义元素的LocalDOM如下:
<template>
<template is="dom-if" if="{{ !sizeName }}">
<span id="icon" class$="{{size}}"></span>
</template>
<span id="name">{{ sizeName }}</span>
</template>
我正在尝试获取 ID 为 #icon
的 :before
伪元素,但 WCT 无法找到它并且测试套件中的 domEl
等同于null
.
我做错了什么?
更新 问题已更新为包含 test-fixture
的完整代码,这揭示了根本原因。
正如您在自己的回答中指出的那样:
- I have two template tags so it did not know which element to target.
这就是你的问题的原因,伪元素实际上与它无关。您会发现,如果您从 test-fixture
中删除其中一个模板,您的原始代码就会起作用(并且会比现在的 IMO 更干净)。
test-fixture
应该只包含 一个 template
并且自定义元素的固定状态作为测试的基线(最常见的分母) .在这种情况下,该基线是单个 size-icon
,但您似乎为每个可能的测试用例添加了一个 template
,但该设置实际上应该像这样出现在测试脚本中:
<test-fixture id="basic">
<template>
<size-icon></size-icon>
</template>
</test-fixture>
<script>
suite('size-icon', function() {
var el;
setup(function() {
el = fixture('basic');
});
function expectIconEquals(done, contents) {
flush(function() {
var domEl = Polymer.dom(el.root).querySelector('#icon');
expect(domEl.innerHTML).to.equal(contents);
done();
});
}
test('when the "size" property is empty, the inner html equals "?"', function(done) {
el.size = "";
expectIconEquals(done, '?');
});
test('when the "size" property is invalid, the inner html equals "?"', function(done) {
el.size = "asdf";
expectIconEquals(done, '?');
});
test('when the "size" property is valid, the inner html equals "<some valid content>"', function(done) {
el.size = "12%";
expectIconEquals(done, '<some valid content>');
});
});
</script>
原问题的答案:
在您的代码中,只有当 sizeName
不是 undefined
并且为空时,span#icon
元素才会被标记。绑定评估类似于 that of computed bindings(即使对于非计算绑定没有明确说明):
The computing function is not called until all dependent properties are defined (!=undefined
). So each dependent properties should have a default value defined in properties (or otherwise be initialized to a non-undefined
value) to ensure the function value is computed.
要解决此问题,请在刷新模板之前将 sizeName
设置为测试中的空字符串。
suite('when no icon size or incorrect icon size is provided', function() {
var el;
setup(function() {
el = fixture('hasWrongSize');
});
test('when the "size" property is incorrect the inner html equals "?"', function(done) {
// #icon exists only when sizeName is empty string
el.sizeName = "";
flush(function() {
var domEl = Polymer.dom(el.root).querySelector('#icon');
expect(domEl).to.not.be.null;
expect(domEl.innerHTML).to.equal('?');
done();
});
});
});
或者,您可以在 dom-module
:
中初始化 sizeName
Polymer({
is: 'size-icon',
properties: {
sizeName: {
type: String,
value: function() { return ""; }
}
}
});
我解决了这个问题。我使用 ':before' 元素来填充 #icon
范围的内容。在尝试 select 时,我 运行 分为两个问题:
- 我有两个模板标签,所以它不知道要定位哪个元素。
- 我错误地 select 伪元素。
这是我用来正确select和测试伪元素的content
属性的代码。
var getBeforeText = function(el) {
return window.getComputedStyle(
getIcon(el), ':before'
).getPropertyValue('content').replace(/"/g, "").replace(/'/g, "");
};
var getIcon = function(el) {
return Polymer.dom(el.root).querySelector('#icon');
};
suite('when no icon size or incorrect icon size is provided', function() {
var el;
setup(function() {
el = fixture('hasWrongSize');
});
test('when the "size" property is incorrect the inner html equals "?"', function(done) {
flush(function() {
expect(getBeforeText(el)).to.equal('?');
done();
});
});
});
伪元素不能直接 select 与普通 JS 一起使用,因为它们不是 DOM 的一部分。
这是我的 属性 声明:
properties: {
size: {
type: String,
value: ''
},
sizeName: {
type: String,
value: ''
}
}
我的CSS:
<style>
:root {
--width: 20px;
--height: 20px;
--border-color: black;
--font-size: 16px;
}
:host {
display: inline-block;
box-sizing: border-box;
height: var(--height);
width: var(--width);
}
#icon {
position: relative;
display: block;
width: var(--width);
height: var(--height);
border-radius: 50%;
border: 1px solid var(--border-color);
font-size: var(--font-size);
@apply(--size-icon);
}
#icon:before {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
content: '?';
text-align: center;
@apply(--size-icon--before);
}
#icon.small:before {content: 's';}
#icon.medium:before {content: 'm';}
#icon.large:before {content: 'l';}
#name {
font-size: var(--font-size);
@apply(--size-name);
}
.hidden {
display: none;
}
</style>
我有一个测试夹具如下:
<test-fixture id="hasWrongSize">
<template>
<size-icon size="asdf"></size-icon>
</template>
<template>
<size-icon size=""></size-icon>
</template>
</test-fixture>
测试套件如下:
suite('when no icon size or incorrect icon size is provided', function() {
var el;
setup(function() {
el = fixture('hasWrongSize');
});
test('when the "size" property is incorrect the inner html equals "?"', function(done) {
flush(function() {
var domEl = Polymer.dom(el.root).querySelector('#icon:before');
expect(domEl.innerHTML).to.equal('?');
done();
});
});
});
自定义元素的LocalDOM如下:
<template>
<template is="dom-if" if="{{ !sizeName }}">
<span id="icon" class$="{{size}}"></span>
</template>
<span id="name">{{ sizeName }}</span>
</template>
我正在尝试获取 ID 为 #icon
的 :before
伪元素,但 WCT 无法找到它并且测试套件中的 domEl
等同于null
.
我做错了什么?
更新 问题已更新为包含 test-fixture
的完整代码,这揭示了根本原因。
正如您在自己的回答中指出的那样:
- I have two template tags so it did not know which element to target.
这就是你的问题的原因,伪元素实际上与它无关。您会发现,如果您从 test-fixture
中删除其中一个模板,您的原始代码就会起作用(并且会比现在的 IMO 更干净)。
test-fixture
应该只包含 一个 template
并且自定义元素的固定状态作为测试的基线(最常见的分母) .在这种情况下,该基线是单个 size-icon
,但您似乎为每个可能的测试用例添加了一个 template
,但该设置实际上应该像这样出现在测试脚本中:
<test-fixture id="basic">
<template>
<size-icon></size-icon>
</template>
</test-fixture>
<script>
suite('size-icon', function() {
var el;
setup(function() {
el = fixture('basic');
});
function expectIconEquals(done, contents) {
flush(function() {
var domEl = Polymer.dom(el.root).querySelector('#icon');
expect(domEl.innerHTML).to.equal(contents);
done();
});
}
test('when the "size" property is empty, the inner html equals "?"', function(done) {
el.size = "";
expectIconEquals(done, '?');
});
test('when the "size" property is invalid, the inner html equals "?"', function(done) {
el.size = "asdf";
expectIconEquals(done, '?');
});
test('when the "size" property is valid, the inner html equals "<some valid content>"', function(done) {
el.size = "12%";
expectIconEquals(done, '<some valid content>');
});
});
</script>
原问题的答案:
在您的代码中,只有当 sizeName
不是 undefined
并且为空时,span#icon
元素才会被标记。绑定评估类似于 that of computed bindings(即使对于非计算绑定没有明确说明):
The computing function is not called until all dependent properties are defined (
!=undefined
). So each dependent properties should have a default value defined in properties (or otherwise be initialized to a non-undefined
value) to ensure the function value is computed.
要解决此问题,请在刷新模板之前将 sizeName
设置为测试中的空字符串。
suite('when no icon size or incorrect icon size is provided', function() {
var el;
setup(function() {
el = fixture('hasWrongSize');
});
test('when the "size" property is incorrect the inner html equals "?"', function(done) {
// #icon exists only when sizeName is empty string
el.sizeName = "";
flush(function() {
var domEl = Polymer.dom(el.root).querySelector('#icon');
expect(domEl).to.not.be.null;
expect(domEl.innerHTML).to.equal('?');
done();
});
});
});
或者,您可以在 dom-module
:
sizeName
Polymer({
is: 'size-icon',
properties: {
sizeName: {
type: String,
value: function() { return ""; }
}
}
});
我解决了这个问题。我使用 ':before' 元素来填充 #icon
范围的内容。在尝试 select 时,我 运行 分为两个问题:
- 我有两个模板标签,所以它不知道要定位哪个元素。
- 我错误地 select 伪元素。
这是我用来正确select和测试伪元素的content
属性的代码。
var getBeforeText = function(el) {
return window.getComputedStyle(
getIcon(el), ':before'
).getPropertyValue('content').replace(/"/g, "").replace(/'/g, "");
};
var getIcon = function(el) {
return Polymer.dom(el.root).querySelector('#icon');
};
suite('when no icon size or incorrect icon size is provided', function() {
var el;
setup(function() {
el = fixture('hasWrongSize');
});
test('when the "size" property is incorrect the inner html equals "?"', function(done) {
flush(function() {
expect(getBeforeText(el)).to.equal('?');
done();
});
});
});
伪元素不能直接 select 与普通 JS 一起使用,因为它们不是 DOM 的一部分。