Spaces:
Running
Running
File size: 4,473 Bytes
a63cedf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | import { describe, test, expect, beforeEach, jest } from '@jest/globals';
import fs from 'fs';
import path from 'path';
// Polyfill crypto for JSDOM/Node environment
if (!global.crypto) {
global.crypto = {
randomUUID: () => 'test-uuid-123'
};
} else if (!global.crypto.randomUUID) {
global.crypto.randomUUID = () => 'test-uuid-123';
}
// Manually load app.js
const appJsPath = path.resolve('app/static/app.js');
const appJsContent = fs.readFileSync(appJsPath, 'utf8');
// Execute in global scope (JSDOM provides window, document etc.)
(0, eval)(appJsContent);
const { dermatologApp } = global.window;
describe('Drag and Drop Logic', () => {
let app;
beforeEach(() => {
// Reset mocks on globals
global.fetch = jest.fn();
// Mock properties on existing window/document if needed
global.document.cookie = '';
const originalCreateElement = global.document.createElement;
global.document.createElement = jest.fn((tag) => {
if (tag === 'sl-alert') {
return {
toast: jest.fn(),
append: jest.fn()
};
}
return originalCreateElement.call(global.document, tag);
});
global.document.body.append = jest.fn();
// Mock customElements if missing
if (!global.customElements) {
global.customElements = {
whenDefined: jest.fn().mockResolvedValue()
};
}
// Initialize app instance
app = dermatologApp();
});
test('handleDrop processes files and resets dragover', async () => {
// Mock handleFiles to isolate handleDrop logic
app.handleFiles = jest.fn();
const mockFile = new File([''], 'test.png', { type: 'image/png' });
const mockEvent = {
dataTransfer: {
files: [mockFile]
}
};
app.dragover = true;
await app.handleDrop(mockEvent);
expect(app.dragover).toBe(false);
expect(app.handleFiles).toHaveBeenCalledWith(mockEvent.dataTransfer.files);
});
test('handleDrop ignores empty file list', async () => {
app.handleFiles = jest.fn();
const mockEvent = {
dataTransfer: {
files: []
}
};
app.dragover = true;
await app.handleDrop(mockEvent);
expect(app.dragover).toBe(false);
expect(app.handleFiles).not.toHaveBeenCalled();
});
test('handleFiles processes files locally and schedules analysis', async () => {
jest.useFakeTimers();
const mockFile = new File(['content'], 'test.png', {
type: 'image/png',
lastModified: Date.now()
});
const mockFiles = [mockFile];
// Mock methods
app.addPhotoToTimeline = jest.fn();
app.analyzeAllPhotos = jest.fn();
// Mock readAsDataURL to return a dummy string
app.readAsDataURL = jest.fn().mockResolvedValue('data:image/png;base64,test');
// Mock getAllPhotos to avoid empty check failure
app.getAllPhotos = jest.fn().mockReturnValue([]);
await app.handleFiles(mockFiles);
// Should NOT call fetch anymore for upload
expect(global.fetch).not.toHaveBeenCalled();
// Should add to timeline
expect(app.addPhotoToTimeline).toHaveBeenCalledWith(expect.objectContaining({
id: 'test-uuid-123',
filename: 'test.png'
}));
// Assert analysis NOT called yet (waiting for timeout)
expect(app.analyzeAllPhotos).not.toHaveBeenCalled();
// Fast-forward time
jest.advanceTimersByTime(300);
// Now assert analysis called
expect(app.analyzeAllPhotos).toHaveBeenCalled();
expect(app.loading).toBe(false);
jest.useRealTimers();
});
test('handleFiles handles local processing failure', async () => {
const mockFile = new File([''], 'test.png', { type: 'image/png' });
// Mock failure in readAsDataURL
app.readAsDataURL = jest.fn().mockRejectedValue(new Error("Local read failed"));
app.analyzeAllPhotos = jest.fn();
await app.handleFiles([mockFile]);
expect(app.error).toBe("Failed to process images: Local read failed");
expect(app.loading).toBe(false);
expect(app.analyzeAllPhotos).not.toHaveBeenCalled();
});
});
|