fix: workover of the monaco update
This commit is contained in:
@@ -158,8 +158,9 @@ mix assets.build
|
||||
|
||||
## Monaco Editor
|
||||
|
||||
Monaco is bundled via esbuild using its ESM entry point (`monaco-editor/esm/vs/editor/editor.api.js`). The
|
||||
bundle is built as part of `mix assets.build` and lives at `priv/static/assets/monaco.js` and `monaco.css`.
|
||||
Monaco is bundled via esbuild using its ESM entry point (`monaco-editor/esm/vs/editor/editor.main.js`). The
|
||||
main bundle is built as part of `mix assets.build` and lives at `priv/static/assets/monaco.js` and
|
||||
`monaco.css`; ESM worker bundles live under `priv/static/assets/monaco/`.
|
||||
|
||||
```bash
|
||||
mix monaco.version # show current monaco-editor version
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// App-wide error reporter — catches JS errors and displays them as an overlay.
|
||||
// Enables debugging in WKWebView where devtools are unavailable.
|
||||
(function () {
|
||||
const overlay = document.createElement("div");
|
||||
overlay.id = "error-reporter";
|
||||
overlay.style.cssText =
|
||||
"position:fixed;bottom:0;left:0;right:0;max-height:200px;overflow:auto;background:#1a1a2e;color:#f0f0f0;font:12px monospace;padding:8px 12px;border-top:2px solid #e74c3c;z-index:99999;display:none;";
|
||||
overlay.innerHTML = '<strong style="color:#e74c3c">⚠ JS Errors</strong><pre id="error-reporter-log"></pre>';
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
const log = document.getElementById("error-reporter-log");
|
||||
|
||||
const append = (msg) => {
|
||||
overlay.style.display = "block";
|
||||
log.textContent += msg + "\n";
|
||||
overlay.scrollTop = overlay.scrollHeight;
|
||||
};
|
||||
|
||||
window.addEventListener("error", (e) => {
|
||||
const src = e.filename || "";
|
||||
const loc = e.lineno !== undefined ? `:${e.lineno}` : "";
|
||||
append(`[${new Date().toLocaleTimeString()}] ${e.message || e.error}\n at ${src}${loc}`);
|
||||
});
|
||||
|
||||
window.addEventListener("unhandledrejection", (e) => {
|
||||
append(`[${new Date().toLocaleTimeString()}] Unhandled rejection: ${e.reason}`);
|
||||
});
|
||||
|
||||
// Also wrap console.error to catch Monaco errors
|
||||
const origError = console.error;
|
||||
console.error = (...args) => {
|
||||
origError.apply(console, args);
|
||||
append(`[${new Date().toLocaleTimeString()}] ${args.join(" ")}`);
|
||||
};
|
||||
})();
|
||||
@@ -4,7 +4,51 @@ import { registerLiquidLanguage, registerMarkdownWithMacrosLanguage } from "./la
|
||||
let monacoLoaderPromise;
|
||||
const monacoEditors = new Map();
|
||||
|
||||
const monacoWorkerUrls = {
|
||||
editor: "/assets/monaco/editor.worker.js",
|
||||
css: "/assets/monaco/css.worker.js",
|
||||
html: "/assets/monaco/html.worker.js",
|
||||
json: "/assets/monaco/json.worker.js",
|
||||
ts: "/assets/monaco/ts.worker.js"
|
||||
};
|
||||
|
||||
const workerNameForLanguage = (label) => {
|
||||
switch (label) {
|
||||
case "css":
|
||||
case "scss":
|
||||
case "less":
|
||||
return "css";
|
||||
case "html":
|
||||
case "handlebars":
|
||||
case "razor":
|
||||
return "html";
|
||||
case "json":
|
||||
return "json";
|
||||
case "typescript":
|
||||
case "javascript":
|
||||
return "ts";
|
||||
default:
|
||||
return "editor";
|
||||
}
|
||||
};
|
||||
|
||||
const ensureMonacoEnvironment = () => {
|
||||
if (globalThis.MonacoEnvironment?.getWorker) {
|
||||
return;
|
||||
}
|
||||
|
||||
globalThis.MonacoEnvironment = {
|
||||
...globalThis.MonacoEnvironment,
|
||||
getWorker(_workerId, label) {
|
||||
const workerName = workerNameForLanguage(label);
|
||||
return new Worker(monacoWorkerUrls[workerName], { name: label, type: "module" });
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const loadMonaco = () => {
|
||||
ensureMonacoEnvironment();
|
||||
|
||||
if (window.monaco?.editor) {
|
||||
ensureMonacoTheme(window.monaco);
|
||||
registerLiquidLanguage(window.monaco);
|
||||
|
||||
1
assets/js/monaco_workers/css.worker.js
Normal file
1
assets/js/monaco_workers/css.worker.js
Normal file
@@ -0,0 +1 @@
|
||||
import "monaco-editor/esm/vs/language/css/css.worker.js";
|
||||
1
assets/js/monaco_workers/editor.worker.js
Normal file
1
assets/js/monaco_workers/editor.worker.js
Normal file
@@ -0,0 +1 @@
|
||||
import "monaco-editor/esm/vs/editor/editor.worker.js";
|
||||
1
assets/js/monaco_workers/html.worker.js
Normal file
1
assets/js/monaco_workers/html.worker.js
Normal file
@@ -0,0 +1 @@
|
||||
import "monaco-editor/esm/vs/language/html/html.worker.js";
|
||||
1
assets/js/monaco_workers/json.worker.js
Normal file
1
assets/js/monaco_workers/json.worker.js
Normal file
@@ -0,0 +1 @@
|
||||
import "monaco-editor/esm/vs/language/json/json.worker.js";
|
||||
1
assets/js/monaco_workers/ts.worker.js
Normal file
1
assets/js/monaco_workers/ts.worker.js
Normal file
@@ -0,0 +1 @@
|
||||
import "monaco-editor/esm/vs/language/typescript/ts.worker.js";
|
||||
@@ -67,6 +67,22 @@ config :esbuild,
|
||||
--loader:.ttf=dataurl
|
||||
),
|
||||
env: %{"NODE_PATH" => Path.expand("../node_modules", __DIR__)}
|
||||
],
|
||||
monaco_workers: [
|
||||
cd: Path.expand("../assets", __DIR__),
|
||||
args: ~w(
|
||||
js/monaco_workers/editor.worker.js
|
||||
js/monaco_workers/css.worker.js
|
||||
js/monaco_workers/html.worker.js
|
||||
js/monaco_workers/json.worker.js
|
||||
js/monaco_workers/ts.worker.js
|
||||
--bundle
|
||||
--target=es2022
|
||||
--format=esm
|
||||
--outdir=../priv/static/assets/monaco
|
||||
--loader:.ttf=dataurl
|
||||
),
|
||||
env: %{"NODE_PATH" => Path.expand("../node_modules", __DIR__)}
|
||||
]
|
||||
|
||||
config :bds, :scripting,
|
||||
|
||||
@@ -17,7 +17,7 @@ defmodule BDS.Desktop.Endpoint do
|
||||
plug(Plug.Static,
|
||||
at: "/assets",
|
||||
from: {:bds, "priv/static/assets"},
|
||||
only: ["app.css", "app.js", "monaco.css", "monaco.js"]
|
||||
only: ["app.css", "app.js", "monaco.css", "monaco.js", "monaco"]
|
||||
)
|
||||
|
||||
plug(BDS.Desktop.Router)
|
||||
|
||||
@@ -9,8 +9,8 @@ defmodule Mix.Tasks.Monaco.Update do
|
||||
This task:
|
||||
|
||||
1. Runs `npm install monaco-editor@<version> --save-dev`
|
||||
2. Removes the old `priv/static/assets/monaco.js` and `monaco.css`
|
||||
3. Rebuilds the Monaco bundle via esbuild (both dev and minified)
|
||||
2. Removes the old Monaco bundle assets
|
||||
3. Rebuilds the Monaco main and worker bundles via esbuild (both dev and minified)
|
||||
|
||||
Use `mix monaco.version` to check the result.
|
||||
|
||||
@@ -27,14 +27,14 @@ defmodule Mix.Tasks.Monaco.Update do
|
||||
Mix.shell().error("Missing version argument.")
|
||||
Mix.shell().info("Usage: mix monaco.update <version>")
|
||||
Mix.shell().info("Example: mix monaco.update 0.55.1")
|
||||
System.at_exit(fn _ -> System.halt(1) end)
|
||||
Mix.raise("missing Monaco version argument")
|
||||
|
||||
[version] ->
|
||||
do_update(version)
|
||||
|
||||
_ ->
|
||||
Mix.shell().error("Too many arguments. Usage: mix monaco.update <version>")
|
||||
System.at_exit(fn _ -> System.halt(1) end)
|
||||
Mix.raise("too many arguments for mix monaco.update")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -49,24 +49,31 @@ defmodule Mix.Tasks.Monaco.Update do
|
||||
# 2. Clean old bundle
|
||||
monaco_js = Path.join(File.cwd!(), "priv/static/assets/monaco.js")
|
||||
monaco_css = Path.join(File.cwd!(), "priv/static/assets/monaco.css")
|
||||
monaco_workers = Path.join(File.cwd!(), "priv/static/assets/monaco")
|
||||
|
||||
for path <- [monaco_js, monaco_css] do
|
||||
for path <- [monaco_js, monaco_css, monaco_workers] do
|
||||
if File.exists?(path) do
|
||||
File.rm!(path)
|
||||
File.rm_rf!(path)
|
||||
end
|
||||
end
|
||||
|
||||
Mix.shell().info("Removed old monaco.js and monaco.css")
|
||||
Mix.shell().info("Removed old Monaco bundle assets")
|
||||
|
||||
# 3. Rebuild via esbuild (dev + minified)
|
||||
Mix.Task.run("esbuild", ["monaco"])
|
||||
Mix.Task.run("esbuild", ["monaco", "--minify"])
|
||||
run_esbuild(["monaco"])
|
||||
run_esbuild(["monaco_workers"])
|
||||
run_esbuild(["monaco", "--minify"])
|
||||
run_esbuild(["monaco_workers", "--minify"])
|
||||
|
||||
# 4. Verify
|
||||
new = current_version()
|
||||
Mix.shell().info("monaco-editor is now at #{new}")
|
||||
end
|
||||
|
||||
defp run_esbuild(args) do
|
||||
Mix.Task.run("esbuild", args)
|
||||
end
|
||||
|
||||
defp current_version do
|
||||
lock = Path.join(File.cwd!(), "package-lock.json")
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ defmodule Mix.Tasks.Monaco.Version do
|
||||
|
||||
mix monaco.version
|
||||
|
||||
Reads the version from package-lock.json. The Monaco bundle lives at
|
||||
`priv/static/assets/monaco.js` and is built via `mix esbuild monaco`.
|
||||
Reads the version from package-lock.json. The Monaco main bundle lives at
|
||||
`priv/static/assets/monaco.js`; worker bundles live under
|
||||
`priv/static/assets/monaco/`.
|
||||
"""
|
||||
|
||||
use Mix.Task
|
||||
@@ -30,12 +31,12 @@ defmodule Mix.Tasks.Monaco.Version do
|
||||
v when is_binary(v) -> Mix.shell().info("monaco-editor: #{v}")
|
||||
nil ->
|
||||
Mix.shell().error("Could not find monaco-editor in package-lock.json")
|
||||
System.at_exit(fn _ -> System.halt(1) end)
|
||||
Mix.raise("could not find monaco-editor in package-lock.json")
|
||||
end
|
||||
|
||||
{:error, reason} ->
|
||||
Mix.shell().error("package-lock.json not found: #{reason}")
|
||||
System.at_exit(fn _ -> System.halt(1) end)
|
||||
Mix.raise("package-lock.json not found: #{reason}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
9
mix.exs
9
mix.exs
@@ -66,8 +66,13 @@ defmodule BDS.MixProject do
|
||||
"ecto.setup": ["ecto.create", "ecto.migrate"],
|
||||
"ecto.reset": ["ecto.drop", "ecto.setup"],
|
||||
"assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"],
|
||||
"assets.build": ["tailwind default", "esbuild default", "esbuild monaco"],
|
||||
"assets.deploy": ["tailwind default --minify", "esbuild default --minify", "esbuild monaco"],
|
||||
"assets.build": ["tailwind default", "esbuild default", "esbuild monaco", "esbuild monaco_workers"],
|
||||
"assets.deploy": [
|
||||
"tailwind default --minify",
|
||||
"esbuild default --minify",
|
||||
"esbuild monaco --minify",
|
||||
"esbuild monaco_workers --minify"
|
||||
],
|
||||
test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"],
|
||||
validate: ["test", "credo --strict", "deps.audit --ignore-file .mix_audit.ignore", "dialyzer"]
|
||||
]
|
||||
|
||||
39
priv/static/assets/app.js
vendored
39
priv/static/assets/app.js
vendored
@@ -8821,7 +8821,46 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
||||
// js/monaco/services.js
|
||||
var monacoLoaderPromise;
|
||||
var monacoEditors = /* @__PURE__ */ new Map();
|
||||
var monacoWorkerUrls = {
|
||||
editor: "/assets/monaco/editor.worker.js",
|
||||
css: "/assets/monaco/css.worker.js",
|
||||
html: "/assets/monaco/html.worker.js",
|
||||
json: "/assets/monaco/json.worker.js",
|
||||
ts: "/assets/monaco/ts.worker.js"
|
||||
};
|
||||
var workerNameForLanguage = (label) => {
|
||||
switch (label) {
|
||||
case "css":
|
||||
case "scss":
|
||||
case "less":
|
||||
return "css";
|
||||
case "html":
|
||||
case "handlebars":
|
||||
case "razor":
|
||||
return "html";
|
||||
case "json":
|
||||
return "json";
|
||||
case "typescript":
|
||||
case "javascript":
|
||||
return "ts";
|
||||
default:
|
||||
return "editor";
|
||||
}
|
||||
};
|
||||
var ensureMonacoEnvironment = () => {
|
||||
if (globalThis.MonacoEnvironment?.getWorker) {
|
||||
return;
|
||||
}
|
||||
globalThis.MonacoEnvironment = {
|
||||
...globalThis.MonacoEnvironment,
|
||||
getWorker(_workerId, label) {
|
||||
const workerName = workerNameForLanguage(label);
|
||||
return new Worker(monacoWorkerUrls[workerName], { name: label, type: "module" });
|
||||
}
|
||||
};
|
||||
};
|
||||
var loadMonaco = () => {
|
||||
ensureMonacoEnvironment();
|
||||
if (window.monaco?.editor) {
|
||||
ensureMonacoTheme(window.monaco);
|
||||
registerLiquidLanguage(window.monaco);
|
||||
|
||||
File diff suppressed because one or more lines are too long
239905
priv/static/assets/monaco.js
vendored
239905
priv/static/assets/monaco.js
vendored
File diff suppressed because one or more lines are too long
93
priv/static/assets/monaco/css.worker.js
vendored
Normal file
93
priv/static/assets/monaco/css.worker.js
vendored
Normal file
File diff suppressed because one or more lines are too long
26
priv/static/assets/monaco/editor.worker.js
vendored
Normal file
26
priv/static/assets/monaco/editor.worker.js
vendored
Normal file
File diff suppressed because one or more lines are too long
470
priv/static/assets/monaco/html.worker.js
vendored
Normal file
470
priv/static/assets/monaco/html.worker.js
vendored
Normal file
File diff suppressed because one or more lines are too long
58
priv/static/assets/monaco/json.worker.js
vendored
Normal file
58
priv/static/assets/monaco/json.worker.js
vendored
Normal file
File diff suppressed because one or more lines are too long
67736
priv/static/assets/monaco/ts.worker.js
vendored
Normal file
67736
priv/static/assets/monaco/ts.worker.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
scripts/desktop_automation_app.exs
Normal file
7
scripts/desktop_automation_app.exs
Normal file
@@ -0,0 +1,7 @@
|
||||
Enum.reduce_while(IO.stream(:stdio, :line), :ok, fn line, _acc ->
|
||||
if String.trim(line) == "stop" do
|
||||
{:halt, :ok}
|
||||
else
|
||||
{:cont, :ok}
|
||||
end
|
||||
end)
|
||||
138
scripts/desktop_automation_runner.mjs
Normal file
138
scripts/desktop_automation_runner.mjs
Normal file
@@ -0,0 +1,138 @@
|
||||
import { chromium } from "playwright";
|
||||
import readline from "node:readline";
|
||||
|
||||
const [url, screenshotDir] = process.argv.slice(2);
|
||||
|
||||
if (!url) {
|
||||
console.log(JSON.stringify({ status: "error", message: "missing automation url" }));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
|
||||
|
||||
try {
|
||||
await page.goto(url, { waitUntil: "networkidle" });
|
||||
await page.locator("#bds-shell-app").waitFor({ state: "visible" });
|
||||
await page.emulateMedia({ reducedMotion: "reduce" });
|
||||
console.log(JSON.stringify({ status: "ready", screenshotDir }));
|
||||
} catch (error) {
|
||||
console.log(JSON.stringify({ status: "error", message: error.message }));
|
||||
await browser.close();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const rl = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });
|
||||
|
||||
for await (const line of rl) {
|
||||
if (!line.trim()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const message = JSON.parse(line);
|
||||
const ref = message.ref;
|
||||
|
||||
try {
|
||||
if (message.command === "snapshot") {
|
||||
const result = await page.evaluate(() => {
|
||||
const text = (selector) => document.querySelector(selector)?.textContent?.trim() ?? null;
|
||||
const texts = (selector, mapper) => Array.from(document.querySelectorAll(selector)).map(mapper);
|
||||
const hasClass = (selector, className) => document.querySelector(selector)?.classList.contains(className) ?? false;
|
||||
|
||||
return {
|
||||
window_title: text("[data-testid='window-title']"),
|
||||
active_view: document.querySelector("[data-testid='activity-button'][data-active='true']")?.dataset.view ?? null,
|
||||
sidebar_visible: !hasClass("[data-testid='sidebar-shell']", "is-hidden"),
|
||||
sidebar_width: document.querySelector("[data-testid='sidebar-shell']")?.getBoundingClientRect().width ?? 0,
|
||||
assistant_visible: !hasClass("[data-testid='assistant-shell']", "is-hidden"),
|
||||
assistant_width: document.querySelector("[data-testid='assistant-shell']")?.getBoundingClientRect().width ?? 0,
|
||||
panel_visible: !hasClass(".panel-shell", "is-hidden"),
|
||||
editor_title: text("[data-testid='editor-title']"),
|
||||
activity_labels: texts("[data-testid='activity-button']", (node) => node.getAttribute("aria-label")),
|
||||
sidebar_sections: texts("[data-testid='sidebar-section-title']", (node) => node.textContent.trim()),
|
||||
editor_meta_labels: texts("[data-testid='editor-meta-label']", (node) => node.textContent.trim())
|
||||
};
|
||||
});
|
||||
|
||||
console.log(JSON.stringify({ ref, status: "ok", result }));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message.command === "click") {
|
||||
await page.locator(message.selector).click();
|
||||
await page.waitForTimeout(50);
|
||||
console.log(JSON.stringify({ ref, status: "ok", result: "ok" }));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message.command === "press") {
|
||||
await page.keyboard.press(message.shortcut);
|
||||
await page.waitForTimeout(50);
|
||||
console.log(JSON.stringify({ ref, status: "ok", result: "ok" }));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message.command === "native_menu_action") {
|
||||
await page.evaluate((action) => {
|
||||
return new Promise((resolve) => {
|
||||
const ackId = `ack-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
||||
const handler = (event) => {
|
||||
if (event.detail?.ackId === ackId) {
|
||||
window.removeEventListener("bds:native-menu-action-ack", handler);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
window.addEventListener("bds:native-menu-action-ack", handler);
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("bds:native-menu-action", { detail: { action, ackId } })
|
||||
);
|
||||
});
|
||||
}, message.action);
|
||||
console.log(JSON.stringify({ ref, status: "ok", result: "ok" }));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message.command === "drag") {
|
||||
const locator = page.locator(message.selector);
|
||||
const box = await locator.boundingBox();
|
||||
|
||||
if (!box) {
|
||||
throw new Error(`unable to drag missing element: ${message.selector}`);
|
||||
}
|
||||
|
||||
const startX = box.x + box.width / 2;
|
||||
const startY = box.y + box.height / 2;
|
||||
await page.mouse.move(startX, startY);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(startX + message.deltaX, startY, { steps: 10 });
|
||||
await page.mouse.up();
|
||||
await page.waitForTimeout(50);
|
||||
console.log(JSON.stringify({ ref, status: "ok", result: "ok" }));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message.command === "reload") {
|
||||
await page.reload({ waitUntil: "networkidle" });
|
||||
await page.locator("#bds-shell-app").waitFor({ state: "visible" });
|
||||
await page.waitForTimeout(100);
|
||||
console.log(JSON.stringify({ ref, status: "ok", result: "ok" }));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message.command === "screenshot") {
|
||||
await page.screenshot({ path: message.path, fullPage: false });
|
||||
console.log(JSON.stringify({ ref, status: "ok", result: message.path }));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message.command === "close") {
|
||||
await browser.close();
|
||||
console.log(JSON.stringify({ ref, status: "ok", result: "closed" }));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log(JSON.stringify({ ref, status: "error", message: `unknown command: ${message.command}` }));
|
||||
} catch (error) {
|
||||
console.log(JSON.stringify({ ref, status: "error", message: error.message }));
|
||||
}
|
||||
}
|
||||
@@ -88,6 +88,7 @@ defmodule BDS.AI.ChatStreamingTest do
|
||||
|
||||
setup do
|
||||
:ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo)
|
||||
Ecto.Adapters.SQL.Sandbox.mode(BDS.Repo, {:shared, self()})
|
||||
|
||||
Application.put_env(:bds, :chat_stream_test_pid, self())
|
||||
Application.put_env(:bds, :chat_stream_scenario, :short)
|
||||
@@ -101,6 +102,7 @@ defmodule BDS.AI.ChatStreamingTest do
|
||||
)
|
||||
|
||||
on_exit(fn ->
|
||||
Ecto.Adapters.SQL.Sandbox.mode(BDS.Repo, :manual)
|
||||
Application.delete_env(:bds, :chat_stream_scenario)
|
||||
|
||||
case original_chat do
|
||||
|
||||
@@ -325,6 +325,8 @@ defmodule BDS.AITest do
|
||||
|
||||
setup do
|
||||
:ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo)
|
||||
Ecto.Adapters.SQL.Sandbox.mode(BDS.Repo, {:shared, self()})
|
||||
on_exit(fn -> Ecto.Adapters.SQL.Sandbox.mode(BDS.Repo, :manual) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
|
||||
@@ -352,6 +352,7 @@ defmodule BDS.DesktopTest do
|
||||
|
||||
assert conn.resp_body =~ ~s(data-phx-main)
|
||||
assert conn.resp_body =~ ~s(href="/assets/app.css")
|
||||
assert conn.resp_body =~ ~s(href="/assets/monaco.css")
|
||||
assert conn.resp_body =~ ~s(src="/assets/app.js")
|
||||
refute conn.resp_body =~ ~s(src="/assets/live.js")
|
||||
refute conn.resp_body =~ ~s(src="/vendor/phoenix/phoenix.min.js")
|
||||
@@ -371,6 +372,31 @@ defmodule BDS.DesktopTest do
|
||||
assert byte_size(js_conn.resp_body) > 0
|
||||
end
|
||||
|
||||
test "desktop endpoint serves Monaco ESM bundle and worker assets" do
|
||||
paths = [
|
||||
"/assets/monaco.css",
|
||||
"/assets/monaco.js",
|
||||
"/assets/monaco/editor.worker.js",
|
||||
"/assets/monaco/css.worker.js",
|
||||
"/assets/monaco/html.worker.js",
|
||||
"/assets/monaco/json.worker.js",
|
||||
"/assets/monaco/ts.worker.js"
|
||||
]
|
||||
|
||||
for path <- paths do
|
||||
asset_conn = conn(:get, "#{path}?k=#{Desktop.Auth.login_key()}")
|
||||
asset_conn = BDS.Desktop.Endpoint.call(asset_conn, BDS.Desktop.Endpoint.init([]))
|
||||
|
||||
assert asset_conn.status == 200
|
||||
assert byte_size(asset_conn.resp_body) > 0
|
||||
end
|
||||
end
|
||||
|
||||
test "desktop automation launch scripts exist at the paths used by automation" do
|
||||
assert File.regular?("/Users/gb/Projects/bDS2/scripts/desktop_automation_app.exs")
|
||||
assert File.regular?("/Users/gb/Projects/bDS2/scripts/desktop_automation_runner.mjs")
|
||||
end
|
||||
|
||||
test "desktop endpoint serves the live shell without extra router-side secret injection" do
|
||||
conn = conn(:get, "/?k=#{Desktop.Auth.login_key()}")
|
||||
conn = BDS.Desktop.Endpoint.call(conn, BDS.Desktop.Endpoint.init([]))
|
||||
|
||||
@@ -358,6 +358,22 @@ defmodule BDS.UI.ShellTest do
|
||||
assert File.exists?("/Users/gb/Projects/bDS2/assets/js/monaco/languages.js")
|
||||
end
|
||||
|
||||
test "monaco ESM build config emits served worker bundles" do
|
||||
mix_exs = File.read!("/Users/gb/Projects/bDS2/mix.exs")
|
||||
config = File.read!("/Users/gb/Projects/bDS2/config/config.exs")
|
||||
services = File.read!("/Users/gb/Projects/bDS2/assets/js/monaco/services.js")
|
||||
update_task = File.read!("/Users/gb/Projects/bDS2/lib/mix/tasks/monaco.update.ex")
|
||||
|
||||
assert mix_exs =~ ~s("esbuild monaco --minify")
|
||||
assert mix_exs =~ ~s("esbuild monaco_workers --minify")
|
||||
assert config =~ "monaco_workers:"
|
||||
assert config =~ "js/monaco_workers/editor.worker.js"
|
||||
assert services =~ "globalThis.MonacoEnvironment"
|
||||
assert services =~ "/assets/monaco/editor.worker.js"
|
||||
assert update_task =~ ~S|run_esbuild(["monaco_workers", "--minify"])|
|
||||
refute File.exists?("/Users/gb/Projects/bDS2/assets/js/error_reporter.js")
|
||||
end
|
||||
|
||||
test "top level shell render uses utility classes for common layout" do
|
||||
template = File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/index.html.heex")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user