mirror of
https://github.com/Noooste/garage-ui.git
synced 2026-08-12 14:38:02 +00:00
c0976a1e1d
* feat(preview): implement object preview functionality with token-based access * docs: update README to include inline object preview feature * test: add range read error handling and attachment content disposition tests
104 lines
4.1 KiB
TypeScript
104 lines
4.1 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import {
|
|
getHighlightLanguage,
|
|
getPreviewKind,
|
|
getPreviewMime,
|
|
getPreviewSizeLimit,
|
|
looksBinary,
|
|
IMAGE_PREVIEW_MAX_BYTES,
|
|
PDF_PREVIEW_MAX_BYTES,
|
|
TEXT_PREVIEW_MAX_BYTES,
|
|
} from './preview-utils';
|
|
|
|
describe('getPreviewKind', () => {
|
|
it('trusts a specific content type first', () => {
|
|
expect(getPreviewKind('image/png', 'noext')).toBe('image');
|
|
expect(getPreviewKind('video/mp4', 'noext')).toBe('video');
|
|
expect(getPreviewKind('audio/mpeg', 'noext')).toBe('audio');
|
|
expect(getPreviewKind('application/pdf', 'noext')).toBe('pdf');
|
|
expect(getPreviewKind('text/plain', 'noext')).toBe('text');
|
|
expect(getPreviewKind('application/json', 'noext')).toBe('text');
|
|
});
|
|
|
|
it('ignores content type parameters', () => {
|
|
expect(getPreviewKind('text/plain; charset=utf-8', 'noext')).toBe('text');
|
|
});
|
|
|
|
it('falls back to the extension when the type is octet-stream', () => {
|
|
expect(getPreviewKind('application/octet-stream', 'photo.JPG')).toBe('image');
|
|
expect(getPreviewKind('application/octet-stream', 'clip.mp4')).toBe('video');
|
|
expect(getPreviewKind('application/octet-stream', 'song.flac')).toBe('audio');
|
|
expect(getPreviewKind('application/octet-stream', 'doc.pdf')).toBe('pdf');
|
|
expect(getPreviewKind('application/octet-stream', 'conf.yaml')).toBe('text');
|
|
expect(getPreviewKind(undefined, 'a/b/c.json')).toBe('text');
|
|
});
|
|
|
|
it('detects svg as image even though the backend rewrites its type', () => {
|
|
expect(getPreviewKind('application/octet-stream', 'logo.svg')).toBe('image');
|
|
});
|
|
|
|
it('detects Dockerfile without an extension', () => {
|
|
expect(getPreviewKind(undefined, 'build/Dockerfile')).toBe('text');
|
|
});
|
|
|
|
it('returns none for unknown files', () => {
|
|
expect(getPreviewKind('application/octet-stream', 'blob.bin')).toBe('none');
|
|
expect(getPreviewKind(undefined, 'noext')).toBe('none');
|
|
expect(getPreviewKind(undefined, 'archive.zip')).toBe('none');
|
|
});
|
|
|
|
it('does not treat a dotfile name as an extension', () => {
|
|
expect(getPreviewKind(undefined, '.gitignore')).toBe('none');
|
|
});
|
|
});
|
|
|
|
describe('getPreviewSizeLimit', () => {
|
|
it('caps documents per kind and leaves media unlimited', () => {
|
|
expect(getPreviewSizeLimit('text')).toBe(TEXT_PREVIEW_MAX_BYTES);
|
|
expect(getPreviewSizeLimit('image')).toBe(IMAGE_PREVIEW_MAX_BYTES);
|
|
expect(getPreviewSizeLimit('pdf')).toBe(PDF_PREVIEW_MAX_BYTES);
|
|
expect(getPreviewSizeLimit('video')).toBeNull();
|
|
expect(getPreviewSizeLimit('audio')).toBeNull();
|
|
expect(getPreviewSizeLimit('none')).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('getPreviewMime', () => {
|
|
it('restores the mime type the backend rewrote', () => {
|
|
expect(getPreviewMime('image', 'application/octet-stream', 'logo.svg')).toBe('image/svg+xml');
|
|
expect(getPreviewMime('pdf', 'application/octet-stream', 'doc.pdf')).toBe('application/pdf');
|
|
});
|
|
it('keeps a usable content type when there is no mapping', () => {
|
|
expect(getPreviewMime('text', 'text/plain', 'readme.txt')).toBe('text/plain');
|
|
expect(getPreviewMime('text', undefined, 'readme.weird')).toBe('application/octet-stream');
|
|
});
|
|
});
|
|
|
|
describe('getHighlightLanguage', () => {
|
|
it('maps common extensions', () => {
|
|
expect(getHighlightLanguage('a.json')).toBe('json');
|
|
expect(getHighlightLanguage('a.yml')).toBe('yaml');
|
|
expect(getHighlightLanguage('a.tsx')).toBe('typescript');
|
|
expect(getHighlightLanguage('Dockerfile')).toBe('dockerfile');
|
|
});
|
|
it('returns null for unmapped extensions', () => {
|
|
expect(getHighlightLanguage('a.log')).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('looksBinary', () => {
|
|
it('accepts ordinary text with newlines and tabs', () => {
|
|
expect(looksBinary('hello\n\tworld\r\n')).toBe(false);
|
|
expect(looksBinary('')).toBe(false);
|
|
});
|
|
it('flags replacement-heavy content', () => {
|
|
expect(looksBinary('���ab')).toBe(true);
|
|
});
|
|
it('flags control-character-heavy content', () => {
|
|
expect(looksBinary('\x00\x01\x02abc')).toBe(true);
|
|
});
|
|
it('tolerates a small fraction of oddities', () => {
|
|
expect(looksBinary('a'.repeat(99) + '\x00')).toBe(false);
|
|
});
|
|
});
|