mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] re-introduce tests
This commit is contained in:
committed by
Aaron Bohy
parent
d569ea1c28
commit
10df0b5f4a
@@ -832,9 +832,7 @@ describe.skip("mount special cases", () => {
|
||||
// fixture.appendChild(span);
|
||||
// const w = new MyWidget();
|
||||
// await w.mount(div);
|
||||
|
||||
// expect(fixture.innerHTML).toBe("<div><div>Hey</div></div><span></span>");
|
||||
|
||||
// await w.mount(span);
|
||||
// expect(fixture.innerHTML).toBe("<div></div><span><div>Hey</div></span>");
|
||||
});
|
||||
@@ -842,7 +840,6 @@ describe.skip("mount special cases", () => {
|
||||
test("widget can be mounted on different target, another situation", async () => {
|
||||
// const def = makeDeferred();
|
||||
// const steps: string[] = [];
|
||||
|
||||
// class MyWidget extends Component {
|
||||
// static template = xml`<div>Hey</div>`;
|
||||
// async willStart() {
|
||||
@@ -857,14 +854,10 @@ describe.skip("mount special cases", () => {
|
||||
// fixture.appendChild(div);
|
||||
// fixture.appendChild(span);
|
||||
// const w = new MyWidget();
|
||||
|
||||
// w.mount(div).catch(() => steps.push("1 catch"));
|
||||
|
||||
// await nextTick();
|
||||
// expect(fixture.innerHTML).toBe("<div></div><span></span>");
|
||||
|
||||
// w.mount(span).then(() => steps.push("2 resolved"));
|
||||
|
||||
// // we wait two microticks because this is the number of internal promises
|
||||
// // that need to be resolved/rejected, and because we want to prove here
|
||||
// // that the first mount operation is cancelled immediately, and not after
|
||||
@@ -874,7 +867,6 @@ describe.skip("mount special cases", () => {
|
||||
// expect(steps).toEqual([]);
|
||||
// await nextTick();
|
||||
// expect(fixture.innerHTML).toBe("<div></div><span></span>");
|
||||
|
||||
// def.resolve();
|
||||
// await nextTick();
|
||||
// expect(steps).toEqual(["2 resolved"]);
|
||||
@@ -884,7 +876,6 @@ describe.skip("mount special cases", () => {
|
||||
test("component can be mounted on same target, another situation", async () => {
|
||||
// const def = makeDeferred();
|
||||
// const steps: string[] = [];
|
||||
|
||||
// class MyWidget extends Component {
|
||||
// static template = xml`<div>Hey</div>`;
|
||||
// async willStart() {
|
||||
@@ -895,18 +886,13 @@ describe.skip("mount special cases", () => {
|
||||
// }
|
||||
// }
|
||||
// const w = new MyWidget();
|
||||
|
||||
// w.mount(fixture).then(() => steps.push("1 resolved"));
|
||||
|
||||
// await nextTick();
|
||||
// expect(fixture.innerHTML).toBe("");
|
||||
|
||||
// w.mount(fixture).then(() => steps.push("2 resolved"));
|
||||
|
||||
// await nextTick();
|
||||
// expect(steps).toEqual([]);
|
||||
// expect(fixture.innerHTML).toBe("");
|
||||
|
||||
// def.resolve();
|
||||
// await nextTick();
|
||||
// expect(fixture.innerHTML).toBe("<div>Hey</div>");
|
||||
@@ -914,43 +900,41 @@ describe.skip("mount special cases", () => {
|
||||
});
|
||||
|
||||
test("mounting a destroyed widget", async () => {
|
||||
// class MyWidget extends Component {
|
||||
// static template = xml`<div>Hey</div>`;
|
||||
// }
|
||||
// const w = new MyWidget();
|
||||
// w.destroy(); // because, why not
|
||||
|
||||
// let error;
|
||||
// try {
|
||||
// await w.mount(fixture);
|
||||
// } catch (e) {
|
||||
// error = e;
|
||||
// }
|
||||
// expect(scheduler.tasks.length).toBe(0);
|
||||
// expect(error).toBeDefined();
|
||||
// expect(error.message).toBe("Cannot mount a destroyed component");
|
||||
// });
|
||||
|
||||
// test("destroying a sub-component cleans itself from parent's vnode", async () => {
|
||||
// class C1 extends Component {
|
||||
// static template = xml`<div><div><t t-esc="props.a"/></div></div>`;
|
||||
// }
|
||||
// class P extends Component {
|
||||
// static components = { C1 };
|
||||
// static template = xml`<div><div><C1 t-props="state" t-if="state.a"/></div></div>`;
|
||||
// state = {
|
||||
// a: "first",
|
||||
// };
|
||||
// }
|
||||
// const parent = new P();
|
||||
// await parent.mount(fixture);
|
||||
// expect(fixture.textContent).toBe("first");
|
||||
// parent.unmount();
|
||||
// parent.state.a = "";
|
||||
// parent.mount(fixture);
|
||||
// parent.state.a = "fixed";
|
||||
// await parent.render();
|
||||
// expect(fixture.textContent).toBe("fixed");
|
||||
// class MyWidget extends Component {
|
||||
// static template = xml`<div>Hey</div>`;
|
||||
// }
|
||||
// const w = new MyWidget();
|
||||
// w.destroy(); // because, why not
|
||||
// let error;
|
||||
// try {
|
||||
// await w.mount(fixture);
|
||||
// } catch (e) {
|
||||
// error = e;
|
||||
// }
|
||||
// expect(scheduler.tasks.length).toBe(0);
|
||||
// expect(error).toBeDefined();
|
||||
// expect(error.message).toBe("Cannot mount a destroyed component");
|
||||
// });
|
||||
// test("destroying a sub-component cleans itself from parent's vnode", async () => {
|
||||
// class C1 extends Component {
|
||||
// static template = xml`<div><div><t t-esc="props.a"/></div></div>`;
|
||||
// }
|
||||
// class P extends Component {
|
||||
// static components = { C1 };
|
||||
// static template = xml`<div><div><C1 t-props="state" t-if="state.a"/></div></div>`;
|
||||
// state = {
|
||||
// a: "first",
|
||||
// };
|
||||
// }
|
||||
// const parent = new P();
|
||||
// await parent.mount(fixture);
|
||||
// expect(fixture.textContent).toBe("first");
|
||||
// parent.unmount();
|
||||
// parent.state.a = "";
|
||||
// parent.mount(fixture);
|
||||
// parent.state.a = "fixed";
|
||||
// await parent.render();
|
||||
// expect(fixture.textContent).toBe("fixed");
|
||||
});
|
||||
|
||||
test("destroying a sub-component cleans itself from parent's vnode, part 2", async () => {
|
||||
@@ -979,12 +963,10 @@ describe.skip("mount special cases", () => {
|
||||
// class C1 extends Component {
|
||||
// static template = xml`<div><div><t t-esc="props.a"/></div></div>`;
|
||||
// }
|
||||
|
||||
// class C2 extends Component {
|
||||
// static template = xml`<C1 a="props.a"/>`;
|
||||
// static components = { C1 };
|
||||
// }
|
||||
|
||||
// class P extends Component {
|
||||
// static components = { C2 };
|
||||
// static template = xml`<div><div><C2 t-props="state" t-if="state.a"/></div></div>`;
|
||||
@@ -1007,7 +989,6 @@ describe.skip("mount special cases", () => {
|
||||
// class C1 extends Component {
|
||||
// static template = xml`<div><div><t t-esc="props.a"/></div></div>`;
|
||||
// }
|
||||
|
||||
// class C2 extends Component {
|
||||
// static template = xml`<C1 a="props.a"/>`;
|
||||
// static components = { C1 };
|
||||
@@ -1029,4 +1010,4 @@ describe.skip("mount special cases", () => {
|
||||
// await parent.render();
|
||||
// expect(fixture.textContent).toBe("fixedsome text");
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
@@ -74,7 +74,7 @@ describe("event handling", () => {
|
||||
});
|
||||
|
||||
test.skip("t-on with prevent and/or stop modifiers", async () => {
|
||||
/* expect.assertions(7);
|
||||
/* expect.assertions(7);
|
||||
qweb.addTemplate(
|
||||
"test",
|
||||
`<div>
|
||||
|
||||
@@ -938,4 +938,35 @@ describe("lifecycle hooks", () => {
|
||||
expect(mounted).toBe(true);
|
||||
expect(created).toBe(true);
|
||||
});
|
||||
|
||||
test.skip("two different call to mounted/willunmount should work", async () => {
|
||||
/*const steps: string[] = [];
|
||||
function useMyHook(i) {
|
||||
onMounted(() => {
|
||||
steps.push("hook:mounted" + i);
|
||||
});
|
||||
onWillUnmount(() => {
|
||||
steps.push("hook:willunmount" + i);
|
||||
});
|
||||
}
|
||||
class MyComponent extends Component {
|
||||
static template = xml`<div>hey</div>`;
|
||||
constructor() {
|
||||
super();
|
||||
useMyHook(1);
|
||||
useMyHook(2);
|
||||
}
|
||||
}
|
||||
const component = new MyComponent();
|
||||
await component.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div>hey</div>");
|
||||
component.unmount();
|
||||
expect(fixture.innerHTML).toBe("");
|
||||
expect(steps).toEqual([
|
||||
"hook:mounted1",
|
||||
"hook:mounted2",
|
||||
"hook:willunmount2",
|
||||
"hook:willunmount1",
|
||||
]);*/
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
describe.skip("reactivity in lifecycle", () => {
|
||||
test.skip("can use a state hook", async () => {
|
||||
/* class Counter extends Component {
|
||||
static template = xml`<div><t t-esc="counter.value"/></div>`;
|
||||
counter = useState({ value: 42 });
|
||||
}
|
||||
const counter = new Counter();
|
||||
await counter.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div>42</div>");
|
||||
counter.counter.value = 3;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div>3</div>");*/
|
||||
});
|
||||
|
||||
test("state changes in willUnmount do not trigger rerender", async () => {
|
||||
// const steps: string[] = [];
|
||||
|
||||
// class Child extends Component {
|
||||
// static template = xml`
|
||||
// <span><t t-esc="props.val"/><t t-esc="state.n"/></span>
|
||||
@@ -17,7 +29,6 @@ describe.skip("reactivity in lifecycle", () => {
|
||||
// patched() {
|
||||
// steps.push("patched");
|
||||
// }
|
||||
|
||||
// willUnmount() {
|
||||
// steps.push("willUnmount");
|
||||
// this.state.n = 3;
|
||||
@@ -32,7 +43,6 @@ describe.skip("reactivity in lifecycle", () => {
|
||||
// static components = { Child };
|
||||
// state = useState({ val: 1, flag: true });
|
||||
// }
|
||||
|
||||
// const widget = await mount(Parent, { target: fixture });
|
||||
// expect(steps).toEqual(["render"]);
|
||||
// expect(fixture.innerHTML).toBe("<div><span>12</span></div>");
|
||||
@@ -52,7 +62,6 @@ describe.skip("reactivity in lifecycle", () => {
|
||||
// this.state.val = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
// const widget = new TestWidget();
|
||||
// await widget.mount(fixture);
|
||||
// expect(fixture.innerHTML).toBe("<div>1</div>");
|
||||
@@ -78,13 +87,11 @@ describe.skip("reactivity in lifecycle", () => {
|
||||
// }
|
||||
// }
|
||||
// TestWidget.prototype.__render = jest.fn(TestWidget.prototype.__render);
|
||||
|
||||
// const widget = new TestWidget();
|
||||
// widget.state.val = 2;
|
||||
// await widget.mount(fixture);
|
||||
// expect(fixture.innerHTML).toBe("<div>2</div>");
|
||||
// expect(TestWidget.prototype.__render).toHaveBeenCalledTimes(1);
|
||||
|
||||
// // unmount and re-mount, as in this case, willStart won't be called, so it's
|
||||
// // slightly different
|
||||
// widget.unmount();
|
||||
@@ -109,14 +116,12 @@ describe.skip("reactivity in lifecycle", () => {
|
||||
// }
|
||||
// TestWidget.prototype.__render = jest.fn(TestWidget.prototype.__render);
|
||||
// TestWidget.prototype.__patch = jest.fn(TestWidget.prototype.__patch);
|
||||
|
||||
// const widget = new TestWidget();
|
||||
// let prom = widget.mount(fixture);
|
||||
// widget.state.val = 2;
|
||||
// await prom;
|
||||
// expect(fixture.innerHTML).toBe("<div>2</div>");
|
||||
// expect(TestWidget.prototype.__render).toHaveBeenCalledTimes(1);
|
||||
|
||||
// // unmount and re-mount, as in this case, willStart won't be called, so it's
|
||||
// // slightly different
|
||||
// widget.unmount();
|
||||
@@ -134,10 +139,8 @@ describe.skip("reactivity in lifecycle", () => {
|
||||
// static template = xml`<div><t t-esc="state.val"/></div>`;
|
||||
// state = useState({ val: 1 });
|
||||
// }
|
||||
|
||||
// const detachedDiv = document.createElement("div");
|
||||
// const app = await mount(App, { target: detachedDiv });
|
||||
|
||||
// expect(detachedDiv.innerHTML).toBe("<div>1</div>");
|
||||
// app.state.val = 2;
|
||||
// await nextTick();
|
||||
@@ -149,12 +152,9 @@ describe.skip("reactivity in lifecycle", () => {
|
||||
// static template = xml`<div><t t-esc="state.val"/></div>`;
|
||||
// state = useState({ val: 1 });
|
||||
// }
|
||||
|
||||
// const detachedDiv = document.createElement("div");
|
||||
// const app = await mount(App, { target: detachedDiv });
|
||||
|
||||
// expect(detachedDiv.innerHTML).toBe("<div>1</div>");
|
||||
|
||||
// app.destroy();
|
||||
// app.state.val = 2;
|
||||
// await nextTick();
|
||||
@@ -173,24 +173,19 @@ describe.skip("reactivity in lifecycle", () => {
|
||||
// child = this;
|
||||
// }
|
||||
// }
|
||||
|
||||
// class Parent extends Component {
|
||||
// static components = { Child };
|
||||
// static template = xml`<div><t t-esc="state.val"/><Child/></div>`;
|
||||
// state = useState({ val: "P1" });
|
||||
// }
|
||||
|
||||
// const parent = new Parent();
|
||||
// await parent.mount(fixture);
|
||||
// expect(fixture.innerHTML).toBe("<div>P1<span>C1</span></div>");
|
||||
|
||||
// parent.unmount();
|
||||
// expect(fixture.innerHTML).toBe("");
|
||||
|
||||
// parent.state.val = "P2";
|
||||
// child.state.val = "C2";
|
||||
|
||||
// await parent.mount(fixture);
|
||||
// expect(fixture.innerHTML).toBe("<div>P2<span>C2</span></div>");
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
@@ -382,7 +382,7 @@ describe("special cases for some specific html attributes/properties", () => {
|
||||
|
||||
test.skip("textarea with t-att-value", () => {
|
||||
// render input with initial value
|
||||
/* qweb.addTemplate("test", `<textarea t-att-value="v"/>`);
|
||||
/* qweb.addTemplate("test", `<textarea t-att-value="v"/>`);
|
||||
const vnode1 = qweb.render("test", { v: "zucchini" });
|
||||
const vnode2 = patch(document.createElement("textarea"), vnode1);
|
||||
let elm = vnode2.elm as HTMLInputElement;
|
||||
@@ -400,7 +400,7 @@ describe("special cases for some specific html attributes/properties", () => {
|
||||
});
|
||||
|
||||
test.skip("select with t-att-value", () => {
|
||||
/* const template = `
|
||||
/* const template = `
|
||||
<select t-att-value="value">
|
||||
<option value="potato">Potato</option>
|
||||
<option value="tomato">Tomato</option>
|
||||
|
||||
@@ -126,7 +126,7 @@ describe("simple templates, mostly static", () => {
|
||||
|
||||
describe("loading templates", () => {
|
||||
test.skip("can initialize qweb with a string", () => {
|
||||
/* const templates = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
/* const templates = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<div t-name="hey">jupiler</div>
|
||||
</templates>`;
|
||||
@@ -153,3 +153,21 @@ describe("loading templates", () => {
|
||||
expect(Object.keys(qweb.templates)).toEqual([]);*/
|
||||
});
|
||||
});
|
||||
|
||||
describe("global template registration", () => {
|
||||
test.skip("can register template globally", () => {
|
||||
// expect.assertions(5);
|
||||
// let qweb = new QWeb();
|
||||
// try {
|
||||
// qweb.render("mytemplate");
|
||||
// } catch (e) {
|
||||
// expect(e.message).toMatch("Template mytemplate does not exist");
|
||||
// }
|
||||
// expect(qweb.templates.mytemplate).toBeUndefined();
|
||||
// QWeb.registerTemplate("mytemplate", "<div>global</div>");
|
||||
// expect(qweb.templates.mytemplate).toBeDefined();
|
||||
// const vnode = qweb.render("mytemplate");
|
||||
// expect(vnode.sel).toBe("div");
|
||||
// expect((vnode as any).children[0].text).toBe("global");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
describe("properly support svg", () => {
|
||||
test.skip("add proper namespace to svg", () => {
|
||||
// qweb.addTemplate(
|
||||
// "test",
|
||||
// `<svg width="100px" height="90px"><circle cx="50" cy="50" r="4" stroke="green" stroke-width="1" fill="yellow"/> </svg>`
|
||||
// );
|
||||
// expect(renderToString(qweb, "test")).toBe(
|
||||
// `<svg width=\"100px\" height=\"90px\"><circle cx=\"50\" cy=\"50\" r=\"4\" stroke=\"green\" stroke-width=\"1\" fill=\"yellow\"></circle> </svg>`
|
||||
// );
|
||||
});
|
||||
|
||||
test.skip("add proper namespace to g tags", () => {
|
||||
// this is necessary if one wants to use components in a svg
|
||||
// qweb.addTemplate(
|
||||
// "test",
|
||||
// `<g><circle cx="50" cy="50" r="4" stroke="green" stroke-width="1" fill="yellow"/> </g>`
|
||||
// );
|
||||
// expect(renderToString(qweb, "test")).toBe(
|
||||
// `<g><circle cx=\"50\" cy=\"50\" r=\"4\" stroke=\"green\" stroke-width=\"1\" fill=\"yellow\"></circle> </g>`
|
||||
// );
|
||||
});
|
||||
});
|
||||
@@ -15,6 +15,13 @@ describe("t-call (template calling)", () => {
|
||||
expect(context.renderToString("caller")).toBe("<div><span>ok</span></div>");
|
||||
});
|
||||
|
||||
test.skip("t-call, global templates", () => {
|
||||
// QWeb.registerTemplate("abcd", '<div><t t-call="john"/></div>');
|
||||
// qweb.addTemplate("john", `<span>desk</span>`);
|
||||
// const expected = "<div><span>desk</span></div>";
|
||||
// expect(trim(renderToString(qweb, "abcd"))).toBe(expected);
|
||||
});
|
||||
|
||||
test("basic caller, no parent node", () => {
|
||||
const context = new TestContext();
|
||||
context.addTemplate("_basic-callee", `<span>ok</span>`);
|
||||
|
||||
@@ -14,6 +14,21 @@ describe("debugging", () => {
|
||||
console.log = consoleLog;
|
||||
});
|
||||
|
||||
test.skip("t-debug on sub template", () => {
|
||||
// const consoleLog = console.log;
|
||||
// console.log = jest.fn();
|
||||
// qweb.addTemplates(`
|
||||
// <templates>
|
||||
// <p t-name="sub" t-debug="">coucou</p>
|
||||
// <div t-name="test">
|
||||
// <t t-call="sub"/>
|
||||
// </div>
|
||||
// </templates>`);
|
||||
// qweb.render("test");
|
||||
// expect(console.log).toHaveBeenCalledTimes(1);
|
||||
// console.log = consoleLog;
|
||||
});
|
||||
|
||||
test("t-log", () => {
|
||||
const consoleLog = console.log;
|
||||
console.log = jest.fn();
|
||||
|
||||
@@ -23,6 +23,28 @@ describe("t-foreach", () => {
|
||||
expect(renderToString(template)).toBe(expected);
|
||||
});
|
||||
|
||||
test.skip("t-key on t-foreach", async () => {
|
||||
// qweb.addTemplate(
|
||||
// "test",
|
||||
// `
|
||||
// <div>
|
||||
// <t t-foreach="things" t-as="thing" t-key="thing">
|
||||
// <span/>
|
||||
// </t>
|
||||
// </div>`
|
||||
// );
|
||||
// let vnode = qweb.render("test", { things: [1, 2] });
|
||||
// vnode = patch(document.createElement("div"), vnode);
|
||||
// let elm = vnode.elm as HTMLElement;
|
||||
// expect(elm.outerHTML).toBe("<div><span></span><span></span></div>");
|
||||
// const first = elm.querySelectorAll("span")[0];
|
||||
// const second = elm.querySelectorAll("span")[1];
|
||||
// patch(vnode, qweb.render("test", { things: [2, 1] }));
|
||||
// expect(elm.outerHTML).toBe("<div><span></span><span></span></div>");
|
||||
// expect(first).toBe(elm.querySelectorAll("span")[1]);
|
||||
// expect(second).toBe(elm.querySelectorAll("span")[0]);
|
||||
});
|
||||
|
||||
test("simple iteration (in a node)", () => {
|
||||
const template = `
|
||||
<div>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
describe.skip("t-key", () => {
|
||||
test("can use t-key directive on a node", () => {
|
||||
// qweb.addTemplate("test", `<div t-key="beer.id"><t t-esc="beer.name"/></div>`);
|
||||
// expect(renderToString(qweb, "test", { beer: { id: 12, name: "Chimay Rouge" } })).toBe(
|
||||
// "<div>Chimay Rouge</div>"
|
||||
// );
|
||||
});
|
||||
|
||||
test("t-key directive in a list", () => {
|
||||
// qweb.addTemplate(
|
||||
// "test",
|
||||
// `<ul>
|
||||
// <li t-foreach="beers" t-as="beer" t-key="beer.id"><t t-esc="beer.name"/></li>
|
||||
// </ul>`
|
||||
// );
|
||||
// expect(
|
||||
// renderToString(qweb, "test", {
|
||||
// beers: [{ id: 12, name: "Chimay Rouge" }],
|
||||
// })
|
||||
// ).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -447,6 +447,50 @@ describe("observe", () => {
|
||||
obj2.key = 3;
|
||||
expect(n).toBe(1);
|
||||
});
|
||||
|
||||
test.skip("call callback when state is changed", async () => {
|
||||
/* const observer = new Observer();
|
||||
observer.notifyCB = jest.fn();
|
||||
const obj: any = observer.observe({ a: 1, b: { c: 2 }, d: [{ e: 3 }], f: 4 });
|
||||
|
||||
expect(observer.notifyCB).toBeCalledTimes(0);
|
||||
|
||||
obj.a = 2;
|
||||
await nextMicroTick();
|
||||
expect(observer.notifyCB).toBeCalledTimes(1);
|
||||
|
||||
obj.b.c = 3;
|
||||
await nextMicroTick();
|
||||
expect(observer.notifyCB).toBeCalledTimes(2);
|
||||
|
||||
obj.d[0].e = 5;
|
||||
await nextMicroTick();
|
||||
expect(observer.notifyCB).toBeCalledTimes(3);
|
||||
|
||||
obj.a = 111;
|
||||
obj.f = 222;
|
||||
await nextMicroTick();
|
||||
expect(observer.notifyCB).toBeCalledTimes(5);*/
|
||||
});
|
||||
|
||||
test.skip("throw error when state is mutated in object if allowMutation=false", async () => {
|
||||
/*const observer = new Observer();
|
||||
observer.allowMutations = false;
|
||||
const obj: any = observer.observe({ a: 1 });
|
||||
expect(() => {
|
||||
obj.a = 2;
|
||||
}).toThrow('Observed state cannot be changed here! (key: "a", val: "2")');*/
|
||||
});
|
||||
|
||||
test.skip("throw error when state is mutated in array if allowMutation=false", async () => {
|
||||
/* const observer = new Observer();
|
||||
observer.allowMutations = false;
|
||||
const obj: any = observer.observe({ a: [1] });
|
||||
|
||||
expect(() => {
|
||||
obj.a.push(2);
|
||||
}).toThrow('Observed state cannot be changed here! (key: "1", val: "2")');*/
|
||||
});
|
||||
});
|
||||
|
||||
describe("unobserve", () => {
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* We can only make one test per file, since the debug tool modify in place
|
||||
* the owl object in a way that is difficult to undo.
|
||||
*/
|
||||
|
||||
// import { debugOwl } from "../../tools/debug";
|
||||
// import * as owl from "../../src/index";
|
||||
|
||||
// import { Component, Env } from "../../src/component/component";
|
||||
// import { xml } from "../../src/tags";
|
||||
// import { useState } from "../../src/hooks";
|
||||
// import { makeTestFixture, makeTestEnv, nextTick } from "../helpers";
|
||||
|
||||
// let fixture: HTMLElement = makeTestFixture();
|
||||
// let env: Env = makeTestEnv();
|
||||
// Component.env = env;
|
||||
|
||||
// debugOwl(owl, {});
|
||||
|
||||
test.skip("can log full lifecycle", async () => {
|
||||
// const steps: string[] = [];
|
||||
// const log = console.log;
|
||||
// console.log = (arg) => steps.push(arg);
|
||||
// class Child extends Component {
|
||||
// static template = xml`<div>child</div>`;
|
||||
// }
|
||||
// class Parent extends Component {
|
||||
// static template = xml`<div><Child t-if="state.flag"/></div>`;
|
||||
// static components = { Child };
|
||||
// state = useState({ flag: false });
|
||||
// }
|
||||
// const parent = new Parent(null, {});
|
||||
// await parent.mount(fixture);
|
||||
// parent.state.flag = true;
|
||||
// await nextTick();
|
||||
// expect(steps).toEqual([
|
||||
// "[OWL_DEBUG] Parent<id=1> constructor, props={}",
|
||||
// "[OWL_DEBUG] Parent<id=1> mount",
|
||||
// "[OWL_DEBUG] Parent<id=1> willStart",
|
||||
// "[OWL_DEBUG] Parent<id=1> rendering template",
|
||||
// "[OWL_DEBUG] Parent<id=1> mounted",
|
||||
// "[OWL_DEBUG] Parent<id=1> render",
|
||||
// "[OWL_DEBUG] Parent<id=1> rendering template",
|
||||
// "[OWL_DEBUG] Child<id=2> constructor, props={}",
|
||||
// "[OWL_DEBUG] Child<id=2> willStart",
|
||||
// "[OWL_DEBUG] Child<id=2> rendering template",
|
||||
// "[OWL_DEBUG] Parent<id=1> willPatch",
|
||||
// "[OWL_DEBUG] Child<id=2> mounted",
|
||||
// "[OWL_DEBUG] Parent<id=1> patched",
|
||||
// ]);
|
||||
// console.log = log;
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* We can only make one test per file, since the debug tool modify in place
|
||||
* the owl object in a way that is difficult to undo.
|
||||
*/
|
||||
|
||||
// import { debugOwl } from "../../tools/debug";
|
||||
// import * as owl from "../../src/index";
|
||||
|
||||
// import { Component, Env } from "../../src/component/component";
|
||||
// import { xml } from "../../src/tags";
|
||||
// import { makeTestFixture, makeTestEnv } from "../helpers";
|
||||
|
||||
// let fixture: HTMLElement = makeTestFixture();
|
||||
// let env: Env = makeTestEnv();
|
||||
// Component.env = env;
|
||||
|
||||
// debugOwl(owl, { logScheduler: true });
|
||||
|
||||
test.skip("can log scheduler start and stop", async () => {
|
||||
// const steps: string[] = [];
|
||||
// const log = console.log;
|
||||
// console.log = (arg) => steps.push(arg);
|
||||
// class Child extends Component {
|
||||
// static template = xml`<div>child</div>`;
|
||||
// }
|
||||
// class Parent extends Component {
|
||||
// static template = xml`<div><Child /></div>`;
|
||||
// static components = { Child };
|
||||
// }
|
||||
// const parent = new Parent(null, {});
|
||||
// await parent.mount(fixture);
|
||||
// expect(steps).toEqual([
|
||||
// "[OWL_DEBUG] Parent<id=1> constructor, props={}",
|
||||
// "[OWL_DEBUG] Parent<id=1> mount",
|
||||
// "[OWL_DEBUG] Parent<id=1> willStart",
|
||||
// "[OWL_DEBUG] scheduler: start running tasks queue",
|
||||
// "[OWL_DEBUG] Parent<id=1> rendering template",
|
||||
// "[OWL_DEBUG] Child<id=2> constructor, props={}",
|
||||
// "[OWL_DEBUG] Child<id=2> willStart",
|
||||
// "[OWL_DEBUG] Child<id=2> rendering template",
|
||||
// "[OWL_DEBUG] Child<id=2> mounted",
|
||||
// "[OWL_DEBUG] Parent<id=1> mounted",
|
||||
// "[OWL_DEBUG] scheduler: stop running tasks queue",
|
||||
// ]);
|
||||
// console.log = log;
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* We can only make one test per file, since the debug tool modify in place
|
||||
* the owl object in a way that is difficult to undo.
|
||||
*/
|
||||
|
||||
// import { debugOwl } from "../../tools/debug";
|
||||
// import * as owl from "../../src/index";
|
||||
|
||||
// import { Component, Env } from "../../src/component/component";
|
||||
// import { xml } from "../../src/tags";
|
||||
// import { makeTestFixture, makeTestEnv, nextTick } from "../helpers";
|
||||
|
||||
// let fixture: HTMLElement = makeTestFixture();
|
||||
// let env: Env = makeTestEnv();
|
||||
// Component.env = env;
|
||||
|
||||
// debugOwl(owl, { logScheduler: true });
|
||||
|
||||
test.skip("log a specific message for render method calls if component is not mounted", async () => {
|
||||
// const steps: string[] = [];
|
||||
// const log = console.log;
|
||||
// console.log = (arg) => steps.push(arg);
|
||||
// class Parent extends Component {
|
||||
// static template = xml`<div><t t-esc="state.value"/></div>`;
|
||||
// state = owl.hooks.useState({ value: 1 });
|
||||
// }
|
||||
// const parent = new Parent(null, {});
|
||||
// await parent.mount(fixture);
|
||||
// parent.unmount();
|
||||
// parent.state.value = 2;
|
||||
// await nextTick();
|
||||
// expect(steps).toEqual([
|
||||
// "[OWL_DEBUG] Parent<id=1> constructor, props={}",
|
||||
// "[OWL_DEBUG] Parent<id=1> mount",
|
||||
// "[OWL_DEBUG] Parent<id=1> willStart",
|
||||
// "[OWL_DEBUG] scheduler: start running tasks queue",
|
||||
// "[OWL_DEBUG] Parent<id=1> rendering template",
|
||||
// "[OWL_DEBUG] Parent<id=1> mounted",
|
||||
// "[OWL_DEBUG] scheduler: stop running tasks queue",
|
||||
// "[OWL_DEBUG] Parent<id=1> willUnmount",
|
||||
// "[OWL_DEBUG] Parent<id=1> render (warning: component is not mounted)",
|
||||
// "[OWL_DEBUG] scheduler: start running tasks queue",
|
||||
// "[OWL_DEBUG] Parent<id=1> rendering template",
|
||||
// "[OWL_DEBUG] scheduler: stop running tasks queue",
|
||||
// ]);
|
||||
// console.log = log;
|
||||
});
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* We can only make one test per file, since the debug tool modify in place
|
||||
* the owl object in a way that is difficult to undo.
|
||||
*/
|
||||
|
||||
// import { debugOwl } from "../../tools/debug";
|
||||
// import * as owl from "../../src/index";
|
||||
|
||||
// import { Component, Env } from "../../src/component/component";
|
||||
// import { xml } from "../../src/tags";
|
||||
// import { makeTestFixture, makeTestEnv } from "../helpers";
|
||||
|
||||
// let fixture: HTMLElement = makeTestFixture();
|
||||
// let env: Env = makeTestEnv();
|
||||
// Component.env = env;
|
||||
|
||||
// debugOwl(owl, { logScheduler: true });
|
||||
|
||||
test.skip("log a sub component with non stringifiable props", async () => {
|
||||
// const steps: string[] = [];
|
||||
// const log = console.log;
|
||||
// console.log = (arg) => steps.push(arg);
|
||||
// class Child extends Component {
|
||||
// static template = xml`<span><t t-esc="props.obj.val"/></span>`;
|
||||
// }
|
||||
// const circularObject: any = { val: 1 };
|
||||
// circularObject.circularObject = circularObject;
|
||||
// class Parent extends Component {
|
||||
// static template = xml`<div><Child obj="obj"/></div>`;
|
||||
// static components = { Child };
|
||||
// obj = circularObject;
|
||||
// }
|
||||
// const parent = new Parent(null, {});
|
||||
// await parent.mount(fixture);
|
||||
// parent.unmount();
|
||||
// expect(steps).toEqual([
|
||||
// "[OWL_DEBUG] Parent<id=1> constructor, props={}",
|
||||
// "[OWL_DEBUG] Parent<id=1> mount",
|
||||
// "[OWL_DEBUG] Parent<id=1> willStart",
|
||||
// "[OWL_DEBUG] scheduler: start running tasks queue",
|
||||
// "[OWL_DEBUG] Parent<id=1> rendering template",
|
||||
// "[OWL_DEBUG] Child<id=2> constructor, props=<JSON error>",
|
||||
// "[OWL_DEBUG] Child<id=2> willStart",
|
||||
// "[OWL_DEBUG] Child<id=2> rendering template",
|
||||
// "[OWL_DEBUG] Child<id=2> mounted",
|
||||
// "[OWL_DEBUG] Parent<id=1> mounted",
|
||||
// "[OWL_DEBUG] scheduler: stop running tasks queue",
|
||||
// "[OWL_DEBUG] Parent<id=1> willUnmount",
|
||||
// "[OWL_DEBUG] Child<id=2> willUnmount",
|
||||
// ]);
|
||||
// console.log = log;
|
||||
});
|
||||
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* Doc Link Checker
|
||||
*
|
||||
* We define here a test to make sure that there are no dead link in the Owl
|
||||
* documentation.
|
||||
*/
|
||||
// import * as fs from "fs";
|
||||
|
||||
// //--------------------------------------------------------------------------
|
||||
// // Helpers
|
||||
// //--------------------------------------------------------------------------
|
||||
|
||||
// interface MarkDownLink {
|
||||
// name: string;
|
||||
// link: string;
|
||||
// }
|
||||
|
||||
// interface MarkDownSection {
|
||||
// name: string;
|
||||
// slug: string;
|
||||
// }
|
||||
|
||||
// interface FileData {
|
||||
// name: string;
|
||||
// path: string[];
|
||||
// fullName: string;
|
||||
// links: MarkDownLink[];
|
||||
// sections: MarkDownSection[];
|
||||
// }
|
||||
|
||||
// const LINK_REGEXP = /\[([^\[]+)\]\(([^\)]+)\)/g;
|
||||
// const HEADING_REGEXP = /\n(#+\s*)(.*)/g;
|
||||
|
||||
// export function addMardownData(fileData): void {
|
||||
// const sep = fileData.path.length > 0 ? "/" : "";
|
||||
// const fullName = fileData.path.join("/") + sep + fileData.name;
|
||||
// const content = fs.readFileSync(fullName, { encoding: "utf8" });
|
||||
// let m;
|
||||
// // get links info
|
||||
// do {
|
||||
// m = LINK_REGEXP.exec(content);
|
||||
// if (m) {
|
||||
// fileData.links.push({ name: m[0], link: m[2] });
|
||||
// }
|
||||
// } while (m);
|
||||
// // get sections info
|
||||
// do {
|
||||
// m = HEADING_REGEXP.exec(content);
|
||||
// if (m) {
|
||||
// fileData.sections.push({ name: m[0], slug: slugify(m[2]) });
|
||||
// }
|
||||
// } while (m);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Returns a list of FileData corresponding to all files that need to be
|
||||
// * validated.
|
||||
// */
|
||||
// function getFiles(path: string[] = []): FileData[] {
|
||||
// if (path.length === 0) {
|
||||
// const baseFiles: FileData[] = [
|
||||
// { name: "README.md", path: [], links: [], sections: [], fullName: "README.md" },
|
||||
// { name: "roadmap.md", path: [], links: [], sections: [], fullName: "roadmap.md" },
|
||||
// ];
|
||||
// const rest = getFiles(["doc"]);
|
||||
// const result = baseFiles.concat(rest);
|
||||
// result.forEach(addMardownData);
|
||||
// return result;
|
||||
// }
|
||||
// const files = fs.readdirSync(path.join("/"), { withFileTypes: true }).map((f) => {
|
||||
// if (f.isDirectory()) {
|
||||
// return getFiles(path.concat(f.name));
|
||||
// }
|
||||
// const fullName = path.join("/") + (path.length > 0 ? "/" : "") + f.name;
|
||||
// return [
|
||||
// {
|
||||
// name: f.name,
|
||||
// path,
|
||||
// links: [],
|
||||
// sections: [],
|
||||
// fullName,
|
||||
// },
|
||||
// ];
|
||||
// });
|
||||
// return Array.prototype.concat(...files);
|
||||
// }
|
||||
|
||||
// const LOCAL_FILES = ["LICENSE", "tools/debug.js"];
|
||||
// export function isLinkValid(link: MarkDownLink, current: FileData, files: FileData[]): boolean {
|
||||
// if (link.link.startsWith("http")) {
|
||||
// // no check on external links
|
||||
// return true;
|
||||
// }
|
||||
// // Step 1: extract path, name, hash
|
||||
// // path = ['doc', 'architecture]
|
||||
// // name = 'rendering.md'
|
||||
// // hash = 'blabla' (or '' if no hash)
|
||||
|
||||
// const parts = link.link.split("#");
|
||||
// const hash = parts[1] || "";
|
||||
// let name;
|
||||
// let path;
|
||||
// if (parts[0]) {
|
||||
// let temp = parts[0].split("/");
|
||||
// name = temp[temp.length - 1];
|
||||
// temp.splice(-1);
|
||||
// path = current.path.slice();
|
||||
// for (let elem of temp) {
|
||||
// if (elem === "..") {
|
||||
// path.splice(-1);
|
||||
// } else if (elem !== ".") {
|
||||
// path.push(elem);
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // there are no file name, so this is a relative link to the current file
|
||||
// name = current.name;
|
||||
// path = current.path;
|
||||
// }
|
||||
|
||||
// // Step 2: build normalized link file name
|
||||
// const linkFullName = path.join("/") + (path.length > 0 ? "/" : "") + name;
|
||||
|
||||
// // Step 3: check link name against white list of local files
|
||||
// if (LOCAL_FILES.includes(linkFullName)) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// // Step 4: check if there is a matching file
|
||||
// let target: FileData | undefined = files.find((f) => f.fullName === linkFullName);
|
||||
// if (!target) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// // Step 5: if necessary, check if there is a corresponding link inside the target
|
||||
// // link name
|
||||
// if (hash) {
|
||||
// if (!target.sections.find((s) => s.slug === hash)) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// // adapted from https://medium.com/@mhagemann/the-ultimate-way-to-slugify-a-url-string-in-javascript-b8e4a0d849e1
|
||||
// function slugify(str) {
|
||||
// const a = "àáäâãåăæçèéëêǵḧìíïîḿńǹñòóöôœøṕŕßśșțùúüûǘẃẍÿź·_,:;";
|
||||
// const b = "aaaaaaaaceeeeghiiiimnnnooooooprssstuuuuuwxyz-----";
|
||||
// const p = new RegExp(a.split("").join("|"), "g");
|
||||
// return str
|
||||
// .toString()
|
||||
// .toLowerCase()
|
||||
// .replace(/\//g, "") // remove /
|
||||
// .replace(/\s+/g, "-") // Replace spaces with -
|
||||
// .replace(p, (c) => b.charAt(a.indexOf(c))) // Replace special characters
|
||||
// .replace(/&/g, "-and-") // Replace & with ‘and’
|
||||
// .replace(/[^\w\-]+/g, "") // Remove all non-word characters
|
||||
// .replace(/\-\-+/g, "-") // Replace multiple - with single -
|
||||
// .replace(/^-+/, "") // Trim - from start of text
|
||||
// .replace(/-+$/, ""); // Trim - from end of text
|
||||
// }
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Test
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
test.skip("All markdown links work", () => {
|
||||
// let linkNumber = 0;
|
||||
// let invalidLinkNumber = 0;
|
||||
// const data = getFiles();
|
||||
// for (let file of data) {
|
||||
// for (let link of file.links) {
|
||||
// linkNumber++;
|
||||
// if (!isLinkValid(link, file, data)) {
|
||||
// console.warn(`Invalid Link: "${link.name}" in "${file.name}"`);
|
||||
// invalidLinkNumber++;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// expect(invalidLinkNumber).toBe(0);
|
||||
// expect(linkNumber).toBeGreaterThan(10);
|
||||
});
|
||||
Reference in New Issue
Block a user