Language and theme follow the account: PATCH /me for the theme, /me's language by default
The server's /api/v2 now has PATCH /me {language, theme} and /me lists its languages and
themes. The theme is the account's and choosing one saves it there (a refusal is said);
a server whose /me lists no themes keeps the earlier choice in the app. The language is the
account's unless Settings chose this computer's or another (kept in the app, as the phone
does); a change of the account's opens the window again in it, once.
Fixtures re-pinned to the server's dev (f7f2ff2), with the new /api/v2 parity ones.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
23 files changed
+783
-84
No files matched your search
@@ -1 +1 @@
|
||||
LLeMbas v2.0.0-beta.8 (d06ca353b801916302f0ce0cc9ae3e5244ff184f) tests/fixtures/api_v2
|
||||
LLeMbas origin/dev (f7f2ff21d303d82e8c46fabed100311f300052c0) tests/fixtures/api_v2
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"id": "chat1",
|
||||
"kind": "chat",
|
||||
"title": "Waybread",
|
||||
"model": "qwen",
|
||||
"folder_id": null,
|
||||
"pinned": false,
|
||||
"archived": false,
|
||||
"temporary": false,
|
||||
"unread": true,
|
||||
"running": false,
|
||||
"mode": "",
|
||||
"effort": "low",
|
||||
"device": null,
|
||||
"device_session_id": null,
|
||||
"parent_chat_id": null,
|
||||
"agents": {
|
||||
"min": 1,
|
||||
"max": 4
|
||||
},
|
||||
"subagents": {
|
||||
"offered": true,
|
||||
"named_only": false,
|
||||
"cap": 32
|
||||
},
|
||||
"created_at": "2026-01-02T03:04:05+00:00",
|
||||
"updated_at": "2026-01-02T03:04:05+00:00"
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"chats": [
|
||||
{
|
||||
"id": "chat1",
|
||||
"kind": "chat",
|
||||
"title": "Waybread",
|
||||
"model": "qwen",
|
||||
"folder_id": null,
|
||||
"pinned": false,
|
||||
"archived": false,
|
||||
"temporary": false,
|
||||
"unread": true,
|
||||
"running": false,
|
||||
"mode": "",
|
||||
"effort": "low",
|
||||
"device": null,
|
||||
"device_session_id": null,
|
||||
"parent_chat_id": null,
|
||||
"agents": {
|
||||
"min": 1,
|
||||
"max": 4
|
||||
},
|
||||
"subagents": null,
|
||||
"created_at": "2026-01-02T03:04:05+00:00",
|
||||
"updated_at": "2026-01-02T03:04:05+00:00"
|
||||
}
|
||||
],
|
||||
"more": false
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"version": "d2f307bf1c7b8d6b",
|
||||
"schedules": [
|
||||
{
|
||||
"id": "sched1",
|
||||
"title": "Waybread check",
|
||||
"instruction": "Check the waybread is wrapped.",
|
||||
"request": "every second Monday at 7:30",
|
||||
"rule": {
|
||||
"at": {
|
||||
"nth": [
|
||||
{
|
||||
"n": 2,
|
||||
"weekday": 0
|
||||
}
|
||||
],
|
||||
"times": [
|
||||
"07:30"
|
||||
]
|
||||
}
|
||||
},
|
||||
"description": "On the second Monday of each month at 07:30",
|
||||
"timezone": "UTC",
|
||||
"enabled": true,
|
||||
"next_run": "2026-01-12T07:30:00+00:00",
|
||||
"next_runs": [
|
||||
"2026-01-12T07:30:00+00:00",
|
||||
"2026-02-09T07:30:00+00:00",
|
||||
"2026-03-09T07:30:00+00:00",
|
||||
"2026-04-13T07:30:00+00:00",
|
||||
"2026-05-11T07:30:00+00:00"
|
||||
],
|
||||
"target": "chat",
|
||||
"mode": "fresh",
|
||||
"notify": "matters",
|
||||
"catch_up": "one",
|
||||
"grace_minutes": null,
|
||||
"model": "qwen",
|
||||
"effort": "high",
|
||||
"agents": null,
|
||||
"tools": [
|
||||
"files",
|
||||
"recall",
|
||||
"search",
|
||||
"fetch",
|
||||
"memory",
|
||||
"skills",
|
||||
"plan"
|
||||
],
|
||||
"origin": "user",
|
||||
"chat_id": "chat1",
|
||||
"fired_count": 3,
|
||||
"failure_streak": 0,
|
||||
"watch": null,
|
||||
"last_error": null,
|
||||
"last_run": {
|
||||
"id": "run1",
|
||||
"schedule_id": "sched1",
|
||||
"status": "ok",
|
||||
"timing": "late",
|
||||
"missed": 0,
|
||||
"due_at": "2026-01-02T03:04:05+00:00",
|
||||
"started_at": "2026-01-02T03:04:05+00:00",
|
||||
"finished_at": "2026-01-02T03:04:05+00:00",
|
||||
"waiting_for": null,
|
||||
"retry_at": null,
|
||||
"progress": null,
|
||||
"attempts": 1,
|
||||
"model": {
|
||||
"id": "gpt-oss",
|
||||
"name": "GPT-OSS",
|
||||
"reason": "switched",
|
||||
"switched_from": "Qwen"
|
||||
},
|
||||
"tokens": {
|
||||
"prompt": 1200,
|
||||
"completion": 340
|
||||
},
|
||||
"cost": null,
|
||||
"chat_id": "chat1",
|
||||
"message_id": "msg2",
|
||||
"report_path": null,
|
||||
"preview": "All the waybread is wrapped.",
|
||||
"error": null,
|
||||
"notified": true,
|
||||
"notification": {
|
||||
"title": "Waybread check",
|
||||
"body": "All the waybread is wrapped.",
|
||||
"public": {
|
||||
"title": "Waybread check",
|
||||
"body": "Finished"
|
||||
},
|
||||
"actions": [
|
||||
"open",
|
||||
"run_again"
|
||||
],
|
||||
"labels": {
|
||||
"open": "Open",
|
||||
"run_again": "Run again"
|
||||
},
|
||||
"ask": ""
|
||||
},
|
||||
"watch": null
|
||||
},
|
||||
"running": false,
|
||||
"created_at": "2026-01-02T03:04:05+00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"path": "/home/frodo",
|
||||
"parent": "/home",
|
||||
"entries": [
|
||||
{
|
||||
"name": "recipes",
|
||||
"path": "/home/frodo/recipes",
|
||||
"kind": "dir",
|
||||
"size": 0,
|
||||
"mime": "",
|
||||
"updated_at": "2026-01-02T03:04:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "lembas.md",
|
||||
"path": "/home/frodo/lembas.md",
|
||||
"kind": "file",
|
||||
"size": 27,
|
||||
"mime": "text/markdown",
|
||||
"updated_at": "2026-01-02T03:04:05+00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"folder": {
|
||||
"id": "fold1",
|
||||
"name": "Waybread",
|
||||
"parent_id": null,
|
||||
"kind": "",
|
||||
"position": 0,
|
||||
"collapsed": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"id": "fold1",
|
||||
"name": "Waybread",
|
||||
"parent_id": null,
|
||||
"kind": "",
|
||||
"position": 0,
|
||||
"collapsed": false
|
||||
},
|
||||
{
|
||||
"id": "fold2",
|
||||
"name": "Recipes",
|
||||
"parent_id": "fold1",
|
||||
"kind": "chat",
|
||||
"position": 1,
|
||||
"collapsed": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"api": 2,
|
||||
"version": "2.0.0",
|
||||
"account": {
|
||||
"id": "user1",
|
||||
"name": "Frodo",
|
||||
"email": "frodo@shire.test"
|
||||
},
|
||||
"language": "sk",
|
||||
"theme": "shire",
|
||||
"default_model": "qwen",
|
||||
"permissions": {
|
||||
"chat.create": true,
|
||||
"chat.delete": false,
|
||||
"chat.model_select": true,
|
||||
"chat.system_prompt": true,
|
||||
"chat.params": true,
|
||||
"files.upload": true,
|
||||
"tools.agent": true,
|
||||
"audio.transcribe": true,
|
||||
"audio.listen": true
|
||||
},
|
||||
"services": {
|
||||
"stt": true,
|
||||
"tts": false,
|
||||
"search": true,
|
||||
"fetch": true,
|
||||
"images": false
|
||||
},
|
||||
"scopes": [
|
||||
"app",
|
||||
"models"
|
||||
],
|
||||
"language_setting": "sk",
|
||||
"languages": [
|
||||
{
|
||||
"id": "en",
|
||||
"name": "English"
|
||||
},
|
||||
{
|
||||
"id": "sk",
|
||||
"name": "Slovenčina"
|
||||
}
|
||||
],
|
||||
"themes": [
|
||||
{
|
||||
"id": "moria",
|
||||
"label": "Moria",
|
||||
"scheme": "dark"
|
||||
},
|
||||
{
|
||||
"id": "shire",
|
||||
"label": "Shire",
|
||||
"scheme": "light"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"memories": [
|
||||
{
|
||||
"id": "mem1",
|
||||
"content": "Prefers lembas warm.",
|
||||
"author": "user",
|
||||
"data_group": {
|
||||
"id": "default",
|
||||
"name": "Default"
|
||||
},
|
||||
"created_at": "2026-01-02T03:04:05+00:00",
|
||||
"updated_at": "2026-01-02T03:04:05+00:00"
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"id": "default",
|
||||
"name": "Default"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"memory": {
|
||||
"id": "mem1",
|
||||
"content": "Prefers lembas warm.",
|
||||
"author": "user",
|
||||
"data_group": {
|
||||
"id": "default",
|
||||
"name": "Default"
|
||||
},
|
||||
"created_at": "2026-01-02T03:04:05+00:00",
|
||||
"updated_at": "2026-01-02T03:04:05+00:00"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"schedule_id": "sched1",
|
||||
"run_id": "run1",
|
||||
"chat_id": "chat1",
|
||||
"status": "ok",
|
||||
"visibility": "private",
|
||||
"actions": [
|
||||
"open",
|
||||
"run_again"
|
||||
],
|
||||
"ask": "",
|
||||
"notification": {
|
||||
"title": "Waybread check",
|
||||
"body": "All the waybread is wrapped.",
|
||||
"public": {
|
||||
"title": "Waybread check",
|
||||
"body": "Finished"
|
||||
},
|
||||
"actions": [
|
||||
"open",
|
||||
"run_again"
|
||||
],
|
||||
"labels": {
|
||||
"open": "Open",
|
||||
"run_again": "Run again"
|
||||
},
|
||||
"ask": ""
|
||||
},
|
||||
"pause_label": "Pause",
|
||||
"title": "LLeMbas",
|
||||
"body": "A scheduled task has finished.",
|
||||
"url": "/scheduled/sched1?run=run1",
|
||||
"kind": "schedule"
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"schedule_id": "sched1",
|
||||
"run_id": "run3",
|
||||
"chat_id": "chat1",
|
||||
"status": "failed",
|
||||
"visibility": "private",
|
||||
"actions": [
|
||||
"open",
|
||||
"run_again",
|
||||
"pause"
|
||||
],
|
||||
"ask": "pause",
|
||||
"notification": {
|
||||
"title": "Waybread check",
|
||||
"body": "Failed 3 times in a row. Pause it?",
|
||||
"public": {
|
||||
"title": "Waybread check",
|
||||
"body": "Failed"
|
||||
},
|
||||
"actions": [
|
||||
"open",
|
||||
"run_again",
|
||||
"pause"
|
||||
],
|
||||
"labels": {
|
||||
"open": "Open",
|
||||
"run_again": "Run again",
|
||||
"pause": "Pause"
|
||||
},
|
||||
"ask": "pause"
|
||||
},
|
||||
"pause_label": "Pause",
|
||||
"title": "LLeMbas",
|
||||
"body": "A scheduled task failed 3 times in a row. Pause it?",
|
||||
"url": "/scheduled/sched1?run=run3",
|
||||
"kind": "schedule_failed"
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"run": {
|
||||
"id": "run1",
|
||||
"schedule_id": "sched1",
|
||||
"status": "ok",
|
||||
"timing": "late",
|
||||
"missed": 0,
|
||||
"due_at": "2026-01-02T03:04:05+00:00",
|
||||
"started_at": "2026-01-02T03:04:05+00:00",
|
||||
"finished_at": "2026-01-02T03:04:05+00:00",
|
||||
"waiting_for": null,
|
||||
"retry_at": null,
|
||||
"progress": null,
|
||||
"attempts": 1,
|
||||
"model": {
|
||||
"id": "gpt-oss",
|
||||
"name": "GPT-OSS",
|
||||
"reason": "switched",
|
||||
"switched_from": "Qwen"
|
||||
},
|
||||
"tokens": {
|
||||
"prompt": 1200,
|
||||
"completion": 340
|
||||
},
|
||||
"cost": null,
|
||||
"chat_id": "chat1",
|
||||
"message_id": "msg2",
|
||||
"report_path": null,
|
||||
"preview": "All the waybread is wrapped.",
|
||||
"error": null,
|
||||
"notified": true,
|
||||
"notification": {
|
||||
"title": "Waybread check",
|
||||
"body": "All the waybread is wrapped.",
|
||||
"public": {
|
||||
"title": "Waybread check",
|
||||
"body": "Finished"
|
||||
},
|
||||
"actions": [
|
||||
"open",
|
||||
"run_again"
|
||||
],
|
||||
"labels": {
|
||||
"open": "Open",
|
||||
"run_again": "Run again"
|
||||
},
|
||||
"ask": ""
|
||||
},
|
||||
"watch": null
|
||||
},
|
||||
"text": "All the waybread is *wrapped*."
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"scope": {
|
||||
"families": [
|
||||
{
|
||||
"gate": "notes",
|
||||
"label": "Notes",
|
||||
"on": true
|
||||
},
|
||||
{
|
||||
"gate": "web",
|
||||
"label": "Web search",
|
||||
"on": false
|
||||
}
|
||||
],
|
||||
"skills": [
|
||||
{
|
||||
"name": "baking",
|
||||
"description": "Bake waybread.",
|
||||
"on": true
|
||||
}
|
||||
],
|
||||
"allow": [
|
||||
"bash:ls *"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"q": "lembas",
|
||||
"in": "all",
|
||||
"offered": [
|
||||
"chats",
|
||||
"files",
|
||||
"memories"
|
||||
],
|
||||
"results": [
|
||||
{
|
||||
"kind": "chats",
|
||||
"more": true,
|
||||
"hits": [
|
||||
{
|
||||
"kind": "chat",
|
||||
"title": "Waybread",
|
||||
"snippet": "…how long does lembas keep & travel?",
|
||||
"marks": [
|
||||
[
|
||||
15,
|
||||
21
|
||||
]
|
||||
],
|
||||
"archived": false,
|
||||
"id": "chat1",
|
||||
"agent": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "files",
|
||||
"more": false,
|
||||
"hits": [
|
||||
{
|
||||
"kind": "file",
|
||||
"title": "bread.md",
|
||||
"snippet": "/home/frodo/bread.md — Lembas recipe",
|
||||
"marks": [
|
||||
[
|
||||
23,
|
||||
29
|
||||
]
|
||||
],
|
||||
"archived": false,
|
||||
"path": "/home/frodo/bread.md"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "memories",
|
||||
"more": false,
|
||||
"hits": [
|
||||
{
|
||||
"kind": "memory",
|
||||
"id": "mem1",
|
||||
"title": "",
|
||||
"snippet": "Prefers lembas warm.",
|
||||
"marks": [
|
||||
[
|
||||
8,
|
||||
14
|
||||
]
|
||||
],
|
||||
"archived": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+54
-22
@@ -994,57 +994,89 @@ test("D4: with no other computer linked there is no choice to make; at 390 px th
|
||||
assert.deepEqual(p.errors, [])
|
||||
})
|
||||
|
||||
// E5: the language and the theme, chosen in Settings and kept in this app.
|
||||
// E5: the language and the theme. The server's /me (fixture me.json) offers its themes and takes
|
||||
// one on PATCH /me; its language is the app's unless Settings chose this computer's or another.
|
||||
|
||||
const ME = fixture("me")
|
||||
const meAs = (over = {}) => ({ ...ME, account: { id: "u1", name: "Ada Example", email: "ada@example.org" }, permissions: {}, ...over })
|
||||
|
||||
async function openSettings(p) {
|
||||
await p.click("#settings-btn")
|
||||
await p.waitForSelector("#set-look")
|
||||
}
|
||||
|
||||
test("E5: the theme is the account's until one is chosen here; chosen, it is drawn at once and kept", async () => {
|
||||
test("E5: the theme is the account's, as /me offers them; chosen, PATCH /me saves it and it is drawn at once", async () => {
|
||||
const p = await page({ status: status(), routes: baseRoutes({ "GET /me": meAs({ language: "en" }), "PATCH /me": meAs({ language: "en", theme: "moria" }) }), streams: {} })
|
||||
await p.waitForFunction(() => document.documentElement.dataset.theme === "shire")
|
||||
await openSettings(p)
|
||||
assert.equal(await p.inputValue("#set-theme"), "shire")
|
||||
assert.deepEqual(await p.$$eval("#set-theme option", (o) => o.map((x) => x.textContent)), ["Moria — dark", "Shire — light"])
|
||||
await p.selectOption("#set-theme", "moria")
|
||||
await p.waitForFunction(() => document.documentElement.dataset.theme === "moria")
|
||||
const [saved] = await p.evaluate(() => window.__mock.api("PATCH", "/me"))
|
||||
assert.deepEqual(saved.args.body, { theme: "moria" })
|
||||
const painted = await p.evaluate(() => window.__mock.calls.filter((c) => c.cmd === "set_theme").map((c) => c.args.name))
|
||||
assert.equal(painted.at(-1), "moria", "the window is painted in it too")
|
||||
assert.equal(await p.inputValue("#set-theme"), "moria")
|
||||
assert.deepEqual(p.errors, [])
|
||||
})
|
||||
|
||||
test("E5: a theme the server refuses is said, and the look stays", async () => {
|
||||
const p = await page({ status: status(), routes: baseRoutes({ "GET /me": meAs({ language: "en" }), "PATCH /me": { __error: { status: 400, detail: "That theme is not offered." } } }), streams: {} })
|
||||
await openSettings(p)
|
||||
await p.selectOption("#set-theme", "moria")
|
||||
await p.waitForSelector("#set-look [role=alert]")
|
||||
assert.match(await p.textContent("#set-look [role=alert]"), /not offered/)
|
||||
assert.equal(await p.evaluate(() => document.documentElement.dataset.theme), "shire")
|
||||
assert.equal(await p.inputValue("#set-theme"), "shire")
|
||||
assert.deepEqual(p.errors, [])
|
||||
})
|
||||
|
||||
test("E5: a server that cannot be told: the theme chosen is kept in the app, over the account's", async () => {
|
||||
const p = await page({ status: status(), routes: baseRoutes({ "GET /me": { id: "u1", name: "Ada Example", email: "ada@example.org", theme: "shire", language: "en", permissions: {} } }), streams: {} })
|
||||
await p.waitForFunction(() => document.documentElement.dataset.theme === "shire")
|
||||
await openSettings(p)
|
||||
assert.equal(await p.inputValue("#set-theme"), "")
|
||||
assert.match(await p.textContent("#set-theme option[value='']"), /account.*Shire/)
|
||||
await p.selectOption("#set-theme", "moria")
|
||||
assert.equal(await p.evaluate(() => document.documentElement.dataset.theme), "moria")
|
||||
const painted = await p.evaluate(() => window.__mock.calls.filter((c) => c.cmd === "set_theme").map((c) => c.args.name))
|
||||
assert.equal(painted.at(-1), "moria", "the window is painted in it too")
|
||||
// Opened again: still Moria, over the account's Shire.
|
||||
await p.waitForFunction(() => document.documentElement.dataset.theme === "moria")
|
||||
assert.equal(await p.evaluate(() => window.__mock.api("PATCH", "/me").length), 0, "nothing sent")
|
||||
await p.reload()
|
||||
await p.waitForSelector("#shell:not([hidden])")
|
||||
await p.waitForFunction(() => window.__mock.calls.some((c) => c.cmd === "set_theme"))
|
||||
assert.equal(await p.evaluate(() => document.documentElement.dataset.theme), "moria")
|
||||
await openSettings(p)
|
||||
assert.equal(await p.inputValue("#set-theme"), "moria")
|
||||
await p.selectOption("#set-theme", "")
|
||||
assert.equal(await p.evaluate(() => document.documentElement.dataset.theme), "shire", "back to the account's")
|
||||
await p.waitForFunction(() => document.documentElement.dataset.theme === "shire")
|
||||
assert.deepEqual(p.errors, [])
|
||||
})
|
||||
|
||||
test("E5: a language chosen here opens the window again in it, the shells let go first; the system's again undoes it", async () => {
|
||||
const p = await page(b3())
|
||||
assert.equal(await p.evaluate(() => document.documentElement.lang), "en")
|
||||
test("E5: the account's language is the app's; this computer's or another, chosen, opens the window again in it, the shells let go first", async () => {
|
||||
const p = await page({ ...b3(), routes: { ...b3().routes, "GET /me": meAs({ language: "de", theme: "moria" }) } })
|
||||
// The account says German: the window opens again in it, once.
|
||||
await p.waitForFunction(() => document.documentElement.lang === "de", null, { timeout: 15000 })
|
||||
await p.waitForSelector("#shell:not([hidden])")
|
||||
assert.equal((await p.textContent("#settings-btn .navrow__label")).trim(), "Einstellungen")
|
||||
await openChatRow(p, "chat2")
|
||||
await p.click('#chat-tools [data-terminal-toggle]')
|
||||
await p.waitForFunction(() => window.__mock.terminals().length === 1)
|
||||
// What the page let go of before it loaded again, kept across the load.
|
||||
await p.evaluate(() => addEventListener("beforeunload", () => localStorage.setItem("test.calls", JSON.stringify(window.__mock.calls.map((c) => c.cmd)))))
|
||||
await openSettings(p)
|
||||
assert.match(await p.textContent("#set-language option[value='']"), /English/)
|
||||
await Promise.all([p.waitForEvent("load"), p.selectOption("#set-language", "de")])
|
||||
await p.waitForSelector("#shell:not([hidden])")
|
||||
assert.equal(await p.evaluate(() => document.documentElement.lang), "de")
|
||||
assert.equal((await p.textContent("#settings-btn .navrow__label")).trim(), "Einstellungen")
|
||||
const before = await p.evaluate(() => JSON.parse(localStorage.getItem("test.calls") || "[]"))
|
||||
assert.ok(before.includes("terminal_close"), "the shell was let go")
|
||||
await openSettings(p)
|
||||
assert.equal(await p.inputValue("#set-language"), "de")
|
||||
assert.match(await p.textContent("#set-look"), /Sprache/)
|
||||
await Promise.all([p.waitForEvent("load"), p.selectOption("#set-language", "")])
|
||||
assert.equal(await p.inputValue("#set-language"), "")
|
||||
assert.match(await p.textContent("#set-language option[value='']"), /Deutsch/)
|
||||
await Promise.all([p.waitForEvent("load"), p.selectOption("#set-language", "system")])
|
||||
await p.waitForSelector("#shell:not([hidden])")
|
||||
assert.equal(await p.evaluate(() => document.documentElement.lang), "en")
|
||||
const before = await p.evaluate(() => JSON.parse(localStorage.getItem("test.calls") || "[]"))
|
||||
assert.ok(before.includes("terminal_close"), "the shell was let go")
|
||||
await p.waitForTimeout(300)
|
||||
assert.equal(await p.evaluate(() => document.documentElement.lang), "en", "the account's German does not take it back")
|
||||
await openSettings(p)
|
||||
assert.equal(await p.inputValue("#set-language"), "system")
|
||||
await Promise.all([p.waitForEvent("load"), p.selectOption("#set-language", "fr")])
|
||||
await p.waitForSelector("#shell:not([hidden])")
|
||||
assert.equal(await p.evaluate(() => document.documentElement.lang), "fr")
|
||||
assert.deepEqual(p.errors, [])
|
||||
})
|
||||
|
||||
|
||||
Reference in new issue
Block a user