Files
browser/platform_web/theme/base-css.test.js
T
npc0-hue 4ea27bda6a Isolate server search from the delete password prompt
The delete confirmation adds a password field. Browsers and password managers
paired it with the only other text field on the page and filled the account
name into the server search box on the server list.

The search input now stays out of the DOM while a delete confirmation is open,
and the toolbar shows a suspended notice styled to match the field it replaces
so the row does not jump. A jsdom test drives the real action menu and dialog
instead of asserting page source strings.
2026-09-15 12:25:17 +08:00

244 lines
14 KiB
JavaScript

import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
function readThemeCss() {
return readFileSync(new URL("./base.css", import.meta.url), "utf8");
}
function compact(value) {
return value.replace(/\s+/g, "");
}
describe("platform web shared theme CSS", () => {
it("keeps plugin lifecycle controls bounded at narrow width", () => {
const css = compact(readThemeCss());
expect(css).toContain("@media(max-width:640px){.plugin-lifecycle-controls{grid-template-columns:minmax(0,1fr)}");
expect(css).toContain("overflow-wrap:anywhere");
});
it("suppresses nested state frames inside shared framed surfaces", () => {
const css = compact(readThemeCss());
expect(css).toContain(".state-view::after,:root[data-theme-palette]:where(");
expect(css).toContain(".state-view::before{content:none;background:00;box-shadow:none;filter:none}");
});
it("keeps server card runtime actions as compact overlay menus", () => {
const css = compact(readThemeCss());
expect(css).toContain(".runtime-action-popover{position:fixed;z-index:45");
expect(css).toContain(".runtime-action-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))");
});
it("keeps runtime task progress display visually explicit", () => {
const css = compact(readThemeCss());
expect(css).toContain(".runtime-task-progress-summary{display:grid");
expect(css).toContain(".runtime-task-progress-summary>span{color:var(--accent)");
expect(css).toContain(".runtime-task-meter-track{height:10px");
});
it("themes shared scrollbars instead of exposing browser-default gutters", () => {
const css = compact(readThemeCss());
expect(css).toContain(":root[data-theme-palette],:root[data-theme-palette]*{scrollbar-color:color-mix(insrgb,var(--accent)62%,var(--surface-solid))color-mix(insrgb,var(--surface-solid)62%,transparent);scrollbar-width:thin}");
expect(css).toContain(":root[data-theme-palette]::-webkit-scrollbar,:root[data-theme-palette]*::-webkit-scrollbar{width:10px;height:10px}");
expect(css).toContain(":root[data-theme-palette]::-webkit-scrollbar-thumb,:root[data-theme-palette]*::-webkit-scrollbar-thumb{min-height:42px;border:2pxsolid");
expect(css).toContain("background:linear-gradient(180deg,color-mix(insrgb,var(--accent)62%,var(--surface-solid)),color-mix(insrgb,var(--gold)46%,var(--accent)))");
expect(css).toContain("::-webkit-scrollbar-corner");
});
it("keeps server card stat tiles readable over busy backgrounds", () => {
const css = compact(readThemeCss());
expect(css).toContain(".server-card-stat{display:grid;gap:2px;padding:8px;border:1pxsolid");
expect(css).toContain("--surface-solid");
expect(css).toContain("font-weight:850");
expect(css).toContain(":root[data-custom-background=true].server-card-stat");
});
it("gives server cards enough room for long status labels", () => {
const css = compact(readThemeCss());
expect(css).toContain(".server-card-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,420px),1fr))");
expect(css).toContain(".server-card-head{display:grid;gap:8px;min-width:0}");
expect(css).toContain(".server-card-head>span:last-child{justify-self:start;white-space:normal");
});
it("keeps magical custom-background signal rows readable without the jelly wash", () => {
const css = compact(readThemeCss());
expect(css).toContain(":root[data-custom-background=true][data-theme-palette=magical-girl].signal-item");
expect(css).toContain("rgba(58,44,56,.72)");
expect(css).toContain("backdrop-filter:blur(12px)saturate(0.92)");
expect(css).not.toContain("var(--jelly-highlight),var(--glass-wash),var(--surface-solid)");
});
it("keeps shared controls off the heavy jelly and corner-sparkle button wash", () => {
const css = readThemeCss();
expect(css).toContain("--control-surface");
expect(css).toContain("--primary-command-surface");
expect(css).not.toContain("background: var(--jelly-highlight), var(--glass-wash), var(--surface-solid)");
expect(css).not.toContain("linear-gradient(145deg, rgba(255, 255, 255, 0.72), transparent 36%)");
});
it("keeps SCUM user identity and economy columns readable", () => {
const css = compact(readThemeCss());
expect(css).toContain(".scum-user-table{min-width:1080px;table-layout:fixed}");
expect(css).toContain(".scum-user-tableth,.scum-user-tabletd{height:38px;padding:6px10px;border-bottom-color:color-mix(insrgb,var(--line)64%,transparent);white-space:nowrap;font-size:13px;line-height:1.2}");
expect(css).toContain(".scum-user-tabletd.provider-actions-cell{padding-right:8px;overflow:visible}");
expect(css).toContain(".scum-user-tableth:nth-child(7),.scum-user-tabletd:nth-child(7){width:156px}");
expect(css).toContain(".scum-mono-cell{font-family:var(--font-mono);font-size:12px}");
});
it("uses shared orbital construct backdrop and button ring effects", () => {
const themeCss = readThemeCss();
const constructRule = themeCss.slice(themeCss.indexOf(".global-orbital-construct"), themeCss.indexOf(".mobile-sidebar-backdrop"));
expect(constructRule).toContain("clip-path:circle(49% at 50% 50%)");
expect(constructRule).toContain("background:var(--orbital-construct-image) center/contain no-repeat transparent");
expect(constructRule).toContain("filter:var(--orbital-construct-filter)");
expect(constructRule).toContain(".global-orbital-construct::before,.global-orbital-construct::after{content:none}");
expect(constructRule).toContain(":root[data-theme-palette=mecha-black] .global-orbital-construct{display:block;opacity:.22}");
expect(constructRule).toContain(":root[data-theme-palette=magical-girl] .global-orbital-construct{display:block;opacity:.24}");
expect(constructRule).toContain(".global-particle-lightfall");
expect(constructRule).toContain(".global-particle-side-ray");
expect(themeCss).not.toContain("global-particle-frame");
expect(themeCss).not.toContain("global-particle-orbit");
expect(themeCss).not.toContain("particle-orbit-drift");
expect(constructRule).toContain("orbital-construct-drift");
expect(constructRule).toContain("prefers-reduced-motion");
expect(constructRule).toContain("var(--command-ring-sheen");
expect(constructRule).toContain(".app-nav-group-button::after");
expect(constructRule).toContain("magic-side-ray-pulse-right");
expect(constructRule).toContain("transform:translateY(1px)");
expect(themeCss).toContain(":root[data-custom-background=true] .global-particle-layer{opacity:.42}");
expect(themeCss).toContain(":root[data-custom-background=true][data-theme-palette=magical-girl] .global-particle-layer{opacity:.54}");
expect(themeCss).not.toContain(":root[data-custom-background=true] .global-particle-layer{opacity:.03}");
});
it("keeps magical-girl custom-background panel overlays restrained", () => {
const css = compact(readThemeCss());
expect(css).toContain(":root[data-custom-background=true][data-theme-palette=magical-girl]{--frame-accessory-opacity:0.22");
expect(css).toContain("--surface:rgba(22,22,29,0.42)");
expect(css).toContain("linear-gradient(180deg,rgba(24,24,31,.22),rgba(18,19,26,.18))");
expect(css).not.toContain("255,119,200,0.78");
});
it("keeps catalog and console panels translucent without fading content", () => {
const css = compact(readThemeCss());
expect(css).toContain(".catalog-card,.console-panel{border:1pxsolidvar(--line);border-radius:8px;background:var(--sugar-dust),linear-gradient(135deg,color-mix(insrgb,var(--surface)22%,transparent),color-mix(insrgb,var(--surface-raised)14%,transparent))");
expect(css).toContain("-webkit-backdrop-filter:blur(10px)saturate(.9);backdrop-filter:blur(10px)saturate(.9)");
expect(css).toContain(":root[data-custom-background=true].catalog-card");
expect(css).toContain("linear-gradient(180deg,rgba(5,10,16,.42),rgba(5,10,16,.34))");
expect(css).not.toContain(".catalog-card,.console-panel{opacity:");
expect(css).not.toContain(".catalog-card,.console-panel{border:1pxsolidvar(--line);border-radius:8px;background:var(--panel-material);backdrop-filter:blur(22px)saturate(1.28)");
});
it("styles runtime task progress as a dialog with staged status", () => {
const css = readThemeCss();
expect(css).toContain(".runtime-task-panel");
expect(css).toContain(".runtime-task-meter-track");
expect(css).toContain(".runtime-task-stages");
expect(css).toContain(".runtime-task-log");
expect(css).toContain("prefers-reduced-motion");
});
it("styles operations surfaces with shared theme materials and narrow-screen collapse", () => {
const css = compact(readThemeCss());
expect(css).toContain(".operations-tray{position:relative;z-index:2");
expect(css).toContain("background:var(--panel-material),var(--surface)");
expect(css).toContain(".operations-tray-panel{position:absolute");
expect(css).toContain("@media(max-width:760px){.operations-command-grid{grid-template-columns:1fr}");
expect(css).toContain(".operations-job-row-failed");
expect(css).toContain("prefers-reduced-motion");
});
it("keeps mobile navigation off-canvas with readable vertical labels", () => {
const css = compact(readThemeCss());
expect(css).toContain(".mobile-sidebar-handle{position:fixed");
expect(css).toContain(".app-sidebar{position:fixed;inset:0auto00");
expect(css).toContain("transform:translateX(calc(-100%-18px))");
expect(css).toContain(".app-sidebar-mobile-open");
expect(css).toContain("grid-template-columns:40pxminmax(0,1fr)");
expect(css).toContain(".app-nav-copystrong{display:block");
});
it("keeps desktop sidebar controls pinned inside the viewport", () => {
const css = compact(readThemeCss());
expect(css).toContain(".app-shell{min-height:100dvh");
expect(css).toContain(".app-sidebar{position:sticky");
expect(css).toContain("height:100dvh");
expect(css).toContain("overflow-y:auto");
expect(css).toContain("overscroll-behavior:contain");
});
it("keeps dialogs and drawers internally scrollable on short viewports", () => {
const css = compact(readThemeCss());
expect(css).toContain(".dialog-panel-header,.drawer-panel>.panel-header{position:sticky");
expect(css).toContain("overflow-y:auto");
expect(css).toContain("overscroll-behavior:contain");
expect(css).toContain("max-height:calc(100dvh-32px)");
expect(css).toContain("max-height:calc(100dvh-20px)");
});
it("keeps the management terminal opaque and large", () => {
const css = compact(readThemeCss());
expect(css).toContain(".terminal-drawer-backdrop{align-items:flex-end;justify-content:center;padding:10dvh00;background:#000;backdrop-filter:none}");
expect(css).toContain(".management-terminal-drawer{width:100%;max-width:none;height:90dvh;max-height:90dvh");
expect(css).toContain("background:#000;backdrop-filter:none;box-shadow:none");
expect(css).toContain(".management-terminal-body{height:100%;grid-template-rows:minmax(0,1fr)auto");
expect(css).toContain(".terminal-output-panel{display:grid;grid-template-rows:autominmax(0,1fr);min-height:0;border:1pxsolid#222;border-radius:8px;background:#000");
expect(css).toContain(".terminal-output-topbar{display:flex;align-items:center;justify-content:space-between");
expect(css).toContain(".terminal-output{display:block;min-height:260px");
expect(css).toContain(".terminal-line{display:grid;grid-template-columns:74pxminmax(0,1fr)");
expect(css).toContain(".terminal-text{min-width:0;white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word");
expect(css).toContain(".terminal-source-system.terminal-text,.terminal-source-platform.terminal-text,.terminal-source-bridge.terminal-text{color:#d2a8ff}");
expect(css).toContain(".terminal-line-error.terminal-text,.terminal-source-stderr.terminal-text,.terminal-source-stderrtime{color:#ff7b72}");
expect(css).toContain(".terminal-quick-command-list{display:grid;grid-template-columns:repeat(4,minmax(0,1fr))");
});
it("keeps deployment workflow fields compact when a mode has one input", () => {
const css = compact(readThemeCss());
expect(css).toContain(".deployment-workflow-body{display:grid;align-content:start;gap:12px;min-height:0}");
expect(css).toContain(".deployment-workflow-body.form-grid{align-content:start;align-items:start;grid-auto-rows:min-content}");
});
it("keeps the guided-install plan compact and responsive inside the deployment workflow", () => {
const css = compact(readThemeCss());
expect(css).toContain(".guided-install-plan{display:grid;gap:10px;padding:12px;border:1pxsolidcolor-mix(insrgb,var(--accent)42%,var(--line));border-radius:8px");
expect(css).toContain(".guided-install-planol{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px");
expect(css).toContain(".guided-install-planol,.maintenance-node-item");
});
it("keeps the suspended server search aligned with the search field it replaces", () => {
const css = compact(readThemeCss());
expect(css).toContain(".server-toolbar.server-search-suspended{flex:11220px;display:inline-flex;align-items:center;min-height:38px");
expect(css).toContain("border:1pxdashedvar(--line)");
});
it("keeps magical card decoration from becoming square background patches", () => {
const css = compact(readThemeCss());
expect(css).toContain(":root[data-theme-palette=magical-girl].catalog-card");
expect(css).toContain("background:var(--sugar-dust),linear-gradient(180deg,color-mix(insrgb,var(--surface)16%,transparent),color-mix(insrgb,var(--surface-raised)10%,transparent));overflow:visible");
expect(css).not.toContain("background-size:56px56px");
expect(css).not.toContain("background-image:var(--corner-sparkle),var(--panel-material)");
expect(css).not.toContain(".global-magic-ring");
});
});