Files
TeleUploader/test/validation.test.ts
T
asepharyana 5d01a9405f refactor(fase0): shared scaffold — crypto, file-url, schemas, test splits
- Add zod dep; new src/shared/validation/schemas.ts (BucketName,
  JsonUploadPayload, LoginBody, DeleteObjects, CompleteMultipart,
  clampMaxKeys, parseOrNull) + test/validation.test.ts
- Dedup timingSafeCompare -> src/shared/utils/crypto.ts (auth
  middleware, authenticate use-case, s3/auth now import it)
- Dedup AuthSession -> single type in dto/auth.ts
- Dedup telegram file URL builder + filename sanitizer to shared
  modules (file-controller now imports the canonical ones)
- Remove duplicate controllers/home.html (canonical: src/home.html)
- Fix stale bootstrap mocks to real module paths; bootstrap now
  asserts public GET vs guarded POST separately
- Fix health assertion to include version field
- package.json: test -> test:unit alias; new test:quarantine for
  network/live tests; register previously unlisted test files
2026-09-14 17:09:52 +07:00

90 lines
3.3 KiB
TypeScript

import { describe, expect, it } from 'bun:test';
import {
BucketNameSchema,
CompleteMultipartBodySchema,
clampMaxKeys,
DeleteObjectsBodySchema,
JsonUploadPayloadSchema,
LoginBodySchema,
parseOrNull,
} from '../src/shared/validation/schemas';
describe('BucketNameSchema (single canonical validator)', () => {
it('accepts valid bucket names', () => {
expect(BucketNameSchema.safeParse('gitea').success).toBe(true);
expect(BucketNameSchema.safeParse('my.bucket-01').success).toBe(true);
});
it('rejects invalid names (format, dots, IP, xn--)', () => {
expect(BucketNameSchema.safeParse('ab').success).toBe(false);
expect(BucketNameSchema.safeParse('UPPERCASE').success).toBe(false);
expect(BucketNameSchema.safeParse('a..b').success).toBe(false);
expect(BucketNameSchema.safeParse('192.168.1.1').success).toBe(false);
expect(BucketNameSchema.safeParse('xn--bcher-kva').success).toBe(false);
});
});
describe('JsonUploadPayloadSchema', () => {
it('accepts file + optional fileName', () => {
expect(
JsonUploadPayloadSchema.safeParse({ file: 'aGVsbG8=', fileName: 'hi.txt' }).success,
).toBe(true);
});
it('defaults fileName and rejects missing/empty file', () => {
const parsed = JsonUploadPayloadSchema.safeParse({ file: 'aGVsbG8=' });
expect(parsed.success && parsed.data.fileName).toBe('file');
expect(JsonUploadPayloadSchema.safeParse({}).success).toBe(false);
expect(JsonUploadPayloadSchema.safeParse({ file: '' }).success).toBe(false);
});
});
describe('LoginBodySchema', () => {
it('accepts a non-empty token and rejects the rest', () => {
expect(LoginBodySchema.safeParse({ token: 'secret' }).success).toBe(true);
expect(LoginBodySchema.safeParse({}).success).toBe(false);
expect(LoginBodySchema.safeParse({ token: '' }).success).toBe(false);
expect(LoginBodySchema.safeParse({ token: 42 }).success).toBe(false);
});
});
describe('DeleteObjectsBodySchema', () => {
it('accepts parsed keys and enforces the 1000-key S3 limit', () => {
expect(DeleteObjectsBodySchema.safeParse({ keys: ['a', 'b'], quiet: false }).success).toBe(
true,
);
expect(
DeleteObjectsBodySchema.safeParse({ keys: new Array(1001).fill('k'), quiet: true }).success,
).toBe(false);
});
});
describe('CompleteMultipartBodySchema', () => {
it('accepts parsed parts and rejects bad part numbers', () => {
expect(
CompleteMultipartBodySchema.safeParse({ parts: [{ partNumber: 1, etag: 'abc' }] }).success,
).toBe(true);
expect(
CompleteMultipartBodySchema.safeParse({ parts: [{ partNumber: 0, etag: 'abc' }] }).success,
).toBe(false);
});
});
describe('clampMaxKeys (unified listing clamp)', () => {
it('clamps into [1, 1000] and falls back to 1000 on garbage', () => {
expect(clampMaxKeys(null)).toBe(1000);
expect(clampMaxKeys('5')).toBe(5);
expect(clampMaxKeys('99999')).toBe(1000);
expect(clampMaxKeys('0')).toBe(1000);
expect(clampMaxKeys('-3')).toBe(1000);
expect(clampMaxKeys('abc')).toBe(1000);
});
});
describe('parseOrNull', () => {
it('returns the value on success and null on failure', () => {
expect(parseOrNull(LoginBodySchema, { token: 'x' })).toEqual({ token: 'x' });
expect(parseOrNull(LoginBodySchema, {})).toBeNull();
});
});