mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
Merge PR #482: подключить vitest и покрыть утилиты юнит-тестами
test: подключить vitest и покрыть утилиты юнит-тестами
This commit is contained in:
23
src/utils/formatTraffic.test.ts
Normal file
23
src/utils/formatTraffic.test.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { formatTraffic } from './formatTraffic';
|
||||
|
||||
vi.mock('../i18n', () => ({
|
||||
default: { t: (_key: string, fallback: string) => fallback },
|
||||
}));
|
||||
|
||||
describe('formatTraffic', () => {
|
||||
it('formats terabytes from 1000 GB up', () => {
|
||||
expect(formatTraffic(1000)).toBe('1.0 TB');
|
||||
expect(formatTraffic(2500)).toBe('2.5 TB');
|
||||
});
|
||||
|
||||
it('formats gigabytes from 1 GB up', () => {
|
||||
expect(formatTraffic(1)).toBe('1.0 GB');
|
||||
expect(formatTraffic(999.94)).toBe('999.9 GB');
|
||||
});
|
||||
|
||||
it('formats sub-gigabyte values as megabytes', () => {
|
||||
expect(formatTraffic(0.5)).toBe('512 MB');
|
||||
expect(formatTraffic(0)).toBe('0 MB');
|
||||
});
|
||||
});
|
||||
29
src/utils/period.test.ts
Normal file
29
src/utils/period.test.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { getMonthToDateRange, isMonthToDate } from './period';
|
||||
|
||||
describe('period', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it('builds a month-to-date range with zero-padded local dates', () => {
|
||||
vi.setSystemTime(new Date(2026, 2, 5));
|
||||
expect(getMonthToDateRange()).toEqual({ startDate: '2026-03-01', endDate: '2026-03-05' });
|
||||
});
|
||||
|
||||
it('recognises the current month-to-date period', () => {
|
||||
vi.setSystemTime(new Date(2026, 6, 13));
|
||||
expect(isMonthToDate({ startDate: '2026-07-01', endDate: '2026-07-13' })).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects day-based and mismatched periods', () => {
|
||||
vi.setSystemTime(new Date(2026, 6, 13));
|
||||
expect(isMonthToDate({ days: 30 })).toBe(false);
|
||||
expect(isMonthToDate({ startDate: '2026-07-01', endDate: '2026-07-12' })).toBe(false);
|
||||
expect(isMonthToDate({})).toBe(false);
|
||||
});
|
||||
});
|
||||
36
src/utils/safeRedirect.test.ts
Normal file
36
src/utils/safeRedirect.test.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { getSafeRedirectPath } from './safeRedirect';
|
||||
|
||||
describe('getSafeRedirectPath', () => {
|
||||
it('returns / for empty values', () => {
|
||||
expect(getSafeRedirectPath(null)).toBe('/');
|
||||
expect(getSafeRedirectPath(undefined)).toBe('/');
|
||||
expect(getSafeRedirectPath('')).toBe('/');
|
||||
});
|
||||
|
||||
it('keeps plain absolute in-app paths', () => {
|
||||
expect(getSafeRedirectPath('/')).toBe('/');
|
||||
expect(getSafeRedirectPath('/dashboard')).toBe('/dashboard');
|
||||
expect(getSafeRedirectPath('/sub/page?tab=devices&x=1')).toBe('/sub/page?tab=devices&x=1');
|
||||
});
|
||||
|
||||
it('rejects protocol-relative and absolute URLs', () => {
|
||||
expect(getSafeRedirectPath('//evil.com')).toBe('/');
|
||||
expect(getSafeRedirectPath('https://evil.com/path')).toBe('/');
|
||||
expect(getSafeRedirectPath('http://evil.com')).toBe('/');
|
||||
});
|
||||
|
||||
it('rejects non-path schemes', () => {
|
||||
expect(getSafeRedirectPath('javascript:alert(1)')).toBe('/');
|
||||
expect(getSafeRedirectPath('data:text/html,x')).toBe('/');
|
||||
});
|
||||
|
||||
it('rejects URL-encoded host smuggling', () => {
|
||||
expect(getSafeRedirectPath('%2F%2Fevil.com')).toBe('/');
|
||||
expect(getSafeRedirectPath('/redirect%3A%2F%2Fevil.com')).toBe('/');
|
||||
});
|
||||
|
||||
it('rejects malformed percent-encoding instead of throwing', () => {
|
||||
expect(getSafeRedirectPath('/%E0%A4%A')).toBe('/');
|
||||
});
|
||||
});
|
||||
28
src/utils/sanitizeSurrogates.test.ts
Normal file
28
src/utils/sanitizeSurrogates.test.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { sanitizeSurrogates } from './sanitizeSurrogates';
|
||||
|
||||
describe('sanitizeSurrogates', () => {
|
||||
it('returns surrogate-free strings unchanged', () => {
|
||||
expect(sanitizeSurrogates('')).toBe('');
|
||||
expect(sanitizeSurrogates('https://host/sub/uuid#remark')).toBe('https://host/sub/uuid#remark');
|
||||
});
|
||||
|
||||
it('keeps valid surrogate pairs intact', () => {
|
||||
expect(sanitizeSurrogates('server 😀 name')).toBe('server 😀 name');
|
||||
});
|
||||
|
||||
it('replaces a lone high surrogate', () => {
|
||||
expect(sanitizeSurrogates('abc\uD83D')).toBe('abc<62>');
|
||||
expect(sanitizeSurrogates('\uD83Dxyz')).toBe('<27>xyz');
|
||||
});
|
||||
|
||||
it('replaces a lone low surrogate', () => {
|
||||
expect(sanitizeSurrogates('abc\uDE00def')).toBe('abc<62>def');
|
||||
});
|
||||
|
||||
it('makes a truncated-emoji string safe for encodeURI', () => {
|
||||
const broken = 'remark \uD83D truncated';
|
||||
expect(() => encodeURI(broken)).toThrow();
|
||||
expect(() => encodeURI(sanitizeSurrogates(broken))).not.toThrow();
|
||||
});
|
||||
});
|
||||
17
src/utils/validation.test.ts
Normal file
17
src/utils/validation.test.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { isValidEmail } from './validation';
|
||||
|
||||
describe('isValidEmail', () => {
|
||||
it('accepts common addresses', () => {
|
||||
expect(isValidEmail('user@example.com')).toBe(true);
|
||||
expect(isValidEmail('a.b+tag@sub.domain.io')).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects malformed addresses', () => {
|
||||
expect(isValidEmail('')).toBe(false);
|
||||
expect(isValidEmail('plain')).toBe(false);
|
||||
expect(isValidEmail('user@host')).toBe(false);
|
||||
expect(isValidEmail('user @example.com')).toBe(false);
|
||||
expect(isValidEmail('user@exa mple.com')).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user