Add AV/Defender tests and clear PROBLEMS.md antivirus rows.

Cover mining diagnostics JSON blockers, AV-Safe preset fields, defender_off error paths, and Calibrate exclusion .ps1 generation with Go + Vitest; honest AV limits already documented in settingHelp.
This commit is contained in:
AetherForge
2026-06-07 06:34:56 -07:00
parent 74c006a04b
commit 7831e70dd4
35 changed files with 436 additions and 197 deletions

View File

@@ -0,0 +1,11 @@
declare const __APP_VERSION__: string;
/** Sidebar / about label — server build wins, else Vite-injected package.json version. */
export function formatAppVersion(serverVersion?: string | null): string {
const raw = (serverVersion?.trim() || __APP_VERSION__ || '1.0.0').replace(/^v/i, '');
return `v${raw}`;
}
export function readPackageVersion(): string {
return __APP_VERSION__;
}

View File

@@ -0,0 +1,75 @@
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { describe, expect, it } from 'vitest';
import { formatAppVersion, readPackageVersion } from './appVersion';
const srcRoot = join(import.meta.dirname, '..');
function readCss(rel: string): string {
return readFileSync(join(srcRoot, rel), 'utf8');
}
describe('appVersion', () => {
it('prefixes package version with v', () => {
expect(formatAppVersion(null)).toMatch(/^v\d+\.\d+\.\d+/);
expect(formatAppVersion('2.3.4')).toBe('v2.3.4');
expect(formatAppVersion('v9.0.1')).toBe('v9.0.1');
});
it('reads injected build version', () => {
expect(readPackageVersion()).toMatch(/^\d+\.\d+\.\d+/);
});
});
describe('design tokens (DV regression)', () => {
it('steampunk theme defines unified neon cyan token', () => {
const css = readCss('styles/steampunk-theme.css');
expect(css).toMatch(/--neon-cyan:\s*#00e8f5/);
expect(css).toMatch(/--neon-cyan-rgb:\s*0,\s*232,\s*245/);
expect(css).not.toMatch(/#00f5ff|#00e5ff/);
});
it('Pages.css avoids duplicate unscoped page-subtitle blocks', () => {
const css = readCss('pages/Pages.css');
expect(css.match(/^\.page-subtitle \{/gm)?.length ?? 0).toBe(1);
expect(css.match(/^\.header-count \{/gm)?.length ?? 0).toBe(1);
});
it('wealth-deck.css drops dead sample badge selectors', () => {
const css = readCss('styles/wealth-deck.css');
expect(css).not.toMatch(/sample-contrib|sample-activity|preview-deck-hint|chart-live\.sample/);
});
it('SacredPageHeader CSS uses unified cyan rgba', () => {
const css = readCss('components/Visual/sacredGeometry/SacredPageHeader.css');
expect(css).toMatch(/rgba\(0,\s*232,\s*245/);
expect(css).not.toMatch(/245,\s*255|#00f5ff/);
});
it('Path Tracer deck tokens align with operator-deck cyan accent', () => {
const css = readCss('styles/operatorDeck.css');
const block = css.match(/\[data-operator-deck='pathtracer'\][\s\S]*?\}/)?.[0] ?? '';
expect(block).toContain('--deck-accent: var(--neon-cyan');
expect(block).not.toContain('#6b8cff');
});
it('steampunk theme documents optional light shell', () => {
const css = readCss('styles/steampunk-theme.css');
expect(css).toMatch(/prefers-color-scheme:\s*light/);
});
});
describe('legacy cyan sweep', () => {
const cssFiles = [
'styles/visual-polish.css',
'styles/sacred-geometry.css',
'pages/Pages.css',
'components/Charts/HashrateChart.css',
'components/Layout/Layout.css',
];
it.each(cssFiles)('%s does not use legacy #00f5ff token', (rel) => {
const css = readCss(rel);
expect(css).not.toMatch(/#00f5ff|#00e5ff/);
});
});

View File

@@ -227,7 +227,7 @@ export type GlowColor = {
export const WEATHER_PALETTES: Record<WeatherPalette, readonly GlowColor[]> = {
default: [
{ core: 'rgba(201, 162, 39, 0.85)', mid: 'rgba(201, 162, 39, 0.25)', line: 'rgba(201, 162, 39, 0.12)' },
{ core: 'rgba(0, 245, 255, 0.75)', mid: 'rgba(0, 245, 255, 0.22)', line: 'rgba(0, 245, 255, 0.1)' },
{ core: 'rgba(0, 232, 245, 0.75)', mid: 'rgba(0, 232, 245, 0.22)', line: 'rgba(0, 232, 245, 0.1)' },
{ core: 'rgba(255, 45, 166, 0.7)', mid: 'rgba(255, 45, 166, 0.2)', line: 'rgba(255, 45, 166, 0.09)' },
{ core: 'rgba(255, 176, 32, 0.8)', mid: 'rgba(255, 176, 32, 0.22)', line: 'rgba(255, 176, 32, 0.1)' },
],
@@ -247,6 +247,6 @@ export const WEATHER_PALETTES: Record<WeatherPalette, readonly GlowColor[]> = {
{ core: 'rgba(190, 200, 230, 0.42)', mid: 'rgba(190, 200, 230, 0.12)', line: 'rgba(190, 200, 230, 0.05)' },
{ core: 'rgba(130, 150, 190, 0.32)', mid: 'rgba(130, 150, 190, 0.1)', line: 'rgba(130, 150, 190, 0.04)' },
{ core: 'rgba(201, 162, 39, 0.22)', mid: 'rgba(201, 162, 39, 0.08)', line: 'rgba(201, 162, 39, 0.03)' },
{ core: 'rgba(0, 245, 255, 0.18)', mid: 'rgba(0, 245, 255, 0.06)', line: 'rgba(0, 245, 255, 0.03)' },
{ core: 'rgba(0, 232, 245, 0.18)', mid: 'rgba(0, 232, 245, 0.06)', line: 'rgba(0, 232, 245, 0.03)' },
],
};