Files
owl/tests/blockdom/block_attributes.test.ts
T
Géry Debongnie f892929c80 [REF] blockdom,compiler: implement properties
Before this commit, properties were just handled as a special case of
attributes. But it does not make that much sense, since they are
different. For example, the `readOnly` property does not have the same
name as the `readonly` attribute.  The confusion probably comes from the
fact that QWeb does not distinguish between property and attributes, so
Owl has to infer which one is which.

With this commit, we introduce a `block-property` directive in blockdom,
and change the compiler to use it in emitted code. It has the additional
benefits of slightly shrinking the runtime code, since the `isProp`
function can now be located in the compiler.
2023-03-01 12:53:37 +01:00

148 lines
4.5 KiB
TypeScript

import { mount, patch, createBlock } from "../../src/runtime/blockdom";
import { makeTestFixture } from "./helpers";
//------------------------------------------------------------------------------
// Setup and helpers
//------------------------------------------------------------------------------
let fixture: HTMLElement;
beforeEach(() => {
fixture = makeTestFixture();
});
afterEach(() => {
fixture.remove();
});
test("simple attribute", async () => {
const block = createBlock('<div block-attribute-0="hello"></div>');
const tree = block(["world"]);
mount(tree, fixture);
expect(fixture.innerHTML).toBe(`<div hello="world"></div>`);
patch(tree, block(["owl"]));
expect(fixture.innerHTML).toBe(`<div hello="owl"></div>`);
});
test("updating attribute with falsy value", async () => {
const block = createBlock('<div block-attribute-0="hello"></div>');
const tree = block([false]);
mount(tree, fixture);
expect(fixture.innerHTML).toBe(`<div></div>`);
patch(tree, block(["owl"]));
expect(fixture.innerHTML).toBe(`<div hello="owl"></div>`);
patch(tree, block([false]));
expect(fixture.innerHTML).toBe(`<div></div>`);
patch(tree, block(["owl"]));
expect(fixture.innerHTML).toBe(`<div hello="owl"></div>`);
patch(tree, block([undefined]));
expect(fixture.innerHTML).toBe(`<div></div>`);
});
test("dynamic attribute (pair)", async () => {
const block = createBlock('<div block-attributes="0"></div>');
const tree = block([["hello", "world"]]);
mount(tree, fixture);
expect(fixture.innerHTML).toBe(`<div hello="world"></div>`);
patch(tree, block([["ola", "mundo"]]));
expect(fixture.innerHTML).toBe(`<div ola="mundo"></div>`);
});
test("dynamic attribute (pair, with false value)", async () => {
const block = createBlock('<div block-attributes="0"></div>');
const tree = block([["hello", false]]);
mount(tree, fixture);
expect(fixture.innerHTML).toBe(`<div></div>`);
patch(tree, block([["hello", "world"]]));
expect(fixture.innerHTML).toBe(`<div hello="world"></div>`);
patch(tree, block([["hello", false]]));
expect(fixture.innerHTML).toBe(`<div></div>`);
});
test("dynamic attribute (object)", async () => {
const block = createBlock('<div block-attributes="0"></div>');
const tree = block([{ hello: "world" }]);
mount(tree, fixture);
expect(fixture.innerHTML).toBe(`<div hello="world"></div>`);
patch(tree, block([{ ola: "mundo" }]));
expect(fixture.innerHTML).toBe(`<div ola="mundo"></div>`);
});
test("dynamic attribute (object), with falsy values", async () => {
const block = createBlock('<div block-attributes="0"></div>');
const tree = block([{ hello: "world", blip: false }]);
mount(tree, fixture);
expect(fixture.innerHTML).toBe(`<div hello="world"></div>`);
patch(tree, block([{ ola: "mundo", blip: undefined }]));
expect(fixture.innerHTML).toBe(`<div ola="mundo"></div>`);
patch(tree, block([{ ola: false, blip: 1 }]));
expect(fixture.innerHTML).toBe(`<div blip="1"></div>`);
patch(tree, block([{ ola: undefined, blip: undefined }]));
expect(fixture.innerHTML).toBe(`<div></div>`);
});
test("class attribute", async () => {
const block = createBlock('<div block-attribute-0="class"></div>');
const tree = block(["fire"]);
mount(tree, fixture);
expect(fixture.innerHTML).toBe(`<div class="fire"></div>`);
patch(tree, block(["water"]));
expect(fixture.innerHTML).toBe(`<div class="water"></div>`);
patch(tree, block([""]));
expect(fixture.innerHTML).toBe(`<div class=""></div>`);
patch(tree, block([0]));
expect(fixture.innerHTML).toBe(`<div class="0"></div>`);
});
test("attribute with undefined value", async () => {
const block = createBlock('<div block-attribute-0="abc"></div>');
const tree = block([undefined]);
mount(tree, fixture);
expect(fixture.innerHTML).toBe(`<div></div>`);
});
test("class attribute with undefined value", async () => {
const block = createBlock('<div block-attribute-0="class"></div>');
const tree = block([undefined]);
mount(tree, fixture);
expect(fixture.innerHTML).toBe(`<div></div>`);
});
test("class attribute (with a preexisting value", async () => {
const block = createBlock('<div class="tomato" block-attribute-0="class"></div>');
const tree = block(["potato"]);
mount(tree, fixture);
expect(fixture.innerHTML).toBe(`<div class="tomato potato"></div>`);
patch(tree, block(["squash"]));
expect(fixture.innerHTML).toBe(`<div class="tomato squash"></div>`);
patch(tree, block([""]));
expect(fixture.innerHTML).toBe(`<div class="tomato"></div>`);
});