bbdb68a6de
Esta commit conteudo a estrutura atomica completa:
- types: Result<T,E>, AsyncState<T>, Paginated<T>, SortConfig<T>
- utils: date, str, num, cn, debounce, throttle, storage, arr, obj
- validators: Zod schemas — email, password, uuid, url, phone, CPF/CNPJ, sanitizedStr, safeParse
- hooks: useToggle, useAsync, useDebounce, useLocalStorage, useMedia, useInterval, useOnClickOutside, useClipboard, useFetch
- components: Button, Input, Alert, Card, Spinner (atomic design pattern)
- build: tsup v8 ESM+CJS + DTS + sourcemaps — 0 erros
- tests: 57 testes 100% usuarios
- docker: multi-stage Dockerfile (node 20-alpine)
- config: vitest, tsup, tsconfig strict, .npmignore
Filosofia atomica:/utils ← /types ← /validators ← /hooks ← /components
Build: npm run build | Test: npm test | Publish: npm publish
🤖 Generated with Pulse (openclaw + nova-self-improver)
157 lines
4.4 KiB
TypeScript
157 lines
4.4 KiB
TypeScript
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');
|
|
});
|
|
});
|