使用 wct 测试含铁-ajax 的聚合物 1.0 组件

Testing polymer 1.0 components with iron-ajax using wct

我在模拟服务器对我的自定义组件中的 iron-ajax 组件的响应时遇到了最困难的时刻。这是我的代码文件。

自定义-component.html:

<link rel="import" href="/iron-ajax/iron-ajax.html">
<link rel="import" href="/internal-component/internal-component.html">

<dom-module id="custom-component">
    <template>
        <iron-ajax url="staticFile.json" auto handle-as="json" last-response={{ajaxResponse}}></iron-ajax>
        <template is="dom-repeat"
                  items={{ajaxResponse}}
                  sort="_sort"
                  id="gridRow">
            <internal-component var1={{item.var1}}
                                   var2={{item.var2}}>
            </internal-component>
        </template>
    </template>
</dom-module>
<script>(some cool scripts that are working...)</script>

自定义组件-tests.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <script src="/webcomponentsjs/webcomponents-lite.js"></script>
    <script src="/web-component-tester/browser.js"></script>
    <script src="/test-fixture/test-fixture-mocha.js"></script>

    <link rel="import" href="/test-fixture/test-fixture.html" />

    <link rel="import" href="/polymer/polymer.html">
    <link rel="import" href="/polymer-ts/polymer-ts.html">

    <link rel="import" href="custom-component.html">
</head>
<body>
<test-fixture id="testElement">
    <template>
        <custom-component></custom-component.>
    </template>
</test-fixture>

<script>
    suite('<custom-component>', function () {
        var testElement;
        var server;
        var responseHeaders = {
            json: { 'Content-Type': 'application/json' },
            plain: { 'Content-Type': 'text/plain' }
        };
        setup(function () {
            replace('custom-component').with('fake-custom-component');
            server = sinon.fakeServer.create();
            server.respondWith('GET', /staticFile\.json/, [
                200,
                responseHeaders.json,
                '[{"var1": "9a","var2": "17n"}]'
            ]);
            testElement = fixture("testElement");
        });
        teardown(function () {
            server.restore();
        });
        suite('testSuite', function () {
            test('test1', function () {
                var ajax = testElement.getElementsByTagName('iron-ajax')[0];
                ajax.lastResponse = null;
                ajax.generateRequest();
                server.respond();
                assert(ajax.lastResponse.hour === "9a");
            });
        });
    });
</script>

</body>
</html>

您会注意到我明确调用了 iron-ajax generateRequest,因为如果我不这样做,那么在我的测试完成(并失败)之前请求甚至不会发生。当显式调用 generateRequest 时,我至少能够使请求发生,但是(即使我正在调用 server.respond())iron-ajax 直到测试完成后才调用 _handleResponse。而且,即使它这样做了,它也没有设置 lastResponse 因为在 iron-ajax 中有一行代码检查是否 (request === this.lastRequest) (它不是)。

我做错了什么?

我想我需要睡个好觉。

我忘了考虑异步请求。我修改了代码以反映以下内容:

suite('<custom-component>', function () {
    var testElement;
    var server;
    var responseHeaders = {
        json: { 'Content-Type': 'application/json' },
        plain: { 'Content-Type': 'text/plain' }
    };
    setup(function () {
        replace('custom-component').with('fake-custom-component');
        server = sinon.fakeServer.create();
        server.respondWith('GET', /staticFile\.json/, [
            200,
            responseHeaders.json,
            '[{"var1": "9a","var2": "17n"}]'
        ]);
        testElement = fixture("testElement");
    });
    teardown(function () {
        server.restore();
    });
    suite('testSuite', function () {
        // note that I added the "done" as a parameter on my test function
        test('test1', function (done) {
            var ajax = testElement.getElementsByTagName('iron-ajax')[0];
            ajax.generateRequest();
            server.respond();

            // note that I added an async event listener here, and moved my test inside.
            ajax.addEventListener('response', function(e) {
                assert(e.target.lastResponse.var1 === "9a");
                done();
            }
        });
    });
});

我现在能够正确拦截响应,并且测试大部分都按预期工作。我仍然有 iron-ajax 的 lastResponse 未设置的问题,但我认为这是另一个问题。

我找到了一个更好的解决方案来测试元素中 iron-ajax 元素的自动功能。

您需要根据 ajax 的请求添加一个事件侦听器来触发您的服务器响应,不需要 generateRequest 也不需要 setTimeout hacks。

这里有一个例子:

            test('test with ajax element', function (done) {
                var ajax = Polymer.dom(myElement.root).querySelector("#ajax_element");

                ajax.addEventListener('request', function (e) {
                    server.respond('GET', '/CALLED_URL', dataResponse);
                });

                ajax.addEventListener('response', function (e) {
                    //DO YOUR EXPECTS HERE
                    done();
                });
            });

作为组件测试,我相信您真的应该测试组件行为而不是 sinon and/or iron-ajax 元素内部。您的请求很可能会更新一些 属性,这将触发一些 DOM 更新。

我也一直讨厌 setTimeouts 在测试中,只是发现 WCT 有一个 flush 方法来处理这些情况(它等待所有异步的东西完成)——只是没有记录在 AJAX 测试部分,但在 DOM 操作上(https://www.polymer-project.org/1.0/docs/tools/tests#test-local-dom)。

因此,我的做法是:

suite('testSuite', function () {
  test('test1', function (done) {
    // assuming iron-ajax with auto
    server.respond();
    flush(function () {
      expect(el.myObject).to.deep.equal(responseObj);

      // in case you're binding the last response to a property
      expect(el.lastResponse).to.deep.equal(responseObj);

      done();
    })
  });
});