是否可以为Knockout创建DOM以绑定到?

时间:2017-01-17 09:57:17

标签: javascript node.js knockout.js jestjs

我们正试图找出如何将Jest.jsKnockout.js一起使用。基本上我们想要创建一个DOM的小片段,例如:

<div class="card" data-bind="component: myCustomComponent"/>

然后能够使用自定义视图模型调用ko.applyBindings(),并使用该DOM片段和Knockout将组件加载到视图模型中,这样我们就可以进行Jest快照测试。

我们正在努力解决的问题是,如何有效地创建适合ko.applyBindings()的DOM片段,因为它需要一个我们不确定如何创建的DOM节点/选择

修改

我已经使用了@ user3297291的回答并将以下示例放在一起,遗憾的是我无法开始工作。这是我将自己放在一起的例子:

const jsdom = require("jsdom");
const ko = require("knockout");

describe("Knockout Test", () => {

    beforeAll(() => {
        ko.components.register("greeting", {
            viewModel: function(params) {
                //params.name = "test";
                //this.message = ko.observable(`Hello ${params.name}`);
                this.message = ko.observable("Hello World!");
            },
            template: '<span data-bind="text: message"/>'
        });
    });

    it("test pass", (done) => {

        jsdom.env(`<div class="wrapper"></div>`, [], (err, window) => {
            var wrapper = window.document.querySelector(".wrapper");
            var element = window.document.createElement("div");

            element.setAttribute("data-bind", 'component: "greeting"');
            wrapper.appendChild(element);

            ko.applyBindings({ name: 'Ian' }, wrapper);

            setTimeout(() => {
                console.log(element.innerHTML);
                expect(element.innerHTML).toMatchSnapshot();
                done();
            }, 10);

          }
        );
    });
});

如果我将element.setAttribute("data-bind", 'component: "greeting"');修改为element.setAttribute("data-bind", 'text: name');,那么它可以正常工作,但加载一个组件(我实际上想要做的事情)似乎总是会导致空element.innerHTML

如果你想重现,那么这是一个package.json,我正在运行npm run jest

{
  "name": "kotest",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "jest": "jest"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "jasmine": "^2.5.3",
    "jest": "^18.1.0",
    "jsdom": "^9.9.1",
    "knockout": "^3.4.1"
  }
}

1 个答案:

答案 0 :(得分:1)

在浏览器的javascript环境中,您可以通过代码创建DOM元素来虚拟测试knockout。例如,您可以这样做:

ko.applyBindings({}, document.createElement("div"));

这意味着您可以通过将组件绑定应用于虚拟<div>并检查其内容来编写任何UI测试。以下示例显示了一些基础知识。

function testComponent(options, test) {
  var wrapper = document.createElement("div");

  // If you have a HTML string, you can do this by setting
  // wrapper.innerHTML = "<div ... ></div>";
  var binding = "component: { name: name, params: params }"
  wrapper.setAttribute("data-bind", binding);
  
  // Apply bindings to virtual element
  ko.applyBindings(options, wrapper);
  
  // Once done, call test with wrapper
  setTimeout(test.bind(wrapper));
};

var messageEditorTest = function() {
  var opts = { name: "message-editor", params: {} };
  
  testComponent(opts, function() {
    var input = this.querySelector("input"),
        display = this.querySelector("span"),
        vm = ko.dataFor(this.firstElementChild);
    
    console.log("MESSAGE EDITOR TESTS:");
    
    console.log("Has an input field:", 
                input !== null);
    
    console.log("Has a display field:",
                display !== null);
    
    console.log("Length is initially zero:",
                display.innerText === "0");
    
    vm.text("Four");
    console.log("Length reflects value input:",
                display.innerText === "4");
                
  });
};

// Component
ko.components.register('message-editor', {
    viewModel: function(params) {
        this.text = ko.observable(params && params.initialText || '');
    },
    template: 'Message: <input data-bind="value: text" /> '
            + '(length: <span data-bind="text: text().length"></span>)'
});

messageEditorTest();
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

现在,如果你想在没有浏览器帮助的情况下在Node.js中进行测试,我不确定它是如何工作的......我认为你可以使用像{{ {3}},或者您可以尝试点击jsdom之类的“测试浏览器”。

编辑:我使用jsdom进行了快速测试,一切似乎都运行得很好

  • 运行npm install jsdom
  • 运行npm install knockout
  • 创建名为test.js的文件:

    var jsdom = require("jsdom");
    var ko = require("knockout");
    
    jsdom.env(
      '<div class="wrapper"></div>',
      [],
      function (err, window) {
        var wrapper = window.document.querySelector(".wrapper");
    
        var element = window.document.createElement("div");
        element.setAttribute("data-bind", "text: test");
        wrapper.appendChild(element);
    
        ko.applyBindings({ test: 'My Test' }, wrapper);
    
        console.log(element.innerHTML); // Logs "My Test"
      }
    );
    
  • 运行node test.js
  • 记录My Test