Skip to main content

Tests and quality

PVE Panel has an automated test suite that runs on GitHub for every change. Releases are only published when it passes.

What is tested​

LayerWhatWhere
Unit2FA codes against the RFC 6238 test vectors, encryption of secrets (incl. tamper detection), single sign-on account rules and MFA detection, version comparison, guest agent handling (stalls, lost results)test/unit/
APIThe real panel process against a simulated Proxmox: sign-in, separate portals, 2FA setup/replay/recovery codes, ownership (404 for foreign servers), creating Linux and Windows servers, private networks, plan limits incl. pending resizes, reinstall (MAC kept, snapshots erased), resize, delete, email settings, invitations, VPN, Tailscale, deleting customerstest/api/
PasskeysRegistration and sign-in with a software authenticator (test/support/soft-authenticator.mjs); phishing origin, missing user verification, forged signature, replayed counter, reused challenge, re-authentication for adding passkeystest/api/passkeys.test.mjs
ExpiryCustomer rules and server dates, reminders (once, not too early), stop at expiry, self-extension, final notice, deletion after the grace period, servers you assigned kept, paused deletions, no deletion without an email warningtest/api/expiry.test.mjs
BrowserPlaywright with Chromium: sign-in, overview, server page, creating a server through the form, admin views, passkeys with Chromium's virtual authenticatortest/e2e/

The simulated Proxmox (test/support/mock-pve.mjs) answers the API calls the panel uses — VMs, templates, clones, tasks, SDN, firewall, snapshots, guest agent including Windows setup and Tailscale, the WireGuard gateway. Each test file starts its own isolated environment (simulated Proxmox, optional mail server, panel process, temporary database) on free ports, so files run in parallel.

Simulated, not real

The tests prove that the panel behaves correctly against the Proxmox API as the simulation models it. They don't replace checking your real environment — see Security model and validate isolation with two test customers before going live.

On GitHub​

WorkflowWhenWhat
Testspull requests, branches other than mainunit + API tests on Node 22 and 24, browser tests
Docker imagemain, release tagsruns the same tests first; builds and publishes the image only if they pass
CodeQLmain, pull requests, weeklycode scanning for security issues (Security → Code scanning)
Documentationchanges in website/builds this site, fails on broken links

If browser tests fail, the run keeps the Playwright report (screenshots, traces) as a downloadable artifact for 14 days.

Running tests locally​

npm install
npm test # unit + API tests (about 2–4 minutes)
npm run test:unit # only unit tests (seconds)
npm run test:api
npm run test:coverage # coverage summary of src/ (see note below)

npx playwright install chromium # once
npm run test:e2e # browser tests

The coverage summary only counts code running inside the test process. API tests run the panel as a separate process, so the code they exercise isn't counted there; real coverage is higher than the number shown.

The tests never read your .env; they use their own temporary settings, ports and database. Set MOCK_PVE_DEBUG=1 to see every call the panel makes to the simulated Proxmox.

Writing a test​

API tests start a stack and use sessions that keep cookies like a browser:

import { test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import { startStack } from '../support/stack.mjs';

let stack;
before(async () => { stack = await startStack(); });
after(async () => { await stack?.stop(); });

test('a customer sees only their own servers', async () => {
const lena = await stack.customerWith('lena@example.com');
assert.deepEqual((await lena.get('/api/vms')).json, []);
});

Helpers in test/support/stack.mjs: adminSession(), customerWith(email, { limits }), offerTemplates(), serverSettled(session, vmid), agentReady(vmid), totp(key), and stack.mock.control('/__lose/<vmid>/1') to simulate guest agent problems.