mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
459 lines
14 KiB
TypeScript
459 lines
14 KiB
TypeScript
import { list, mount, multi, patch, text, createBlock, VNode, withKey } from "../../src/blockdom";
|
|
import { makeTestFixture } from "./helpers";
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Setup and helpers
|
|
//------------------------------------------------------------------------------
|
|
|
|
let fixture: HTMLElement;
|
|
|
|
beforeEach(() => {
|
|
fixture = makeTestFixture();
|
|
});
|
|
|
|
afterEach(() => {
|
|
fixture.remove();
|
|
});
|
|
|
|
function kText(str: string, key: any): VNode {
|
|
return withKey(text(str), key);
|
|
}
|
|
|
|
function n(n: number) {
|
|
return kText(String(n), n);
|
|
}
|
|
|
|
const span = createBlock("<span><block-text-0/></span>");
|
|
const p = createBlock("<p><block-text-0/></p>");
|
|
|
|
function kSpan(str: string, key: any): VNode {
|
|
return withKey(span([str]), key);
|
|
}
|
|
|
|
function kPair(n: number): VNode {
|
|
const bnodes = [p([String(n)]), p([String(n)])];
|
|
return withKey(multi(bnodes), n);
|
|
}
|
|
|
|
describe("list node: misc", () => {
|
|
test("list node", async () => {
|
|
const bnodes = [1, 2, 3].map((key) => kText(`text${key}`, key));
|
|
|
|
const tree = list(bnodes);
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("text1text2text3");
|
|
});
|
|
|
|
test("list vnode can be used as text", () => {
|
|
mount(text(list([text("a"), text("b")]) as any), fixture);
|
|
expect(fixture.innerHTML).toBe("ab");
|
|
});
|
|
|
|
test("a list block can be removed and leaves nothing", async () => {
|
|
const bnodes = [
|
|
{ id: 1, name: "sheep" },
|
|
{ id: 2, name: "cow" },
|
|
].map((elem) => kText(elem.name, elem.id));
|
|
|
|
const tree = list(bnodes);
|
|
expect(fixture.childNodes.length).toBe(0);
|
|
mount(tree, fixture);
|
|
expect(fixture.childNodes.length).toBe(3);
|
|
expect(fixture.innerHTML).toBe("sheepcow");
|
|
|
|
tree.remove();
|
|
expect(fixture.innerHTML).toBe("");
|
|
expect(fixture.childNodes.length).toBe(0);
|
|
});
|
|
|
|
test("patching a list block inside an elem block", async () => {
|
|
const block = createBlock("<div><block-child-0/></div>");
|
|
const tree = block();
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("<div></div>");
|
|
|
|
patch(tree, block([], [list([1, 2, 3].map(n))]));
|
|
expect(fixture.innerHTML).toBe("<div>123</div>");
|
|
|
|
patch(tree, block([], [list([])]));
|
|
expect(fixture.innerHTML).toBe("<div></div>");
|
|
|
|
patch(tree, block([], [list([1, 2, 3].map(n))]));
|
|
expect(fixture.innerHTML).toBe("<div>123</div>");
|
|
});
|
|
|
|
test("list of lists", async () => {
|
|
const tree = list([
|
|
withKey(list([kText("a1", "1"), kText("a2", "2")]), "a"),
|
|
withKey(list([kText("b1", "1"), kText("b2", "2")]), "b"),
|
|
]);
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("a1a2b1b2");
|
|
|
|
patch(
|
|
tree,
|
|
list([
|
|
withKey(list([kText("b1", "1"), kText("b2", "2")]), "b"),
|
|
withKey(list([kText("a1", "1"), kText("a2", "2")]), "a"),
|
|
])
|
|
);
|
|
|
|
expect(fixture.innerHTML).toBe("b1b2a1a2");
|
|
|
|
patch(
|
|
tree,
|
|
list([
|
|
withKey(list([kText("a2", "2"), kText("a1", "1")]), "a"),
|
|
withKey(list([kText("b2", "2"), kText("b1", "1")]), "b"),
|
|
])
|
|
);
|
|
|
|
expect(fixture.innerHTML).toBe("a2a1b2b1");
|
|
});
|
|
});
|
|
|
|
describe("adding/removing elements", () => {
|
|
test("removing elements", () => {
|
|
const tree = list([kText("a", "a")]);
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("a");
|
|
|
|
patch(tree, list([]));
|
|
expect(fixture.innerHTML).toBe("");
|
|
});
|
|
|
|
test("removing 1 elements from 2", () => {
|
|
const tree = list([kText("a", "a"), kText("b", "b")]);
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("ab");
|
|
|
|
patch(tree, list([kText("a", "a")]));
|
|
expect(fixture.innerHTML).toBe("a");
|
|
});
|
|
|
|
test("removing elements", () => {
|
|
const tree = list([kSpan("a", "a")]);
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("<span>a</span>");
|
|
|
|
patch(tree, list([]));
|
|
expect(fixture.innerHTML).toBe("");
|
|
});
|
|
|
|
test("removing elements, variation", () => {
|
|
const f = (i: number) => {
|
|
const b = multi([span([`a${i}`]), span([`b${i}`])]);
|
|
b.key = i;
|
|
return b;
|
|
};
|
|
const tree = list([f(1), f(2)]);
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("<span>a1</span><span>b1</span><span>a2</span><span>b2</span>");
|
|
|
|
patch(tree, list([]));
|
|
expect(fixture.innerHTML).toBe("");
|
|
});
|
|
|
|
test("adding one element at the end", () => {
|
|
const tree = list([n(1), n(2)]);
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("12");
|
|
|
|
patch(tree, list([n(1), n(2), n(3)]));
|
|
expect(fixture.innerHTML).toBe("123");
|
|
});
|
|
|
|
test("adding one element at the end", () => {
|
|
const tree = list([n(1)]);
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("1");
|
|
|
|
patch(tree, list([n(1), n(2), n(3)]));
|
|
expect(fixture.innerHTML).toBe("123");
|
|
});
|
|
|
|
test("prepend elements: 4,5 => 1,2,3,4,5", () => {
|
|
const tree = list([n(4), n(5)]);
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("45");
|
|
|
|
patch(tree, list([n(1), n(2), n(3), n(4), n(5)]));
|
|
expect(fixture.innerHTML).toBe("12345");
|
|
});
|
|
|
|
test("prepend elements: 4,5 => 1,2,3,4,5 (with multi)", () => {
|
|
const tree = list([kPair(4), kPair(5)]);
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("<p>4</p><p>4</p><p>5</p><p>5</p>");
|
|
|
|
patch(tree, list([1, 2, 3, 4, 5].map(kPair)));
|
|
expect(fixture.innerHTML).toBe(
|
|
"<p>1</p><p>1</p><p>2</p><p>2</p><p>3</p><p>3</p><p>4</p><p>4</p><p>5</p><p>5</p>"
|
|
);
|
|
});
|
|
|
|
test("add element in middle: 1,2,4,5 => 1,2,3,4,5", () => {
|
|
const tree = list([1, 2, 4, 5].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("1245");
|
|
|
|
patch(tree, list([1, 2, 3, 4, 5].map(n)));
|
|
expect(fixture.innerHTML).toBe("12345");
|
|
});
|
|
|
|
test("add element in middle: 1,2,4,5 => 1,2,3,4,5 (multi)", () => {
|
|
const tree = list([1, 2, 4, 5].map(kPair));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe(
|
|
"<p>1</p><p>1</p><p>2</p><p>2</p><p>4</p><p>4</p><p>5</p><p>5</p>"
|
|
);
|
|
|
|
patch(tree, list([1, 2, 3, 4, 5].map(kPair)));
|
|
expect(fixture.innerHTML).toBe(
|
|
"<p>1</p><p>1</p><p>2</p><p>2</p><p>3</p><p>3</p><p>4</p><p>4</p><p>5</p><p>5</p>"
|
|
);
|
|
});
|
|
|
|
test("add element at beginning and end: 2,3,4 => 1,2,3,4,5", () => {
|
|
const tree = list([2, 3, 4].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("234");
|
|
|
|
patch(tree, list([1, 2, 3, 4, 5].map(n)));
|
|
expect(fixture.innerHTML).toBe("12345");
|
|
});
|
|
|
|
test("add element at beginning and end: 2,3,4 => 1,2,3,4,5 (multi)", () => {
|
|
const tree = list([2, 3, 4].map(kPair));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("<p>2</p><p>2</p><p>3</p><p>3</p><p>4</p><p>4</p>");
|
|
|
|
patch(tree, list([1, 2, 3, 4, 5].map(kPair)));
|
|
expect(fixture.innerHTML).toBe(
|
|
"<p>1</p><p>1</p><p>2</p><p>2</p><p>3</p><p>3</p><p>4</p><p>4</p><p>5</p><p>5</p>"
|
|
);
|
|
});
|
|
|
|
test("adds children: [] => [1,2,3]", () => {
|
|
const tree = list([].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("");
|
|
|
|
patch(tree, list([1, 2, 3].map(n)));
|
|
expect(fixture.innerHTML).toBe("123");
|
|
});
|
|
|
|
test("adds children: [] => [1,2,3] (multi)", () => {
|
|
const tree = list([].map(kPair));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("");
|
|
|
|
patch(tree, list([1, 2, 3].map(kPair)));
|
|
expect(fixture.innerHTML).toBe("<p>1</p><p>1</p><p>2</p><p>2</p><p>3</p><p>3</p>");
|
|
});
|
|
|
|
test("adds children: [] => [1,2,3] (inside elem)", () => {
|
|
const block = createBlock("<p><block-child-0/></p>");
|
|
const tree = block([], []);
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("<p></p>");
|
|
|
|
patch(tree, block([], [list([1, 2, 3].map(n))]));
|
|
expect(fixture.innerHTML).toBe("<p>123</p>");
|
|
});
|
|
|
|
test("adds children: [] => [1,2,3] (inside elem, multi)", () => {
|
|
const block = createBlock("<p><block-child-0/></p>");
|
|
const tree = block([], []);
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("<p></p>");
|
|
|
|
patch(tree, block([], [list([1, 2, 3].map(kPair))]));
|
|
expect(fixture.innerHTML).toBe("<p><p>1</p><p>1</p><p>2</p><p>2</p><p>3</p><p>3</p></p>");
|
|
});
|
|
|
|
test("remove children: [1,2,3] => []", () => {
|
|
const tree = list([1, 2, 3].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("123");
|
|
|
|
patch(tree, list([].map(n)));
|
|
expect(fixture.innerHTML).toBe("");
|
|
});
|
|
|
|
test("remove children: [1,2,3] => [] (multi)", () => {
|
|
const tree = list([1, 2, 3].map(kPair));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("<p>1</p><p>1</p><p>2</p><p>2</p><p>3</p><p>3</p>");
|
|
|
|
patch(tree, list([].map(kPair)));
|
|
expect(fixture.innerHTML).toBe("");
|
|
});
|
|
|
|
test("remove children: [1,2,3] => [] (inside elem)", () => {
|
|
const block = createBlock("<p><block-child-0/></p>");
|
|
const tree = block([], [list([1, 2, 3].map(n))]);
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("<p>123</p>");
|
|
|
|
patch(tree, block([], [list([])]));
|
|
expect(fixture.innerHTML).toBe("<p></p>");
|
|
});
|
|
|
|
test("remove children from the beginning: [1,2,3,4,5] => [3,4,5]", () => {
|
|
const tree = list([1, 2, 3, 4, 5].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("12345");
|
|
|
|
patch(tree, list([3, 4, 5].map(n)));
|
|
expect(fixture.innerHTML).toBe("345");
|
|
});
|
|
|
|
test("remove children from the beginning: [1,2,3,4,5] => [3,4,5] (multi)", () => {
|
|
const tree = list([1, 2, 3, 4, 5].map(kPair));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe(
|
|
"<p>1</p><p>1</p><p>2</p><p>2</p><p>3</p><p>3</p><p>4</p><p>4</p><p>5</p><p>5</p>"
|
|
);
|
|
patch(tree, list([3, 4, 5].map(kPair)));
|
|
expect(fixture.innerHTML).toBe("<p>3</p><p>3</p><p>4</p><p>4</p><p>5</p><p>5</p>");
|
|
});
|
|
|
|
test("remove children from the end: [1,2,3,4,5] => [1,2,3]", () => {
|
|
const tree = list([1, 2, 3, 4, 5].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("12345");
|
|
|
|
patch(tree, list([1, 2, 3].map(n)));
|
|
expect(fixture.innerHTML).toBe("123");
|
|
});
|
|
|
|
test("remove children from the middle: [1,2,3,4,5] => [1,2,4,5]", () => {
|
|
const tree = list([1, 2, 3, 4, 5].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("12345");
|
|
|
|
patch(tree, list([1, 2, 4, 5].map(n)));
|
|
expect(fixture.innerHTML).toBe("1245");
|
|
});
|
|
});
|
|
|
|
describe("element reordering", () => {
|
|
test("move element forward: [1,2,3,4] => [2,3,1,4]", () => {
|
|
const tree = list([1, 2, 3, 4].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("1234");
|
|
|
|
patch(tree, list([2, 3, 1, 4].map(n)));
|
|
expect(fixture.innerHTML).toBe("2314");
|
|
});
|
|
|
|
test("move element forward: [1,2,3,4] => [2,3,1,4] (multi)", () => {
|
|
const tree = list([1, 2, 3, 4].map(kPair));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe(
|
|
"<p>1</p><p>1</p><p>2</p><p>2</p><p>3</p><p>3</p><p>4</p><p>4</p>"
|
|
);
|
|
patch(tree, list([2, 3, 1, 4].map(kPair)));
|
|
expect(fixture.innerHTML).toBe(
|
|
"<p>2</p><p>2</p><p>3</p><p>3</p><p>1</p><p>1</p><p>4</p><p>4</p>"
|
|
);
|
|
});
|
|
|
|
test("move element to end: [1,2,3] => [2,3,1]", () => {
|
|
const tree = list([1, 2, 3].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("123");
|
|
|
|
patch(tree, list([2, 3, 1].map(n)));
|
|
expect(fixture.innerHTML).toBe("231");
|
|
});
|
|
|
|
test("move element to end: [1,2,3] => [2,3,1] (multi)", () => {
|
|
const tree = list([1, 2, 3].map(kPair));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("<p>1</p><p>1</p><p>2</p><p>2</p><p>3</p><p>3</p>");
|
|
|
|
patch(tree, list([2, 3, 1].map(kPair)));
|
|
expect(fixture.innerHTML).toBe("<p>2</p><p>2</p><p>3</p><p>3</p><p>1</p><p>1</p>");
|
|
});
|
|
|
|
test("move element backward: [1,2,3,4] => [1,4,2,3]", () => {
|
|
const tree = list([1, 2, 3, 4].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("1234");
|
|
|
|
patch(tree, list([1, 4, 2, 3].map(n)));
|
|
expect(fixture.innerHTML).toBe("1423");
|
|
});
|
|
|
|
test("swaps first and last: [1,2,3,4] => [4,3,2,1]", () => {
|
|
const tree = list([1, 2, 3, 4].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("1234");
|
|
|
|
patch(tree, list([4, 3, 2, 1].map(n)));
|
|
expect(fixture.innerHTML).toBe("4321");
|
|
});
|
|
});
|
|
|
|
describe("miscellaneous operations", () => {
|
|
test("move to left and replace: [1,2,3,4,5] => [4,1,2,3,6]", () => {
|
|
const tree = list([1, 2, 3, 4, 5].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("12345");
|
|
|
|
patch(tree, list([4, 1, 2, 3, 6].map(n)));
|
|
expect(fixture.innerHTML).toBe("41236");
|
|
});
|
|
|
|
test("move to left and replace: [1,2,3,4,5] => [4,1,2,3,6] (multi)", () => {
|
|
const tree = list([1, 2, 3, 4, 5].map(kPair));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe(
|
|
"<p>1</p><p>1</p><p>2</p><p>2</p><p>3</p><p>3</p><p>4</p><p>4</p><p>5</p><p>5</p>"
|
|
);
|
|
|
|
patch(tree, list([4, 1, 2, 3, 6].map(kPair)));
|
|
expect(fixture.innerHTML).toBe(
|
|
"<p>4</p><p>4</p><p>1</p><p>1</p><p>2</p><p>2</p><p>3</p><p>3</p><p>6</p><p>6</p>"
|
|
);
|
|
});
|
|
|
|
test("move to left and leave hole: [1,4,5] => [4,6]", () => {
|
|
const tree = list([1, 4, 5].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("145");
|
|
|
|
patch(tree, list([4, 6].map(n)));
|
|
expect(fixture.innerHTML).toBe("46");
|
|
});
|
|
|
|
test("[2,4,5] => [4,5,3]", () => {
|
|
const tree = list([2, 4, 5].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("245");
|
|
|
|
patch(tree, list([4, 5, 3].map(n)));
|
|
expect(fixture.innerHTML).toBe("453");
|
|
});
|
|
|
|
test("reverse elements [1,2,3,4,5,6,7,8] => [8,7,6,5,4,3,2,1]", () => {
|
|
const tree = list([1, 2, 3, 4, 5, 6, 7, 8].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("12345678");
|
|
|
|
patch(tree, list([8, 7, 6, 5, 4, 3, 2, 1].map(n)));
|
|
expect(fixture.innerHTML).toBe("87654321");
|
|
});
|
|
|
|
test("some permutation [0,1,2,3,4,5] => [4,3,2,1,5,0]", () => {
|
|
const tree = list([0, 1, 2, 3, 4, 5].map(n));
|
|
mount(tree, fixture);
|
|
expect(fixture.innerHTML).toBe("012345");
|
|
|
|
patch(tree, list([4, 3, 2, 1, 5, 0].map(n)));
|
|
expect(fixture.innerHTML).toBe("432150");
|
|
});
|
|
});
|