19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:30:27 +01:00
parent d1963a3c3a
commit 2d3ee4855a
7430 changed files with 2687981 additions and 2965473 deletions

View file

@ -158,10 +158,11 @@ describe("level 1", () => {
await makeMockEnv();
await expect(
getService("orm").searchRead("oui", [], ["id", "name", "age", "surname"])
getService("orm").searchRead("oui", [], ["id", "name", "age", "surname", "create_date"])
).resolves.toEqual([
{
id: 1,
create_date: luxon.DateTime.utc().toSQL().slice(0, 19),
name: "John Doe",
age: 42,
surname: "doedoe",

View file

@ -10,6 +10,8 @@ import {
} from "@web/../tests/web_test_helpers";
import { localization } from "@web/core/l10n/localization";
import { ConnectionLostError, rpc } from "@web/core/network/rpc";
class Partner extends models.Model {
_name = "res.partner";
@ -152,15 +154,15 @@ defineModels([Partner, Bar, Foo]);
* kwargs: Record<string, any>;
* [key: string]: any;
* }} params
* @returns
*/
const ormRequest = async (params) => {
const response = await fetch(`/web/dataset/call_kw/${params.model}/${params.method}`, {
function fetchCallKw(params) {
return fetch(`/web/dataset/call_kw/${params.model}/${params.method}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
id: nextJsonRpcId++,
jsonrpc: "2.0",
method: "call",
params: {
@ -170,6 +172,19 @@ const ormRequest = async (params) => {
},
}),
});
}
/**
* @param {{
* model: string;
* method: string;
* args: any[];
* kwargs: Record<string, any>;
* [key: string]: any;
* }} params
*/
const ormRequest = async (params) => {
const response = await fetchCallKw(params);
const { error, result } = await response.json();
if (error) {
console.error(error);
@ -178,6 +193,17 @@ const ormRequest = async (params) => {
return result;
};
/**
* Minimal parameters to have a request considered as a JSON-RPC request
*/
const JSON_RPC_BASIC_PARAMS = {
body: "{}",
headers: {
["Content-Type"]: "application/json",
},
};
let nextJsonRpcId = 0;
describe.current.tags("headless");
test("onRpc: normal result", async () => {
@ -189,35 +215,17 @@ test("onRpc: normal result", async () => {
expect(response).toBeInstanceOf(Response);
await expect(response.json()).resolves.toEqual({ result: "result", error: null });
await expect(response.text()).resolves.toBe("result");
});
test("onRpc: error handling", async () => {
class CustomError extends Error {
name = "CustomError";
}
onRpc("/boom", () => {
throw new CustomError("boom");
throw new Error("boom");
});
await makeMockServer();
const response = await fetch("/boom");
expect(response).toBeInstanceOf(Response);
await expect(response.json()).resolves.toEqual({
result: null,
error: {
code: 418,
data: {
name: "CustomError",
},
message: "boom",
type: "CustomError",
},
});
await expect(fetch("/boom")).rejects.toThrow("boom");
});
test("onRpc: pure, normal result", async () => {
@ -246,6 +254,97 @@ test("onRpc: pure, error handling", async () => {
await expect(fetch("/boom")).rejects.toThrow("boom");
});
test("onRpc: JSON-RPC normal result", async () => {
onRpc("/get_result", () => "get_result value");
await makeMockServer();
const response = await fetch("/get_result", JSON_RPC_BASIC_PARAMS);
expect(response).toBeInstanceOf(Response);
const result = await response.json();
expect(result).toMatchObject({
result: "get_result value",
});
expect(result).not.toInclude("error");
});
test("onRpc: JSON-RPC error handling", async () => {
class CustomError extends Error {
name = "CustomError";
}
onRpc("/boom", () => {
throw new CustomError("boom");
});
await makeMockServer();
const response = await fetch("/boom", JSON_RPC_BASIC_PARAMS);
expect(response).toBeInstanceOf(Response);
const result = await response.json();
expect(result).not.toInclude("result");
expect(result).toMatchObject({
error: {
code: 200,
data: {
name: "CustomError",
message: "boom",
},
message: "boom",
type: "server",
},
});
});
test("rpc: calls on mock server", async () => {
onRpc("/route", () => "pure route response");
onRpc("http://pure.route.com/", () => "external route response");
onRpc("/boom", () => {
throw new Error("Boom");
});
onRpc(
"/boom/pure",
() => {
throw new Error("Pure boom");
},
{ pure: true }
);
await makeMockServer();
await expect(rpc("/route")).resolves.toBe("pure route response");
await expect(rpc("http://pure.route.com/")).resolves.toBe("external route response");
await expect(rpc("/boom")).rejects.toThrow("RPC_ERROR: Boom");
await expect(rpc("/boom/pure")).rejects.toThrow(ConnectionLostError);
// MockServer error handling with 'rpc'
await expect(rpc("/unknown/route")).rejects.toThrow(
"Unimplemented server route: /unknown/route"
);
await expect(rpc("https://unknown.route")).rejects.toThrow(
"Unimplemented server external URL: https://unknown.route"
);
await expect(
rpc("/web/dataset/call_kw/fake.model/fake_method", {
model: "fake.model",
method: "fake_method",
})
).rejects.toThrow(
`Cannot find a definition for model "fake.model": could not get model from server environment`
);
});
test("performRPC: custom response", async () => {
const customResponse = new Response("{}", { status: 418 });
onRpc(() => customResponse);
await makeMockServer();
await expect(fetchCallKw({})).resolves.toBe(customResponse);
});
test("performRPC: search with active_test=false", async () => {
await makeMockServer();
const result = await ormRequest({