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 的完整代码,这揭示了根本原因。

正如您在自己的回答中指出的那样:

  1. 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 时,我 运行 分为两个问题:

  1. 我有两个模板标签,所以它不知道要定位哪个元素。
  2. 我错误地 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 的一部分。