diff --git a/packages/desktop-gui/cypress/integration/global_mode_spec.coffee b/packages/desktop-gui/cypress/integration/global_mode_spec.coffee
index cd8d2e99dae6..fa4f84f53c87 100644
--- a/packages/desktop-gui/cypress/integration/global_mode_spec.coffee
+++ b/packages/desktop-gui/cypress/integration/global_mode_spec.coffee
@@ -133,13 +133,10 @@ describe "Global Mode", ->
describe "going back", ->
beforeEach ->
- cy.contains("Back").click()
-
- it "returns to intro on click of back button", ->
- cy.shouldBeOnIntro()
+ @closeProject = @util.deferred()
+ @ipc.closeProject.returns(@closeProject.promise)
- it "removes project name from title", ->
- cy.title().should("equal", "Cypress")
+ cy.contains("Back").click()
it "removes ipc listeners", ->
expect(@ipc.offOpenProject).to.be.called
@@ -148,3 +145,17 @@ describe "Global Mode", ->
it "closes project", ->
expect(@ipc.closeProject).to.be.called
+
+ it "shows loader", ->
+ cy.get(".loader")
+ cy.contains("Closing project...")
+
+ describe "when finished closing", ->
+ beforeEach ->
+ @closeProject.resolve()
+
+ it "goes to intro", ->
+ cy.shouldBeOnIntro()
+
+ it "removes project name from title", ->
+ cy.title().should("equal", "Cypress")
diff --git a/packages/desktop-gui/cypress/integration/project_nav_spec.coffee b/packages/desktop-gui/cypress/integration/project_nav_spec.coffee
index 2bf803f87bdc..9be75d4e60f8 100644
--- a/packages/desktop-gui/cypress/integration/project_nav_spec.coffee
+++ b/packages/desktop-gui/cypress/integration/project_nav_spec.coffee
@@ -14,8 +14,8 @@ describe "Project Nav", ->
cy.stub(@ipc, "getRuns").resolves(@runs)
cy.stub(@ipc, "getSpecs").yields(null, @specs)
cy.stub(@ipc, "getRecordKeys").resolves([])
- cy.stub(@ipc, "launchBrowser")
cy.stub(@ipc, "closeBrowser").resolves(null)
+ cy.stub(@ipc, "onBrowserClose")
cy.stub(@ipc, "pingApiServer").resolves()
cy.stub(@ipc, "closeProject")
cy.stub(@ipc, "externalOpen")
@@ -26,6 +26,9 @@ describe "Project Nav", ->
@openProject = @util.deferred()
cy.stub(@ipc, "openProject").returns(@openProject.promise)
+ @launchBrowser = @util.deferred()
+ cy.stub(@ipc, "launchBrowser").returns(@launchBrowser.promise)
+
start()
context "project nav", ->
@@ -134,8 +137,8 @@ describe "Project Nav", ->
context "browser opened after choosing spec", ->
beforeEach ->
- @ipc.launchBrowser.yields(null, {browserOpened: true})
cy.contains(".file", "app_spec").click()
+ @launchBrowser.resolve()
it "displays browser icon as opened", ->
cy.get(".browsers-list>a").first().find("i")
@@ -150,25 +153,41 @@ describe "Project Nav", ->
describe "stop browser", ->
beforeEach ->
+ @closeBrowser = @util.deferred()
+ @ipc.closeBrowser.returns(@closeBrowser.promise)
+
cy.get(".close-browser").click()
- it "calls close:browser on click of stop button", ->
+ it "calls ipc close:browser", ->
expect(@ipc.closeBrowser).to.be.called
- it "hides close button on click of stop", ->
+ it "hides close button", ->
cy.get(".close-browser").should("not.exist")
- it "re-enables browser dropdown", ->
- cy.get(".browsers-list>a").first()
- .should("not.have.class", "disabled")
+ it "blocks the UI and shows closing loader while browser is closing", ->
+ cy.get(".ui-blocker")
+ cy.get(".browsers-list").find(".fa-refresh.fa-spin")
+ cy.contains("Closing Chrome 50")
- it "displays default browser icon", ->
- cy.get(".browsers-list>a").first()
- .find(".fa-chrome")
+ describe "when browser is finished closing", ->
+ beforeEach ->
+ @closeBrowser.resolve()
+
+ it "re-enables browser dropdown", ->
+ cy.get(".browsers-list>a").first()
+ .should("not.have.class", "disabled")
+
+ it "displays default browser icon", ->
+ cy.get(".browsers-list>a").first()
+ .find(".fa-chrome")
+
+ it "unblocks the UI", ->
+ cy.get(".ui-blocker").should("not.exist")
describe "browser is closed manually", ->
beforeEach ->
- @ipc.launchBrowser.yield(null, {browserClosed: true})
+ cy.stub(@ipc, "awaitBrowserClose").resolves()
+ @ipc.onBrowserClose.yield()
it "hides close browser button", ->
cy.get(".close-browser").should("not.be.visible")
diff --git a/packages/desktop-gui/cypress/integration/project_spec.coffee b/packages/desktop-gui/cypress/integration/project_spec.coffee
index 7aec8d18f9ba..5fa84a778513 100644
--- a/packages/desktop-gui/cypress/integration/project_spec.coffee
+++ b/packages/desktop-gui/cypress/integration/project_spec.coffee
@@ -45,10 +45,20 @@ describe "Project", ->
it "re-opens project if config changes", ->
cy.shouldBeOnProjectSpecs().then =>
@ipc.onConfigChanged.yield()
- expect(@ipc.closeProject).to.be.called
- expect(@ipc.openProject).to.be.called
+ cy.wrap(@ipc.closeProject).should("be.called")
+ cy.wrap(@ipc.openProject).should("be.called")
cy.shouldBeOnProjectSpecs()
+ describe "opening", ->
+ beforeEach ->
+ @openProject = @util.deferred()
+ @ipc.openProject.returns(@openProject.promise)
+ @start()
+
+ it "shows loader", ->
+ cy.get(".loader")
+ cy.contains("Opening project...")
+
describe "warnings", ->
beforeEach ->
@start()
diff --git a/packages/desktop-gui/cypress/integration/projects_list_spec.coffee b/packages/desktop-gui/cypress/integration/projects_list_spec.coffee
index 66831ef0554c..4168209a6dbb 100644
--- a/packages/desktop-gui/cypress/integration/projects_list_spec.coffee
+++ b/packages/desktop-gui/cypress/integration/projects_list_spec.coffee
@@ -41,7 +41,9 @@ describe "Projects List", ->
@start()
it "loads projects and shows loader", ->
- cy.get(".projects-list .loader").then =>
+ cy.get(".projects-list .loader")
+ .should("have.text", "Loading projects...")
+ .then =>
expect(@ipc.getProjects).to.be.called
describe "when loaded", ->
diff --git a/packages/desktop-gui/cypress/integration/runs_list_spec.coffee b/packages/desktop-gui/cypress/integration/runs_list_spec.coffee
index f586bbcc12ca..45814fd506cd 100644
--- a/packages/desktop-gui/cypress/integration/runs_list_spec.coffee
+++ b/packages/desktop-gui/cypress/integration/runs_list_spec.coffee
@@ -72,6 +72,7 @@ describe "Runs List", ->
it "pings api server", ->
expect(@ipc.pingApiServer).to.be.called
cy.get(".loader")
+ cy.contains("Loading runs...")
describe "success", ->
beforeEach ->
@@ -425,6 +426,7 @@ describe "Runs List", ->
it "shows loading spinner", ->
cy.get(".loader")
+ cy.contains("Loading runs...")
it "shows runs when getting runs succeeds", ->
@getRuns.resolve(@runs)
diff --git a/packages/desktop-gui/cypress/integration/settings_spec.coffee b/packages/desktop-gui/cypress/integration/settings_spec.coffee
index b6ceb975a130..020cd8c93863 100644
--- a/packages/desktop-gui/cypress/integration/settings_spec.coffee
+++ b/packages/desktop-gui/cypress/integration/settings_spec.coffee
@@ -197,16 +197,23 @@ describe "Settings", ->
newConfig.browsers = @browsers
@openProject.resolve(newConfig)
- @goToSettings()
- cy.contains("Configuration").click()
+ @goToSettings().then =>
+ @openProject2ndCall = @util.deferred()
+ @ipc.openProject.onCall(1).returns(@openProject2ndCall.promise)
+ @ipc.onConfigChanged.yield()
- it "displays updated config", ->
- newConfig = @util.deepClone(@config)
- newConfig.resolved.baseUrl.value = "http://localhost:7777"
- @ipc.openProject.onCall(1).resolves(newConfig)
- @ipc.onConfigChanged.yield()
+ it "re-opens the project", ->
+ cy.wrap(@ipc.openProject).should("be.calledTwice")
- cy.contains("http://localhost:7777")
+ describe "when project re-opens", ->
+ beforeEach ->
+ newConfig = @util.deepClone(@config)
+ newConfig.resolved.baseUrl.value = "http://localhost:7777"
+ @openProject2ndCall.resolve(newConfig)
+
+ it "displays updated config", ->
+ cy.contains("Configuration").click()
+ cy.contains("http://localhost:7777")
describe "errors", ->
beforeEach ->
diff --git a/packages/desktop-gui/cypress/integration/setup_project_modal_spec.coffee b/packages/desktop-gui/cypress/integration/setup_project_modal_spec.coffee
index 3a1cb4a0cded..15c0657d264d 100644
--- a/packages/desktop-gui/cypress/integration/setup_project_modal_spec.coffee
+++ b/packages/desktop-gui/cypress/integration/setup_project_modal_spec.coffee
@@ -48,6 +48,10 @@ describe "Set Up Project", ->
beforeEach ->
@getCurrentUser.resolve(@user)
+ it "shows loader while orgs load", ->
+ cy.get(".btn").contains("Set up project").click()
+ cy.get(".loader")
+
describe "general behavior", ->
beforeEach ->
@getOrgs.resolve(@orgs)
@@ -343,6 +347,7 @@ describe "Set Up Project", ->
beforeEach ->
cy.stub(@ipc, "windowOpen").resolves()
cy.stub(@ipc, "logIn").resolves(@user)
+ @getOrgs.resolve()
cy.contains("button", "Log In with GitHub").click()
it "shows setup", ->
diff --git a/packages/desktop-gui/cypress/integration/specs_list_spec.coffee b/packages/desktop-gui/cypress/integration/specs_list_spec.coffee
index 450fa6d7e2f3..e40ec624ed17 100644
--- a/packages/desktop-gui/cypress/integration/specs_list_spec.coffee
+++ b/packages/desktop-gui/cypress/integration/specs_list_spec.coffee
@@ -10,9 +10,9 @@ describe "Specs List", ->
cy.stub(@ipc, "getOptions").resolves({projectRoot: "/foo/bar"})
cy.stub(@ipc, "getCurrentUser").resolves(@user)
- cy.stub(@ipc, "getSpecs").yields(null, @specs)
+ cy.stub(@ipc, "getSpecs")
cy.stub(@ipc, "closeBrowser").resolves(null)
- cy.stub(@ipc, "launchBrowser")
+ cy.stub(@ipc, "launchBrowser").resolves()
cy.stub(@ipc, "openFinder")
cy.stub(@ipc, "externalOpen")
cy.stub(@ipc, "onboardingClosed")
@@ -23,6 +23,11 @@ describe "Specs List", ->
start()
+ it "shows loader", ->
+ @openProject.resolve(@config)
+ cy.get(".loader")
+ cy.contains("Loading specs...")
+
describe "no specs", ->
beforeEach ->
@ipc.getSpecs.yields(null, [])
@@ -47,6 +52,7 @@ describe "Specs List", ->
describe "first time onboarding specs", ->
beforeEach ->
+ @ipc.getSpecs.yields(null, @specs)
@config.isNewProject = true
@openProject.resolve(@config)
@@ -123,10 +129,11 @@ describe "Specs List", ->
cy
.contains(".btn", "Run all specs").click()
.then ->
- launchArgs = @ipc.launchBrowser.lastCall.args
+ expect(@ipc.launchBrowser).to.be.called
- expect(launchArgs[0].browser.name).to.eq "chrome"
- expect(launchArgs[0].spec.name).to.eq "All Specs"
+ launchArgs = @ipc.launchBrowser.lastCall.args[0]
+ expect(launchArgs.browser.name).to.eq "chrome"
+ expect(launchArgs.spec.name).to.eq "All Specs"
describe "all specs running in browser", ->
beforeEach ->
@@ -266,16 +273,15 @@ describe "Specs List", ->
@openProject.resolve(@config)
cy.contains(".file a", "app_spec.coffee").as("firstSpec")
- it "closes then launches browser on click of file", ->
+ it "launches browser on click of file", ->
cy.get("@firstSpec")
.click()
.then ->
- expect(@ipc.closeBrowser).to.be.called
+ expect(@ipc.launchBrowser).to.be.called
- launchArgs = @ipc.launchBrowser.lastCall.args
-
- expect(launchArgs[0].browser.name).to.equal("chrome")
- expect(launchArgs[0].spec.relative).to.equal("cypress/integration/app_spec.coffee")
+ launchArgs = @ipc.launchBrowser.lastCall.args[0]
+ expect(launchArgs.browser.name).to.equal("chrome")
+ expect(launchArgs.spec.relative).to.equal("cypress/integration/app_spec.coffee")
it "adds 'active' class on click", ->
cy.get("@firstSpec")
@@ -315,9 +321,9 @@ describe "Specs List", ->
cy.get("@deepSpec").should("have.class", "active")
context "switching specs", ->
-
beforeEach ->
@ipc.getSpecs.yields(null, @specs)
+ @ipc.launchBrowser
@openProject.resolve(@config)
cy
.get(".file").contains("a", "app_spec.coffee").as("firstSpec")
diff --git a/packages/desktop-gui/cypress/integration/update_banner_spec.coffee b/packages/desktop-gui/cypress/integration/update_banner_spec.coffee
index b50e8f4475ea..7c8f337ee223 100644
--- a/packages/desktop-gui/cypress/integration/update_banner_spec.coffee
+++ b/packages/desktop-gui/cypress/integration/update_banner_spec.coffee
@@ -18,6 +18,7 @@ describe "Update Banner", ->
{ @start, @ipc } = win.App
cy.stub(@ipc, "getCurrentUser").resolves(@user)
+ cy.stub(@ipc, "openProject").resolves(@config)
cy.stub(@ipc, "windowOpen")
cy.stub(@ipc, "externalOpen")
@@ -98,7 +99,6 @@ describe "Update Banner", ->
describe "in specs list", ->
beforeEach ->
cy.stub(@ipc, "getOptions").resolves({version: OLD_VERSION, projectRoot: "/foo/bar"})
- cy.stub(@ipc, "openProject").resolves(@config)
cy.stub(@ipc, "getSpecs").yields(null, @specs)
@start()
@updaterCheck.resolve(NEW_VERSION)
diff --git a/packages/desktop-gui/package.json b/packages/desktop-gui/package.json
index a0a0827e9a89..63b8e79e0552 100644
--- a/packages/desktop-gui/package.json
+++ b/packages/desktop-gui/package.json
@@ -49,7 +49,6 @@
"rebuild-node-sass": "1.1.0",
"react-bootstrap-modal": "4.2.0",
"react-dom": "^16.7.0",
- "react-loader": "^2.4.5",
- "zunder": "6.3.0"
+ "zunder": "6.3.2"
}
}
diff --git a/packages/desktop-gui/src/app/app.jsx b/packages/desktop-gui/src/app/app.jsx
index 1e46d6b8ee37..1ac28a95afa3 100644
--- a/packages/desktop-gui/src/app/app.jsx
+++ b/packages/desktop-gui/src/app/app.jsx
@@ -1,7 +1,6 @@
import _ from 'lodash'
import { observer } from 'mobx-react'
import React, { Component } from 'react'
-import Loader from 'react-loader'
import appApi from '../lib/app-api'
import C from '../lib/constants'
@@ -12,6 +11,7 @@ import viewStore from '../lib/view-store'
import Intro from './intro'
import Layout from './layout'
+import Loader from '../lib/loader'
import Project from '../project/project'
@observer
@@ -30,7 +30,7 @@ class App extends Component {
render () {
switch (viewStore.currentView.name) {
case C.LOADING:
- return
+ return
case C.INTRO:
return (
diff --git a/packages/desktop-gui/src/app/layout.jsx b/packages/desktop-gui/src/app/layout.jsx
index 580d618ebf66..92ed220d2d33 100644
--- a/packages/desktop-gui/src/app/layout.jsx
+++ b/packages/desktop-gui/src/app/layout.jsx
@@ -5,6 +5,7 @@ import GlobalError from './global-error'
import Footer from '../footer/footer'
import LoginModal from '../auth/login-modal'
import UpdateBanner from '../update/update-banner'
+import UiBlocker from './ui-blocker'
export default ({ children }) => {
return (
@@ -15,6 +16,7 @@ export default ({ children }) => {
+
)
}
diff --git a/packages/desktop-gui/src/app/nav.jsx b/packages/desktop-gui/src/app/nav.jsx
index cc4804330122..08c8bb33d496 100644
--- a/packages/desktop-gui/src/app/nav.jsx
+++ b/packages/desktop-gui/src/app/nav.jsx
@@ -8,6 +8,7 @@ import viewStore from '../lib/view-store'
import ipc from '../lib/ipc'
import { gravatarUrl } from '../lib/utils'
import { Link, routes } from '../lib/routing'
+import projectsApi from '../projects/projects-api'
import Dropdown from '../dropdown/dropdown'
@@ -51,7 +52,7 @@ export default class Nav extends Component {
// global mode, on project page
if (appStore.isGlobalMode && project) {
return (
-
+
Back
)
@@ -122,12 +123,16 @@ export default class Nav extends Component {
}
- _select = (item) => {
+ _select (item) {
if (item.id === 'logout') {
authApi.logOut()
}
}
+ _unloadProject () {
+ return projectsApi.closeProject(viewStore.currentView.project)
+ }
+
_showLogin () {
authStore.setShowingLogin(true)
}
diff --git a/packages/desktop-gui/src/app/ui-blocker.jsx b/packages/desktop-gui/src/app/ui-blocker.jsx
new file mode 100644
index 000000000000..33bdc2d35ab0
--- /dev/null
+++ b/packages/desktop-gui/src/app/ui-blocker.jsx
@@ -0,0 +1,16 @@
+import React from 'react'
+import { createPortal } from 'react-dom'
+import { observer } from 'mobx-react'
+
+import appStore from '../lib/app-store'
+
+const UiBlocker = observer(() => {
+ if (!appStore.isUiBlocked) return null
+
+ return createPortal(
+ ,
+ document.getElementById('ui-blocker')
+ )
+})
+
+export default UiBlocker
diff --git a/packages/desktop-gui/src/app/ui-blocker.scss b/packages/desktop-gui/src/app/ui-blocker.scss
new file mode 100644
index 000000000000..701cde0d4a9c
--- /dev/null
+++ b/packages/desktop-gui/src/app/ui-blocker.scss
@@ -0,0 +1,8 @@
+.ui-blocker {
+ bottom: 0;
+ left: 0;
+ position: fixed;
+ right: 0;
+ top: 0;
+ z-index: 99999;
+}
diff --git a/packages/desktop-gui/src/auth/login-modal.jsx b/packages/desktop-gui/src/auth/login-modal.jsx
index 6f3ea1328d73..c25f0e777825 100644
--- a/packages/desktop-gui/src/auth/login-modal.jsx
+++ b/packages/desktop-gui/src/auth/login-modal.jsx
@@ -1,8 +1,8 @@
import { observer } from 'mobx-react'
import React, { Component } from 'react'
import BootstrapModal from 'react-bootstrap-modal'
-import Loader from 'react-loader'
+import Loader from '../lib/loader'
import LoginForm from './login-form'
import authStore from './auth-store'
import ipc from '../lib/ipc'
@@ -51,7 +51,7 @@ class LoginContent extends Component {
return (
x
-
+
)
}
diff --git a/packages/desktop-gui/src/index.hbs b/packages/desktop-gui/src/index.hbs
index 59f83e139d96..66e1f72e2890 100644
--- a/packages/desktop-gui/src/index.hbs
+++ b/packages/desktop-gui/src/index.hbs
@@ -9,6 +9,7 @@
+