0889ee9117
feat(hooks): add useLiveStream generic WebSocket hook - supports websocket/sse/polling transports - exponential backoff reconnect with jitter - circular buffer with configurable size - typed filter callback per use case - manual disconnect + reconnect + error state feat(hooks): add useLiveMetrics derived hook - sliding time-window cut - moving average (configurable window) - current / avg / min / max / ratePerSecond - zero allocations per tick (memoized) feat(charts): add LiveMetricChart molecule (Recharts) - line + area variants, grid + tooltip - moving-average overlay (dashed) - ConnectionStatus atom in header - status bar + compact mode - 100% responsive, GPU via SVG ViewBox feat(atoms): add ConnectionStatus indicator - 5 states: disconnected/connecting/connected/reconnecting/error - animated pulse, JetBrains Mono, pill style - exported helpers: formatLatency / formatBytes docs(pkg): bump v0.1.0 → v0.2.0, add recharts peerDep
157 lines
4.4 KiB
TypeScript
Executable File
157 lines
4.4 KiB
TypeScript
Executable File
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
emailSchema,
|
|
passwordSchema,
|
|
passwordConfirmSchema,
|
|
uuidSchema,
|
|
urlSchema,
|
|
phoneSchema,
|
|
documentoSchema,
|
|
sanitizedStr,
|
|
required,
|
|
safeParse,
|
|
} from '../src/validators';
|
|
|
|
describe('emailSchema', () => {
|
|
it('aceita email valido e normaliza para lowercase', () => {
|
|
const r = safeParse(emailSchema, 'TESTE@EXAMPLE.COM');
|
|
expect(r.success).toBe(true);
|
|
if (r.success) expect(r.data).toBe('teste@example.com');
|
|
});
|
|
|
|
it('rejeita email invalido', () => {
|
|
expect(safeParse(emailSchema, 'not-an-email').success).toBe(false);
|
|
});
|
|
|
|
it('aceita email com dominio internacionalizado', () => {
|
|
expect(safeParse(emailSchema, 'user@mail.co.uk').success).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('passwordSchema', () => {
|
|
it('rejeita senha menor que 8 caracteres', () => {
|
|
expect(safeParse(passwordSchema, 'Abc1234').success).toBe(false);
|
|
});
|
|
|
|
it('rejeita senha sem numero', () => {
|
|
expect(safeParse(passwordSchema, 'Abcdefgh').success).toBe(false);
|
|
});
|
|
|
|
it('rejeita senha sem letra maiuscula', () => {
|
|
expect(safeParse(passwordSchema, 'abcdefgh123').success).toBe(false);
|
|
});
|
|
|
|
it('aceita senha valida', () => {
|
|
expect(safeParse(passwordSchema, 'Minha#Senh@1234').success).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('passwordConfirmSchema', () => {
|
|
it('retorna erro quando senhas nao coincidem', () => {
|
|
const r = safeParse(
|
|
passwordConfirmSchema,
|
|
{ password: 'Abc12345', confirm: 'Zxy98765' },
|
|
);
|
|
expect(r.success).toBe(false);
|
|
});
|
|
|
|
it('aceita quando senhas coincidem', () => {
|
|
const r = safeParse(
|
|
passwordConfirmSchema,
|
|
{ password: 'Abc12345', confirm: 'Abc12345' },
|
|
);
|
|
expect(r.success).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('uuidSchema', () => {
|
|
it('aceita UUID valido', () => {
|
|
expect(
|
|
safeParse(uuidSchema, '550e8400-e29b-41d4-a716-446655440000').success,
|
|
).toBe(true);
|
|
});
|
|
|
|
it('rejeita string que nao e UUID', () => {
|
|
expect(safeParse(uuidSchema, 'nao-e-uuid').success).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('urlSchema', () => {
|
|
it('aceita URL valida', () => {
|
|
const r = safeParse(urlSchema, 'https://exemplo.com');
|
|
expect(r.success).toBe(true);
|
|
if (r.success) expect(r.data).toBe('https://exemplo.com');
|
|
});
|
|
|
|
it('transforma string vazia em undefined', () => {
|
|
const r = safeParse(urlSchema, '');
|
|
expect(r.success).toBe(true);
|
|
if (r.success) expect(r.data).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('phoneSchema', () => {
|
|
it('aceita telefone formato (11) 98765-4321', () => {
|
|
expect(safeParse(phoneSchema, '(11) 98765-4321').success).toBe(true);
|
|
});
|
|
|
|
it('aceita telefone sem parentesis nem tracos', () => {
|
|
expect(safeParse(phoneSchema, '11987654321').success).toBe(true);
|
|
});
|
|
|
|
it('rejeita telefone com poucos digitos', () => {
|
|
expect(safeParse(phoneSchema, '123').success).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('documentoSchema', () => {
|
|
it('aceita CPF com 11 digitos', () => {
|
|
const r = safeParse(documentoSchema, '123.456.789-09');
|
|
expect(r.success).toBe(true);
|
|
if (r.success) expect(r.data).toBe('12345678909');
|
|
});
|
|
|
|
it('aceita CNPJ com 14 digitos', () => {
|
|
const r = safeParse(documentoSchema, '12.345.678/0001-95');
|
|
expect(r.success).toBe(true);
|
|
if (r.success) expect(r.data).toBe('12345678000195');
|
|
});
|
|
|
|
it('rejeita documento com tamanho invalido', () => {
|
|
expect(safeParse(documentoSchema, '12345').success).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('sanitizedStr', () => {
|
|
it('remove tags HTML e mantem texto corporizado', () => {
|
|
const r = safeParse(sanitizedStr, '<b>hello</b> world');
|
|
expect(r.success).toBe(true);
|
|
if (r.success) expect(r.data).toBe('hello world');
|
|
});
|
|
|
|
it('rejeita string que fica vazia apos sanitizar', () => {
|
|
expect(safeParse(sanitizedStr, '<p></p>').success).toBe(false);
|
|
expect(safeParse(sanitizedStr, ' ').success).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('required wrapper', () => {
|
|
it('transforma string vazia em erro', () => {
|
|
const schema = required(emailSchema);
|
|
expect(safeParse(schema, '').success).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('safeParse', () => {
|
|
it('retorna erro formatado quando falha', () => {
|
|
const r = safeParse(passwordSchema, 'curta');
|
|
expect(r.success).toBe(false);
|
|
});
|
|
|
|
it('retorna dados quando sucesso', () => {
|
|
const r = safeParse(emailSchema, 'teste@exemplo.com');
|
|
expect(r.success).toBe(true);
|
|
if (r.success) expect(r.data).toBe('teste@exemplo.com');
|
|
});
|
|
});
|