- Add safety checks for window.openTTSModal and window.openTranslateModal availability - Implement fallback dynamic imports if window functions not available - Prevents "window.openTTSModal is not a function" and "window.openTranslateModal is not a function" errors - Provides graceful error handling with user feedback if modal imports fail - Resolves loading order dependency issues between ui.js and embed modal This ensures modal buttons work regardless of script loading order.
108 lines
No EOL
2.6 KiB
JavaScript
108 lines
No EOL
2.6 KiB
JavaScript
// Jest test setup for modal testing
|
|
import { JSDOM } from 'jsdom';
|
|
|
|
// Set up DOM environment
|
|
const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>', {
|
|
url: 'https://example.com',
|
|
pretendToBeVisual: true,
|
|
resources: 'usable'
|
|
});
|
|
|
|
global.document = dom.window.document;
|
|
global.window = dom.window;
|
|
global.navigator = dom.window.navigator;
|
|
global.HTMLElement = dom.window.HTMLElement;
|
|
global.Element = dom.window.Element;
|
|
|
|
// Mock localStorage
|
|
const localStorageMock = {
|
|
getItem: jest.fn(),
|
|
setItem: jest.fn(),
|
|
removeItem: jest.fn(),
|
|
clear: jest.fn(),
|
|
};
|
|
global.localStorage = localStorageMock;
|
|
|
|
// Mock fetch
|
|
global.fetch = jest.fn();
|
|
|
|
// Mock window.matchMedia
|
|
Object.defineProperty(window, 'matchMedia', {
|
|
writable: true,
|
|
value: jest.fn().mockImplementation(query => ({
|
|
matches: false,
|
|
media: query,
|
|
onchange: null,
|
|
addListener: jest.fn(), // deprecated
|
|
removeListener: jest.fn(), // deprecated
|
|
addEventListener: jest.fn(),
|
|
removeEventListener: jest.fn(),
|
|
dispatchEvent: jest.fn(),
|
|
})),
|
|
});
|
|
|
|
// Mock dialog element if not available
|
|
if (typeof HTMLDialogElement === 'undefined') {
|
|
global.HTMLDialogElement = class HTMLDialogElement extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
this.open = false;
|
|
}
|
|
|
|
show() {
|
|
this.open = true;
|
|
}
|
|
|
|
showModal() {
|
|
this.open = true;
|
|
}
|
|
|
|
close() {
|
|
this.open = false;
|
|
}
|
|
};
|
|
|
|
// Register as a custom element
|
|
if (customElements && !customElements.get('dialog')) {
|
|
customElements.define('dialog', HTMLDialogElement);
|
|
}
|
|
}
|
|
|
|
// Global test helpers
|
|
global.createMockModal = () => {
|
|
const modal = document.createElement('dialog');
|
|
modal.id = 'test-modal';
|
|
document.body.appendChild(modal);
|
|
return modal;
|
|
};
|
|
|
|
global.createMockEvent = (type, properties = {}) => {
|
|
const event = new Event(type, { bubbles: true, cancelable: true });
|
|
Object.assign(event, properties);
|
|
return event;
|
|
};
|
|
|
|
// Cleanup function to reset mocks between tests
|
|
global.resetMocks = () => {
|
|
localStorageMock.getItem.mockClear();
|
|
localStorageMock.setItem.mockClear();
|
|
localStorageMock.removeItem.mockClear();
|
|
localStorageMock.clear.mockClear();
|
|
global.fetch.mockClear();
|
|
|
|
// Clear DOM
|
|
document.body.innerHTML = '';
|
|
document.head.innerHTML = '';
|
|
|
|
// Reset window properties
|
|
delete window.UNCLOSEAI_CUSTOM_STYLING;
|
|
delete window.uncloseaiEmbeddedModalOpen;
|
|
delete window.openTTSModal;
|
|
delete window.openTranslateModal;
|
|
delete window.toggleUncloseaiEmbeddedModal;
|
|
};
|
|
|
|
// Run cleanup before each test
|
|
beforeEach(() => {
|
|
resetMocks();
|
|
}); |