mirror of
https://github.com/bringout/oca-ocb-technical.git
synced 2026-04-20 10:52:01 +02:00
19.0 vanilla
This commit is contained in:
parent
5faf7397c5
commit
2696f14ed7
721 changed files with 220375 additions and 91221 deletions
|
|
@ -0,0 +1,190 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { Macro } from "@web/core/macro";
|
||||
import { beforeEach, expect, test } from "@odoo/hoot";
|
||||
import { advanceTime, animationFrame, press } from "@odoo/hoot-dom";
|
||||
import {
|
||||
contains,
|
||||
defineModels,
|
||||
fields,
|
||||
mockService,
|
||||
models,
|
||||
mountView,
|
||||
onRpc,
|
||||
patchWithCleanup,
|
||||
} from "@web/../tests/web_test_helpers";
|
||||
|
||||
async function simulateBarCode(chars) {
|
||||
for (const char of chars) {
|
||||
await press(char);
|
||||
}
|
||||
}
|
||||
|
||||
class Product extends models.Model {
|
||||
name = fields.Char({ string: "Product name" });
|
||||
int_field = fields.Integer({ string: "Integer" });
|
||||
int_field_2 = fields.Integer({ string: "Integer" });
|
||||
barcode = fields.Char({ string: "Barcode" });
|
||||
_records = [
|
||||
{ id: 1, name: "Large Cabinet", barcode: "1234567890" },
|
||||
{ id: 2, name: "Cabinet with Doors", barcode: "0987654321" },
|
||||
];
|
||||
}
|
||||
|
||||
defineModels([Product]);
|
||||
|
||||
let macro;
|
||||
async function macroIsComplete() {
|
||||
while (!macro.isComplete) {
|
||||
await advanceTime(100);
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
patchWithCleanup(Macro.prototype, {
|
||||
start() {
|
||||
super.start(...arguments);
|
||||
macro = this;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test("Button with barcode_trigger", async () => {
|
||||
mockService("action", {
|
||||
doActionButton: (data) => {
|
||||
expect.step(data.name);
|
||||
},
|
||||
});
|
||||
|
||||
mockService("notification", {
|
||||
add: (params) => {
|
||||
expect.step(params.type);
|
||||
},
|
||||
});
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "product",
|
||||
arch: `<form>
|
||||
<header>
|
||||
<button name="do_something" string="Validate" type="object" barcode_trigger="DOIT"/>
|
||||
<button name="do_something_else" string="Validate" type="object" invisible="1" barcode_trigger="DOTHAT"/>
|
||||
</header>
|
||||
</form>`,
|
||||
resId: 2,
|
||||
});
|
||||
// OBTDOIT
|
||||
await simulateBarCode(["O", "B", "T", "D", "O", "I", "T", "Enter"]);
|
||||
// OBTDOTHAT (should not call execute_action as the button isn't visible)
|
||||
await simulateBarCode(["O", "B", "T", "D", "O", "T", "H", "A", "T", "Enter"]);
|
||||
expect.verifySteps(["do_something"]);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test("Two buttons with same barcode_trigger and the same string and action", async () => {
|
||||
mockService("action", {
|
||||
doActionButton: (data) => {
|
||||
expect.step(data.name);
|
||||
},
|
||||
});
|
||||
|
||||
mockService("notification", {
|
||||
add: (params) => {
|
||||
expect.step(params.type);
|
||||
},
|
||||
});
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "product",
|
||||
arch: `<form>
|
||||
<header>
|
||||
<button name="do_something" string="Validate" type="object" invisible="0" barcode_trigger="DOIT"/>
|
||||
<button name="do_something" string="Validate" type="object" invisible="1" barcode_trigger="DOIT"/>
|
||||
</header>
|
||||
</form>`,
|
||||
resId: 2,
|
||||
});
|
||||
// OBTDOIT should call execute_action as the first button is visible
|
||||
await simulateBarCode(["O", "B", "T", "D", "O", "I", "T", "Enter"]);
|
||||
await animationFrame();
|
||||
expect.verifySteps(["do_something"]);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test("edit, save and cancel buttons", async () => {
|
||||
onRpc("web_save", () => expect.step("save"));
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "product",
|
||||
arch: '<form><field name="name"/></form>',
|
||||
resId: 1,
|
||||
});
|
||||
|
||||
// OCDEDIT
|
||||
await simulateBarCode(["O", "C", "D", "E", "D", "I", "T", "Enter"]);
|
||||
// dummy change to check that it actually saves
|
||||
await contains(".o_field_widget input").edit("test", { confirm: "blur" });
|
||||
|
||||
// OCDSAVE
|
||||
await simulateBarCode(["O", "C", "D", "S", "A", "V", "E", "Enter"]);
|
||||
expect.verifySteps(["save"]);
|
||||
|
||||
// OCDEDIT
|
||||
await simulateBarCode(["O", "C", "D", "E", "D", "I", "T", "Enter"]);
|
||||
// dummy change to check that it correctly discards
|
||||
await contains(".o_field_widget input").edit("test", { confirm: "blur" });
|
||||
// OCDDISC
|
||||
await simulateBarCode(["O", "C", "D", "D", "I", "S", "C", "Enter"]);
|
||||
expect.verifySteps([]);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test("pager buttons", async () => {
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "product",
|
||||
arch: '<form><field name="name"/></form>',
|
||||
resId: 1,
|
||||
resIds: [1, 2],
|
||||
});
|
||||
|
||||
expect(".o_field_widget input").toHaveValue("Large Cabinet");
|
||||
// OCDNEXT
|
||||
await simulateBarCode(["O", "C", "D", "N", "E", "X", "T", "Enter"]);
|
||||
await animationFrame();
|
||||
expect(".o_field_widget input").toHaveValue("Cabinet with Doors");
|
||||
|
||||
// OCDPREV
|
||||
await simulateBarCode(["O", "C", "D", "P", "R", "E", "V", "Enter"]);
|
||||
await animationFrame();
|
||||
expect(".o_field_widget input").toHaveValue("Large Cabinet");
|
||||
|
||||
// OCDPAGERLAST
|
||||
await simulateBarCode(["O", "C", "D", "P", "A", "G", "E", "R", "L", "A", "S", "T", "Enter"]);
|
||||
// need to await 2 macro steps
|
||||
await macroIsComplete();
|
||||
await animationFrame();
|
||||
expect(".o_field_widget input").toHaveValue("Cabinet with Doors");
|
||||
|
||||
// OCDPAGERFIRST
|
||||
await simulateBarCode([
|
||||
"O",
|
||||
"C",
|
||||
"D",
|
||||
"P",
|
||||
"A",
|
||||
"G",
|
||||
"E",
|
||||
"R",
|
||||
"F",
|
||||
"I",
|
||||
"R",
|
||||
"S",
|
||||
"T",
|
||||
"Enter",
|
||||
]);
|
||||
// need to await 2 macro steps
|
||||
await macroIsComplete();
|
||||
await animationFrame();
|
||||
expect(".o_field_widget input").toHaveValue("Large Cabinet");
|
||||
});
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { beforeEach, expect, test } from "@odoo/hoot";
|
||||
import { getActiveElement, queryFirst, keyDown, click } from "@odoo/hoot-dom";
|
||||
import { mountWithCleanup, patchWithCleanup } from "@web/../tests/web_test_helpers";
|
||||
import { barcodeService } from "@barcodes/barcode_service";
|
||||
import { Component, xml } from "@odoo/owl";
|
||||
|
||||
beforeEach(() => {
|
||||
patchWithCleanup(barcodeService, {
|
||||
maxTimeBetweenKeysInMs: 0,
|
||||
isMobileChrome: true,
|
||||
});
|
||||
});
|
||||
class Root extends Component {
|
||||
static template = xml`
|
||||
<form>
|
||||
<input name="email" type="email"/>
|
||||
<input name="number" type="number"/>
|
||||
<input name="password" type="password"/>
|
||||
<input name="tel" type="tel"/>
|
||||
<input name="text"/>
|
||||
<input name="explicit_text" type="text"/>
|
||||
<textarea></textarea>
|
||||
<div contenteditable="true"></div>
|
||||
<select name="select">
|
||||
<option value="option1">Option 1</option>
|
||||
<option value="option2">Option 2</option>
|
||||
</select>
|
||||
</form>`;
|
||||
static props = ["*"];
|
||||
}
|
||||
|
||||
test.tags("mobile");
|
||||
test("barcode field automatically focus behavior", async () => {
|
||||
expect.assertions(10);
|
||||
await mountWithCleanup(Root);
|
||||
|
||||
// Some elements doesn't need to keep the focus
|
||||
await click(document.body);
|
||||
await keyDown("a");
|
||||
expect(getActiveElement()).toHaveProperty("name", "barcode", {
|
||||
message: "hidden barcode input should have the focus",
|
||||
});
|
||||
|
||||
let element = queryFirst("select");
|
||||
await click(element);
|
||||
await keyDown("b");
|
||||
expect(getActiveElement()).toHaveProperty("name", "barcode", {
|
||||
message: "hidden barcode input should have the focus",
|
||||
});
|
||||
|
||||
// Those elements absolutely need to keep the focus:
|
||||
// inputs elements:
|
||||
const keepFocusedElements = ["email", "number", "password", "tel", "text", "explicit_text"];
|
||||
for (let i = 0; i < keepFocusedElements.length; ++i) {
|
||||
element = queryFirst(`input[name=${keepFocusedElements[i]}]`);
|
||||
await click(element);
|
||||
await keyDown("c");
|
||||
expect(`input[name=${keepFocusedElements[i]}]`).toBeFocused({
|
||||
message: `input ${keepFocusedElements[i]} should keep focus`,
|
||||
});
|
||||
}
|
||||
// textarea element
|
||||
element = queryFirst(`textarea`);
|
||||
await click(element);
|
||||
await keyDown("d");
|
||||
expect(`textarea`).toBeFocused({ message: "textarea should keep focus" });
|
||||
// contenteditable elements
|
||||
element = queryFirst(`[contenteditable=true]`);
|
||||
await click(element);
|
||||
await keyDown("e");
|
||||
expect(`[contenteditable=true]`).toBeFocused({
|
||||
message: "contenteditable should keep focus",
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { expect, test } from "@odoo/hoot";
|
||||
import { BarcodeParser } from "@barcodes/js/barcode_parser";
|
||||
|
||||
test.tags("headless");
|
||||
test("Test check digit", async () => {
|
||||
const nomenclature = {
|
||||
id: 1,
|
||||
name: "normal",
|
||||
upc_ean_conv: "always",
|
||||
rules: [
|
||||
{
|
||||
id: 1,
|
||||
name: "Product Barcodes",
|
||||
barcode_nomenclature_id: 1,
|
||||
sequence: 90,
|
||||
type: "product",
|
||||
encoding: "any",
|
||||
pattern: ".*",
|
||||
},
|
||||
],
|
||||
};
|
||||
const barcodeNomenclature = new BarcodeParser({ nomenclature });
|
||||
|
||||
let ean8 = "87111125";
|
||||
expect(barcodeNomenclature.get_barcode_check_digit(ean8)).toEqual(+ean8[ean8.length - 1]);
|
||||
ean8 = "4725992";
|
||||
expect(barcodeNomenclature.get_barcode_check_digit(ean8 + "0")).toEqual(8);
|
||||
let ean13 = "1234567891231";
|
||||
expect(barcodeNomenclature.get_barcode_check_digit(ean13)).toEqual(+ean13[ean13.length - 1]);
|
||||
ean13 = "962434754318";
|
||||
expect(barcodeNomenclature.get_barcode_check_digit(ean13 + "0")).toEqual(4);
|
||||
let utca = "692771981161";
|
||||
expect(barcodeNomenclature.get_barcode_check_digit(utca)).toEqual(+utca[utca.length - 1]);
|
||||
utca = "71679131569";
|
||||
expect(barcodeNomenclature.get_barcode_check_digit(utca + "0")).toEqual(7);
|
||||
});
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { expect, test } from "@odoo/hoot";
|
||||
import { waitFor } from "@odoo/hoot-dom";
|
||||
import { Component, xml } from "@odoo/owl";
|
||||
import { BarcodeScanner } from "@barcodes/components/barcode_scanner";
|
||||
import { contains, mountWithCleanup } from "@web/../tests/web_test_helpers";
|
||||
|
||||
test.tags("desktop");
|
||||
test("Display notification for media device permission on barcode scanning", async () => {
|
||||
navigator.mediaDevices.getUserMedia = function () {
|
||||
return Promise.reject(new DOMException("", "NotAllowedError"));
|
||||
};
|
||||
|
||||
class BarcodeScan extends Component {
|
||||
static template = xml`
|
||||
<div>
|
||||
<BarcodeScanner onBarcodeScanned="(ev) => this.onBarcodeScanned(ev)"/>
|
||||
</div>
|
||||
`;
|
||||
static components = { BarcodeScanner };
|
||||
static props = ["*"];
|
||||
}
|
||||
|
||||
await mountWithCleanup(BarcodeScan);
|
||||
await contains("a.o_mobile_barcode").click();
|
||||
await waitFor(".modal-body:contains(camera)");
|
||||
expect(".modal-body").toHaveText(
|
||||
"Unable to access camera\nCould not start scanning. Odoo needs your authorization first."
|
||||
);
|
||||
});
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { beforeEach, expect, test } from "@odoo/hoot";
|
||||
import { animationFrame } from "@odoo/hoot-mock";
|
||||
import { FormController } from "@web/views/form/form_controller";
|
||||
import {
|
||||
contains,
|
||||
defineModels,
|
||||
fields,
|
||||
models,
|
||||
mountView,
|
||||
onRpc,
|
||||
patchWithCleanup,
|
||||
} from "@web/../tests/web_test_helpers";
|
||||
import { barcodeService } from "@barcodes/barcode_service";
|
||||
import { press } from "@odoo/hoot-dom";
|
||||
|
||||
async function simulateBarCode(chars) {
|
||||
for (const char of chars) {
|
||||
await press(char);
|
||||
}
|
||||
}
|
||||
class Product extends models.Model {
|
||||
name = fields.Char({ string: "Product name" });
|
||||
float_field = fields.Float({ string: "Float" });
|
||||
float_field_2 = fields.Float({ string: "Float" });
|
||||
barcode = fields.Char({ string: "Barcode" });
|
||||
_records = [
|
||||
{ id: 1, name: "Large Cabinet", barcode: "1234567890" },
|
||||
{ id: 2, name: "Cabinet with Doors", barcode: "0987654321" },
|
||||
];
|
||||
}
|
||||
|
||||
defineModels([Product]);
|
||||
|
||||
beforeEach(() => {
|
||||
patchWithCleanup(barcodeService, {
|
||||
maxTimeBetweenKeysInMs: 0,
|
||||
});
|
||||
});
|
||||
|
||||
test.tags("mobile");
|
||||
test("widget field_float_scannable", async () => {
|
||||
Product._records[0].float_field = 4;
|
||||
|
||||
const onBarcodeScanned = (event) => {
|
||||
expect.step(`barcode scanned ${event.detail.barcode}`);
|
||||
};
|
||||
|
||||
const view = await mountView({
|
||||
type: "form",
|
||||
resModel: "product",
|
||||
resId: 1,
|
||||
arch: /*xml*/ `
|
||||
<form>press
|
||||
<field name="display_name"/>
|
||||
<field name="float_field" widget="field_float_scannable"/>
|
||||
<field name="float_field_2"/>
|
||||
</form>
|
||||
`,
|
||||
});
|
||||
view.env.services.barcode.bus.addEventListener("barcode_scanned", onBarcodeScanned);
|
||||
|
||||
expect(".o_field_widget[name=float_field] input").toHaveValue("4.00");
|
||||
|
||||
// we check here that a scan on the field_float_scannable widget triggers a
|
||||
// barcode event
|
||||
await contains(".o_field_widget[name=float_field] input").focus();
|
||||
await simulateBarCode(["6", "0", "1", "6", "4", "7", "8", "5"]);
|
||||
await animationFrame();
|
||||
expect.verifySteps(["barcode scanned 60164785"]);
|
||||
expect(".o_field_widget[name=float_field] input").toBeFocused();
|
||||
|
||||
// we check here that a scan on the field without widget does not trigger a
|
||||
// barcode event
|
||||
await contains(".o_field_widget[name=float_field_2] input").focus();
|
||||
await simulateBarCode(["6", "0", "1", "6", "4", "7", "8", "5"]);
|
||||
await animationFrame();
|
||||
expect.verifySteps([]);
|
||||
|
||||
view.env.services.barcode.bus.removeEventListener("barcode_scanned", onBarcodeScanned);
|
||||
});
|
||||
|
||||
test.tags("mobile");
|
||||
test("do no update form twice after a command barcode scanned", async () => {
|
||||
patchWithCleanup(FormController.prototype, {
|
||||
onPagerUpdate(...args) {
|
||||
expect.step("update");
|
||||
super.onPagerUpdate(...args);
|
||||
},
|
||||
});
|
||||
|
||||
onRpc("web_read", () => {
|
||||
expect.step("web_read");
|
||||
});
|
||||
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "product",
|
||||
arch: /*xml*/ `
|
||||
<form>
|
||||
<field name="display_name"/>
|
||||
<field name="float_field" widget="field_float_scannable"/>
|
||||
</form>
|
||||
`,
|
||||
resId: 1,
|
||||
resIds: [1, 2],
|
||||
});
|
||||
|
||||
expect.verifySteps(["web_read"]);
|
||||
|
||||
// switch to next record
|
||||
await simulateBarCode(["O", "C", "D", "N", "E", "X", "T", "Enter"]);
|
||||
|
||||
// a first update is done to reload the data (thus followed by a read), but
|
||||
// update shouldn't be called afterwards
|
||||
expect.verifySteps(["update", "web_read"]);
|
||||
});
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { triggerEvent } from "@web/../tests/helpers/utils";
|
||||
|
||||
export function simulateBarCode(chars, target = document.body, selector = undefined) {
|
||||
for (let char of chars) {
|
||||
triggerEvent(target, selector, "keydown", {
|
||||
key: char,
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue