Skip to content

Commit

Permalink
Adds unit tests for keybinding.js
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronbrethorst committed Jan 17, 2025
1 parent 2116195 commit 3810463
Showing 1 changed file with 158 additions and 0 deletions.
158 changes: 158 additions & 0 deletions src/tests/lib/keybinding.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { keybinding } from '$lib/keybinding';

describe('keybinding action', () => {
let node;
let mockWindow;
let currentHandler;

beforeEach(() => {
node = {
click: vi.fn()
};

mockWindow = {
addEventListener: vi.fn((event, handler) => {
if (event === 'keydown') {
currentHandler = handler;
}
}),
removeEventListener: vi.fn((event, handler) => {
if (event === 'keydown' && handler === currentHandler) {
currentHandler = null;
}
})
};

// Set up mock window
const originalWindow = global.window;
global.window = mockWindow;

beforeEach.cleanup = () => {
global.window = originalWindow;
};
});

afterEach(() => {
beforeEach.cleanup?.();
vi.clearAllMocks();
currentHandler = null;
});

const triggerKeydown = (keyParams) => {
const event = {
code: keyParams.code || '',
altKey: keyParams.alt || false,
shiftKey: keyParams.shift || false,
ctrlKey: keyParams.control || false,
metaKey: keyParams.control || false,
preventDefault: vi.fn()
};

if (currentHandler) {
currentHandler(event);
}
return event;
};

it('adds keydown event listener on initialization', () => {
keybinding(node, { code: 'KeyA' });
expect(mockWindow.addEventListener).toHaveBeenCalledWith('keydown', expect.any(Function));
});

it('removes existing listener before adding new one on update', () => {
let params = { code: 'KeyA' };
const action = keybinding(node, params);

// Clear the initial setup calls
mockWindow.addEventListener.mockClear();
mockWindow.removeEventListener.mockClear();

// Update the params object directly
params.code = 'KeyB';
action.update();

expect(mockWindow.removeEventListener).toHaveBeenCalledTimes(1);
expect(mockWindow.addEventListener).toHaveBeenCalledTimes(1);
});

it('removes listener on destroy', () => {
const action = keybinding(node, { code: 'KeyA' });
action.destroy();

expect(mockWindow.removeEventListener).toHaveBeenCalled();
});

it('only responds to matching key code', () => {
keybinding(node, { code: 'KeyA' });

triggerKeydown({ code: 'KeyB' });
expect(node.click).not.toHaveBeenCalled();

triggerKeydown({ code: 'KeyA' });
expect(node.click).toHaveBeenCalledTimes(1);
});

it('responds to updated key code', () => {
// Create params object that we'll modify
let params = { code: 'KeyA' };
const action = keybinding(node, params);

// Verify initial binding works
triggerKeydown({ code: 'KeyA' });
expect(node.click).toHaveBeenCalledTimes(1);

// Update params and trigger update
node.click.mockClear();
params.code = 'KeyB';
action.update();

// Verify new binding works
triggerKeydown({ code: 'KeyB' });
expect(node.click).toHaveBeenCalledTimes(1);

// Verify old binding doesn't work
node.click.mockClear();
triggerKeydown({ code: 'KeyA' });
expect(node.click).not.toHaveBeenCalled();
});

it('handles modifier keys correctly', () => {
keybinding(node, {
code: 'KeyA',
alt: true,
shift: true,
control: true
});

triggerKeydown({ code: 'KeyA' });
expect(node.click).not.toHaveBeenCalled();

triggerKeydown({ code: 'KeyA', alt: true });
expect(node.click).not.toHaveBeenCalled();

triggerKeydown({ code: 'KeyA', alt: true, shift: true, control: true });
expect(node.click).toHaveBeenCalledTimes(1);
});

it('handles meta key as control', () => {
keybinding(node, {
code: 'KeyA',
control: true
});

const event = triggerKeydown({ code: 'KeyA', control: true });
expect(node.click).toHaveBeenCalledTimes(1);
expect(event.preventDefault).toHaveBeenCalled();
});

it('triggers callback instead of click when provided', () => {
const callback = vi.fn();
keybinding(node, { code: 'KeyA', callback });

triggerKeydown({ code: 'KeyA' });

expect(callback).toHaveBeenCalledTimes(1);
expect(node.click).not.toHaveBeenCalled();
});
});

0 comments on commit 3810463

Please sign in to comment.