start: private new-tab dashboard at /start (tasks, notifications, backups/timers, server + containers, service status, trackers, editable links, / search)
All checks were successful
Deploy production / deploy (push) Successful in 2m39s
All checks were successful
Deploy production / deploy (push) Successful in 2m39s
- home schema: home.links (seeded, owner-editable) and home.snapshots (written by a host collector) - deploy/home-collector: stdlib Python + systemd user timer (60s) that snapshots /proc stats, docker containers, systemd timers, service HTTP checks and ntfy topics via a limited role - extras/newtab-extension: MV3 new-tab override, zipped to static/newtab-extension.zip - owner-only pages skip Google Analytics; /trackers/health#body anchor for weigh-ins
This commit is contained in:
49
src/lib/home.test.ts
Normal file
49
src/lib/home.test.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { ago, bytes, linkInput, timerStatus, type TimerState } from './home';
|
||||
|
||||
describe('linkInput', () => {
|
||||
it('adds https:// and lowercases the section', () => {
|
||||
expect(linkInput.parse({ title: ' Gmail ', url: 'mail.google.com', section: 'Daily' })).toEqual(
|
||||
{
|
||||
title: 'Gmail',
|
||||
url: 'https://mail.google.com',
|
||||
section: 'daily'
|
||||
}
|
||||
);
|
||||
});
|
||||
it('rejects other schemes and empty titles', () => {
|
||||
expect(linkInput.safeParse({ title: 'x', url: 'javascript:alert(1)' }).success).toBe(false);
|
||||
expect(linkInput.safeParse({ title: ' ', url: 'https://a.b' }).success).toBe(false);
|
||||
});
|
||||
it('defaults the section', () => {
|
||||
expect(linkInput.parse({ title: 'a', url: 'https://a.b', section: '' }).section).toBe('links');
|
||||
});
|
||||
});
|
||||
|
||||
describe('timerStatus', () => {
|
||||
const t: TimerState = {
|
||||
label: 'x',
|
||||
unit: 'x',
|
||||
scope: 'user',
|
||||
last: 100,
|
||||
next: 1000,
|
||||
running: false,
|
||||
result: 'success',
|
||||
exitStatus: 0
|
||||
};
|
||||
it('flags failures and late timers', () => {
|
||||
expect(timerStatus(t, 1000)).toBe('ok');
|
||||
expect(timerStatus({ ...t, result: 'exit-code' }, 1000)).toBe('fail');
|
||||
expect(timerStatus(t, 1000 + 16 * 60)).toBe('late');
|
||||
expect(timerStatus({ ...t, running: true }, 99999)).toBe('running');
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatting', () => {
|
||||
it('formats bytes and relative times', () => {
|
||||
expect(bytes(8 * 1024 ** 3)).toBe('8.0 GB');
|
||||
expect(ago(0, 30_000)).toBe('now');
|
||||
expect(ago(0, 5 * 60_000)).toBe('5m ago');
|
||||
expect(ago(3 * 3600_000, 0)).toBe('in 3h');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user