Initial commit: Core packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:45 +02:00
commit 12c29a983b
9512 changed files with 8379910 additions and 0 deletions

View file

@ -0,0 +1,157 @@
/** @odoo-module **/
import {
click,
editInput,
getFixture,
nextTick,
patchWithCleanup,
} from "@web/../tests/helpers/utils";
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
import { registry } from "@web/core/registry";
import { AttachDocumentWidget } from "@web/views/widgets/attach_document/attach_document";
const serviceRegistry = registry.category("services");
let target;
let serverData;
QUnit.module("Widgets", (hooks) => {
hooks.beforeEach(() => {
target = getFixture();
serverData = {
models: {
partner: {
fields: {
display_name: { string: "Displayed name", type: "char" },
},
records: [
{
id: 1,
display_name: "first record",
},
],
onchanges: {},
},
},
};
setupViewRegistries();
});
QUnit.module("AttachDocument");
QUnit.test("attach document widget calls action with attachment ids", async function (assert) {
let fileInput;
patchWithCleanup(AttachDocumentWidget.prototype, {
setup() {
this._super();
fileInput = this.fileInput;
},
});
serviceRegistry.add("http", {
start: () => ({
post: (route, params) => {
assert.step("post");
assert.strictEqual(route, "/web/binary/upload_attachment");
assert.strictEqual(params.model, "partner");
assert.strictEqual(params.id, 1);
return '[{ "id": 5 }, { "id": 2 }]';
},
}),
});
await makeView({
type: "form",
resModel: "partner",
serverData,
resId: 1,
mockRPC(route, args) {
assert.step(args.method);
if (args.method === "my_action") {
assert.deepEqual(args.model, "partner");
assert.deepEqual(args.args, [1]);
assert.deepEqual(args.kwargs.attachment_ids, [5, 2]);
return true;
}
if (args.method === "write") {
assert.deepEqual(args.args[1], { display_name: "yop" });
}
if (args.method === "read") {
assert.deepEqual(args.args[0], [1]);
}
},
arch: `
<form>
<widget name="attach_document" action="my_action" string="Attach document"/>
<field name="display_name" required="1"/>
</form>`,
});
assert.verifySteps(["get_views", "read"]);
await editInput(target, "[name='display_name'] input", "yop");
await click(target, ".o_attach_document");
fileInput.dispatchEvent(new Event("change"));
await nextTick();
assert.verifySteps(["write", "read", "post", "my_action", "read"]);
});
QUnit.test(
"attach document widget calls action with attachment ids on a new record",
async function (assert) {
let fileInput;
patchWithCleanup(AttachDocumentWidget.prototype, {
setup() {
this._super();
fileInput = this.fileInput;
},
});
serviceRegistry.add("http", {
start: () => ({
post: (route, params) => {
assert.step("post");
assert.strictEqual(route, "/web/binary/upload_attachment");
assert.strictEqual(params.model, "partner");
assert.strictEqual(params.id, 2);
return '[{ "id": 5 }, { "id": 2 }]';
},
}),
});
await makeView({
type: "form",
resModel: "partner",
serverData,
mockRPC(route, args) {
assert.step(args.method);
if (args.method === "my_action") {
assert.deepEqual(args.model, "partner");
assert.deepEqual(args.args, [2]);
assert.deepEqual(args.kwargs.attachment_ids, [5, 2]);
return true;
}
if (args.method === "create") {
assert.deepEqual(args.args[0], { display_name: "yop" });
}
if (args.method === "read") {
assert.deepEqual(args.args[0], [2]);
}
},
arch: `
<form>
<widget name="attach_document" action="my_action" string="Attach document"/>
<field name="display_name" required="1"/>
</form>`,
});
assert.verifySteps(["get_views", "onchange"]);
await editInput(target, "[name='display_name'] input", "yop");
await click(target, ".o_attach_document");
fileInput.dispatchEvent(new Event("change"));
await nextTick();
assert.verifySteps(["create", "read", "post", "my_action", "read"]);
}
);
});

View file

@ -0,0 +1,155 @@
/** @odoo-module **/
import { click, getFixture, patchWithCleanup } from "@web/../tests/helpers/utils";
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
import { NameAndSignature } from "@web/core/signature/name_and_signature";
let serverData;
let target;
QUnit.module("Widgets", (hooks) => {
hooks.beforeEach(() => {
target = getFixture();
serverData = {
models: {
partner: {
fields: {
display_name: { string: "Name", type: "char" },
product_id: {
string: "Product Name",
type: "many2one",
relation: "product",
},
__last_update: { type: "datetime" },
sign: { string: "Signature", type: "binary" },
},
records: [
{
id: 1,
display_name: "Pop's Chock'lit",
product_id: 7,
},
],
onchanges: {},
},
product: {
fields: {
name: { string: "Product Name", type: "char" },
},
records: [
{
id: 7,
display_name: "Veggie Burger",
},
],
},
},
};
setupViewRegistries();
});
QUnit.module("Signature Widget");
QUnit.test("Signature widget renders a Sign button", async function (assert) {
assert.expect(5);
patchWithCleanup(NameAndSignature.prototype, {
setup() {
this._super.apply(this, arguments);
assert.strictEqual(this.props.signature.name, "");
},
});
await makeView({
type: "form",
resModel: "partner",
resId: 1,
serverData,
arch: `<form>
<header>
<widget name="signature" string="Sign"/>
</header>
</form>`,
mockRPC: async (route, args) => {
if (route === "/web/sign/get_fonts/") {
return {};
}
},
});
assert.hasClass(
target.querySelector("button.o_sign_button"),
"btn-secondary",
"The button must have the 'btn-secondary' class as \"highlight=0\""
);
assert.containsOnce(
target,
".o_widget_signature button.o_sign_button",
"Should have a signature widget button"
);
assert.containsNone(target, ".modal-dialog", "Should not have any modal");
// Clicks on the sign button to open the sign modal.
await click(target, ".o_widget_signature button.o_sign_button");
assert.containsOnce(target, ".modal-dialog", "Should have one modal opened");
});
QUnit.test("Signature widget: full_name option", async function (assert) {
patchWithCleanup(NameAndSignature.prototype, {
setup() {
this._super.apply(this, arguments);
assert.step(this.props.signature.name);
},
});
await makeView({
type: "form",
resModel: "partner",
resId: 1,
serverData,
arch: `<form>
<header>
<widget name="signature" string="Sign" full_name="display_name"/>
</header>
<field name="display_name"/>
</form>`,
mockRPC: async (route) => {
if (route === "/web/sign/get_fonts/") {
return {};
}
},
});
// Clicks on the sign button to open the sign modal.
await click(target, "span.o_sign_label");
assert.containsOnce(target, ".modal .modal-body a.o_web_sign_auto_button");
assert.verifySteps(["Pop's Chock'lit"]);
});
QUnit.test("Signature widget: highlight option", async function (assert) {
await makeView({
type: "form",
resModel: "partner",
resId: 1,
serverData,
arch: `<form>
<header>
<widget name="signature" string="Sign" highlight="1"/>
</header>
</form>`,
mockRPC: async (route, args) => {
if (route === "/web/sign/get_fonts/") {
return {};
}
},
});
assert.hasClass(
target.querySelector("button.o_sign_button"),
"btn-primary",
"The button must have the 'btn-primary' class as \"highlight=1\""
);
// Clicks on the sign button to open the sign modal.
await click(target, ".o_widget_signature button.o_sign_button");
assert.containsNone(target, ".modal .modal-body a.o_web_sign_auto_button");
});
});

View file

@ -0,0 +1,170 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { makeFakeLocalizationService } from "../../helpers/mock_services";
import { getFixture, click, clickSave } from "../../helpers/utils";
import { makeView, setupViewRegistries } from "../helpers";
let serverData;
let fixture;
QUnit.module("Widgets", ({ beforeEach }) => {
beforeEach(() => {
fixture = getFixture();
setupViewRegistries();
serverData = {
models: {
partner: {
fields: {
id: { type: "integer", string: "ID" },
sun: { type: "boolean", string: "Sun" },
mon: { type: "boolean", string: "Mon" },
tue: { type: "boolean", string: "Tue" },
wed: { type: "boolean", string: "Wed" },
thu: { type: "boolean", string: "Thu" },
fri: { type: "boolean", string: "Fri" },
sat: { type: "boolean", string: "Sat" },
},
records: [
{
id: 1,
sun: false,
mon: false,
tue: false,
wed: false,
thu: false,
fri: false,
sat: false,
},
],
},
},
};
});
QUnit.module("WeekDays");
QUnit.test("simple week recurrence widget", async (assert) => {
assert.expect(13);
let writeCall = 0;
registry.category("services", makeFakeLocalizationService({ weekStart: 1 }));
await makeView({
type: "form",
resModel: "partner",
resId: 1,
serverData,
arch: `
<form>
<sheet>
<group>
<widget name="week_days" />
</group>
</sheet>
</form>
`,
mockRPC(route, { args, method }) {
if (method === "write") {
writeCall++;
if (writeCall === 1) {
assert.ok(args[1].sun, "value of sunday should be true");
}
if (writeCall === 2) {
assert.notOk(args[1].sun, "value of sunday should be false");
assert.ok(args[1].mon, "value of monday should be true");
assert.ok(args[1].tue, "value of tuesday should be true");
}
}
},
});
const labelsTexts = [...fixture.querySelectorAll(".o_recurrent_weekday_label")].map((el) =>
el.innerText.trim()
);
assert.deepEqual(
labelsTexts,
["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
"labels should be short week names"
);
assert.containsNone(
fixture,
".form-check input:disabled",
"all inputs should be enabled in readonly mode"
);
await click(fixture.querySelector("td:nth-child(7) input"));
assert.ok(
fixture.querySelector("td:nth-child(7) input").checked,
"sunday checkbox should be checked"
);
await clickSave(fixture);
await click(fixture.querySelector("td:nth-child(1) input"));
assert.ok(
fixture.querySelector("td:nth-child(1) input").checked,
"monday checkbox should be checked"
);
await click(fixture.querySelector("td:nth-child(2) input"));
assert.ok(
fixture.querySelector("td:nth-child(2) input").checked,
"tuesday checkbox should be checked"
);
// uncheck Sunday checkbox and check write call
await click(fixture.querySelector("td:nth-child(7) input"));
assert.notOk(
fixture.querySelector("td:nth-child(7) input").checked,
"sunday checkbox should be unchecked"
);
await clickSave(fixture);
assert.notOk(
fixture.querySelector("td:nth-child(7) input").checked,
"sunday checkbox should be unchecked"
);
assert.ok(
fixture.querySelector("td:nth-child(1) input").checked,
"monday checkbox should be checked"
);
assert.ok(
fixture.querySelector("td:nth-child(2) input").checked,
"tuesday checkbox should be checked"
);
});
QUnit.test(
"week recurrence widget show week start as per language configuration",
async (assert) => {
registry.category("services", makeFakeLocalizationService({ weekStart: 5 }));
await makeView({
type: "form",
resModel: "partner",
resId: 1,
serverData,
arch: `
<form>
<sheet>
<group>
<widget name="week_days" />
</group>
</sheet>
</form>
`,
});
const labels = [...fixture.querySelectorAll(".o_recurrent_weekday_label")].map((el) =>
el.textContent.trim()
);
assert.deepEqual(
labels,
["Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu"],
"labels should be short week names"
);
}
);
});