You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
211 lines
7.3 KiB
TypeScript
211 lines
7.3 KiB
TypeScript
import { assert } from "@esm-bundle/chai";
|
|
|
|
import { init, h, thunk, VNode } from "../../src/index";
|
|
|
|
const patch = init([]);
|
|
|
|
describe("thunk", function () {
|
|
let elm: any, vnode0: any;
|
|
beforeEach(function () {
|
|
elm = vnode0 = document.createElement("div");
|
|
});
|
|
it("returns vnode with data and render function", function () {
|
|
function numberInSpan(n: number) {
|
|
return h("span", `Number is ${n}`);
|
|
}
|
|
const vnode = thunk("span", "num", numberInSpan, [22]);
|
|
assert.deepEqual(vnode.sel, "span");
|
|
assert.deepEqual(vnode.data.key, "num");
|
|
assert.deepEqual(vnode.data.args, [22]);
|
|
});
|
|
it("calls render function once on data change", function () {
|
|
let called = 0;
|
|
function numberInSpan(n: number) {
|
|
called++;
|
|
return h("span", { key: "num" }, `Number is ${n}`);
|
|
}
|
|
const vnode1 = h("div", [thunk("span", "num", numberInSpan, [1])]);
|
|
const vnode2 = h("div", [thunk("span", "num", numberInSpan, [2])]);
|
|
patch(vnode0, vnode1);
|
|
assert.strictEqual(called, 1);
|
|
patch(vnode1, vnode2);
|
|
assert.strictEqual(called, 2);
|
|
});
|
|
it("does not call render function on data unchanged", function () {
|
|
let called = 0;
|
|
function numberInSpan(n: number) {
|
|
called++;
|
|
return h("span", { key: "num" }, `Number is ${n}`);
|
|
}
|
|
const vnode1 = h("div", [thunk("span", "num", numberInSpan, [1])]);
|
|
const vnode2 = h("div", [thunk("span", "num", numberInSpan, [1])]);
|
|
patch(vnode0, vnode1);
|
|
assert.strictEqual(called, 1);
|
|
patch(vnode1, vnode2);
|
|
assert.strictEqual(called, 1);
|
|
});
|
|
it("calls render function once on data-length change", function () {
|
|
let called = 0;
|
|
function numberInSpan(n: number) {
|
|
called++;
|
|
return h("span", { key: "num" }, `Number is ${n}`);
|
|
}
|
|
const vnode1 = h("div", [thunk("span", "num", numberInSpan, [1])]);
|
|
const vnode2 = h("div", [thunk("span", "num", numberInSpan, [1, 2])]);
|
|
patch(vnode0, vnode1);
|
|
assert.strictEqual(called, 1);
|
|
patch(vnode1, vnode2);
|
|
assert.strictEqual(called, 2);
|
|
});
|
|
it("calls render function once on function change", function () {
|
|
let called = 0;
|
|
function numberInSpan(n: number) {
|
|
called++;
|
|
return h("span", { key: "num" }, `Number is ${n}`);
|
|
}
|
|
function numberInSpan2(n: number) {
|
|
called++;
|
|
return h("span", { key: "num" }, `Number really is ${n}`);
|
|
}
|
|
const vnode1 = h("div", [thunk("span", "num", numberInSpan, [1])]);
|
|
const vnode2 = h("div", [thunk("span", "num", numberInSpan2, [1])]);
|
|
patch(vnode0, vnode1);
|
|
assert.strictEqual(called, 1);
|
|
patch(vnode1, vnode2);
|
|
assert.strictEqual(called, 2);
|
|
});
|
|
it("renders correctly", function () {
|
|
let called = 0;
|
|
function numberInSpan(n: number) {
|
|
called++;
|
|
return h("span", { key: "num" }, `Number is ${n}`);
|
|
}
|
|
const vnode1 = h("div", [thunk("span", "num", numberInSpan, [1])]);
|
|
const vnode2 = h("div", [thunk("span", "num", numberInSpan, [1])]);
|
|
const vnode3 = h("div", [thunk("span", "num", numberInSpan, [2])]);
|
|
elm = patch(vnode0, vnode1).elm;
|
|
assert.strictEqual(elm.firstChild.tagName.toLowerCase(), "span");
|
|
assert.strictEqual(elm.firstChild.innerHTML, "Number is 1");
|
|
elm = patch(vnode1, vnode2).elm;
|
|
assert.strictEqual(elm.firstChild.tagName.toLowerCase(), "span");
|
|
assert.strictEqual(elm.firstChild.innerHTML, "Number is 1");
|
|
elm = patch(vnode2, vnode3).elm;
|
|
assert.strictEqual(elm.firstChild.tagName.toLowerCase(), "span");
|
|
assert.strictEqual(elm.firstChild.innerHTML, "Number is 2");
|
|
assert.strictEqual(called, 2);
|
|
});
|
|
it("supports leaving out the `key` argument", function () {
|
|
function vnodeFn(s: string) {
|
|
return h("span.number", "Hello " + s);
|
|
}
|
|
const vnode1 = thunk("span.number", vnodeFn, ["World!"]);
|
|
elm = patch(vnode0, vnode1).elm;
|
|
assert.strictEqual(elm.innerText, "Hello World!");
|
|
});
|
|
it("renders correctly when root", function () {
|
|
let called = 0;
|
|
function numberInSpan(n: number) {
|
|
called++;
|
|
return h("span", { key: "num" }, `Number is ${n}`);
|
|
}
|
|
const vnode1 = thunk("span", "num", numberInSpan, [1]);
|
|
const vnode2 = thunk("span", "num", numberInSpan, [1]);
|
|
const vnode3 = thunk("span", "num", numberInSpan, [2]);
|
|
|
|
elm = patch(vnode0, vnode1).elm;
|
|
assert.strictEqual(elm.tagName.toLowerCase(), "span");
|
|
assert.strictEqual(elm.innerHTML, "Number is 1");
|
|
|
|
elm = patch(vnode1, vnode2).elm;
|
|
assert.strictEqual(elm.tagName.toLowerCase(), "span");
|
|
assert.strictEqual(elm.innerHTML, "Number is 1");
|
|
|
|
elm = patch(vnode2, vnode3).elm;
|
|
assert.strictEqual(elm.tagName.toLowerCase(), "span");
|
|
assert.strictEqual(elm.innerHTML, "Number is 2");
|
|
assert.strictEqual(called, 2);
|
|
});
|
|
it("can be replaced and removed", function () {
|
|
function numberInSpan(n: number) {
|
|
return h("span", { key: "num" }, `Number is ${n}`);
|
|
}
|
|
function oddEven(n: number): VNode {
|
|
const prefix = n % 2 === 0 ? "Even" : "Odd";
|
|
return h("div", { key: oddEven as any }, `${prefix}: ${n}`);
|
|
}
|
|
const vnode1 = h("div", [thunk("span", "num", numberInSpan, [1])]);
|
|
const vnode2 = h("div", [thunk("div", "oddEven", oddEven, [4])]);
|
|
|
|
elm = patch(vnode0, vnode1).elm;
|
|
assert.strictEqual(elm.firstChild.tagName.toLowerCase(), "span");
|
|
assert.strictEqual(elm.firstChild.innerHTML, "Number is 1");
|
|
|
|
elm = patch(vnode1, vnode2).elm;
|
|
assert.strictEqual(elm.firstChild.tagName.toLowerCase(), "div");
|
|
assert.strictEqual(elm.firstChild.innerHTML, "Even: 4");
|
|
});
|
|
it("can be replaced and removed when root", function () {
|
|
function numberInSpan(n: number) {
|
|
return h("span", { key: "num" }, `Number is ${n}`);
|
|
}
|
|
function oddEven(n: number): VNode {
|
|
const prefix = n % 2 === 0 ? "Even" : "Odd";
|
|
return h("div", { key: oddEven as any }, `${prefix}: ${n}`);
|
|
}
|
|
const vnode1 = thunk("span", "num", numberInSpan, [1]);
|
|
const vnode2 = thunk("div", "oddEven", oddEven, [4]);
|
|
|
|
elm = patch(vnode0, vnode1).elm;
|
|
assert.strictEqual(elm.tagName.toLowerCase(), "span");
|
|
assert.strictEqual(elm.innerHTML, "Number is 1");
|
|
|
|
elm = patch(vnode1, vnode2).elm;
|
|
assert.strictEqual(elm.tagName.toLowerCase(), "div");
|
|
assert.strictEqual(elm.innerHTML, "Even: 4");
|
|
});
|
|
it("invokes destroy hook on thunks", function () {
|
|
let called = 0;
|
|
function destroyHook() {
|
|
called++;
|
|
}
|
|
function numberInSpan(n: number) {
|
|
return h(
|
|
"span",
|
|
{ key: "num", hook: { destroy: destroyHook } },
|
|
`Number is ${n}`
|
|
);
|
|
}
|
|
const vnode1 = h("div", [
|
|
h("div", "Foo"),
|
|
thunk("span", "num", numberInSpan, [1]),
|
|
h("div", "Foo")
|
|
]);
|
|
const vnode2 = h("div", [h("div", "Foo"), h("div", "Foo")]);
|
|
patch(vnode0, vnode1);
|
|
patch(vnode1, vnode2);
|
|
assert.strictEqual(called, 1);
|
|
});
|
|
it("invokes remove hook on thunks", function () {
|
|
let called = 0;
|
|
function hook() {
|
|
called++;
|
|
}
|
|
function numberInSpan(n: number) {
|
|
return h(
|
|
"span",
|
|
{ key: "num", hook: { remove: hook } },
|
|
`Number is ${n}`
|
|
);
|
|
}
|
|
const vnode1 = h("div", [
|
|
h("div", "Foo"),
|
|
thunk("span", "num", numberInSpan, [1]),
|
|
h("div", "Foo")
|
|
]);
|
|
const vnode2 = h("div", [h("div", "Foo"), h("div", "Foo")]);
|
|
patch(vnode0, vnode1);
|
|
patch(vnode1, vnode2);
|
|
assert.strictEqual(called, 1);
|
|
});
|
|
});
|