Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,18 @@ jobs:
run: python -m unittest discover tests -v

- name: Set up Node for frontend smoke test
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
if: matrix.python-version == '3.13'
uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm

- name: Install frontend test dependencies
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
if: matrix.python-version == '3.13'
run: npm ci

- name: Install Playwright Chromium
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
if: matrix.python-version == '3.13'
run: npx playwright install chromium

- name: Prepare pinned llama.cpp CPU binaries
Expand Down Expand Up @@ -99,6 +99,6 @@ jobs:
print(f'Prepared llama.cpp {pin["tag"]}: {pin["asset"]}')
PY

- name: Run frontend tests with required flag compatibility
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
- name: Run frontend tests
if: matrix.python-version == '3.13'
run: npm test
4 changes: 2 additions & 2 deletions docs/tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ node tests/frontend/llama_flags_supported_unit.cjs --require-binaries

An explicit `LLAMA_GUI_LLAMA_BIN_DIR` (or legacy `LLAMA_CPP_BIN_DIR`) requires both executables and disables fallback to other installations. Missing binaries, failed/timed-out `--help`, and unsupported flags fail the check. `--require-binaries` also requires an explicit directory. This checks advertised flag names, including negated booleans; it does not validate enum values or GPU execution. Fork-only flags are excluded.

The Ubuntu/Python 3.13 CI job installs the `libgomp1` OpenMP runtime, downloads the exact CPU release in `tests/llama-cpp-pin.json`, verifies its SHA256, and sets the explicit directory before `npm test`. Update the tag, asset, and checksum together from an official llama.cpp release, then run compatibility before accepting the new pin. No model or GPU is needed.
The Ubuntu and Windows/Python 3.13 CI jobs run `npm test`, including the unit and browser suites. The Ubuntu job also installs the `libgomp1` OpenMP runtime, downloads the exact CPU release in `tests/llama-cpp-pin.json`, verifies its SHA256, and sets the explicit directory for required binary compatibility. The Windows job uses the same optional binary check as the release workflow. Update the tag, asset, and checksum together from an official llama.cpp release, then run compatibility before accepting the new pin. No model or GPU is needed.

```powershell
npm run test:frontend
```

Runs the Playwright smoke test for browser-level shared-state sync. This is also the only suite that can cover the Configure sampler preset panel, because `renderFlags()` destroys and rebuilds it — the `<select>` an assertion reads is a different element than the one that was clicked, which a `node:vm` harness cannot reproduce.

The browser suite has named `node:test` scenarios with fresh browser contexts and API fixtures. Shared controls, authentication, inference, Chat streaming/recovery/compaction, samplers, external servers, custom launch arguments, backend activation, model switching, preset focus, model folders, and Monitor behavior run independently. A scenario failure does not prevent the remaining scenarios from running. To run one scenario:
The browser suite has named `node:test` scenarios with fresh browser contexts and API fixtures. Shared controls, authentication, inference, Chat streaming/recovery/compaction, samplers, external servers, custom launch arguments, backend activation, model switching, preset focus, model folders, and Monitor behavior run independently. A scenario failure does not prevent the remaining scenarios from running. Smoke-test startup failures retain the original error as their cause and include captured page errors, or an explicit indication that none were captured. An injected Configure rendering failure verifies the startup-timeout diagnostic. To run one scenario:

```powershell
node --test --test-name-pattern="benchmark actions" tests/frontend/flag_sync_smoke.cjs
Expand Down
36 changes: 33 additions & 3 deletions tests/frontend/flag_sync_smoke.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2124,9 +2124,13 @@ async function runScenario(browser, port, verify) {
});
});

await page.goto(`http://127.0.0.1:${port}/`, { waitUntil: "domcontentloaded" });
await page.waitForFunction(() => window.LlamaGui?.flagCore && window.LlamaGui?.configFlagsUi);
await page.waitForSelector("#flag-ctx_size", { state: "attached" });
try {
await page.goto(`http://127.0.0.1:${port}/`, { waitUntil: "domcontentloaded" });
await page.waitForFunction(() => window.LlamaGui?.flagCore && window.LlamaGui?.configFlagsUi);
await page.waitForSelector("#flag-ctx_size", { state: "attached" });
} catch (error) {
throw new Error(`${error.message}\nPage errors during startup:\n${pageErrors.join("\n") || "(none captured)"}`, { cause: error });
}
assert.deepEqual(lifecycleWarnings, [], "initial lifecycle rendering must have configured dependencies");

if (typeof verify === "function") {
Expand Down Expand Up @@ -4506,6 +4510,32 @@ async function verifyOfficialBackendDiscovery(page) {
assert.deepEqual(writes, [], "discovery never installs or switches toolkits");
}

test("startup timeouts report page errors", { timeout: 45000 }, async () => {
const failingBrowser = {
async newPage() {
const page = await browser.newPage();
page.setDefaultTimeout(5000);
await page.addInitScript(() => {
document.addEventListener("DOMContentLoaded", () => {
window.LlamaGui.configFlagsUi.renderFlags = () => {
throw new Error("Injected Configure startup failure");
};
}, { once: true });
});
return page;
},
};
await assert.rejects(
runScenario(failingBrowser, port, () => assert.fail("scenario must not run after failed startup")),
error => {
assert.equal(error.cause?.name, "TimeoutError");
assert.match(error.message, /#flag-ctx_size/);
assert.match(error.message, /Page errors during startup:\nInjected Configure startup failure/);
return true;
},
);
});

for (const [name, verify = name] of [
["preset imports and safe notifications"],
["mirrored launch controls and Configure search"],
Expand Down
Loading