mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-22 04:09:22 +00:00

# Description of Changes Currently, the `tsconfig.json` file enforces strict type checking, but nothing in CI checks that the code is actually correctly typed. [Vite only transpiles TypeScript code](https://vite.dev/guide/features.html#transpile-only) so doesn't ensure that the TS code we're running is correct. This PR adds running of the type checker to CI and fixes the type errors that have already crept into the codebase. Note that many of the changes I've made to 'fix the types' are just using `any` to disable the type checker because the code is under too much churn to fix anything properly at the moment. I still think enabling the type checker now is the best course of action though because otherwise we'll never be able to fix all of them, and it should at least help us not break things when adding new code. Co-authored-by: James <james@crosscourtanalytics.com>
366 lines
11 KiB
TypeScript
366 lines
11 KiB
TypeScript
/**
|
|
* Tests for auto-detection and smart conversion features in useConvertParameters
|
|
* This covers the analyzeFileTypes function and related smart detection logic
|
|
*/
|
|
|
|
import { describe, test, expect } from 'vitest';
|
|
import { renderHook, act, waitFor } from '@testing-library/react';
|
|
import { useConvertParameters } from './useConvertParameters';
|
|
|
|
describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|
|
|
describe('Single File Detection', () => {
|
|
|
|
test('should detect single file extension and set auto-target', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const pdfFile = [{ name: 'document.pdf' }];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(pdfFile);
|
|
});
|
|
|
|
expect(result.current.parameters.fromExtension).toBe('pdf');
|
|
expect(result.current.parameters.toExtension).toBe(''); // No auto-selection for multiple targets
|
|
expect(result.current.parameters.isSmartDetection).toBe(false);
|
|
expect(result.current.parameters.smartDetectionType).toBe('none');
|
|
});
|
|
|
|
test('should handle unknown file types with file-to-pdf fallback', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const unknownFile = [{ name: 'document.xyz' }, { name: 'image.jpggg' }];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(unknownFile);
|
|
});
|
|
|
|
expect(result.current.parameters.fromExtension).toBe('any');
|
|
expect(result.current.parameters.toExtension).toBe('pdf'); // Fallback to file-to-pdf
|
|
expect(result.current.parameters.isSmartDetection).toBe(true);
|
|
});
|
|
|
|
test('should handle files without extensions', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const noExtFile = [{ name: 'document' }];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(noExtFile);
|
|
});
|
|
|
|
expect(result.current.parameters.fromExtension).toBe('any');
|
|
expect(result.current.parameters.toExtension).toBe('pdf'); // Fallback to file-to-pdf
|
|
});
|
|
|
|
|
|
});
|
|
|
|
describe('Multiple Identical Files', () => {
|
|
|
|
test('should detect multiple PDF files and set auto-target', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const pdfFiles = [
|
|
{ name: 'doc1.pdf' },
|
|
{ name: 'doc2.pdf' },
|
|
{ name: 'doc3.pdf' }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(pdfFiles);
|
|
});
|
|
|
|
expect(result.current.parameters.fromExtension).toBe('pdf');
|
|
expect(result.current.parameters.toExtension).toBe(''); // Auto-selected
|
|
expect(result.current.parameters.isSmartDetection).toBe(false);
|
|
expect(result.current.parameters.smartDetectionType).toBe('none');
|
|
});
|
|
|
|
test('should handle multiple unknown file types with fallback', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const unknownFiles = [
|
|
{ name: 'file1.xyz' },
|
|
{ name: 'file2.xyz' }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(unknownFiles);
|
|
});
|
|
|
|
expect(result.current.parameters.fromExtension).toBe('any');
|
|
expect(result.current.parameters.toExtension).toBe('pdf');
|
|
expect(result.current.parameters.isSmartDetection).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('Smart Detection - All Images', () => {
|
|
|
|
test('should detect all image files and enable smart detection', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const imageFiles = [
|
|
{ name: 'photo1.jpg' },
|
|
{ name: 'photo2.png' },
|
|
{ name: 'photo3.gif' }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(imageFiles);
|
|
});
|
|
|
|
expect(result.current.parameters.fromExtension).toBe('image');
|
|
expect(result.current.parameters.toExtension).toBe('pdf');
|
|
expect(result.current.parameters.isSmartDetection).toBe(true);
|
|
expect(result.current.parameters.smartDetectionType).toBe('images');
|
|
});
|
|
|
|
test('should handle mixed case image extensions', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const imageFiles = [
|
|
{ name: 'photo1.JPG' },
|
|
{ name: 'photo2.PNG' }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(imageFiles);
|
|
});
|
|
|
|
expect(result.current.parameters.isSmartDetection).toBe(true);
|
|
expect(result.current.parameters.smartDetectionType).toBe('images');
|
|
});
|
|
});
|
|
|
|
describe('Smart Detection - All Web Files', () => {
|
|
|
|
test('should detect all web files and enable web smart detection', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const webFiles = [
|
|
{ name: 'page1.html' },
|
|
{ name: 'archive.zip' }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(webFiles);
|
|
});
|
|
|
|
expect(result.current.parameters.fromExtension).toBe('html');
|
|
expect(result.current.parameters.toExtension).toBe('pdf');
|
|
expect(result.current.parameters.isSmartDetection).toBe(true);
|
|
expect(result.current.parameters.smartDetectionType).toBe('web');
|
|
});
|
|
|
|
test('should handle mixed case web extensions', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const webFiles = [
|
|
{ name: 'page1.HTML' },
|
|
{ name: 'archive.ZIP' }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(webFiles);
|
|
});
|
|
|
|
expect(result.current.parameters.isSmartDetection).toBe(true);
|
|
expect(result.current.parameters.smartDetectionType).toBe('web');
|
|
});
|
|
|
|
test('should detect multiple web files and enable web smart detection', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const zipFiles = [
|
|
{ name: 'site1.zip' },
|
|
{ name: 'site2.html' }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(zipFiles);
|
|
});
|
|
|
|
expect(result.current.parameters.fromExtension).toBe('html');
|
|
expect(result.current.parameters.toExtension).toBe('pdf');
|
|
expect(result.current.parameters.isSmartDetection).toBe(true);
|
|
expect(result.current.parameters.smartDetectionType).toBe('web');
|
|
});
|
|
});
|
|
|
|
describe('Smart Detection - Mixed File Types', () => {
|
|
|
|
test('should detect mixed file types and enable smart detection', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const mixedFiles = [
|
|
{ name: 'document.pdf' },
|
|
{ name: 'spreadsheet.xlsx' },
|
|
{ name: 'presentation.pptx' }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(mixedFiles);
|
|
});
|
|
|
|
expect(result.current.parameters.fromExtension).toBe('any');
|
|
expect(result.current.parameters.toExtension).toBe('pdf');
|
|
expect(result.current.parameters.isSmartDetection).toBe(true);
|
|
expect(result.current.parameters.smartDetectionType).toBe('mixed');
|
|
});
|
|
|
|
test('should detect mixed images and documents as mixed type', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const mixedFiles = [
|
|
{ name: 'photo.jpg' },
|
|
{ name: 'document.pdf' },
|
|
{ name: 'text.txt' }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(mixedFiles);
|
|
});
|
|
|
|
expect(result.current.parameters.isSmartDetection).toBe(true);
|
|
expect(result.current.parameters.smartDetectionType).toBe('mixed');
|
|
});
|
|
|
|
test('should handle mixed with unknown file types', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const mixedFiles = [
|
|
{ name: 'document.pdf' },
|
|
{ name: 'unknown.xyz' },
|
|
{ name: 'noextension' }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(mixedFiles);
|
|
});
|
|
|
|
expect(result.current.parameters.isSmartDetection).toBe(true);
|
|
expect(result.current.parameters.smartDetectionType).toBe('mixed');
|
|
});
|
|
});
|
|
|
|
describe('Smart Detection Endpoint Resolution', () => {
|
|
|
|
test('should return correct endpoint for image smart detection', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const imageFiles = [
|
|
{ name: 'photo1.jpg' },
|
|
{ name: 'photo2.png' }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(imageFiles);
|
|
});
|
|
|
|
expect(result.current.getEndpointName()).toBe('img-to-pdf');
|
|
expect(result.current.getEndpoint()).toBe('/api/v1/convert/img/pdf');
|
|
});
|
|
|
|
test('should return correct endpoint for web smart detection', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const webFiles = [
|
|
{ name: 'page1.html' },
|
|
{ name: 'archive.zip' }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(webFiles);
|
|
});
|
|
|
|
expect(result.current.getEndpointName()).toBe('html-to-pdf');
|
|
expect(result.current.getEndpoint()).toBe('/api/v1/convert/html/pdf');
|
|
});
|
|
|
|
test('should return correct endpoint for mixed smart detection', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const mixedFiles = [
|
|
{ name: 'document.pdf' },
|
|
{ name: 'spreadsheet.xlsx' }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(mixedFiles);
|
|
});
|
|
|
|
expect(result.current.getEndpointName()).toBe('file-to-pdf');
|
|
expect(result.current.getEndpoint()).toBe('/api/v1/convert/file/pdf');
|
|
});
|
|
});
|
|
|
|
describe('Auto-Target Selection Logic', () => {
|
|
|
|
test('should select single available target automatically', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
// Markdown has only one conversion target (PDF)
|
|
const mdFile = [{ name: 'readme.md' }];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(mdFile);
|
|
});
|
|
|
|
expect(result.current.parameters.fromExtension).toBe('md');
|
|
expect(result.current.parameters.toExtension).toBe('pdf'); // Only available target
|
|
});
|
|
|
|
test('should not auto-select when multiple targets available', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
// PDF has multiple conversion targets, so no auto-selection
|
|
const pdfFile = [{ name: 'document.pdf' }];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(pdfFile);
|
|
});
|
|
|
|
expect(result.current.parameters.fromExtension).toBe('pdf');
|
|
// Should NOT auto-select when multiple targets available
|
|
expect(result.current.parameters.toExtension).toBe('');
|
|
});
|
|
});
|
|
|
|
describe('Edge Cases', () => {
|
|
|
|
test('should handle empty file names', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const emptyFiles = [{ name: '' }];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(emptyFiles);
|
|
});
|
|
|
|
expect(result.current.parameters.fromExtension).toBe('any');
|
|
expect(result.current.parameters.toExtension).toBe('pdf');
|
|
});
|
|
|
|
test('should handle malformed file objects', () => {
|
|
const { result } = renderHook(() => useConvertParameters());
|
|
|
|
const malformedFiles: Array<{name: string}> = [
|
|
{ name: 'valid.pdf' },
|
|
// @ts-ignore - Testing runtime resilience
|
|
{ name: null },
|
|
// @ts-ignore
|
|
{ name: undefined }
|
|
];
|
|
|
|
act(() => {
|
|
result.current.analyzeFileTypes(malformedFiles);
|
|
});
|
|
|
|
// Should still process the valid file and handle gracefully
|
|
expect(result.current.parameters.isSmartDetection).toBe(true);
|
|
expect(result.current.parameters.smartDetectionType).toBe('mixed');
|
|
});
|
|
});
|
|
});
|