mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
97564a7612
Updating my node version to v16, I noticed many tests breaking, because the way errors are formatted did change. This commit ensures that the test suite keeps working for all node versions.
273 lines
8.3 KiB
TypeScript
273 lines
8.3 KiB
TypeScript
import { Component, Env } from "../../src/component/component";
|
|
import { QWeb } from "../../src/qweb/qweb";
|
|
import { xml } from "../../src/tags";
|
|
import { useState, useRef } from "../../src/hooks";
|
|
import { makeTestFixture, makeTestEnv, nextTick } from "../helpers";
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Setup and helpers
|
|
//------------------------------------------------------------------------------
|
|
|
|
// We create before each test:
|
|
// - fixture: a div, appended to the DOM, intended to be the target of dom
|
|
// manipulations. Note that it is removed after each test.
|
|
// - env: a WEnv, necessary to create new components
|
|
|
|
let fixture: HTMLElement;
|
|
let env: Env;
|
|
|
|
beforeEach(() => {
|
|
fixture = makeTestFixture();
|
|
env = makeTestEnv();
|
|
Component.env = env;
|
|
});
|
|
|
|
afterEach(() => {
|
|
fixture.remove();
|
|
});
|
|
|
|
describe("class and style attributes with t-component", () => {
|
|
test("class is properly added on widget root el", async () => {
|
|
class Child extends Component {
|
|
static template = xml`<div class="c"/>`;
|
|
}
|
|
class ParentWidget extends Component {
|
|
static template = xml`<div><Child class="a b"/></div>`;
|
|
static components = { Child };
|
|
}
|
|
const widget = new ParentWidget();
|
|
await widget.mount(fixture);
|
|
expect(fixture.innerHTML).toBe(`<div><div class="c a b"></div></div>`);
|
|
});
|
|
|
|
test("empty class attribute is not added on widget root el", async () => {
|
|
class Child extends Component {
|
|
static template = xml`<span/>`;
|
|
}
|
|
class Parent extends Component {
|
|
static template = xml`<div><Child class=""/></div>`;
|
|
static components = { Child };
|
|
}
|
|
const widget = new Parent();
|
|
await widget.mount(fixture);
|
|
expect(fixture.innerHTML).toBe(`<div><span></span></div>`);
|
|
});
|
|
|
|
test("t-att-class is properly added/removed on widget root el", async () => {
|
|
class Child extends Component {
|
|
static template = xml`<div class="c"/>`;
|
|
}
|
|
class ParentWidget extends Component {
|
|
static template = xml`<div><Child t-att-class="{a:state.a, b:state.b}"/></div>`;
|
|
static components = { Child };
|
|
state = useState({ a: true, b: false });
|
|
}
|
|
const widget = new ParentWidget();
|
|
await widget.mount(fixture);
|
|
expect(fixture.innerHTML).toBe(`<div><div class="c a"></div></div>`);
|
|
expect(QWeb.TEMPLATES[ParentWidget.template].fn.toString());
|
|
|
|
widget.state.a = false;
|
|
widget.state.b = true;
|
|
await nextTick();
|
|
expect(fixture.innerHTML).toBe(`<div><div class="c b"></div></div>`);
|
|
});
|
|
|
|
test("class with extra whitespaces", async () => {
|
|
env.qweb.addTemplate(
|
|
"ParentWidget",
|
|
`<div>
|
|
<Child class="a b c d"/>
|
|
</div>`
|
|
);
|
|
class Child extends Component {}
|
|
class ParentWidget extends Component {
|
|
static components = { Child };
|
|
}
|
|
env.qweb.addTemplate("Child", `<div/>`);
|
|
const widget = new ParentWidget();
|
|
await widget.mount(fixture);
|
|
expect(fixture.innerHTML).toBe(`<div><div class="a b c d"></div></div>`);
|
|
});
|
|
|
|
test("t-att-class is properly added/removed on widget root el (v2)", async () => {
|
|
env.qweb.addTemplates(`
|
|
<templates>
|
|
<div t-name="ParentWidget">
|
|
<Child class="a" t-att-class="{ b: state.b }" t-ref="child"/>
|
|
</div>
|
|
<span t-name="Child" class="c" t-att-class="{ d: state.d }"/>
|
|
</templates>`);
|
|
|
|
class Child extends Component {
|
|
state = useState({ d: true });
|
|
}
|
|
class ParentWidget extends Component {
|
|
static components = { Child };
|
|
state = useState({ b: true });
|
|
child = useRef("child");
|
|
}
|
|
const widget = new ParentWidget();
|
|
await widget.mount(fixture);
|
|
|
|
const span = fixture.querySelector("span")!;
|
|
expect(span.className).toBe("c d a b");
|
|
|
|
widget.state.b = false;
|
|
await nextTick();
|
|
expect(span.className).toBe("c d a");
|
|
|
|
(widget.child.comp as Child).state.d = false;
|
|
await nextTick();
|
|
expect(span.className).toBe("c a");
|
|
|
|
widget.state.b = true;
|
|
await nextTick();
|
|
expect(span.className).toBe("c a b");
|
|
|
|
(widget.child.comp as Child).state.d = true;
|
|
await nextTick();
|
|
expect(span.className).toBe("c a b d");
|
|
expect(env.qweb.templates.ParentWidget.fn.toString()).toMatchSnapshot();
|
|
expect(env.qweb.templates.Child.fn.toString()).toMatchSnapshot();
|
|
});
|
|
|
|
test("t-att-class is properly added/removed on widget root el (v3)", async () => {
|
|
env.qweb.addTemplates(`
|
|
<templates>
|
|
<div t-name="ParentWidget">
|
|
<Child class="a" t-att-class="state.b ? 'b' : ''" t-ref="child"/>
|
|
</div>
|
|
<span t-name="Child" class="c" t-att-class="state.d ? 'd' : ''"/>
|
|
</templates>`);
|
|
|
|
class Child extends Component {
|
|
state = useState({ d: true });
|
|
}
|
|
class ParentWidget extends Component {
|
|
static components = { Child };
|
|
state = useState({ b: true });
|
|
child = useRef("child");
|
|
}
|
|
const widget = new ParentWidget();
|
|
await widget.mount(fixture);
|
|
|
|
const span = fixture.querySelector("span")!;
|
|
expect(span.className).toBe("c d a b");
|
|
|
|
widget.state.b = false;
|
|
await nextTick();
|
|
expect(span.className).toBe("c d a");
|
|
|
|
(widget.child.comp as Child).state.d = false;
|
|
await nextTick();
|
|
expect(span.className).toBe("c a");
|
|
|
|
widget.state.b = true;
|
|
await nextTick();
|
|
expect(span.className).toBe("c a b");
|
|
|
|
(widget.child.comp as Child).state.d = true;
|
|
await nextTick();
|
|
expect(span.className).toBe("c a b d");
|
|
expect(env.qweb.templates.ParentWidget.fn.toString()).toMatchSnapshot();
|
|
expect(env.qweb.templates.Child.fn.toString()).toMatchSnapshot();
|
|
});
|
|
|
|
test("class on components do not interfere with user defined classes", async () => {
|
|
env.qweb.addTemplates(`
|
|
<templates>
|
|
<div t-name="App" t-att-class="{ c: state.c }" />
|
|
</templates>`);
|
|
|
|
class App extends Component {
|
|
state = useState({ c: true });
|
|
mounted() {
|
|
this.el!.classList.add("user");
|
|
}
|
|
}
|
|
|
|
const widget = new App();
|
|
await widget.mount(fixture);
|
|
|
|
expect(fixture.innerHTML).toBe('<div class="c user"></div>');
|
|
|
|
widget.state.c = false;
|
|
await nextTick();
|
|
|
|
expect(fixture.innerHTML).toBe('<div class="user"></div>');
|
|
});
|
|
|
|
test("style is properly added on widget root el", async () => {
|
|
env.qweb.addTemplate(
|
|
"ParentWidget",
|
|
`
|
|
<div>
|
|
<t t-component="child" style="font-weight: bold;"/>
|
|
</div>`
|
|
);
|
|
|
|
class SomeComponent extends Component {
|
|
static template = xml`<div/>`;
|
|
}
|
|
|
|
class ParentWidget extends Component {
|
|
static components = { child: SomeComponent };
|
|
}
|
|
const widget = new ParentWidget();
|
|
await widget.mount(fixture);
|
|
expect(fixture.innerHTML).toBe(`<div><div style="font-weight: bold;"></div></div>`);
|
|
});
|
|
|
|
test("dynamic t-att-style is properly added and updated on widget root el", async () => {
|
|
env.qweb.addTemplate(
|
|
"ParentWidget",
|
|
`
|
|
<div>
|
|
<t t-component="child" t-att-style="state.style"/>
|
|
</div>`
|
|
);
|
|
|
|
class SomeComponent extends Component {
|
|
static template = xml`<div/>`;
|
|
}
|
|
|
|
class ParentWidget extends Component {
|
|
static components = { child: SomeComponent };
|
|
state = useState({ style: "font-size: 20px" });
|
|
}
|
|
const widget = new ParentWidget();
|
|
await widget.mount(fixture);
|
|
|
|
expect(env.qweb.templates.ParentWidget.fn.toString()).toMatchSnapshot();
|
|
|
|
expect(fixture.innerHTML).toBe(`<div><div style="font-size: 20px;"></div></div>`);
|
|
|
|
widget.state.style = "font-size: 30px";
|
|
await nextTick();
|
|
|
|
expect(fixture.innerHTML).toBe(`<div><div style="font-size: 30px;"></div></div>`);
|
|
});
|
|
|
|
test("error in subcomponent with class", async () => {
|
|
class Child extends Component {
|
|
static template = xml`<div t-esc="this.will.crash"/>`;
|
|
}
|
|
class ParentWidget extends Component {
|
|
static template = xml`<div><Child class="a"/></div>`;
|
|
static components = { Child };
|
|
}
|
|
const widget = new ParentWidget();
|
|
let error;
|
|
try {
|
|
await widget.mount(fixture);
|
|
} catch (e) {
|
|
error = e;
|
|
}
|
|
expect(error).toBeDefined();
|
|
const regexp = /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g
|
|
expect(error.message).toMatch(regexp);
|
|
expect(fixture.innerHTML).toBe("");
|
|
});
|
|
});
|