screenshot-chrome-extension/tests/preference-persistence.test.js
Karthikeyan N a018c36d67
Add copy to clipboard and save to pc toggle.
* escaped node modules from vcs

* feat: added copy to clipboard feature

* feat: added tests

* feat: added feature spec

* feat: added toggle for save to pc

* feat: added tests

* refactor: change toggle from '?' button to the 'switch' component

* Fix failing tests

* Update gitignore and remove unnecessary files

* Remove tooltips because they are unnecessary

---------

Co-authored-by: Joey Yakimowich-Payne <jyapayne@gmail.com>
2025-08-13 13:29:57 -06:00

414 lines
No EOL
13 KiB
JavaScript

/**
* Test suite for clipboard preference persistence across browser sessions
* Tests storage, retrieval, and default behavior of clipboard preferences
*/
// Mock Chrome APIs
global.chrome = {
storage: {
sync: {
get: jest.fn(),
set: jest.fn()
}
},
runtime: {
sendMessage: jest.fn()
},
tabs: {
query: jest.fn(),
sendMessage: jest.fn()
}
};
// Mock DOM APIs
global.document = {
createElement: jest.fn(() => ({
style: {},
classList: { add: jest.fn(), remove: jest.fn() },
appendChild: jest.fn(),
click: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
id: '',
checked: false,
value: ''
})),
head: { appendChild: jest.fn() },
body: { appendChild: jest.fn() },
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
querySelectorAll: jest.fn(() => []),
getElementById: jest.fn()
};
global.window = {
close: jest.fn(),
setTimeout: jest.fn((fn) => fn())
};
describe('Clipboard Preference Persistence', () => {
let mockClipboardToggle;
let mockBackgroundSelect;
beforeEach(() => {
jest.clearAllMocks();
// Mock DOM elements
mockClipboardToggle = {
checked: false,
addEventListener: jest.fn()
};
mockBackgroundSelect = {
value: 'black',
addEventListener: jest.fn()
};
global.document.getElementById = jest.fn((id) => {
switch (id) {
case 'clipboard-toggle':
return mockClipboardToggle;
case 'background-select':
return mockBackgroundSelect;
case 'start-selector':
return { addEventListener: jest.fn(), style: { display: 'block' } };
case 'stop-selector':
return { addEventListener: jest.fn(), style: { display: 'none' } };
case 'status':
return { textContent: '', className: '', style: { display: 'none' } };
default:
return null;
}
});
});
test('should load default clipboard preference when no saved preference exists', async () => {
// Mock storage returning no saved preferences
global.chrome.storage.sync.get.mockResolvedValue({});
// Simulate popup script loading
const popupScript = `
document.addEventListener('DOMContentLoaded', async () => {
const clipboardToggle = document.getElementById('clipboard-toggle');
const saved = await chrome.storage.sync.get(['backgroundPreference', 'copyToClipboard']);
clipboardToggle.checked = saved.copyToClipboard !== undefined ? saved.copyToClipboard : true;
});
`;
// Execute the popup script logic
await new Promise(resolve => {
global.document.addEventListener = jest.fn((event, callback) => {
if (event === 'DOMContentLoaded') {
callback();
resolve();
}
});
eval(popupScript);
});
expect(global.chrome.storage.sync.get).toHaveBeenCalledWith(['backgroundPreference', 'copyToClipboard']);
expect(mockClipboardToggle.checked).toBe(true); // Default should be true
});
test('should load saved clipboard preference when it exists', async () => {
// Mock storage returning saved preferences
global.chrome.storage.sync.get.mockResolvedValue({
backgroundPreference: 'white',
copyToClipboard: false
});
// Simulate popup script loading
const popupScript = `
document.addEventListener('DOMContentLoaded', async () => {
const clipboardToggle = document.getElementById('clipboard-toggle');
const saved = await chrome.storage.sync.get(['backgroundPreference', 'copyToClipboard']);
clipboardToggle.checked = saved.copyToClipboard !== undefined ? saved.copyToClipboard : true;
});
`;
// Execute the popup script logic
await new Promise(resolve => {
global.document.addEventListener = jest.fn((event, callback) => {
if (event === 'DOMContentLoaded') {
callback();
resolve();
}
});
eval(popupScript);
});
expect(mockClipboardToggle.checked).toBe(false); // Should load saved value
});
test('should save clipboard preference when toggle is changed', async () => {
let changeCallback;
mockClipboardToggle.addEventListener = jest.fn((event, callback) => {
if (event === 'change') {
changeCallback = callback;
}
});
// Simulate popup script initialization
const popupScript = `
document.addEventListener('DOMContentLoaded', async () => {
const clipboardToggle = document.getElementById('clipboard-toggle');
clipboardToggle.addEventListener('change', () => {
chrome.storage.sync.set({ copyToClipboard: clipboardToggle.checked });
});
});
`;
// Execute the popup script logic
await new Promise(resolve => {
global.document.addEventListener = jest.fn((event, callback) => {
if (event === 'DOMContentLoaded') {
callback();
resolve();
}
});
eval(popupScript);
});
// Simulate user toggling the checkbox
mockClipboardToggle.checked = true;
changeCallback();
expect(global.chrome.storage.sync.set).toHaveBeenCalledWith({ copyToClipboard: true });
});
test('should persist clipboard preference across multiple sessions', async () => {
// Simulate first session - user enables clipboard
global.chrome.storage.sync.get.mockResolvedValueOnce({});
let firstSessionChangeCallback;
mockClipboardToggle.addEventListener = jest.fn((event, callback) => {
if (event === 'change') {
firstSessionChangeCallback = callback;
}
});
// First session initialization
await new Promise(resolve => {
global.document.addEventListener = jest.fn((event, callback) => {
if (event === 'DOMContentLoaded') {
callback();
resolve();
}
});
const popupScript = `
document.addEventListener('DOMContentLoaded', async () => {
const clipboardToggle = document.getElementById('clipboard-toggle');
const saved = await chrome.storage.sync.get(['backgroundPreference', 'copyToClipboard']);
clipboardToggle.checked = saved.copyToClipboard !== undefined ? saved.copyToClipboard : true;
clipboardToggle.addEventListener('change', () => {
chrome.storage.sync.set({ copyToClipboard: clipboardToggle.checked });
});
});
`;
eval(popupScript);
});
// User disables clipboard in first session
mockClipboardToggle.checked = false;
firstSessionChangeCallback();
expect(global.chrome.storage.sync.set).toHaveBeenCalledWith({ copyToClipboard: false });
// Simulate second session - should load the saved preference
jest.clearAllMocks();
global.chrome.storage.sync.get.mockResolvedValueOnce({
copyToClipboard: false
});
// Reset mock element
mockClipboardToggle.checked = true; // Reset to opposite of expected
// Second session initialization
await new Promise(resolve => {
global.document.addEventListener = jest.fn((event, callback) => {
if (event === 'DOMContentLoaded') {
callback();
resolve();
}
});
const popupScript = `
document.addEventListener('DOMContentLoaded', async () => {
const clipboardToggle = document.getElementById('clipboard-toggle');
const saved = await chrome.storage.sync.get(['backgroundPreference', 'copyToClipboard']);
clipboardToggle.checked = saved.copyToClipboard !== undefined ? saved.copyToClipboard : true;
});
`;
eval(popupScript);
});
expect(mockClipboardToggle.checked).toBe(false); // Should load saved preference from first session
});
test('should handle storage errors gracefully', async () => {
// Mock storage error
global.chrome.storage.sync.get.mockRejectedValue(new Error('Storage error'));
let errorOccurred = false;
try {
const popupScript = `
document.addEventListener('DOMContentLoaded', async () => {
try {
const clipboardToggle = document.getElementById('clipboard-toggle');
const saved = await chrome.storage.sync.get(['backgroundPreference', 'copyToClipboard']);
clipboardToggle.checked = saved.copyToClipboard !== undefined ? saved.copyToClipboard : true;
} catch (error) {
// Should fall back to default behavior
const clipboardToggle = document.getElementById('clipboard-toggle');
clipboardToggle.checked = true; // Default value
}
});
`;
await new Promise(resolve => {
global.document.addEventListener = jest.fn((event, callback) => {
if (event === 'DOMContentLoaded') {
callback();
resolve();
}
});
eval(popupScript);
});
} catch (error) {
errorOccurred = true;
}
expect(errorOccurred).toBe(false); // Should handle error gracefully
expect(mockClipboardToggle.checked).toBe(true); // Should fall back to default
});
test('should save both background and clipboard preferences independently', async () => {
let clipboardChangeCallback;
let backgroundChangeCallback;
mockClipboardToggle.addEventListener = jest.fn((event, callback) => {
if (event === 'change') {
clipboardChangeCallback = callback;
}
});
mockBackgroundSelect.addEventListener = jest.fn((event, callback) => {
if (event === 'change') {
backgroundChangeCallback = callback;
}
});
// Initialize popup script
const popupScript = `
document.addEventListener('DOMContentLoaded', async () => {
const backgroundSelect = document.getElementById('background-select');
const clipboardToggle = document.getElementById('clipboard-toggle');
backgroundSelect.addEventListener('change', () => {
chrome.storage.sync.set({ backgroundPreference: backgroundSelect.value });
});
clipboardToggle.addEventListener('change', () => {
chrome.storage.sync.set({ copyToClipboard: clipboardToggle.checked });
});
});
`;
await new Promise(resolve => {
global.document.addEventListener = jest.fn((event, callback) => {
if (event === 'DOMContentLoaded') {
callback();
resolve();
}
});
eval(popupScript);
});
// Change background preference
mockBackgroundSelect.value = 'transparent';
backgroundChangeCallback();
expect(global.chrome.storage.sync.set).toHaveBeenCalledWith({ backgroundPreference: 'transparent' });
// Change clipboard preference
mockClipboardToggle.checked = false;
clipboardChangeCallback();
expect(global.chrome.storage.sync.set).toHaveBeenCalledWith({ copyToClipboard: false });
// Verify both calls were made independently
expect(global.chrome.storage.sync.set).toHaveBeenCalledTimes(2);
});
test('should include clipboard preference in message to content script', async () => {
// Mock tab query and message sending
global.chrome.tabs.query.mockResolvedValue([{ id: 123, url: 'https://example.com' }]);
global.chrome.tabs.sendMessage.mockResolvedValue();
let startButtonCallback;
const mockStartButton = {
addEventListener: jest.fn((event, callback) => {
if (event === 'click') {
startButtonCallback = callback;
}
}),
style: { display: 'block' }
};
global.document.getElementById = jest.fn((id) => {
switch (id) {
case 'start-selector':
return mockStartButton;
case 'clipboard-toggle':
return { checked: true }; // Clipboard enabled
case 'background-select':
return { value: 'white' };
case 'status':
return { textContent: '', className: '', style: { display: 'none' } };
default:
return mockClipboardToggle;
}
});
// Initialize popup script
const popupScript = `
document.addEventListener('DOMContentLoaded', async () => {
const startBtn = document.getElementById('start-selector');
const backgroundSelect = document.getElementById('background-select');
const clipboardToggle = document.getElementById('clipboard-toggle');
startBtn.addEventListener('click', async () => {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
await chrome.tabs.sendMessage(tab.id, {
action: 'startSelector',
background: backgroundSelect.value,
copyToClipboard: clipboardToggle.checked
});
});
});
`;
await new Promise(resolve => {
global.document.addEventListener = jest.fn((event, callback) => {
if (event === 'DOMContentLoaded') {
callback();
resolve();
}
});
eval(popupScript);
});
// Simulate start button click
await startButtonCallback();
expect(global.chrome.tabs.sendMessage).toHaveBeenCalledWith(123, {
action: 'startSelector',
background: 'white',
copyToClipboard: true
});
});
});