import { createBlock, mount, patch, remove, text } from "../../src/blockdom"; import { makeTestFixture } from "./helpers"; //------------------------------------------------------------------------------ // Setup and helpers //------------------------------------------------------------------------------ let fixture: HTMLElement; beforeEach(() => { fixture = makeTestFixture(); }); afterEach(() => { fixture.remove(); }); describe("adding/patching blocks", () => { test("simple block", async () => { const block = createBlock("
foo
"); const tree = block(); expect(tree.el).toBe(undefined); mount(tree, fixture); expect(tree.el).not.toBe(undefined); expect(fixture.innerHTML).toBe("
foo
"); }); test("block with dynamic content", async () => { const block = createBlock("

"); const tree = block(["foo"]); mount(tree, fixture); expect(fixture.innerHTML).toBe("

foo

"); patch(tree, block(["bar"])); expect(fixture.innerHTML).toBe("

bar

"); patch(tree, block(["foo"])); expect(fixture.innerHTML).toBe("

foo

"); }); test("block with 2 dynamic text nodes", async () => { const block = createBlock("

"); const tree = block(["foo", "bar"]); mount(tree, fixture); expect(fixture.innerHTML).toBe("

foo

bar
"); patch(tree, block(["appa", "yip yip"])); expect(fixture.innerHTML).toBe("

appa

yip yip
"); }); test("block with multiple references", async () => { const block1 = createBlock( "

" ); const tree = block1(["1", "2", "3", "4"]); mount(tree, fixture); expect(fixture.innerHTML).toBe("
1

23

4
"); }); test("falsy values in block nodes", () => { const cases = [ [false, "false"], [undefined, ""], [null, ""], [0, "0"], ["", ""], ]; const block = createBlock("

"); for (let [value, result] of cases) { const fixture = makeTestFixture(); mount(block([value as any]), fixture); expect(fixture.innerHTML).toBe(`

${result}

`); } }); }); describe("sub blocks", () => { test("block with subblock (only child)", async () => { const block1 = createBlock("
"); const block2 = createBlock("

yip yip

"); const tree = block1([], [block2()]); mount(tree, fixture); expect(fixture.innerHTML).toBe("

yip yip

"); }); test("block with subblock (first child with sibling)", async () => { const block1 = createBlock("
something
"); const block2 = createBlock("

yip yip

"); const tree = block1([], [block2()]); mount(tree, fixture); expect(fixture.innerHTML).toBe("

yip yip

something
"); }); test("block with subblock (last child with sibling)", async () => { const block1 = createBlock("
something
"); const block2 = createBlock("

yip yip

"); const tree = block1([], [block2()]); mount(tree, fixture); expect(fixture.innerHTML).toBe("
something

yip yip

"); }); test("block with 2 subblocks", async () => { const block1 = createBlock("
"); const block2 = createBlock("

yip yip

"); const tree = block1([], [block2(), text("appa")]); mount(tree, fixture); expect(fixture.innerHTML).toBe("

yip yip

appa
"); }); test("block with subblock with siblings", async () => { const block1 = createBlock("

1

2

"); const block2 = createBlock("

yip yip

"); const tree = block1([], [block2()]); mount(tree, fixture); expect(fixture.innerHTML).toBe("

1

yip yip

2

"); }); test("block with text, subblock and siblings", async () => { let block1 = createBlock(`

beforeafter

`); let tree = block1([], [text("water"), text("fire")]); mount(tree, fixture); expect(fixture.innerHTML).toBe("

beforewaterafter

fire
"); }); test("block with conditional child", async () => { const block1 = createBlock("

"); const block2 = createBlock("foo"); const tree = block1(); mount(tree, fixture); expect(fixture.innerHTML).toBe("

"); patch(tree, block1([], [block2()])); expect(fixture.innerHTML).toBe("

foo

"); patch(tree, block1()); expect(fixture.innerHTML).toBe("

"); }); test("block with subblock with dynamic content", async () => { const block1 = createBlock("
"); const block2 = createBlock("

"); const tree = block1([], [block2(["yip yip"])]); mount(tree, fixture); expect(fixture.innerHTML).toBe("

yip yip

"); patch(tree, block1([], [block2(["foo"])])); expect(fixture.innerHTML).toBe("

foo

"); }); test("block with dynamic content and subblock", async () => { const block1 = createBlock("

"); const block2 = createBlock("

sub block

"); const tree = block1(["yip yip"], [block2()]); mount(tree, fixture); expect(fixture.innerHTML).toBe("

sub block

yip yip

"); patch(tree, block1(["foo"], [block2()])); expect(fixture.innerHTML).toBe("

sub block

foo

"); }); }); describe("remove elem blocks", () => { test("elem block can be removed", async () => { const block = createBlock("
foo
"); const tree = block(); mount(tree, fixture); expect(fixture.innerHTML).toBe("
foo
"); remove(tree); expect(fixture.innerHTML).toBe(""); expect(fixture.childNodes.length).toBe(0); }); }); describe("misc", () => { test("constructed block as correct number of refs", () => { const block = createBlock("

"); const tree = block(["a", "b"]); mount(tree, fixture); expect(fixture.innerHTML).toBe("

a

b

"); expect((tree as any).refs.length).toBe(2); }); test("block vnode can be used as text", () => { const block = createBlock("

a

"); mount(text(block() as any), fixture); expect(fixture.textContent).toBe("

a

"); }); test("block vnode can be used to represent a ", () => { const block = createBlock("tomato"); const tree = block(); const fixture = document.createElement("table"); mount(tree, fixture); expect(fixture.outerHTML).toBe("
tomato
"); }); test("block vnode with can be used as text ", () => { const block = createBlock("tomato"); mount(text(block() as any), fixture); expect(fixture.textContent).toBe("tomato"); }); test("call toString for function/objects if used as inline text in block", () => { const block = createBlock("

"); const f = () => 3; const g = () => 4; g.toString = () => "tostring"; mount(block([f, g]), fixture); expect(fixture.innerHTML).toBe("

() => 3tostring

"); }); test("block with 2 subblocks: variation", async () => { const block = createBlock("2"); const tree = block([], [text("1"), text("3")]); mount(tree, fixture); expect(fixture.innerHTML).toBe("123"); }); test("block with 2 subblocks: another variation", async () => { const block = createBlock( `2` ); const tree = block(["world"], [text("1"), text("3")]); mount(tree, fixture); expect(fixture.innerHTML).toBe(`123`); }); // test.skip("reusing a block skips patching process", async () => { // const block = createBlock('
'); // const foo = block(["foo"]); // const bar = block(["bar"]); // let fooCounter = 0; // let barCounter = 0; // let fooValue = "foo"; // let barValue = "bar"; // Object.defineProperty(foo.data, 0, { // get() { // fooCounter++; // return fooValue; // }, // }); // Object.defineProperty(bar.data, 0, { // get() { // barCounter++; // return barValue; // }, // set(val) { // barValue = val; // }, // }); // const bdom = multi([foo, bar]); // mount(bdom, fixture); // expect(fooCounter).toBe(1); // expect(barCounter).toBe(1); // expect(fixture.innerHTML).toBe("
foo
bar
"); // patch(bdom, multi([foo, block(["otherbar"])])); // expect(fixture.innerHTML).toBe("foootherbar"); // expect(fooCounter).toBe(1); // expect(barCounter).toBe(2); // }); });