added messages list, new client form, logic for client Apps plus others
This commit is contained in:
@@ -0,0 +1,325 @@
|
||||
import Keybindings from "../../../src/js/modules/Keybindings/Keybindings";
|
||||
|
||||
describe("Keybindings module", () => {
|
||||
/** @type {Keybindings} */
|
||||
let keybindingsMod;
|
||||
let mockTable;
|
||||
|
||||
beforeEach(() => {
|
||||
// Create mock optionsList
|
||||
const mockOptionsList = {
|
||||
register: jest.fn(),
|
||||
generate: jest.fn().mockImplementation((defaults, options) => {
|
||||
return { ...defaults, ...options };
|
||||
})
|
||||
};
|
||||
|
||||
// Create mock eventBus
|
||||
const mockEventBus = {
|
||||
subscribe: jest.fn(),
|
||||
unsubscribe: jest.fn(),
|
||||
subscribed: jest.fn(),
|
||||
subscriptionChange: jest.fn(),
|
||||
dispatch: jest.fn(),
|
||||
chain: jest.fn(),
|
||||
confirm: jest.fn()
|
||||
};
|
||||
|
||||
// Create mock externalEvents
|
||||
const mockExternalEvents = {
|
||||
dispatch: jest.fn(),
|
||||
subscribed: jest.fn(),
|
||||
subscriptionChange: jest.fn()
|
||||
};
|
||||
|
||||
// Create a simplified mock of the table
|
||||
mockTable = {
|
||||
options: {
|
||||
keybindings: false // Disable default keybindings for most tests
|
||||
},
|
||||
element: {
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
focus: jest.fn()
|
||||
},
|
||||
rowManager: {
|
||||
element: {
|
||||
clientHeight: 200,
|
||||
scrollHeight: 600,
|
||||
scrollTop: 200
|
||||
},
|
||||
scrollToRow: jest.fn(),
|
||||
getDisplayRows: jest.fn().mockReturnValue([
|
||||
{ id: 1 },
|
||||
{ id: 2 },
|
||||
{ id: 3 }
|
||||
]),
|
||||
displayRowsCount: 3
|
||||
},
|
||||
columnManager: {
|
||||
optionsList: mockOptionsList
|
||||
},
|
||||
optionsList: mockOptionsList,
|
||||
eventBus: mockEventBus,
|
||||
externalEvents: mockExternalEvents,
|
||||
registerTableFunction: jest.fn(),
|
||||
initGuard: jest.fn()
|
||||
};
|
||||
|
||||
// Mock the prototype methods of the Module class
|
||||
jest.spyOn(Keybindings.prototype, 'registerTableOption').mockImplementation(function(key, value) {
|
||||
this.table.optionsList.register(key, value);
|
||||
});
|
||||
|
||||
jest.spyOn(Keybindings.prototype, 'registerColumnOption').mockImplementation(function(key, value) {
|
||||
this.table.columnManager.optionsList.register(key, value);
|
||||
});
|
||||
|
||||
// Mock subscribe method which is used in initialize
|
||||
jest.spyOn(Keybindings.prototype, 'subscribe').mockImplementation(function(key, callback) {
|
||||
return this.table.eventBus.subscribe(key, callback);
|
||||
});
|
||||
|
||||
// Create an instance of the Keybindings module with the mock table
|
||||
keybindingsMod = new Keybindings(mockTable);
|
||||
|
||||
// Mock the dispatch method
|
||||
keybindingsMod.dispatch = jest.fn();
|
||||
|
||||
// Mock registerTableFunction
|
||||
keybindingsMod.registerTableFunction = function(name, callback) {
|
||||
mockTable.registerTableFunction(name, callback);
|
||||
};
|
||||
|
||||
// Initialize the module
|
||||
keybindingsMod.initialize();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("should register keybindings table option during construction", () => {
|
||||
const testActionFunc = jest.fn();
|
||||
const mod = new Keybindings({
|
||||
...mockTable,
|
||||
options: {
|
||||
keybindings: {
|
||||
testAction: "ctrl + q"
|
||||
}
|
||||
},
|
||||
});
|
||||
Object.assign(Keybindings.actions, {
|
||||
testAction: testActionFunc,
|
||||
})
|
||||
mod.initialize();
|
||||
mod.keydownBinding(new KeyboardEvent("keydown", { key: "q", ctrlKey: true }));
|
||||
mod.keyupBinding(new KeyboardEvent("keyup", { key: "q", ctrlKey: true }));
|
||||
expect(testActionFunc).toHaveBeenCalled();
|
||||
})
|
||||
|
||||
it("should initialize watchKeys and pressedKeys as empty when keybindings disabled", () => {
|
||||
// With keybindings:false, the module should initialize empty structures
|
||||
expect(keybindingsMod.watchKeys).toEqual({});
|
||||
expect(keybindingsMod.pressedKeys).toEqual([]);
|
||||
});
|
||||
|
||||
it("should map default bindings when keybindings is enabled", () => {
|
||||
// Create a new instance with enabled keybindings
|
||||
mockTable.options.keybindings = {};
|
||||
keybindingsMod = new Keybindings(mockTable);
|
||||
keybindingsMod.dispatch = jest.fn();
|
||||
|
||||
// Mock the mapBinding method to inspect what it's called with
|
||||
keybindingsMod.mapBinding = jest.fn();
|
||||
|
||||
keybindingsMod.initialize();
|
||||
|
||||
// Verify that mapBinding was called at least once
|
||||
expect(keybindingsMod.mapBinding).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should map bindings through the public API", () => {
|
||||
// Create a separate instance to ensure clean state
|
||||
const instance = new Keybindings({...mockTable, options: {keybindings: false}});
|
||||
|
||||
// Initialize the instance to set up watchKeys
|
||||
instance.initialize();
|
||||
|
||||
// Add a spy to track key binding objects
|
||||
let capturedBindings = [];
|
||||
const originalMapBinding = instance.mapBinding;
|
||||
instance.mapBinding = jest.fn((action, binding) => {
|
||||
capturedBindings.push({action, binding});
|
||||
return originalMapBinding.call(instance, action, binding);
|
||||
});
|
||||
|
||||
// Map a simple binding
|
||||
const bindings = {
|
||||
scrollToStart: "ctrl + home"
|
||||
};
|
||||
|
||||
// Call the method
|
||||
instance.mapBindings(bindings);
|
||||
|
||||
// Verify mapBinding was called with expected parameters
|
||||
expect(instance.mapBinding).toHaveBeenCalledWith("scrollToStart", "ctrl + home");
|
||||
expect(capturedBindings.length).toBeGreaterThan(0);
|
||||
|
||||
// Verify the first binding was for scrollToStart
|
||||
const capturedBinding = capturedBindings[0];
|
||||
expect(capturedBinding.action).toBe("scrollToStart");
|
||||
expect(capturedBinding.binding).toBe("ctrl + home");
|
||||
});
|
||||
|
||||
it("should handle key combinations correctly", () => {
|
||||
// Mock a key binding
|
||||
const binding = {
|
||||
action: jest.fn(),
|
||||
keys: [38], // UP arrow
|
||||
ctrl: true,
|
||||
shift: false,
|
||||
meta: false
|
||||
};
|
||||
|
||||
// Create a mock event
|
||||
const event = {
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
metaKey: false
|
||||
};
|
||||
|
||||
// Set pressed keys
|
||||
keybindingsMod.pressedKeys = [38];
|
||||
|
||||
// Test binding check - should match
|
||||
const result = keybindingsMod.checkBinding(event, binding);
|
||||
expect(result).toBe(true);
|
||||
expect(binding.action).toHaveBeenCalled();
|
||||
|
||||
// Test with non-matching modifiers
|
||||
event.shiftKey = true;
|
||||
const nonMatchResult = keybindingsMod.checkBinding(event, binding);
|
||||
expect(nonMatchResult).toBe(false);
|
||||
});
|
||||
|
||||
it("should handle clearing bindings", () => {
|
||||
// Set up the binding references
|
||||
keybindingsMod.keyupBinding = jest.fn();
|
||||
keybindingsMod.keydownBinding = jest.fn();
|
||||
|
||||
// Call clear bindings
|
||||
keybindingsMod.clearBindings();
|
||||
|
||||
// Check that event listeners were removed
|
||||
expect(keybindingsMod.table.element.removeEventListener).toHaveBeenCalledWith("keydown", keybindingsMod.keyupBinding);
|
||||
expect(keybindingsMod.table.element.removeEventListener).toHaveBeenCalledWith("keyup", keybindingsMod.keydownBinding);
|
||||
});
|
||||
|
||||
it("should execute scrollPageUp action by calling scrollToRow for first row when scroll would be negative", () => {
|
||||
// Create mock event
|
||||
const event = {
|
||||
preventDefault: jest.fn()
|
||||
};
|
||||
|
||||
// Change scrollTop to a small value to trigger the "else" branch
|
||||
keybindingsMod.table.rowManager.element.scrollTop = 100;
|
||||
keybindingsMod.table.rowManager.element.clientHeight = 200;
|
||||
|
||||
// Execute the action directly to test the scrollToRow path
|
||||
Keybindings.actions.scrollPageUp.call(keybindingsMod, event);
|
||||
|
||||
// Check scrollToRow was called with first row
|
||||
expect(keybindingsMod.table.rowManager.scrollToRow).toHaveBeenCalledWith({ id: 1 });
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
expect(keybindingsMod.table.element.focus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should execute scrollPageDown action by calling scrollToRow for last row", () => {
|
||||
// Create mock event
|
||||
const event = {
|
||||
preventDefault: jest.fn()
|
||||
};
|
||||
|
||||
// Set scrollTop and scrollHeight to trigger the "else" branch
|
||||
keybindingsMod.table.rowManager.element.scrollTop = 500;
|
||||
keybindingsMod.table.rowManager.element.clientHeight = 200;
|
||||
keybindingsMod.table.rowManager.element.scrollHeight = 600;
|
||||
|
||||
// Execute the action directly
|
||||
Keybindings.actions.scrollPageDown.call(keybindingsMod, event);
|
||||
|
||||
// Check that the right methods were called
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
expect(keybindingsMod.table.element.focus).toHaveBeenCalled();
|
||||
|
||||
// Check scrollToRow was called with last row since we're at the bottom
|
||||
expect(keybindingsMod.table.rowManager.scrollToRow).toHaveBeenCalledWith({ id: 3 });
|
||||
});
|
||||
|
||||
it("should execute scrollToStart action correctly", () => {
|
||||
// Create mock event
|
||||
const event = {
|
||||
preventDefault: jest.fn()
|
||||
};
|
||||
|
||||
// Execute the action
|
||||
Keybindings.actions.scrollToStart.call(keybindingsMod, event);
|
||||
|
||||
// Check that event was prevented
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
|
||||
// Check that focus was called
|
||||
expect(keybindingsMod.table.element.focus).toHaveBeenCalled();
|
||||
|
||||
// Check scrollToRow was called with first row
|
||||
expect(keybindingsMod.table.rowManager.scrollToRow).toHaveBeenCalledWith({ id: 1 });
|
||||
});
|
||||
|
||||
it("should execute scrollToEnd action correctly", () => {
|
||||
// Create mock event
|
||||
const event = {
|
||||
preventDefault: jest.fn()
|
||||
};
|
||||
|
||||
// Execute the action
|
||||
Keybindings.actions.scrollToEnd.call(keybindingsMod, event);
|
||||
|
||||
// Check that event was prevented
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
|
||||
// Check that focus was called
|
||||
expect(keybindingsMod.table.element.focus).toHaveBeenCalled();
|
||||
|
||||
// Check scrollToRow was called with last row
|
||||
expect(keybindingsMod.table.rowManager.scrollToRow).toHaveBeenCalledWith({ id: 3 });
|
||||
});
|
||||
|
||||
it("should execute keyBlock action correctly", () => {
|
||||
// Create mock event
|
||||
const event = {
|
||||
stopPropagation: jest.fn(),
|
||||
preventDefault: jest.fn()
|
||||
};
|
||||
|
||||
// Execute the action
|
||||
Keybindings.actions.keyBlock.call(keybindingsMod, event);
|
||||
|
||||
// Check that event methods were called
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should execute navigation actions correctly", () => {
|
||||
// Test all navigation actions
|
||||
const actions = ["navPrev", "navNext", "navUp", "navDown", "navLeft", "navRight"];
|
||||
const events = {};
|
||||
|
||||
actions.forEach(action => {
|
||||
events[action] = { };
|
||||
Keybindings.actions[action].call(keybindingsMod, events[action]);
|
||||
expect(keybindingsMod.dispatch).toHaveBeenCalledWith(`keybinding-${action.replace("nav", "nav-").toLowerCase()}`, events[action]);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user