mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[REF] tests: move properties tests in own file
This commit is contained in:
committed by
Sam Degueldre
parent
a35b9814c0
commit
f0fb3ab64e
@@ -146,58 +146,3 @@ test("class attribute (with a preexisting value", async () => {
|
|||||||
expect(fixture.innerHTML).toBe(`<div class="tomato"></div>`);
|
expect(fixture.innerHTML).toBe(`<div class="tomato"></div>`);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("properties", () => {
|
|
||||||
test("input with value attribute", () => {
|
|
||||||
// render input with initial value
|
|
||||||
const block = createBlock(`<input block-attribute-0="value"/>`);
|
|
||||||
|
|
||||||
const tree = block(["zucchini"]);
|
|
||||||
mount(tree, fixture);
|
|
||||||
// const bnode1 = renderToBdom(template, { v: "zucchini" });
|
|
||||||
// const fixture = makeTestFixture();
|
|
||||||
// mount(bnode1, fixture);
|
|
||||||
const input = fixture.querySelector("input")!;
|
|
||||||
expect(input.value).toBe("zucchini");
|
|
||||||
|
|
||||||
// change value manually in input, to simulate user input
|
|
||||||
input.value = "tomato";
|
|
||||||
expect(input.value).toBe("tomato");
|
|
||||||
|
|
||||||
// rerender with a different value, and patch actual dom, to check that
|
|
||||||
// input value was properly reset by owl
|
|
||||||
patch(tree, block(["potato"]));
|
|
||||||
expect(input.value).toBe("potato");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("input with value attribute, and falsy value given", () => {
|
|
||||||
const block = createBlock(`<input block-attribute-0="value"/>`);
|
|
||||||
|
|
||||||
const tree = block([undefined]);
|
|
||||||
mount(tree, fixture);
|
|
||||||
const input = fixture.querySelector("input")!;
|
|
||||||
expect(input.value).toBe("");
|
|
||||||
|
|
||||||
patch(tree, block([null]));
|
|
||||||
expect(input.value).toBe("");
|
|
||||||
|
|
||||||
patch(tree, block([0]));
|
|
||||||
expect(input.value).toBe("0");
|
|
||||||
|
|
||||||
patch(tree, block([""]));
|
|
||||||
expect(input.value).toBe("");
|
|
||||||
|
|
||||||
patch(tree, block([false]));
|
|
||||||
expect(input.value).toBe("");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("input type=checkbox with checked attribute", () => {
|
|
||||||
// render input with initial value
|
|
||||||
const block = createBlock(`<input type="checkbox" block-attribute-0="checked"/>`);
|
|
||||||
|
|
||||||
const tree = block([true]);
|
|
||||||
mount(tree, fixture);
|
|
||||||
expect(fixture.innerHTML).toBe(`<input type="checkbox">`);
|
|
||||||
const input = fixture.querySelector("input")!;
|
|
||||||
expect(input.checked).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
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("input with value attribute", () => {
|
||||||
|
// render input with initial value
|
||||||
|
const block = createBlock(`<input block-attribute-0="value"/>`);
|
||||||
|
|
||||||
|
const tree = block(["zucchini"]);
|
||||||
|
mount(tree, fixture);
|
||||||
|
// const bnode1 = renderToBdom(template, { v: "zucchini" });
|
||||||
|
// const fixture = makeTestFixture();
|
||||||
|
// mount(bnode1, fixture);
|
||||||
|
const input = fixture.querySelector("input")!;
|
||||||
|
expect(input.value).toBe("zucchini");
|
||||||
|
|
||||||
|
// change value manually in input, to simulate user input
|
||||||
|
input.value = "tomato";
|
||||||
|
expect(input.value).toBe("tomato");
|
||||||
|
|
||||||
|
// rerender with a different value, and patch actual dom, to check that
|
||||||
|
// input value was properly reset by owl
|
||||||
|
patch(tree, block(["potato"]));
|
||||||
|
expect(input.value).toBe("potato");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("input with value attribute, and falsy value given", () => {
|
||||||
|
const block = createBlock(`<input block-attribute-0="value"/>`);
|
||||||
|
|
||||||
|
const tree = block([undefined]);
|
||||||
|
mount(tree, fixture);
|
||||||
|
const input = fixture.querySelector("input")!;
|
||||||
|
expect(input.value).toBe("");
|
||||||
|
|
||||||
|
patch(tree, block([null]));
|
||||||
|
expect(input.value).toBe("");
|
||||||
|
|
||||||
|
patch(tree, block([0]));
|
||||||
|
expect(input.value).toBe("0");
|
||||||
|
|
||||||
|
patch(tree, block([""]));
|
||||||
|
expect(input.value).toBe("");
|
||||||
|
|
||||||
|
patch(tree, block([false]));
|
||||||
|
expect(input.value).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("input type=checkbox with checked attribute", () => {
|
||||||
|
// render input with initial value
|
||||||
|
const block = createBlock(`<input type="checkbox" block-attribute-0="checked"/>`);
|
||||||
|
|
||||||
|
const tree = block([true]);
|
||||||
|
mount(tree, fixture);
|
||||||
|
expect(fixture.innerHTML).toBe(`<input type="checkbox">`);
|
||||||
|
const input = fixture.querySelector("input")!;
|
||||||
|
expect(input.checked).toBe(true);
|
||||||
|
});
|
||||||
@@ -28,20 +28,6 @@ exports[`attributes changing a class with t-att-class 1`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`attributes changing an attribute with t-att- 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<div block-attribute-0=\\"value\\"/>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let attr1 = ctx['v'];
|
|
||||||
return block1([attr1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`attributes class and t-att-class should combine together 1`] = `
|
exports[`attributes class and t-att-class should combine together 1`] = `
|
||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
@@ -238,62 +224,6 @@ exports[`attributes dynamic formatted attributes with a dash 1`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`attributes dynamic input value: falsy values 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let attr1 = new String((0) === 0 ? 0 : ((0) || \\"\\"));
|
|
||||||
return block1([attr1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`attributes dynamic input value: falsy values 2`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let attr1 = new String((false) === 0 ? 0 : ((false) || \\"\\"));
|
|
||||||
return block1([attr1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`attributes dynamic input value: falsy values 3`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let attr1 = new String((undefined) === 0 ? 0 : ((undefined) || \\"\\"));
|
|
||||||
return block1([attr1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`attributes dynamic input value: falsy values 4`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let attr1 = new String(('') === 0 ? 0 : (('') || \\"\\"));
|
|
||||||
return block1([attr1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`attributes dynamic undefined class attribute 1`] = `
|
exports[`attributes dynamic undefined class attribute 1`] = `
|
||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
@@ -777,20 +707,6 @@ exports[`attributes updating classes (with obj notation) 1`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`attributes updating property with falsy value 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let attr1 = new String((ctx['v']) === 0 ? 0 : ((ctx['v']) || \\"\\"));
|
|
||||||
return block1([attr1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`attributes various escapes 1`] = `
|
exports[`attributes various escapes 1`] = `
|
||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
@@ -819,114 +735,3 @@ exports[`attributes various escapes 2 1`] = `
|
|||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`special cases for some specific html attributes/properties input of type checkbox with t-att-indeterminate 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<input type=\\"checkbox\\" block-attribute-0=\\"indeterminate\\"/>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let attr1 = new Boolean(ctx['v']);
|
|
||||||
return block1([attr1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`special cases for some specific html attributes/properties input type= checkbox, with t-att-checked 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<input type=\\"checkbox\\" block-attribute-0=\\"checked\\"/>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let attr1 = new Boolean(ctx['flag']);
|
|
||||||
return block1([attr1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`special cases for some specific html attributes/properties input with t-att-value (patching with same value 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let attr1 = new String((ctx['v']) === 0 ? 0 : ((ctx['v']) || \\"\\"));
|
|
||||||
return block1([attr1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`special cases for some specific html attributes/properties input with t-att-value 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let attr1 = new String((ctx['v']) === 0 ? 0 : ((ctx['v']) || \\"\\"));
|
|
||||||
return block1([attr1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`special cases for some specific html attributes/properties input, type checkbox, with t-att-checked (patching with same value 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<input type=\\"checkbox\\" block-attribute-0=\\"checked\\"/>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let attr1 = new Boolean(ctx['v']);
|
|
||||||
return block1([attr1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`special cases for some specific html attributes/properties select with t-att-value 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<select block-attribute-0=\\"value\\"><option value=\\"potato\\">Potato</option><option value=\\"tomato\\">Tomato</option><option value=\\"onion\\">Onion</option></select>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let attr1 = new String((ctx['value']) === 0 ? 0 : ((ctx['value']) || \\"\\"));
|
|
||||||
return block1([attr1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`special cases for some specific html attributes/properties textarea with t-att-value 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<textarea block-attribute-0=\\"value\\"/>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let attr1 = new String((ctx['v']) === 0 ? 0 : ((ctx['v']) || \\"\\"));
|
|
||||||
return block1([attr1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`special cases for some specific html attributes/properties various boolean html attributes 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><input type=\\"checkbox\\" checked=\\"checked\\"/><input checked=\\"checked\\"/><div checked=\\"checked\\"/><div selected=\\"selected\\"/><option selected=\\"selected\\" other=\\"1\\"/><input readonly=\\"readonly\\"/><button disabled=\\"disabled\\"/></div>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
return block1();
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|||||||
@@ -0,0 +1,196 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`changing an attribute with t-att- 1`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<div block-attribute-0=\\"value\\"/>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let attr1 = ctx['v'];
|
||||||
|
return block1([attr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`dynamic input value: falsy values 1`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let attr1 = new String((0) === 0 ? 0 : ((0) || \\"\\"));
|
||||||
|
return block1([attr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`dynamic input value: falsy values 2`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let attr1 = new String((false) === 0 ? 0 : ((false) || \\"\\"));
|
||||||
|
return block1([attr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`dynamic input value: falsy values 3`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let attr1 = new String((undefined) === 0 ? 0 : ((undefined) || \\"\\"));
|
||||||
|
return block1([attr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`dynamic input value: falsy values 4`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let attr1 = new String(('') === 0 ? 0 : (('') || \\"\\"));
|
||||||
|
return block1([attr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`input of type checkbox with t-att-indeterminate 1`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<input type=\\"checkbox\\" block-attribute-0=\\"indeterminate\\"/>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let attr1 = new Boolean(ctx['v']);
|
||||||
|
return block1([attr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`input type= checkbox, with t-att-checked 1`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<input type=\\"checkbox\\" block-attribute-0=\\"checked\\"/>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let attr1 = new Boolean(ctx['flag']);
|
||||||
|
return block1([attr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`input with t-att-value (patching with same value 1`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let attr1 = new String((ctx['v']) === 0 ? 0 : ((ctx['v']) || \\"\\"));
|
||||||
|
return block1([attr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`input with t-att-value 1`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let attr1 = new String((ctx['v']) === 0 ? 0 : ((ctx['v']) || \\"\\"));
|
||||||
|
return block1([attr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`input, type checkbox, with t-att-checked (patching with same value 1`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<input type=\\"checkbox\\" block-attribute-0=\\"checked\\"/>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let attr1 = new Boolean(ctx['v']);
|
||||||
|
return block1([attr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`select with t-att-value 1`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<select block-attribute-0=\\"value\\"><option value=\\"potato\\">Potato</option><option value=\\"tomato\\">Tomato</option><option value=\\"onion\\">Onion</option></select>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let attr1 = new String((ctx['value']) === 0 ? 0 : ((ctx['value']) || \\"\\"));
|
||||||
|
return block1([attr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`textarea with t-att-value 1`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<textarea block-attribute-0=\\"value\\"/>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let attr1 = new String((ctx['v']) === 0 ? 0 : ((ctx['v']) || \\"\\"));
|
||||||
|
return block1([attr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`updating property with falsy value 1`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<input block-attribute-0=\\"value\\"/>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
let attr1 = new String((ctx['v']) === 0 ? 0 : ((ctx['v']) || \\"\\"));
|
||||||
|
return block1([attr1]);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`various boolean html attributes 1`] = `
|
||||||
|
"function anonymous(app, bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
|
let block1 = createBlock(\`<div><input type=\\"checkbox\\" checked=\\"checked\\"/><input checked=\\"checked\\"/><div checked=\\"checked\\"/><div selected=\\"selected\\"/><option selected=\\"selected\\" other=\\"1\\"/><input readonly=\\"readonly\\"/><button disabled=\\"disabled\\"/></div>\`);
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return block1();
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
@@ -315,62 +315,6 @@ describe("attributes", () => {
|
|||||||
).toBe('<div class="a b d"></div>');
|
).toBe('<div class="a b d"></div>');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("changing an attribute with t-att-", () => {
|
|
||||||
// render input with initial value
|
|
||||||
const template = `<div t-att-value="v"/>`;
|
|
||||||
const bnode1 = renderToBdom(template, { v: "zucchini" });
|
|
||||||
const fixture = makeTestFixture();
|
|
||||||
mount(bnode1, fixture);
|
|
||||||
|
|
||||||
expect(fixture.innerHTML).toBe('<div value="zucchini"></div>');
|
|
||||||
|
|
||||||
const bnode2 = renderToBdom(template, { v: "potato" });
|
|
||||||
patch(bnode1, bnode2);
|
|
||||||
expect(fixture.innerHTML).toBe('<div value="potato"></div>');
|
|
||||||
|
|
||||||
const bnode3 = renderToBdom(template, { v: "" });
|
|
||||||
patch(bnode1, bnode3);
|
|
||||||
// not sure about this. maybe we want to remove the attribute?
|
|
||||||
expect(fixture.innerHTML).toBe('<div value=""></div>');
|
|
||||||
});
|
|
||||||
|
|
||||||
test("dynamic input value: falsy values", () => {
|
|
||||||
// 0 doesn't fall back to empty string
|
|
||||||
expect(renderToBdom(`<input t-att-value="0"/>`)).toEqual({ data: [new String("0")] });
|
|
||||||
expect(renderToBdom(`<input t-att-value="false"/>`)).toEqual({ data: [new String("")] });
|
|
||||||
expect(renderToBdom(`<input t-att-value="undefined"/>`)).toEqual({ data: [new String("")] });
|
|
||||||
expect(renderToBdom(`<input t-att-value="''"/>`)).toEqual({ data: [new String("")] });
|
|
||||||
});
|
|
||||||
|
|
||||||
test("updating property with falsy value", async () => {
|
|
||||||
// render input with initial value
|
|
||||||
const template = `<input t-att-value="v"></input>`;
|
|
||||||
const bnode1 = renderToBdom(template, { v: false });
|
|
||||||
const fixture = makeTestFixture();
|
|
||||||
mount(bnode1, fixture);
|
|
||||||
|
|
||||||
const input = fixture.querySelector("input")!;
|
|
||||||
expect(input.value).toBe("");
|
|
||||||
|
|
||||||
patch(bnode1, renderToBdom(template, { v: "owl" }));
|
|
||||||
expect(input.value).toBe("owl");
|
|
||||||
|
|
||||||
patch(bnode1, renderToBdom(template, { v: false }));
|
|
||||||
expect(input.value).toBe("");
|
|
||||||
|
|
||||||
patch(bnode1, renderToBdom(template, { v: "owl" }));
|
|
||||||
expect(input.value).toBe("owl");
|
|
||||||
|
|
||||||
patch(bnode1, renderToBdom(template, { v: undefined }));
|
|
||||||
expect(input.value).toBe("");
|
|
||||||
|
|
||||||
patch(bnode1, renderToBdom(template, { v: "owl" }));
|
|
||||||
expect(input.value).toBe("owl");
|
|
||||||
|
|
||||||
patch(bnode1, renderToBdom(template, { v: null }));
|
|
||||||
expect(input.value).toBe("");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("changing a class with t-att-class", () => {
|
test("changing a class with t-att-class", () => {
|
||||||
// render input with initial value
|
// render input with initial value
|
||||||
const template = `<div t-att-class="v"/>`;
|
const template = `<div t-att-class="v"/>`;
|
||||||
@@ -428,134 +372,3 @@ describe("attributes", () => {
|
|||||||
expect(fixture.innerHTML).toBe('<div class="hoy a b"></div>');
|
expect(fixture.innerHTML).toBe('<div class="hoy a b"></div>');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("special cases for some specific html attributes/properties", () => {
|
|
||||||
test("input type= checkbox, with t-att-checked", () => {
|
|
||||||
const template = `<input type="checkbox" t-att-checked="flag"/>`;
|
|
||||||
const result = renderToString(template, { flag: true });
|
|
||||||
expect(result).toBe(`<input type="checkbox">`);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("various boolean html attributes", () => {
|
|
||||||
// will cause the template to be snapshotted
|
|
||||||
renderToString(`
|
|
||||||
<div>
|
|
||||||
<input type="checkbox" checked="checked"/>
|
|
||||||
<input checked="checked"/>
|
|
||||||
<div checked="checked"/>
|
|
||||||
<div selected="selected"/>
|
|
||||||
<option selected="selected" other="1"/>
|
|
||||||
<input readonly="readonly"/>
|
|
||||||
<button disabled="disabled"/>
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("input with t-att-value", () => {
|
|
||||||
// render input with initial value
|
|
||||||
const template = `<input t-att-value="v"/>`;
|
|
||||||
const bnode1 = renderToBdom(template, { v: "zucchini" });
|
|
||||||
const fixture = makeTestFixture();
|
|
||||||
mount(bnode1, fixture);
|
|
||||||
const input = fixture.querySelector("input")!;
|
|
||||||
expect(input.value).toBe("zucchini");
|
|
||||||
|
|
||||||
// change value manually in input, to simulate user input
|
|
||||||
input.value = "tomato";
|
|
||||||
expect(input.value).toBe("tomato");
|
|
||||||
|
|
||||||
// rerender with a different value, and patch actual dom, to check that
|
|
||||||
// input value was properly reset by owl
|
|
||||||
const bnode2 = renderToBdom(template, { v: "potato" });
|
|
||||||
patch(bnode1, bnode2);
|
|
||||||
expect(input.value).toBe("potato");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("input with t-att-value (patching with same value", () => {
|
|
||||||
// render input with initial value
|
|
||||||
const template = `<input t-att-value="v"/>`;
|
|
||||||
const bnode1 = renderToBdom(template, { v: "zucchini" });
|
|
||||||
const fixture = makeTestFixture();
|
|
||||||
mount(bnode1, fixture);
|
|
||||||
const input = fixture.querySelector("input")!;
|
|
||||||
expect(input.value).toBe("zucchini");
|
|
||||||
|
|
||||||
// change value manually in input, to simulate user input
|
|
||||||
input.value = "tomato";
|
|
||||||
expect(input.value).toBe("tomato");
|
|
||||||
|
|
||||||
const bnode2 = renderToBdom(template, { v: "zucchini" });
|
|
||||||
patch(bnode1, bnode2);
|
|
||||||
expect(input.value).toBe("zucchini");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("input, type checkbox, with t-att-checked (patching with same value", () => {
|
|
||||||
// render input with initial value
|
|
||||||
const template = `<input type="checkbox" t-att-checked="v"/>`;
|
|
||||||
const bnode1 = renderToBdom(template, { v: true });
|
|
||||||
const fixture = makeTestFixture();
|
|
||||||
mount(bnode1, fixture);
|
|
||||||
const input = fixture.querySelector("input")!;
|
|
||||||
expect(input.checked).toBe(true);
|
|
||||||
|
|
||||||
// change checked manually in input, to simulate user input
|
|
||||||
input.checked = false;
|
|
||||||
expect(input.checked).toBe(false);
|
|
||||||
|
|
||||||
const bnode2 = renderToBdom(template, { v: true });
|
|
||||||
patch(bnode1, bnode2);
|
|
||||||
expect(input.checked).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("input of type checkbox with t-att-indeterminate", () => {
|
|
||||||
const template = `<input type="checkbox" t-att-indeterminate="v"/>`;
|
|
||||||
const bnode1 = renderToBdom(template, { v: true });
|
|
||||||
const fixture = makeTestFixture();
|
|
||||||
mount(bnode1, fixture);
|
|
||||||
const input = fixture.querySelector("input")!;
|
|
||||||
expect(input.indeterminate).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("textarea with t-att-value", () => {
|
|
||||||
// render textarea with initial value
|
|
||||||
const template = `<textarea t-att-value="v"/>`;
|
|
||||||
const bnode1 = renderToBdom(template, { v: "zucchini" });
|
|
||||||
const fixture = makeTestFixture();
|
|
||||||
mount(bnode1, fixture);
|
|
||||||
const elm = fixture.querySelector("textarea")!;
|
|
||||||
expect(elm.value).toBe("zucchini");
|
|
||||||
|
|
||||||
// change value manually in textarea, to simulate user textarea
|
|
||||||
elm.value = "tomato";
|
|
||||||
expect(elm.value).toBe("tomato");
|
|
||||||
|
|
||||||
// rerender with a different value, and patch actual dom, to check that
|
|
||||||
// textarea value was properly reset by owl
|
|
||||||
const bnode2 = renderToBdom(template, { v: "potato" });
|
|
||||||
patch(bnode1, bnode2);
|
|
||||||
expect(elm.value).toBe("potato");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("select with t-att-value", () => {
|
|
||||||
const template = `
|
|
||||||
<select t-att-value="value">
|
|
||||||
<option value="potato">Potato</option>
|
|
||||||
<option value="tomato">Tomato</option>
|
|
||||||
<option value="onion">Onion</option>
|
|
||||||
</select>`;
|
|
||||||
const bnode1 = renderToBdom(template, { value: "tomato" });
|
|
||||||
const fixture = makeTestFixture();
|
|
||||||
mount(bnode1, fixture);
|
|
||||||
const elm = fixture.querySelector("select")!;
|
|
||||||
expect(elm.value).toBe("tomato");
|
|
||||||
|
|
||||||
elm.value = "potato";
|
|
||||||
expect(elm.value).toBe("potato");
|
|
||||||
|
|
||||||
// rerender with a different value, and patch actual dom, to check that
|
|
||||||
// select value was properly reset by owl
|
|
||||||
const bnode2 = renderToBdom(template, { value: "onion" });
|
|
||||||
patch(bnode1, bnode2);
|
|
||||||
expect(elm.value).toBe("onion");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -0,0 +1,189 @@
|
|||||||
|
import { mount, patch } from "../../src/runtime/blockdom";
|
||||||
|
import { makeTestFixture, renderToBdom, renderToString, snapshotEverything } from "../helpers";
|
||||||
|
|
||||||
|
snapshotEverything();
|
||||||
|
test("changing an attribute with t-att-", () => {
|
||||||
|
// render input with initial value
|
||||||
|
const template = `<div t-att-value="v"/>`;
|
||||||
|
const bnode1 = renderToBdom(template, { v: "zucchini" });
|
||||||
|
const fixture = makeTestFixture();
|
||||||
|
mount(bnode1, fixture);
|
||||||
|
|
||||||
|
expect(fixture.innerHTML).toBe('<div value="zucchini"></div>');
|
||||||
|
|
||||||
|
const bnode2 = renderToBdom(template, { v: "potato" });
|
||||||
|
patch(bnode1, bnode2);
|
||||||
|
expect(fixture.innerHTML).toBe('<div value="potato"></div>');
|
||||||
|
|
||||||
|
const bnode3 = renderToBdom(template, { v: "" });
|
||||||
|
patch(bnode1, bnode3);
|
||||||
|
// not sure about this. maybe we want to remove the attribute?
|
||||||
|
expect(fixture.innerHTML).toBe('<div value=""></div>');
|
||||||
|
});
|
||||||
|
|
||||||
|
test("dynamic input value: falsy values", () => {
|
||||||
|
// 0 doesn't fall back to empty string
|
||||||
|
expect(renderToBdom(`<input t-att-value="0"/>`)).toEqual({ data: [new String("0")] });
|
||||||
|
expect(renderToBdom(`<input t-att-value="false"/>`)).toEqual({ data: [new String("")] });
|
||||||
|
expect(renderToBdom(`<input t-att-value="undefined"/>`)).toEqual({ data: [new String("")] });
|
||||||
|
expect(renderToBdom(`<input t-att-value="''"/>`)).toEqual({ data: [new String("")] });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("updating property with falsy value", async () => {
|
||||||
|
// render input with initial value
|
||||||
|
const template = `<input t-att-value="v"></input>`;
|
||||||
|
const bnode1 = renderToBdom(template, { v: false });
|
||||||
|
const fixture = makeTestFixture();
|
||||||
|
mount(bnode1, fixture);
|
||||||
|
|
||||||
|
const input = fixture.querySelector("input")!;
|
||||||
|
expect(input.value).toBe("");
|
||||||
|
|
||||||
|
patch(bnode1, renderToBdom(template, { v: "owl" }));
|
||||||
|
expect(input.value).toBe("owl");
|
||||||
|
|
||||||
|
patch(bnode1, renderToBdom(template, { v: false }));
|
||||||
|
expect(input.value).toBe("");
|
||||||
|
|
||||||
|
patch(bnode1, renderToBdom(template, { v: "owl" }));
|
||||||
|
expect(input.value).toBe("owl");
|
||||||
|
|
||||||
|
patch(bnode1, renderToBdom(template, { v: undefined }));
|
||||||
|
expect(input.value).toBe("");
|
||||||
|
|
||||||
|
patch(bnode1, renderToBdom(template, { v: "owl" }));
|
||||||
|
expect(input.value).toBe("owl");
|
||||||
|
|
||||||
|
patch(bnode1, renderToBdom(template, { v: null }));
|
||||||
|
expect(input.value).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test("input type= checkbox, with t-att-checked", () => {
|
||||||
|
const template = `<input type="checkbox" t-att-checked="flag"/>`;
|
||||||
|
const result = renderToString(template, { flag: true });
|
||||||
|
expect(result).toBe(`<input type="checkbox">`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("various boolean html attributes", () => {
|
||||||
|
// will cause the template to be snapshotted
|
||||||
|
renderToString(`
|
||||||
|
<div>
|
||||||
|
<input type="checkbox" checked="checked"/>
|
||||||
|
<input checked="checked"/>
|
||||||
|
<div checked="checked"/>
|
||||||
|
<div selected="selected"/>
|
||||||
|
<option selected="selected" other="1"/>
|
||||||
|
<input readonly="readonly"/>
|
||||||
|
<button disabled="disabled"/>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("input with t-att-value", () => {
|
||||||
|
// render input with initial value
|
||||||
|
const template = `<input t-att-value="v"/>`;
|
||||||
|
const bnode1 = renderToBdom(template, { v: "zucchini" });
|
||||||
|
const fixture = makeTestFixture();
|
||||||
|
mount(bnode1, fixture);
|
||||||
|
const input = fixture.querySelector("input")!;
|
||||||
|
expect(input.value).toBe("zucchini");
|
||||||
|
|
||||||
|
// change value manually in input, to simulate user input
|
||||||
|
input.value = "tomato";
|
||||||
|
expect(input.value).toBe("tomato");
|
||||||
|
|
||||||
|
// rerender with a different value, and patch actual dom, to check that
|
||||||
|
// input value was properly reset by owl
|
||||||
|
const bnode2 = renderToBdom(template, { v: "potato" });
|
||||||
|
patch(bnode1, bnode2);
|
||||||
|
expect(input.value).toBe("potato");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("input with t-att-value (patching with same value", () => {
|
||||||
|
// render input with initial value
|
||||||
|
const template = `<input t-att-value="v"/>`;
|
||||||
|
const bnode1 = renderToBdom(template, { v: "zucchini" });
|
||||||
|
const fixture = makeTestFixture();
|
||||||
|
mount(bnode1, fixture);
|
||||||
|
const input = fixture.querySelector("input")!;
|
||||||
|
expect(input.value).toBe("zucchini");
|
||||||
|
|
||||||
|
// change value manually in input, to simulate user input
|
||||||
|
input.value = "tomato";
|
||||||
|
expect(input.value).toBe("tomato");
|
||||||
|
|
||||||
|
const bnode2 = renderToBdom(template, { v: "zucchini" });
|
||||||
|
patch(bnode1, bnode2);
|
||||||
|
expect(input.value).toBe("zucchini");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("input, type checkbox, with t-att-checked (patching with same value", () => {
|
||||||
|
// render input with initial value
|
||||||
|
const template = `<input type="checkbox" t-att-checked="v"/>`;
|
||||||
|
const bnode1 = renderToBdom(template, { v: true });
|
||||||
|
const fixture = makeTestFixture();
|
||||||
|
mount(bnode1, fixture);
|
||||||
|
const input = fixture.querySelector("input")!;
|
||||||
|
expect(input.checked).toBe(true);
|
||||||
|
|
||||||
|
// change checked manually in input, to simulate user input
|
||||||
|
input.checked = false;
|
||||||
|
expect(input.checked).toBe(false);
|
||||||
|
|
||||||
|
const bnode2 = renderToBdom(template, { v: true });
|
||||||
|
patch(bnode1, bnode2);
|
||||||
|
expect(input.checked).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("input of type checkbox with t-att-indeterminate", () => {
|
||||||
|
const template = `<input type="checkbox" t-att-indeterminate="v"/>`;
|
||||||
|
const bnode1 = renderToBdom(template, { v: true });
|
||||||
|
const fixture = makeTestFixture();
|
||||||
|
mount(bnode1, fixture);
|
||||||
|
const input = fixture.querySelector("input")!;
|
||||||
|
expect(input.indeterminate).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("textarea with t-att-value", () => {
|
||||||
|
// render textarea with initial value
|
||||||
|
const template = `<textarea t-att-value="v"/>`;
|
||||||
|
const bnode1 = renderToBdom(template, { v: "zucchini" });
|
||||||
|
const fixture = makeTestFixture();
|
||||||
|
mount(bnode1, fixture);
|
||||||
|
const elm = fixture.querySelector("textarea")!;
|
||||||
|
expect(elm.value).toBe("zucchini");
|
||||||
|
|
||||||
|
// change value manually in textarea, to simulate user textarea
|
||||||
|
elm.value = "tomato";
|
||||||
|
expect(elm.value).toBe("tomato");
|
||||||
|
|
||||||
|
// rerender with a different value, and patch actual dom, to check that
|
||||||
|
// textarea value was properly reset by owl
|
||||||
|
const bnode2 = renderToBdom(template, { v: "potato" });
|
||||||
|
patch(bnode1, bnode2);
|
||||||
|
expect(elm.value).toBe("potato");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("select with t-att-value", () => {
|
||||||
|
const template = `
|
||||||
|
<select t-att-value="value">
|
||||||
|
<option value="potato">Potato</option>
|
||||||
|
<option value="tomato">Tomato</option>
|
||||||
|
<option value="onion">Onion</option>
|
||||||
|
</select>`;
|
||||||
|
const bnode1 = renderToBdom(template, { value: "tomato" });
|
||||||
|
const fixture = makeTestFixture();
|
||||||
|
mount(bnode1, fixture);
|
||||||
|
const elm = fixture.querySelector("select")!;
|
||||||
|
expect(elm.value).toBe("tomato");
|
||||||
|
|
||||||
|
elm.value = "potato";
|
||||||
|
expect(elm.value).toBe("potato");
|
||||||
|
|
||||||
|
// rerender with a different value, and patch actual dom, to check that
|
||||||
|
// select value was properly reset by owl
|
||||||
|
const bnode2 = renderToBdom(template, { value: "onion" });
|
||||||
|
patch(bnode1, bnode2);
|
||||||
|
expect(elm.value).toBe("onion");
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user