diff --git a/.eslintignore b/.eslintignore index 1e654ae4c95e..07b52e352103 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,5 @@ __snapshots__ -packages/server/lib/scaffold/plugins/index.js +packages/server/lib/scaffold/background/index.js packages/server/lib/scaffold/support/index.js packages/server/lib/scaffold/support/commands.js packages/server/test/fixtures diff --git a/cli/schema/cypress.schema.json b/cli/schema/cypress.schema.json index e76d3a223444..9ed7e5bdb3e8 100644 --- a/cli/schema/cypress.schema.json +++ b/cli/schema/cypress.schema.json @@ -84,10 +84,10 @@ "default": "cypress/integration", "description": "Path to folder containing integration test files" }, - "pluginsFile": { + "backgroundFile": { "type": ["string", "boolean"], - "default": "cypress/plugins/index.js", - "description": "Path to plugins file. (Pass false to disable)" + "default": "cypress/background/index.js", + "description": "Path to background file. (Pass false to disable)" }, "screenshotsFolder": { "type": "string", diff --git a/cli/test/lib/logger_spec.js b/cli/test/lib/logger_spec.js index 284d57ad828c..98079c0e7b5c 100644 --- a/cli/test/lib/logger_spec.js +++ b/cli/test/lib/logger_spec.js @@ -1,7 +1,7 @@ require('../spec_helper') const la = require('lazy-ass') -const {stripIndent, stripIndents} = require('common-tags') +const { stripIndent, stripIndents } = require('common-tags') const snapshot = require('../support/snapshot') describe('stripIndent', () => { @@ -12,6 +12,7 @@ describe('stripIndent', () => { third line last line ` + // should preserve the structure of the text snapshot(removed) }) @@ -21,7 +22,8 @@ describe('stripIndent', () => { const removed = stripIndent(text) // removed 1 level of indentation and trimmed the string const expected = 'foo\n bar' - la(removed === expected, 'removed indent is\n' + removed) + + la(removed === expected, `removed indent is\n${removed}`) }) it('can be used with nested message', () => { @@ -33,6 +35,7 @@ describe('stripIndent', () => { last line ` + // should have NO indents // first line // diff --git a/cli/types/index.d.ts b/cli/types/index.d.ts index 97dfec2831d0..e362be366e81 100644 --- a/cli/types/index.d.ts +++ b/cli/types/index.d.ts @@ -1995,10 +1995,10 @@ declare namespace Cypress { */ integrationFolder: string /** - * Path to plugins file. (Pass false to disable) - * @default "cypress/plugins/index.js" + * Path to background file. (Pass false to disable) + * @default "cypress/background/index.js" */ - pluginsFile: string + backgroundFile: string /** * Path to folder where screenshots will be saved from [cy.screenshot()](https://on.cypress.io/screenshot) command or after a headless or CI run’s test failure * @default "cypress/screenshots" @@ -2266,14 +2266,14 @@ declare namespace Cypress { * * @param {Window} contentWindow the remote page's window object */ - onBeforeLoad(win: Window): void + onStart(win: Window): void /** * Called once your page has fired its load event. * * @param {Window} contentWindow the remote page's window object */ - onLoad(win: Window): void + onReady(win: Window): void /** * Cypress will automatically apply the right authorization headers @@ -3931,7 +3931,17 @@ declare namespace Cypress { (fn: (currentSubject: Subject) => void): Chainable } - // for just a few events like "window:alert" it makes sense to allow passing cy.stub() or + /** + * Page details included with actions like 'page:start' + */ + interface PageDetails { + win: Window + url: string + statusCode?: number + headers?: { [key: string]: string } + } + + // for just a few events like "page:alert" it makes sense to allow passing cy.stub() or // a user callback function. Others probably only need a callback function. /** @@ -3959,7 +3969,7 @@ declare namespace Cypress { // stub "window.alert" in a single test it('shows alert', () => { const stub = cy.stub() - cy.on('window:alert', stub) + cy.on('page:alert', stub) // trigger application code that calls alert(...) .then(() => { expect(stub).to.have.been.calledOnce @@ -3974,20 +3984,20 @@ declare namespace Cypress { * @see https://on.cypress.io/catalog-of-events#App-Events * @example ``` - cy.on('window:confirm', (str) => { + cy.on('page:confirm', (str) => { console.log(str) return false // simulate "Cancel" }) ``` */ - (action: 'window:confirm', fn: ((text: string) => false | void) | SinonSpyAgent | SinonSpyAgent): void + (action: 'page:confirm', fn: ((text: string) => false | void) | SinonSpyAgent | SinonSpyAgent): void /** * Fires when your app calls the global `window.alert()` method. * Cypress will auto accept alerts. You cannot change this behavior. * @example ``` const stub = cy.stub() - cy.on('window:alert', stub) + cy.on('page:alert', stub) // assume the button calls window.alert() cy.get('.my-button') .click() @@ -3997,87 +4007,87 @@ declare namespace Cypress { ``` * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'window:alert', fn: ((text: string) => void) | SinonSpyAgent | SinonSpyAgent): void + (action: 'page:alert', fn: ((text: string) => void) | SinonSpyAgent | SinonSpyAgent): void /** - * Fires as the page begins to load, but before any of your applications JavaScript has executed. This fires at the exact same time as `cy.visit()` `onBeforeLoad` callback. Useful to modify the window on a page transition. + * Fires as the page begins to load, but before any of your applications JavaScript has executed. This fires at the exact same time as `cy.visit()` `onStart` callback. Useful to modify the window on a page transition. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'window:before:load', fn: (win: Window) => void): void + (action: 'page:start', fn: (details: PageDetails) => void): void /** - * Fires after all your resources have finished loading after a page transition. This fires at the exact same time as a `cy.visit()` `onLoad` callback. + * Fires after all your resources have finished loading after a page transition. This fires at the exact same time as a `cy.visit()` `onReady` callback. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'window:load', fn: (win: Window) => void): void + (action: 'page:ready', fn: (details: PageDetails) => void): void /** - * Fires when your application is about to navigate away. The real event object is provided to you. Your app may have set a `returnValue` on the event, which is useful to assert on. + * Fires when your application is has unloaded and is navigating away. The real event object is provided to you. This event is not cancelable. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'window:before:unload', fn: (event: BeforeUnloadEvent) => void): void + (action: 'page:end', fn: (details: PageDetails) => void): void /** - * Fires when your application is has unloaded and is navigating away. The real event object is provided to you. This event is not cancelable. + * Fires when your application is about to navigate away. The real event object is provided to you. Your app may have set a `returnValue` on the event, which is useful to assert on. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'window:unload', fn: (event: Event) => void): void + (action: 'before:window:unload', fn: (event: BeforeUnloadEvent) => void): void /** * Fires whenever Cypress detects that your application's URL has changed. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'url:changed', fn: (url: string) => void): void + (action: 'page:url:changed', fn: (url: string) => void): void /** * Fires when the test has failed. It is technically possible to prevent the test from actually failing by binding to this event and invoking an async `done` callback. However this is **strongly discouraged**. Tests should never legitimately fail. This event exists because it's extremely useful for debugging purposes. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'fail', fn: (error: Error, mocha: Mocha.IRunnable) => void): void + (action: 'test:fail', fn: (error: Error, mocha: Mocha.IRunnable) => void): void /** * Fires whenever the viewport changes via a `cy.viewport()` or naturally when Cypress resets the viewport to the default between tests. Useful for debugging purposes. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'viewport:changed', fn: (viewport: Viewport) => void): void + (action: 'viewport:change', fn: (viewport: Viewport) => void): void /** * Fires whenever **Cypress** is scrolling your application. This event is fired when Cypress is {% url 'waiting for and calculating actionability' interacting-with-elements %}. It will scroll to 'uncover' elements currently being covered. This event is extremely useful to debug why Cypress may think an element is not interactive. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'scrolled', fn: ($el: JQuery) => void): void + (action: 'internal:scrolled', fn: ($el: JQuery) => void): void /** * Fires when a cy command is first invoked and enqueued to be run later. Useful for debugging purposes if you're confused about the order in which commands will execute. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'command:enqueued', fn: (command: EnqueuedCommand) => void): void + (action: 'internal:commandEnqueue', fn: (command: EnqueuedCommand) => void): void /** * Fires when cy begins actually running and executing your command. Useful for debugging and understanding how the command queue is async. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'command:start', fn: (command: CommandQueue) => void): void + (action: 'internal:commandStart', fn: (command: CommandQueue) => void): void /** * Fires when cy finishes running and executing your command. Useful for debugging and understanding how commands are handled. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'command:end', fn: (command: CommandQueue) => void): void + (action: 'internal:commandEnd', fn: (command: CommandQueue) => void): void /** * Fires whenever a command begins its retrying routines. This is called on the trailing edge after Cypress has internally waited for the retry interval. Useful to understand **why** a command is retrying, and generally includes the actual error causing the retry to happen. When commands fail the final error is the one that actually bubbles up to fail the test. This event is essentially to debug why Cypress is failing. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'command:retry', fn: (command: CommandQueue) => void): void + (action: 'internal:commandRetry', fn: (command: CommandQueue) => void): void /** * Fires whenever a command emits this event so it can be displayed in the Command Log. Useful to see how internal cypress commands utilize the {% url 'Cypress.log()' cypress-log %} API. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'log:added', fn: (log: any, interactive: boolean) => void): void + (action: 'internal:log', fn: (log: any, interactive: boolean) => void): void /** * Fires whenever a command's attributes changes. This event is debounced to prevent it from firing too quickly and too often. Useful to see how internal cypress commands utilize the {% url 'Cypress.log()' cypress-log %} API. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'log:changed', fn: (log: any, interactive: boolean) => void): void + (action: 'internal:logChange', fn: (log: any, interactive: boolean) => void): void /** * Fires before the test and all **before** and **beforeEach** hooks run. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'test:before:run', fn: (attributes: ObjectLike, test: Mocha.ITest) => void): void + (action: 'test:start', fn: (attributes: ObjectLike, test: Mocha.ITest) => void): void /** * Fires after the test and all **afterEach** and **after** hooks run. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'test:after:run', fn: (attributes: ObjectLike, test: Mocha.ITest) => void): void + (action: 'test:end', fn: (attributes: ObjectLike, test: Mocha.ITest) => void): void } // $CommandQueue from `command_queue.coffee` - a lot to type. Might be more useful if it was written in TS diff --git a/cli/types/tests/actions.ts b/cli/types/tests/actions.ts index ae407691ce85..5fb58271f0cd 100644 --- a/cli/types/tests/actions.ts +++ b/cli/types/tests/actions.ts @@ -3,77 +3,77 @@ Cypress.on('uncaught:exception', (error, runnable) => { runnable // $ExpectType IRunnable }) -Cypress.on('window:confirm', (text) => { +Cypress.on('page:confirm', (text) => { text // $ExpectType string }) -Cypress.on('window:alert', (text) => { +Cypress.on('page:alert', (text) => { text // $ExpectType string }) -Cypress.on('window:before:load', (win) => { - win // $ExpectType Window +Cypress.on('page:start', (details) => { + details // $ExpectType PageDetails }) -Cypress.on('window:load', (win) => { - win // $ExpectType Window +Cypress.on('page:ready', (details) => { + details // $ExpectType PageDetails }) -Cypress.on('window:before:unload', (event) => { - event // $ExpectType BeforeUnloadEvent +Cypress.on('page:end', (details) => { + details // $ExpectType PageDetails }) -Cypress.on('window:unload', (event) => { - event // $ExpectType Event +Cypress.on('before:window:unload', (event) => { + event // $ExpectType BeforeUnloadEvent }) -Cypress.on('url:changed', (url) => { +Cypress.on('page:url:changed', (url) => { url // $ExpectType string }) -Cypress.on('fail', (error, mocha) => { +Cypress.on('test:fail', (error, mocha) => { error // $ExpectType Error mocha // $ExpectType IRunnable }) -Cypress.on('viewport:changed', (viewport) => { +Cypress.on('viewport:change', (viewport) => { viewport // $ExpectType Viewport }) -Cypress.on('scrolled', ($el) => { +Cypress.on('internal:scrolled', ($el) => { $el // $ExpectType JQuery }) -Cypress.on('command:enqueued', (command) => { +Cypress.on('internal:commandEnqueue', (command) => { command // $ExpectType EnqueuedCommand }) -Cypress.on('command:start', (command) => { +Cypress.on('internal:commandStart', (command) => { command // $ExpectType CommandQueue }) -Cypress.on('command:end', (command) => { +Cypress.on('internal:commandEnd', (command) => { command // $ExpectType CommandQueue }) -Cypress.on('command:retry', (command) => { +Cypress.on('internal:commandRetry', (command) => { command // $ExpectType CommandQueue }) -Cypress.on('log:added', (log, interactive: boolean) => { +Cypress.on('internal:log', (log, interactive: boolean) => { log // $ExpectTyped any }) -Cypress.on('log:changed', (log, interactive: boolean) => { +Cypress.on('internal:logChange', (log, interactive: boolean) => { log // $ExpectTyped any }) -Cypress.on('test:before:run', (attributes , test) => { +Cypress.on('test:start', (attributes , test) => { attributes // $ExpectType ObjectLike test // $ExpectType ITest }) -Cypress.on('test:after:run', (attributes , test) => { +Cypress.on('test:end', (attributes , test) => { attributes // $ExpectType ObjectLike test // $ExpectType ITest }) diff --git a/cli/types/tests/kitchen-sink.ts b/cli/types/tests/kitchen-sink.ts index 23856750a39d..27d7d0071d62 100644 --- a/cli/types/tests/kitchen-sink.ts +++ b/cli/types/tests/kitchen-sink.ts @@ -48,21 +48,21 @@ Cypress.browser // $ExpectType Browser // stubbing window.alert type on "Cypress" should // work with plain function or with a Sinon stub -Cypress.on('window:alert', () => { }) -Cypress.on('window:alert', cy.spy()) -Cypress.on('window:alert', cy.stub()) +Cypress.on('page:alert', () => { }) +Cypress.on('page:alert', cy.spy()) +Cypress.on('page:alert', cy.stub()) // same for a single test -cy.on('window:alert', () => { }) -cy.on('window:alert', cy.spy()) -cy.on('window:alert', cy.stub()) +cy.on('page:alert', () => { }) +cy.on('page:alert', cy.spy()) +cy.on('page:alert', cy.stub()) // window:confirm stubbing -Cypress.on('window:confirm', () => { }) -Cypress.on('window:confirm', cy.spy()) -Cypress.on('window:confirm', cy.stub()) -cy.on('window:confirm', () => { }) -cy.on('window:confirm', cy.spy()) -cy.on('window:confirm', cy.stub()) +Cypress.on('page:confirm', () => { }) +Cypress.on('page:confirm', cy.spy()) +Cypress.on('page:confirm', cy.stub()) +cy.on('page:confirm', () => { }) +cy.on('page:confirm', cy.spy()) +cy.on('page:confirm', cy.stub()) // specifying HTTP method directly in the options object cy.request({ diff --git a/packages/desktop-gui/cypress.json b/packages/desktop-gui/cypress.json index 4822cf18ffd1..250ec141ee81 100644 --- a/packages/desktop-gui/cypress.json +++ b/packages/desktop-gui/cypress.json @@ -1,6 +1,6 @@ { "projectId": "ypt4pf", - "pluginsFile": false, + "backgroundFile": false, "viewportWidth": 800, "viewportHeight": 550 } diff --git a/packages/desktop-gui/cypress/fixtures/config.json b/packages/desktop-gui/cypress/fixtures/config.json index fe243710d4e7..f44403408856 100644 --- a/packages/desktop-gui/cypress/fixtures/config.json +++ b/packages/desktop-gui/cypress/fixtures/config.json @@ -159,7 +159,7 @@ ] }, { - "name": "plugins", + "name": "background", "children": [ { "name": "index.js" 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 790e9b969e90..62a9dc9399f5 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") @@ -158,25 +161,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 7d4a2a3b550b..33d8734ee64a 100644 --- a/packages/desktop-gui/cypress/integration/project_spec.coffee +++ b/packages/desktop-gui/cypress/integration/project_spec.coffee @@ -44,10 +44,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 "polling", -> beforeEach -> @ipc.getProjectStatus.resolves(@projectStatuses[0]) 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 1ce22af0ad27..9ef15c5d79e8 100644 --- a/packages/desktop-gui/cypress/integration/settings_spec.coffee +++ b/packages/desktop-gui/cypress/integration/settings_spec.coffee @@ -236,16 +236,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 01caa1a6ba68..09b06bb5785b 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) @@ -63,7 +69,7 @@ describe "Specs List", -> cy.contains("commands.js") cy.contains("defaults.js") cy.contains("index.js") - cy.contains("span", "plugins").siblings("ul").within -> + cy.contains("span", "background").siblings("ul").within -> cy.contains("index.js") it "lists folders and files alphabetically", -> @@ -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 -> @@ -273,16 +280,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") @@ -322,9 +328,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 f6e9774b3cab..f06b8345f2ae 100644 --- a/packages/desktop-gui/cypress/integration/update_banner_spec.coffee +++ b/packages/desktop-gui/cypress/integration/update_banner_spec.coffee @@ -12,12 +12,13 @@ describe "Update Banner", -> cy.fixture("specs").as("specs") cy.visitIndex({ - onBeforeLoad: (win) -> + onStart: (win) -> cy.spy(win, "setInterval") }).then (win) -> { @start, @ipc } = win.App cy.stub(@ipc, "getCurrentUser").resolves(@user) + cy.stub(@ipc, "openProject").resolves(@config) cy.stub(@ipc, "windowOpen") cy.stub(@ipc, "externalOpen") @@ -99,7 +100,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 8fd24d637a22..47587be618c2 100644 --- a/packages/desktop-gui/package.json +++ b/packages/desktop-gui/package.json @@ -50,7 +50,6 @@ "rebuild-node-sass": "1.1.0", "react-bootstrap-modal": "4.2.0", "react-dom": "16.8.6", - "react-loader": "2.4.5", "zunder": "6.4.1" } } diff --git a/packages/desktop-gui/src/app/app.jsx b/packages/desktop-gui/src/app/app.jsx index 729f1ee02bfe..7a4911dd1643 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 }) => {