Skip to content

Commit

Permalink
ADDED: new menu/combo for to toggle split view
Browse files Browse the repository at this point in the history
ADDED: new menu.accelerators.spec file
FIXED: Fs.generic API.join would cause a stack overflow
  • Loading branch information
warpdesign committed Nov 2, 2019
1 parent 14fae5b commit 3d6bce1
Show file tree
Hide file tree
Showing 12 changed files with 320 additions and 45 deletions.
16 changes: 2 additions & 14 deletions e2e/cypress/integration/keyboard.hotkeys.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ describe("keyboard hotkeys", () => {
function createStubs() {
stubs.navHistory = [];

cy.window().then(win => {
cy.log('hello');
return cy.window().then(win => {
const views = win.appState.winStates[0].views;
for (let view of views) {
for (let cache of view.caches) {
Expand Down Expand Up @@ -76,19 +77,6 @@ describe("keyboard hotkeys", () => {
expect(stubs.navHistory[0]).to.be.calledWith(-1);
});
});

it("should not change view in single view mode", () => {
cy.get("#view_0").should("have.class", "active");
cy.get("#view_1").should("not.have.class", "active");

cy.get('.data-cy-toggle-splitview')
.click();

cy.triggerHotkey(`{ctrl}{shift}{rightarrow}`).then(() => {
cy.get("#view_1").should("not.have.class", "active");
cy.get("#view_0").should("have.class", "active");
});
});
// it("should open devtools", () => {
// cy.triggerHotkey(`{alt}${MOD_KEY}i`).then(() => {
// expect(ipcRenderer.send).to.be.calledOnce;
Expand Down
255 changes: 255 additions & 0 deletions e2e/cypress/integration/menu.accelerators.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
/// <reference types="cypress"/>

import { Classes } from "@blueprintjs/core";

/**
* NOTE: Combos are events that are supposed to be sent from the main process
* after a menu (or its associated shortcut) has been selected.
*
* Since we are running inside the browser (Electron testing support is coming soon,
* see: https://www.cypress.io/blog/2019/09/26/testing-electron-js-applications-using-cypress-alpha-release/),
* we are sending fake combo events to simulate the user selecting a menu item or pressing the associated
* accelerator combo.
*/
describe("combo hotkeys", () => {
const stubs: any = {
navHistory: []
};

let caches:any;

function resetSelection() {
cy.window().then(win => {
win.appState.winStates[0].views.forEach((view: any) => {
caches =
view.caches.forEach((cache: any) => {
cache.reset();
});
});
});
}

function createStubs() {
stubs.navHistory = [];

cy.window().then(win => {
const views = win.appState.winStates[0].views;
for (let view of views) {
for (let cache of view.caches) {
stubs.navHistory.push(cy.spy(cache, "navHistory"));
}
}

// activate splitView mode
const winState = win.appState.winStates[0];
winState.splitView = true;

// stub copy/paste functions
cy.stub(win.appState, 'copySelectedItemsPath').as('copySelectedItemsPath');
// stub reload view
cy.stub(win.appState, 'refreshActiveView').as('refreshActiveView');
// stub first cache.openTerminal
cy.stub(win.appState.winStates[0].views[0].caches[0], 'openTerminal').as('openTerminal');
// stub first view.cycleTab
cy.stub(win.appState.winStates[0].views[0], 'cycleTab').as('cycleTab');
// stub first view.addCache
cy.stub(win.appState.winStates[0].views[0], 'addCache').as('addCache');
// stub first view.closeTab
cy.stub(win.appState.winStates[0].views[0], 'closeTab').as('closeTab');
// stub first win.toggleSplitView
cy.spy(win.appState.winStates[0], 'toggleSplitViewMode').as('toggleSplitViewMode');
});
}

function getCaches() {
cy.window().then(win => {
caches = win.appState.winStates[0].views[0].caches;
});
}

before(() => {
return cy.visit("http://127.0.0.1:8080");
});

beforeEach(() => {
createStubs();
resetSelection();
getCaches();
// load files
cy.CDAndList(0, "/");
cy.get("#view_0 [data-cy-path]")
.invoke("val", "/")
.focus()
.blur();
});

it("should not show toast message on copy path if no file selected", () => {
// no selection: triggering fake combo should not show toast message
cy.triggerFakeCombo("CmdOrCtrl+Shift+C");

cy.get(`.${Classes.TOAST}`)
.should('not.be.visible');

cy.get('@copySelectedItemsPath')
.should('be.calledWith', caches[0], false);
});

it("should copy file path to cb & show toast message if a file is selected", () => {
// select first element
cy.get("#view_0 [data-cy-file]:first")
.click();

cy.triggerFakeCombo("CmdOrCtrl+Shift+C");

cy.get('@copySelectedItemsPath')
.should('be.calledWith', caches[0], false);

cy.get(`.${Classes.TOAST}`)
.should('be.visible')
.find('button')
.click();
});

it("should not show toast message on copy filename if no file selected", () => {
// no selection: triggering fake combo should not show toast message
cy.triggerFakeCombo("CmdOrCtrl+Shift+N");

cy.get(`.${Classes.TOAST}`)
.should('not.be.visible');

cy.get('@copySelectedItemsPath')
.should('be.calledWith', caches[0], true);
});

it("should copy file filename & show toast message if a file is selected", () => {
// select first element
cy.get("#view_0 [data-cy-file]:first")
.click();

cy.triggerFakeCombo("CmdOrCtrl+Shift+N");

cy.get('@copySelectedItemsPath')
.should('be.calledWith', caches[0], true);

cy.get(`.${Classes.TOAST}`)
.should('be.visible')
.find('button')
.click();
});

it("should open shortcuts dialog", () => {
cy.triggerFakeCombo("CmdOrCtrl+S");

cy.get('.shortcutsDialog')
.should('be.visible');

// close dialog
cy.get(`.${Classes.DIALOG_FOOTER} .data-cy-close`)
.click();

// wait for dialog to be closed otherwise
// it could still be visible in next it()
cy.get('.shortcutsDialog')
.should('not.be.visible');
});

it("should open prefs dialog", () => {
cy.triggerFakeCombo("CmdOrCtrl+,");

cy.get('.data-cy-prefs-dialog')
.should('be.visible');

// close dialog
cy.get(`.${Classes.DIALOG_FOOTER} .data-cy-close`)
.click();

// wait for dialog to be closed otherwise
// it could still be visible in next it()
cy.get('.shortcutsDialog')
.should('not.be.visible');
});

it("should reload file view", () => {
cy.triggerFakeCombo("CmdOrCtrl+R");

cy.get('@refreshActiveView')
.should('be.calledOnce');
});

it("should open terminal", () => {
cy.triggerFakeCombo("CmdOrCtrl+K");

cy.get('@openTerminal')
.should('be.calledOnce');
});

it("should activate next tab", () => {
cy.triggerFakeCombo("Ctrl+Tab");

cy.get('@cycleTab')
.should('be.calledOnce')
.should('be.calledWith', 1);
});

it("should activate previous tab", () => {
cy.triggerFakeCombo("Ctrl+Shift+Tab");

cy.get('@cycleTab')
.should('be.calledOnce')
.should('be.calledWith', -1);
});

it("should open a new tab", () => {
cy.triggerFakeCombo("CmdOrCtrl+T");

cy.get('@addCache')
.should('be.calledOnce');
});

it("should close tab", () => {
cy.triggerFakeCombo("CmdOrCtrl+W");

cy.get('@closeTab')
.should('be.calledOnce');
});

it("should toggle split view", () => {
// initial state: split view active
cy.get("#view_1")
.should("not.have.class", "active")
.and('be.visible');

cy.get("#view_0")
.should("have.class", "active")
.and('be.visible');

// de-activate split view
cy.triggerFakeCombo("CmdOrCtrl+Shift+Alt+V");

// check status: we should have only one call
cy.get('@toggleSplitViewMode')
.should('be.calledOnce');

cy.get("#view_0")
.should('be.visible')
.and('have.class', 'active');

cy.get("#view_1")
.should('not.be.visible');

// re-activate split view
cy.triggerFakeCombo("CmdOrCtrl+Shift+Alt+V");

// check status: should have two calls now
cy.get('@toggleSplitViewMode')
.should('be.calledTwice');

cy.get("#view_0")
.should('be.visible')
.and('not.have.class', 'active');

cy.get("#view_1")
.should('be.visible')
.and('have.class', 'active');
});
});
34 changes: 29 additions & 5 deletions e2e/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,32 @@ declare global {
namespace Cypress {
interface Chainable {
/**
* Yields "foo"
* Yields "json object"
*
* @returns {typeof foo}
* @returns {typeof object}
* @memberof Chainable
* @example
* cy.foo().then(f = ...) // f is "foo"
* cy.CDAndList('/').then(json => ...)
*/
CDAndList: typeof CDList;
/**
* Yields document.body
*
* @returns {typeof Body}
* @memberof Chainable
* @example
* cy.triggerHotkey('{meta}f').then(body => ...)
*/
triggerHotkey: typeof triggerHotkey;
/**
* Yields document
*
* @returns {typeof Document}
* @memberof Chainable
* @example
* cy.triggerFakeCombo('CmdOrCtrl+Shift+C').then(doc => ...)
*/
triggerFakeCombo: typeof triggerFakeCombo
}
}
}
Expand All @@ -29,9 +46,16 @@ export function CDList(viewId = 0, path: string, fixture = "files.json") {
});
}

export function triggerHotkey(hotkey: string) {
return cy.get("body").type(hotkey);
export function triggerHotkey(hotkey: string, options = {}) {
return cy.get("body").type(hotkey, options);
}

export function triggerFakeCombo(combo: string, data = { title: "hey!"}) {
cy.log('triggering', { combo, data });
return cy.document()
.trigger('menu_accelerator', { combo, data } );
}

Cypress.Commands.add("CDAndList", CDList);
Cypress.Commands.add("triggerHotkey", triggerHotkey);
Cypress.Commands.add("triggerFakeCombo", triggerFakeCombo);
4 changes: 2 additions & 2 deletions e2e/webpack.config.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ const baseConfig = {
},
externals: {
os: `{release: function() { return "${release}"}, tmpdir: function() { return "/tmpdir" }, homedir: function() { return "/homedir" }}`,
process: `{process: "foo", platform: "${platform}"}`,
process: `{process: "React-Explorer", platform: "${platform}"}`,
electron:
'{ipcRenderer: {send: function() {}, on: function() {}}, remote: { getCurrentWindow: () => {}, Menu: { buildFromTemplate: function() { return { popup: function() {}, closePopup: function() { } };}},app: { getLocale: function() { return "en"; }, getPath: function(str) { return "cy_" + str; } } } }',
'{ipcRenderer: {send: function() {}, on: function(event, method) { document.addEventListener(event, function(e) { method(e, {data: e.data, combo: e.combo}); })}}, remote: { getCurrentWindow: () => {}, Menu: { buildFromTemplate: function() { return { popup: function() {}, closePopup: function() { } };}},app: { getLocale: function() { return "en"; }, getPath: function(str) { return "cy_" + str; } } } }',
child_process: "{exec: function(str, cb) { cb(); }}",
fs: "{}",
path: "{}",
Expand Down
6 changes: 4 additions & 2 deletions src/components/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ class NavComponent extends React.Component<WithNamespaces> {
};

onToggleSplitView = () => {
const winState = this.appState.winStates[0];
winState.toggleSplitViewMode();
if (this.appState.isExplorer) {
const winState = this.appState.winStates[0];
winState.toggleSplitViewMode();
}
};

onOpenPrefs = () => {
Expand Down
1 change: 1 addition & 0 deletions src/components/WithMenuAccelerators.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export function WithMenuAccelerators<
e: MenuAcceleratorEvent,
data: { combo: string; data: any }
) => {
console.log('******* onAccelerator !!', e, data);
// check if combo is valid
const callback = this.getCallback(data.combo);
if (typeof callback === "function") {
Expand Down
5 changes: 3 additions & 2 deletions src/components/dialogs/ShortcutsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class ShortcutsDialogClass extends React.Component<IShortcutsProps>{
{ combo: "mod + s", label: t('SHORTCUT.MAIN.KEYBOARD_SHORTCUTS') },
{ combo: "mod + ,", label: t('SHORTCUT.MAIN.PREFERENCES') },
{ combo: "alt + mod + i", label: t('SHORTCUT.OPEN_DEVTOOLS') },
{ combo: "mod + q", label: t('SHORTCUT.MAIN.QUIT') }
{ combo: "mod + q", label: t('SHORTCUT.MAIN.QUIT') },
{ combo: "mod + alt + shift + v", label: t('NAV.SPLITVIEW') }
],
// group: t('SHORTCUT.GROUP.ACTIVE_VIEW')
[
Expand Down Expand Up @@ -111,7 +112,7 @@ class ShortcutsDialogClass extends React.Component<IShortcutsProps>{
</div>
<div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<Button onClick={this.onClose}>
<Button onClick={this.onClose} className="data-cy-close">
{t('COMMON.CLOSE')}
</Button>
</div>
Expand Down
Loading

0 comments on commit 3d6bce1

Please sign in to comment.