mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-11 11:15:24 +03:00
Fix bug of Linter error
This commit is contained in:
parent
83c2956679
commit
23dee756ca
@ -1,500 +1,522 @@
|
||||
const ContextMenuManager = require("../src/context-menu-manager")
|
||||
const ContextMenuManager = require('../src/context-menu-manager');
|
||||
|
||||
describe("ContextMenuManager", function () {
|
||||
let [contextMenu, parent, child, grandchild] = []
|
||||
describe('ContextMenuManager', function() {
|
||||
let [contextMenu, parent, child, grandchild] = [];
|
||||
|
||||
beforeEach(function () {
|
||||
const {resourcePath} = atom.getLoadSettings()
|
||||
contextMenu = new ContextMenuManager({keymapManager: atom.keymaps})
|
||||
contextMenu.initialize({resourcePath})
|
||||
beforeEach(function() {
|
||||
const { resourcePath } = atom.getLoadSettings();
|
||||
contextMenu = new ContextMenuManager({ keymapManager: atom.keymaps });
|
||||
contextMenu.initialize({ resourcePath });
|
||||
|
||||
parent = document.createElement("div")
|
||||
child = document.createElement("div")
|
||||
grandchild = document.createElement("div")
|
||||
parent.tabIndex = -1
|
||||
child.tabIndex = -1
|
||||
grandchild.tabIndex = -1
|
||||
parent.classList.add("parent")
|
||||
child.classList.add("child")
|
||||
grandchild.classList.add("grandchild")
|
||||
child.appendChild(grandchild)
|
||||
parent.appendChild(child)
|
||||
parent = document.createElement('div');
|
||||
child = document.createElement('div');
|
||||
grandchild = document.createElement('div');
|
||||
parent.tabIndex = -1;
|
||||
child.tabIndex = -1;
|
||||
grandchild.tabIndex = -1;
|
||||
parent.classList.add('parent');
|
||||
child.classList.add('child');
|
||||
grandchild.classList.add('grandchild');
|
||||
child.appendChild(grandchild);
|
||||
parent.appendChild(child);
|
||||
|
||||
document.body.appendChild(parent)
|
||||
})
|
||||
document.body.appendChild(parent);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
document.body.blur()
|
||||
document.body.removeChild(parent)
|
||||
})
|
||||
afterEach(function() {
|
||||
document.body.blur();
|
||||
document.body.removeChild(parent);
|
||||
});
|
||||
|
||||
describe("::add(itemsBySelector)", function () {
|
||||
it("can add top-level menu items that can be removed with the returned disposable", function () {
|
||||
describe('::add(itemsBySelector)', function() {
|
||||
it('can add top-level menu items that can be removed with the returned disposable', function() {
|
||||
const disposable = contextMenu.add({
|
||||
".parent": [{label: "A", command: "a"}],
|
||||
".child": [{label: "B", command: "b"}],
|
||||
".grandchild": [{label: "C", command: "c"}],
|
||||
})
|
||||
'.parent': [{ label: 'A', command: 'a' }],
|
||||
'.child': [{ label: 'B', command: 'b' }],
|
||||
'.grandchild': [{ label: 'C', command: 'c' }]
|
||||
});
|
||||
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([
|
||||
{label: "C", id: "C", command: "c"},
|
||||
{label: "B", id: "B", command: "b"},
|
||||
{label: "A", id: "A", command: "a"},
|
||||
])
|
||||
{ label: 'C', id: 'C', command: 'c' },
|
||||
{ label: 'B', id: 'B', command: 'b' },
|
||||
{ label: 'A', id: 'A', command: 'a' }
|
||||
]);
|
||||
|
||||
disposable.dispose()
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([])
|
||||
})
|
||||
disposable.dispose();
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([]);
|
||||
});
|
||||
|
||||
it("can add submenu items to existing menus that can be removed with the returned disposable", function () {
|
||||
it('can add submenu items to existing menus that can be removed with the returned disposable', function() {
|
||||
const disposable1 = contextMenu.add({
|
||||
".grandchild": [{label: "A", submenu: [{label: "B", command: "b"}]}],
|
||||
})
|
||||
'.grandchild': [{ label: 'A', submenu: [{ label: 'B', command: 'b' }] }]
|
||||
});
|
||||
const disposable2 = contextMenu.add({
|
||||
".grandchild": [{label: "A", submenu: [{label: "C", command: "c"}]}],
|
||||
})
|
||||
'.grandchild': [{ label: 'A', submenu: [{ label: 'C', command: 'c' }] }]
|
||||
});
|
||||
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([
|
||||
{
|
||||
label: "A",
|
||||
id: "A",
|
||||
label: 'A',
|
||||
id: 'A',
|
||||
submenu: [
|
||||
{label: "B", id: "B", command: "b"},
|
||||
{label: "C", id: "C", command: "c"},
|
||||
],
|
||||
},
|
||||
])
|
||||
{ label: 'B', id: 'B', command: 'b' },
|
||||
{ label: 'C', id: 'C', command: 'c' }
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
disposable2.dispose()
|
||||
disposable2.dispose();
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([
|
||||
{
|
||||
label: "A",
|
||||
id: "A",
|
||||
submenu: [{label: "B", id: "B", command: "b"}],
|
||||
},
|
||||
])
|
||||
label: 'A',
|
||||
id: 'A',
|
||||
submenu: [{ label: 'B', id: 'B', command: 'b' }]
|
||||
}
|
||||
]);
|
||||
|
||||
disposable1.dispose()
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([])
|
||||
})
|
||||
disposable1.dispose();
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([]);
|
||||
});
|
||||
|
||||
it("favors the most specific / recently added item in the case of a duplicate label", function () {
|
||||
grandchild.classList.add("foo")
|
||||
it('favors the most specific / recently added item in the case of a duplicate label', function() {
|
||||
grandchild.classList.add('foo');
|
||||
|
||||
const disposable1 = contextMenu.add({
|
||||
".grandchild": [{label: "A", command: "a"}],
|
||||
})
|
||||
'.grandchild': [{ label: 'A', command: 'a' }]
|
||||
});
|
||||
const disposable2 = contextMenu.add({
|
||||
".grandchild.foo": [{label: "A", command: "b"}],
|
||||
})
|
||||
'.grandchild.foo': [{ label: 'A', command: 'b' }]
|
||||
});
|
||||
const disposable3 = contextMenu.add({
|
||||
".grandchild": [{label: "A", command: "c"}],
|
||||
})
|
||||
'.grandchild': [{ label: 'A', command: 'c' }]
|
||||
});
|
||||
|
||||
contextMenu.add({
|
||||
".child": [{label: "A", command: "d"}],
|
||||
})
|
||||
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([{label: "A", id: "A", command: "b"}])
|
||||
|
||||
disposable2.dispose()
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([{label: "A", id: "A", command: "c"}])
|
||||
|
||||
disposable3.dispose()
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([{label: "A", id: "A", command: "a"}])
|
||||
|
||||
disposable1.dispose()
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([{label: "A", id: "A", command: "d"}])
|
||||
})
|
||||
|
||||
it("allows multiple separators, but not adjacent to each other", function () {
|
||||
contextMenu.add({
|
||||
".grandchild": [
|
||||
{label: "A", command: "a"},
|
||||
{type: "separator"},
|
||||
{type: "separator"},
|
||||
{label: "B", command: "b"},
|
||||
{type: "separator"},
|
||||
{type: "separator"},
|
||||
{label: "C", command: "c"},
|
||||
],
|
||||
})
|
||||
'.child': [{ label: 'A', command: 'd' }]
|
||||
});
|
||||
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([
|
||||
{label: "A", id: "A", command: "a"},
|
||||
{type: "separator"},
|
||||
{label: "B", id: "B", command: "b"},
|
||||
{type: "separator"},
|
||||
{label: "C", id: "C", command: "c"},
|
||||
])
|
||||
})
|
||||
{ label: 'A', id: 'A', command: 'b' }
|
||||
]);
|
||||
|
||||
it("excludes items marked for display in devMode unless in dev mode", function () {
|
||||
contextMenu.add({
|
||||
".grandchild": [
|
||||
{label: "A", command: "a", devMode: true},
|
||||
{label: "B", command: "b", devMode: false},
|
||||
],
|
||||
})
|
||||
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([{label: "B", id: "B", command: "b"}])
|
||||
|
||||
contextMenu.devMode = true
|
||||
disposable2.dispose();
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([
|
||||
{label: "A", id: "A", command: "a"},
|
||||
{label: "B", id: "B", command: "b"},
|
||||
])
|
||||
})
|
||||
{ label: 'A', id: 'A', command: 'c' }
|
||||
]);
|
||||
|
||||
it("allows items to be associated with `created` hooks which are invoked on template construction with the item and event", function () {
|
||||
let createdEvent = null
|
||||
disposable3.dispose();
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([
|
||||
{ label: 'A', id: 'A', command: 'a' }
|
||||
]);
|
||||
|
||||
disposable1.dispose();
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([
|
||||
{ label: 'A', id: 'A', command: 'd' }
|
||||
]);
|
||||
});
|
||||
|
||||
it('allows multiple separators, but not adjacent to each other', function() {
|
||||
contextMenu.add({
|
||||
'.grandchild': [
|
||||
{ label: 'A', command: 'a' },
|
||||
{ type: 'separator' },
|
||||
{ type: 'separator' },
|
||||
{ label: 'B', command: 'b' },
|
||||
{ type: 'separator' },
|
||||
{ type: 'separator' },
|
||||
{ label: 'C', command: 'c' }
|
||||
]
|
||||
});
|
||||
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([
|
||||
{ label: 'A', id: 'A', command: 'a' },
|
||||
{ type: 'separator' },
|
||||
{ label: 'B', id: 'B', command: 'b' },
|
||||
{ type: 'separator' },
|
||||
{ label: 'C', id: 'C', command: 'c' }
|
||||
]);
|
||||
});
|
||||
|
||||
it('excludes items marked for display in devMode unless in dev mode', function() {
|
||||
contextMenu.add({
|
||||
'.grandchild': [
|
||||
{ label: 'A', command: 'a', devMode: true },
|
||||
{ label: 'B', command: 'b', devMode: false }
|
||||
]
|
||||
});
|
||||
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([
|
||||
{ label: 'B', id: 'B', command: 'b' }
|
||||
]);
|
||||
|
||||
contextMenu.devMode = true;
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual([
|
||||
{ label: 'A', id: 'A', command: 'a' },
|
||||
{ label: 'B', id: 'B', command: 'b' }
|
||||
]);
|
||||
});
|
||||
|
||||
it('allows items to be associated with `created` hooks which are invoked on template construction with the item and event', function() {
|
||||
let createdEvent = null;
|
||||
|
||||
const item = {
|
||||
label: "A",
|
||||
command: "a",
|
||||
label: 'A',
|
||||
command: 'a',
|
||||
created(event) {
|
||||
this.command = "b"
|
||||
createdEvent = event
|
||||
},
|
||||
}
|
||||
this.command = 'b';
|
||||
createdEvent = event;
|
||||
}
|
||||
};
|
||||
|
||||
contextMenu.add({".grandchild": [item]})
|
||||
contextMenu.add({ '.grandchild': [item] });
|
||||
|
||||
const dispatchedEvent = {target: grandchild}
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([{label: "A", id: "A", command: "b"}])
|
||||
expect(item.command).toBe("a") // doesn't modify original item template
|
||||
expect(createdEvent).toBe(dispatchedEvent)
|
||||
})
|
||||
const dispatchedEvent = { target: grandchild };
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([
|
||||
{ label: 'A', id: 'A', command: 'b' }
|
||||
]);
|
||||
expect(item.command).toBe('a'); // doesn't modify original item template
|
||||
expect(createdEvent).toBe(dispatchedEvent);
|
||||
});
|
||||
|
||||
it("allows items to be associated with `shouldDisplay` hooks which are invoked on construction to determine whether the item should be included", function () {
|
||||
let shouldDisplayEvent = null
|
||||
let shouldDisplay = true
|
||||
it('allows items to be associated with `shouldDisplay` hooks which are invoked on construction to determine whether the item should be included', function() {
|
||||
let shouldDisplayEvent = null;
|
||||
let shouldDisplay = true;
|
||||
|
||||
const item = {
|
||||
label: "A",
|
||||
command: "a",
|
||||
label: 'A',
|
||||
command: 'a',
|
||||
shouldDisplay(event) {
|
||||
this.foo = "bar"
|
||||
shouldDisplayEvent = event
|
||||
return shouldDisplay
|
||||
},
|
||||
}
|
||||
contextMenu.add({".grandchild": [item]})
|
||||
this.foo = 'bar';
|
||||
shouldDisplayEvent = event;
|
||||
return shouldDisplay;
|
||||
}
|
||||
};
|
||||
contextMenu.add({ '.grandchild': [item] });
|
||||
|
||||
const dispatchedEvent = {target: grandchild}
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([{label: "A", id: "A", command: "a"}])
|
||||
expect(item.foo).toBeUndefined() // doesn't modify original item template
|
||||
expect(shouldDisplayEvent).toBe(dispatchedEvent)
|
||||
const dispatchedEvent = { target: grandchild };
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([
|
||||
{ label: 'A', id: 'A', command: 'a' }
|
||||
]);
|
||||
expect(item.foo).toBeUndefined(); // doesn't modify original item template
|
||||
expect(shouldDisplayEvent).toBe(dispatchedEvent);
|
||||
|
||||
shouldDisplay = false
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([])
|
||||
})
|
||||
shouldDisplay = false;
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([]);
|
||||
});
|
||||
|
||||
it("prunes a trailing separator", function () {
|
||||
it('prunes a trailing separator', function() {
|
||||
contextMenu.add({
|
||||
".grandchild": [
|
||||
{label: "A", command: "a"},
|
||||
{type: "separator"},
|
||||
{label: "B", command: "b"},
|
||||
{type: "separator"},
|
||||
],
|
||||
})
|
||||
'.grandchild': [
|
||||
{ label: 'A', command: 'a' },
|
||||
{ type: 'separator' },
|
||||
{ label: 'B', command: 'b' },
|
||||
{ type: 'separator' }
|
||||
]
|
||||
});
|
||||
|
||||
expect(contextMenu.templateForEvent({target: grandchild}).length).toBe(3)
|
||||
})
|
||||
expect(contextMenu.templateForEvent({ target: grandchild }).length).toBe(
|
||||
3
|
||||
);
|
||||
});
|
||||
|
||||
it("prunes a leading separator", function () {
|
||||
it('prunes a leading separator', function() {
|
||||
contextMenu.add({
|
||||
".grandchild": [
|
||||
{type: "separator"},
|
||||
{label: "A", command: "a"},
|
||||
{type: "separator"},
|
||||
{label: "B", command: "b"},
|
||||
],
|
||||
})
|
||||
'.grandchild': [
|
||||
{ type: 'separator' },
|
||||
{ label: 'A', command: 'a' },
|
||||
{ type: 'separator' },
|
||||
{ label: 'B', command: 'b' }
|
||||
]
|
||||
});
|
||||
|
||||
expect(contextMenu.templateForEvent({target: grandchild}).length).toBe(3)
|
||||
})
|
||||
expect(contextMenu.templateForEvent({ target: grandchild }).length).toBe(
|
||||
3
|
||||
);
|
||||
});
|
||||
|
||||
it("prunes duplicate separators", function () {
|
||||
it('prunes duplicate separators', function() {
|
||||
contextMenu.add({
|
||||
".grandchild": [
|
||||
{label: "A", command: "a"},
|
||||
{type: "separator"},
|
||||
{type: "separator"},
|
||||
{label: "B", command: "b"},
|
||||
],
|
||||
})
|
||||
'.grandchild': [
|
||||
{ label: 'A', command: 'a' },
|
||||
{ type: 'separator' },
|
||||
{ type: 'separator' },
|
||||
{ label: 'B', command: 'b' }
|
||||
]
|
||||
});
|
||||
|
||||
expect(contextMenu.templateForEvent({target: grandchild}).length).toBe(3)
|
||||
})
|
||||
expect(contextMenu.templateForEvent({ target: grandchild }).length).toBe(
|
||||
3
|
||||
);
|
||||
});
|
||||
|
||||
it("prunes all redundant separators", function () {
|
||||
it('prunes all redundant separators', function() {
|
||||
contextMenu.add({
|
||||
".grandchild": [
|
||||
{type: "separator"},
|
||||
{type: "separator"},
|
||||
{label: "A", command: "a"},
|
||||
{type: "separator"},
|
||||
{type: "separator"},
|
||||
{label: "B", command: "b"},
|
||||
{label: "C", command: "c"},
|
||||
{type: "separator"},
|
||||
{type: "separator"},
|
||||
],
|
||||
})
|
||||
'.grandchild': [
|
||||
{ type: 'separator' },
|
||||
{ type: 'separator' },
|
||||
{ label: 'A', command: 'a' },
|
||||
{ type: 'separator' },
|
||||
{ type: 'separator' },
|
||||
{ label: 'B', command: 'b' },
|
||||
{ label: 'C', command: 'c' },
|
||||
{ type: 'separator' },
|
||||
{ type: 'separator' }
|
||||
]
|
||||
});
|
||||
|
||||
expect(contextMenu.templateForEvent({target: grandchild}).length).toBe(4)
|
||||
})
|
||||
expect(contextMenu.templateForEvent({ target: grandchild }).length).toBe(
|
||||
4
|
||||
);
|
||||
});
|
||||
|
||||
it("throws an error when the selector is invalid", function () {
|
||||
let addError = null
|
||||
it('throws an error when the selector is invalid', function() {
|
||||
let addError = null;
|
||||
try {
|
||||
contextMenu.add({"<>": [{label: "A", command: "a"}]})
|
||||
contextMenu.add({ '<>': [{ label: 'A', command: 'a' }] });
|
||||
} catch (error) {
|
||||
addError = error
|
||||
addError = error;
|
||||
}
|
||||
expect(addError.message).toContain("<>")
|
||||
})
|
||||
expect(addError.message).toContain('<>');
|
||||
});
|
||||
|
||||
it("calls `created` hooks for submenu items", function () {
|
||||
it('calls `created` hooks for submenu items', function() {
|
||||
const item = {
|
||||
label: "A",
|
||||
command: "B",
|
||||
label: 'A',
|
||||
command: 'B',
|
||||
submenu: [
|
||||
{
|
||||
label: "C",
|
||||
label: 'C',
|
||||
created(event) {
|
||||
this.label = "D"
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
contextMenu.add({".grandchild": [item]})
|
||||
this.label = 'D';
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
contextMenu.add({ '.grandchild': [item] });
|
||||
|
||||
const dispatchedEvent = {target: grandchild}
|
||||
const dispatchedEvent = { target: grandchild };
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([
|
||||
{
|
||||
label: "A",
|
||||
id: "A",
|
||||
command: "B",
|
||||
label: 'A',
|
||||
id: 'A',
|
||||
command: 'B',
|
||||
submenu: [
|
||||
{
|
||||
label: "D",
|
||||
id: "D",
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
label: 'D',
|
||||
id: 'D'
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("::templateForEvent(target)", function () {
|
||||
let [keymaps, item] = []
|
||||
describe('::templateForEvent(target)', function() {
|
||||
let [keymaps, item] = [];
|
||||
|
||||
beforeEach(function () {
|
||||
keymaps = atom.keymaps.add("source", {
|
||||
".child": {
|
||||
"ctrl-a": "test:my-command",
|
||||
"shift-b": "test:my-other-command",
|
||||
},
|
||||
})
|
||||
beforeEach(function() {
|
||||
keymaps = atom.keymaps.add('source', {
|
||||
'.child': {
|
||||
'ctrl-a': 'test:my-command',
|
||||
'shift-b': 'test:my-other-command'
|
||||
}
|
||||
});
|
||||
item = {
|
||||
label: "My Command",
|
||||
command: "test:my-command",
|
||||
label: 'My Command',
|
||||
command: 'test:my-command',
|
||||
submenu: [
|
||||
{
|
||||
label: "My Other Command",
|
||||
command: "test:my-other-command",
|
||||
},
|
||||
],
|
||||
}
|
||||
contextMenu.add({".parent": [item]})
|
||||
})
|
||||
label: 'My Other Command',
|
||||
command: 'test:my-other-command'
|
||||
}
|
||||
]
|
||||
};
|
||||
contextMenu.add({ '.parent': [item] });
|
||||
});
|
||||
|
||||
afterEach(() => keymaps.dispose())
|
||||
afterEach(() => keymaps.dispose());
|
||||
|
||||
it("adds Electron-style accelerators to items that have keybindings", function () {
|
||||
child.focus()
|
||||
const dispatchedEvent = {target: child}
|
||||
it('adds Electron-style accelerators to items that have keybindings', function() {
|
||||
child.focus();
|
||||
const dispatchedEvent = { target: child };
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([
|
||||
{
|
||||
label: "My Command",
|
||||
id: "My Command",
|
||||
command: "test:my-command",
|
||||
accelerator: "Ctrl+A",
|
||||
label: 'My Command',
|
||||
id: 'My Command',
|
||||
command: 'test:my-command',
|
||||
accelerator: 'Ctrl+A',
|
||||
submenu: [
|
||||
{
|
||||
label: "My Other Command",
|
||||
id: "My Other Command",
|
||||
command: "test:my-other-command",
|
||||
accelerator: "Shift+B",
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
})
|
||||
label: 'My Other Command',
|
||||
id: 'My Other Command',
|
||||
command: 'test:my-other-command',
|
||||
accelerator: 'Shift+B'
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it("adds accelerators when a parent node has key bindings for a given command", function () {
|
||||
grandchild.focus()
|
||||
const dispatchedEvent = {target: grandchild}
|
||||
it('adds accelerators when a parent node has key bindings for a given command', function() {
|
||||
grandchild.focus();
|
||||
const dispatchedEvent = { target: grandchild };
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([
|
||||
{
|
||||
label: "My Command",
|
||||
id: "My Command",
|
||||
command: "test:my-command",
|
||||
accelerator: "Ctrl+A",
|
||||
label: 'My Command',
|
||||
id: 'My Command',
|
||||
command: 'test:my-command',
|
||||
accelerator: 'Ctrl+A',
|
||||
submenu: [
|
||||
{
|
||||
label: "My Other Command",
|
||||
id: "My Other Command",
|
||||
command: "test:my-other-command",
|
||||
accelerator: "Shift+B",
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
})
|
||||
label: 'My Other Command',
|
||||
id: 'My Other Command',
|
||||
command: 'test:my-other-command',
|
||||
accelerator: 'Shift+B'
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not add accelerators when a child node has key bindings for a given command", function () {
|
||||
parent.focus()
|
||||
const dispatchedEvent = {target: parent}
|
||||
it('does not add accelerators when a child node has key bindings for a given command', function() {
|
||||
parent.focus();
|
||||
const dispatchedEvent = { target: parent };
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([
|
||||
{
|
||||
label: "My Command",
|
||||
id: "My Command",
|
||||
command: "test:my-command",
|
||||
label: 'My Command',
|
||||
id: 'My Command',
|
||||
command: 'test:my-command',
|
||||
submenu: [
|
||||
{
|
||||
label: "My Other Command",
|
||||
id: "My Other Command",
|
||||
command: "test:my-other-command",
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
})
|
||||
label: 'My Other Command',
|
||||
id: 'My Other Command',
|
||||
command: 'test:my-other-command'
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it("adds accelerators based on focus, not context menu target", function () {
|
||||
grandchild.focus()
|
||||
const dispatchedEvent = {target: parent}
|
||||
it('adds accelerators based on focus, not context menu target', function() {
|
||||
grandchild.focus();
|
||||
const dispatchedEvent = { target: parent };
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([
|
||||
{
|
||||
label: "My Command",
|
||||
id: "My Command",
|
||||
command: "test:my-command",
|
||||
accelerator: "Ctrl+A",
|
||||
label: 'My Command',
|
||||
id: 'My Command',
|
||||
command: 'test:my-command',
|
||||
accelerator: 'Ctrl+A',
|
||||
submenu: [
|
||||
{
|
||||
label: "My Other Command",
|
||||
id: "My Other Command",
|
||||
command: "test:my-other-command",
|
||||
accelerator: "Shift+B",
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
})
|
||||
label: 'My Other Command',
|
||||
id: 'My Other Command',
|
||||
command: 'test:my-other-command',
|
||||
accelerator: 'Shift+B'
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not add accelerators for multi-keystroke key bindings", function () {
|
||||
atom.keymaps.add("source", {
|
||||
".child": {
|
||||
"ctrl-a ctrl-b": "test:multi-keystroke-command",
|
||||
},
|
||||
})
|
||||
contextMenu.clear()
|
||||
it('does not add accelerators for multi-keystroke key bindings', function() {
|
||||
atom.keymaps.add('source', {
|
||||
'.child': {
|
||||
'ctrl-a ctrl-b': 'test:multi-keystroke-command'
|
||||
}
|
||||
});
|
||||
contextMenu.clear();
|
||||
contextMenu.add({
|
||||
".parent": [
|
||||
'.parent': [
|
||||
{
|
||||
label: "Multi-keystroke command",
|
||||
command: "test:multi-keystroke-command",
|
||||
},
|
||||
],
|
||||
})
|
||||
label: 'Multi-keystroke command',
|
||||
command: 'test:multi-keystroke-command'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
child.focus()
|
||||
child.focus();
|
||||
|
||||
const label = process.platform === "darwin" ? "⌃A ⌃B" : "Ctrl+A Ctrl+B"
|
||||
expect(contextMenu.templateForEvent({target: child})).toEqual([
|
||||
const label = process.platform === 'darwin' ? '⌃A ⌃B' : 'Ctrl+A Ctrl+B';
|
||||
expect(contextMenu.templateForEvent({ target: child })).toEqual([
|
||||
{
|
||||
label: `Multi-keystroke command [${label}]`,
|
||||
id: `Multi-keystroke command`,
|
||||
command: "test:multi-keystroke-command",
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
command: 'test:multi-keystroke-command'
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("::templateForEvent(target) (sorting)", function () {
|
||||
it("applies simple sorting rules", function () {
|
||||
describe('::templateForEvent(target) (sorting)', function() {
|
||||
it('applies simple sorting rules', function() {
|
||||
contextMenu.add({
|
||||
".parent": [
|
||||
'.parent': [
|
||||
{
|
||||
label: "My Command",
|
||||
command: "test:my-command",
|
||||
after: ["test:my-other-command"],
|
||||
label: 'My Command',
|
||||
command: 'test:my-command',
|
||||
after: ['test:my-other-command']
|
||||
},
|
||||
{
|
||||
label: "My Other Command",
|
||||
command: "test:my-other-command",
|
||||
},
|
||||
],
|
||||
})
|
||||
const dispatchedEvent = {target: parent}
|
||||
label: 'My Other Command',
|
||||
command: 'test:my-other-command'
|
||||
}
|
||||
]
|
||||
});
|
||||
const dispatchedEvent = { target: parent };
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([
|
||||
{
|
||||
label: "My Other Command",
|
||||
id: "My Other Command",
|
||||
command: "test:my-other-command",
|
||||
label: 'My Other Command',
|
||||
id: 'My Other Command',
|
||||
command: 'test:my-other-command'
|
||||
},
|
||||
{
|
||||
label: "My Command",
|
||||
id: "My Command",
|
||||
command: "test:my-command",
|
||||
after: ["test:my-other-command"],
|
||||
},
|
||||
])
|
||||
})
|
||||
label: 'My Command',
|
||||
id: 'My Command',
|
||||
command: 'test:my-command',
|
||||
after: ['test:my-other-command']
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it("applies sorting rules recursively to submenus", function () {
|
||||
it('applies sorting rules recursively to submenus', function() {
|
||||
contextMenu.add({
|
||||
".parent": [
|
||||
'.parent': [
|
||||
{
|
||||
label: "Parent",
|
||||
label: 'Parent',
|
||||
submenu: [
|
||||
{
|
||||
label: "My Command",
|
||||
command: "test:my-command",
|
||||
after: ["test:my-other-command"],
|
||||
label: 'My Command',
|
||||
command: 'test:my-command',
|
||||
after: ['test:my-other-command']
|
||||
},
|
||||
{
|
||||
label: "My Other Command",
|
||||
command: "test:my-other-command",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
const dispatchedEvent = {target: parent}
|
||||
label: 'My Other Command',
|
||||
command: 'test:my-other-command'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
const dispatchedEvent = { target: parent };
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([
|
||||
{
|
||||
label: "Parent",
|
||||
label: 'Parent',
|
||||
id: `Parent`,
|
||||
submenu: [
|
||||
{
|
||||
label: "My Other Command",
|
||||
id: "My Other Command",
|
||||
command: "test:my-other-command",
|
||||
label: 'My Other Command',
|
||||
id: 'My Other Command',
|
||||
command: 'test:my-other-command'
|
||||
},
|
||||
{
|
||||
label: "My Command",
|
||||
id: "My Command",
|
||||
command: "test:my-command",
|
||||
after: ["test:my-other-command"],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
label: 'My Command',
|
||||
id: 'My Command',
|
||||
command: 'test:my-command',
|
||||
after: ['test:my-other-command']
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,171 +1,206 @@
|
||||
const path = require("path")
|
||||
const MenuManager = require("../src/menu-manager")
|
||||
const path = require('path');
|
||||
const MenuManager = require('../src/menu-manager');
|
||||
|
||||
describe("MenuManager", function () {
|
||||
let menu = null
|
||||
describe('MenuManager', function() {
|
||||
let menu = null;
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(function() {
|
||||
menu = new MenuManager({
|
||||
keymapManager: atom.keymaps,
|
||||
packageManager: atom.packages,
|
||||
})
|
||||
spyOn(menu, "sendToBrowserProcess") // Do not modify Atom's actual menus
|
||||
menu.initialize({resourcePath: atom.getLoadSettings().resourcePath})
|
||||
})
|
||||
packageManager: atom.packages
|
||||
});
|
||||
spyOn(menu, 'sendToBrowserProcess'); // Do not modify Atom's actual menus
|
||||
menu.initialize({ resourcePath: atom.getLoadSettings().resourcePath });
|
||||
});
|
||||
|
||||
describe("::add(items)", function () {
|
||||
it("can add new menus that can be removed with the returned disposable", function () {
|
||||
const disposable = menu.add([{label: "A", submenu: [{label: "B", command: "b"}]}])
|
||||
expect(menu.template).toEqual([{label: "A", id: "A", submenu: [{label: "B", id: "B", command: "b"}]}])
|
||||
disposable.dispose()
|
||||
expect(menu.template).toEqual([])
|
||||
})
|
||||
describe('::add(items)', function() {
|
||||
it('can add new menus that can be removed with the returned disposable', function() {
|
||||
const disposable = menu.add([
|
||||
{ label: 'A', submenu: [{ label: 'B', command: 'b' }] }
|
||||
]);
|
||||
expect(menu.template).toEqual([
|
||||
{
|
||||
label: 'A',
|
||||
id: 'A',
|
||||
submenu: [{ label: 'B', id: 'B', command: 'b' }]
|
||||
}
|
||||
]);
|
||||
disposable.dispose();
|
||||
expect(menu.template).toEqual([]);
|
||||
});
|
||||
|
||||
it("can add submenu items to existing menus that can be removed with the returned disposable", function () {
|
||||
const disposable1 = menu.add([{label: "A", submenu: [{label: "B", command: "b"}]}])
|
||||
it('can add submenu items to existing menus that can be removed with the returned disposable', function() {
|
||||
const disposable1 = menu.add([
|
||||
{ label: 'A', submenu: [{ label: 'B', command: 'b' }] }
|
||||
]);
|
||||
const disposable2 = menu.add([
|
||||
{
|
||||
label: "A",
|
||||
submenu: [{label: "C", submenu: [{label: "D", command: "d"}]}],
|
||||
},
|
||||
])
|
||||
label: 'A',
|
||||
submenu: [{ label: 'C', submenu: [{ label: 'D', command: 'd' }] }]
|
||||
}
|
||||
]);
|
||||
const disposable3 = menu.add([
|
||||
{
|
||||
label: "A",
|
||||
submenu: [{label: "C", submenu: [{label: "E", command: "e"}]}],
|
||||
},
|
||||
])
|
||||
label: 'A',
|
||||
submenu: [{ label: 'C', submenu: [{ label: 'E', command: 'e' }] }]
|
||||
}
|
||||
]);
|
||||
|
||||
expect(menu.template).toEqual([
|
||||
{
|
||||
label: "A",
|
||||
id: "A",
|
||||
label: 'A',
|
||||
id: 'A',
|
||||
submenu: [
|
||||
{label: "B", id: "B", command: "b"},
|
||||
{ label: 'B', id: 'B', command: 'b' },
|
||||
{
|
||||
label: "C",
|
||||
id: "C",
|
||||
label: 'C',
|
||||
id: 'C',
|
||||
submenu: [
|
||||
{label: "D", id: "D", command: "d"},
|
||||
{label: "E", id: "E", command: "e"},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
{ label: 'D', id: 'D', command: 'd' },
|
||||
{ label: 'E', id: 'E', command: 'e' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
disposable3.dispose()
|
||||
disposable3.dispose();
|
||||
expect(menu.template).toEqual([
|
||||
{
|
||||
label: "A",
|
||||
id: "A",
|
||||
label: 'A',
|
||||
id: 'A',
|
||||
submenu: [
|
||||
{label: "B", id: "B", command: "b"},
|
||||
{label: "C", id: "C", submenu: [{label: "D", id: "D", command: "d"}]},
|
||||
],
|
||||
},
|
||||
])
|
||||
{ label: 'B', id: 'B', command: 'b' },
|
||||
{
|
||||
label: 'C',
|
||||
id: 'C',
|
||||
submenu: [{ label: 'D', id: 'D', command: 'd' }]
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
disposable2.dispose()
|
||||
expect(menu.template).toEqual([{label: "A", id: "A", submenu: [{label: "B", id: "B", command: "b"}]}])
|
||||
disposable2.dispose();
|
||||
expect(menu.template).toEqual([
|
||||
{
|
||||
label: 'A',
|
||||
id: 'A',
|
||||
submenu: [{ label: 'B', id: 'B', command: 'b' }]
|
||||
}
|
||||
]);
|
||||
|
||||
disposable1.dispose()
|
||||
expect(menu.template).toEqual([])
|
||||
})
|
||||
disposable1.dispose();
|
||||
expect(menu.template).toEqual([]);
|
||||
});
|
||||
|
||||
it("does not add duplicate labels to the same menu", function () {
|
||||
const originalItemCount = menu.template.length
|
||||
menu.add([{label: "A", submenu: [{label: "B", command: "b"}]}])
|
||||
menu.add([{label: "A", submenu: [{label: "B", command: "b"}]}])
|
||||
it('does not add duplicate labels to the same menu', function() {
|
||||
const originalItemCount = menu.template.length;
|
||||
menu.add([{ label: 'A', submenu: [{ label: 'B', command: 'b' }] }]);
|
||||
menu.add([{ label: 'A', submenu: [{ label: 'B', command: 'b' }] }]);
|
||||
expect(menu.template[originalItemCount]).toEqual({
|
||||
label: "A",
|
||||
id: "A",
|
||||
submenu: [{label: "B", id: "B", command: "b"}],
|
||||
})
|
||||
})
|
||||
})
|
||||
label: 'A',
|
||||
id: 'A',
|
||||
submenu: [{ label: 'B', id: 'B', command: 'b' }]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("::update()", function () {
|
||||
const originalPlatform = process.platform
|
||||
afterEach(() => Object.defineProperty(process, "platform", {value: originalPlatform}))
|
||||
describe('::update()', function() {
|
||||
const originalPlatform = process.platform;
|
||||
afterEach(() =>
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform })
|
||||
);
|
||||
|
||||
it("sends the current menu template and associated key bindings to the browser process", function () {
|
||||
menu.add([{label: "A", submenu: [{label: "B", command: "b"}]}])
|
||||
atom.keymaps.add("test", {"atom-workspace": {"ctrl-b": "b"}})
|
||||
menu.update()
|
||||
advanceClock(1)
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]["b"]).toEqual(["ctrl-b"])
|
||||
})
|
||||
it('sends the current menu template and associated key bindings to the browser process', function() {
|
||||
menu.add([{ label: 'A', submenu: [{ label: 'B', command: 'b' }] }]);
|
||||
atom.keymaps.add('test', { 'atom-workspace': { 'ctrl-b': 'b' } });
|
||||
menu.update();
|
||||
advanceClock(1);
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]['b']).toEqual([
|
||||
'ctrl-b'
|
||||
]);
|
||||
});
|
||||
|
||||
it("omits key bindings that are mapped to unset! in any context", function () {
|
||||
it('omits key bindings that are mapped to unset! in any context', function() {
|
||||
// it would be nice to be smarter about omitting, but that would require a much
|
||||
// more dynamic interaction between the currently focused element and the menu
|
||||
menu.add([{label: "A", submenu: [{label: "B", command: "b"}]}])
|
||||
atom.keymaps.add("test", {"atom-workspace": {"ctrl-b": "b"}})
|
||||
atom.keymaps.add("test", {"atom-text-editor": {"ctrl-b": "unset!"}})
|
||||
advanceClock(1)
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]["b"]).toBeUndefined()
|
||||
})
|
||||
menu.add([{ label: 'A', submenu: [{ label: 'B', command: 'b' }] }]);
|
||||
atom.keymaps.add('test', { 'atom-workspace': { 'ctrl-b': 'b' } });
|
||||
atom.keymaps.add('test', { 'atom-text-editor': { 'ctrl-b': 'unset!' } });
|
||||
advanceClock(1);
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]['b']).toBeUndefined();
|
||||
});
|
||||
|
||||
it("omits key bindings that could conflict with AltGraph characters on macOS", function () {
|
||||
Object.defineProperty(process, "platform", {value: "darwin"})
|
||||
it('omits key bindings that could conflict with AltGraph characters on macOS', function() {
|
||||
Object.defineProperty(process, 'platform', { value: 'darwin' });
|
||||
menu.add([
|
||||
{
|
||||
label: "A",
|
||||
label: 'A',
|
||||
submenu: [
|
||||
{label: "B", command: "b"},
|
||||
{label: "C", command: "c"},
|
||||
{label: "D", command: "d"},
|
||||
],
|
||||
},
|
||||
])
|
||||
{ label: 'B', command: 'b' },
|
||||
{ label: 'C', command: 'c' },
|
||||
{ label: 'D', command: 'd' }
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
atom.keymaps.add("test", {
|
||||
"atom-workspace": {
|
||||
"alt-b": "b",
|
||||
"alt-shift-C": "c",
|
||||
"alt-cmd-d": "d",
|
||||
},
|
||||
})
|
||||
atom.keymaps.add('test', {
|
||||
'atom-workspace': {
|
||||
'alt-b': 'b',
|
||||
'alt-shift-C': 'c',
|
||||
'alt-cmd-d': 'd'
|
||||
}
|
||||
});
|
||||
|
||||
advanceClock(1)
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]["b"]).toBeUndefined()
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]["c"]).toBeUndefined()
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]["d"]).toEqual(["alt-cmd-d"])
|
||||
})
|
||||
advanceClock(1);
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]['b']).toBeUndefined();
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]['c']).toBeUndefined();
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]['d']).toEqual([
|
||||
'alt-cmd-d'
|
||||
]);
|
||||
});
|
||||
|
||||
it("omits key bindings that could conflict with AltGraph characters on Windows", function () {
|
||||
Object.defineProperty(process, "platform", {value: "win32"})
|
||||
it('omits key bindings that could conflict with AltGraph characters on Windows', function() {
|
||||
Object.defineProperty(process, 'platform', { value: 'win32' });
|
||||
menu.add([
|
||||
{
|
||||
label: "A",
|
||||
label: 'A',
|
||||
submenu: [
|
||||
{label: "B", command: "b"},
|
||||
{label: "C", command: "c"},
|
||||
{label: "D", command: "d"},
|
||||
],
|
||||
},
|
||||
])
|
||||
{ label: 'B', command: 'b' },
|
||||
{ label: 'C', command: 'c' },
|
||||
{ label: 'D', command: 'd' }
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
atom.keymaps.add("test", {
|
||||
"atom-workspace": {
|
||||
"ctrl-alt-b": "b",
|
||||
"ctrl-alt-shift-C": "c",
|
||||
"ctrl-alt-cmd-d": "d",
|
||||
},
|
||||
})
|
||||
atom.keymaps.add('test', {
|
||||
'atom-workspace': {
|
||||
'ctrl-alt-b': 'b',
|
||||
'ctrl-alt-shift-C': 'c',
|
||||
'ctrl-alt-cmd-d': 'd'
|
||||
}
|
||||
});
|
||||
|
||||
advanceClock(1)
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]["b"]).toBeUndefined()
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]["c"]).toBeUndefined()
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]["d"]).toEqual(["ctrl-alt-cmd-d"])
|
||||
})
|
||||
})
|
||||
advanceClock(1);
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]['b']).toBeUndefined();
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]['c']).toBeUndefined();
|
||||
expect(menu.sendToBrowserProcess.argsForCall[0][1]['d']).toEqual([
|
||||
'ctrl-alt-cmd-d'
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it("updates the application menu when a keymap is reloaded", function () {
|
||||
spyOn(menu, "update")
|
||||
const keymapPath = path.join(__dirname, "fixtures", "packages", "package-with-keymaps", "keymaps", "keymap-1.cson")
|
||||
atom.keymaps.reloadKeymap(keymapPath)
|
||||
expect(menu.update).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
it('updates the application menu when a keymap is reloaded', function() {
|
||||
spyOn(menu, 'update');
|
||||
const keymapPath = path.join(
|
||||
__dirname,
|
||||
'fixtures',
|
||||
'packages',
|
||||
'package-with-keymaps',
|
||||
'keymaps',
|
||||
'keymap-1.cson'
|
||||
);
|
||||
atom.keymaps.reloadKeymap(keymapPath);
|
||||
expect(menu.update).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user