فهرست منبع

Merge pull request #252 from smiclea/cypress

Add, reorganise, fix and improve Cypress e2e tests
Dorin Paslaru 8 سال پیش
والد
کامیت
1a5254d1e4
25فایلهای تغییر یافته به همراه507 افزوده شده و 242 حذف شده
  1. 2 2
      package.json
  2. 25 6
      private/cypress/config.template.js
  3. 0 0
      private/cypress/integration/1 - login/Invalid Login.js
  4. 1 1
      private/cypress/integration/2 - create endpoints/Create Azure Endpoint.js
  5. 12 11
      private/cypress/integration/2 - create endpoints/Create OCI Endpoint.js
  6. 1 1
      private/cypress/integration/2 - create endpoints/Create Openstack Endpoint.js
  7. 1 1
      private/cypress/integration/2 - create endpoints/Create VmWare Endpoint.js
  8. 59 0
      private/cypress/integration/3 - duplicate endpoints/Duplicate Azure Endpoint.js
  9. 59 0
      private/cypress/integration/3 - duplicate endpoints/Duplicate OCI Endpoint.js
  10. 130 0
      private/cypress/integration/4 - migrations and replicas/Openstack -> OCI Migration.js
  11. 28 15
      private/cypress/integration/4 - migrations and replicas/VmWare -> Azure Replica/1 - Create replica.js
  12. 0 0
      private/cypress/integration/4 - migrations and replicas/VmWare -> Azure Replica/2 - Scheduler Operations.js
  13. 9 5
      private/cypress/integration/4 - migrations and replicas/VmWare -> Azure Replica/3 - Delete replica.js
  14. 22 4
      private/cypress/integration/4 - migrations and replicas/VmWare -> Openstack Migration.js
  15. 0 0
      private/cypress/integration/5 - delete endpoints/Delete Azure endpoint.js
  16. 4 4
      private/cypress/integration/5 - delete endpoints/Delete OCI endpoint.js
  17. 0 0
      private/cypress/integration/5 - delete endpoints/Delete Openstack endpoint.js
  18. 0 0
      private/cypress/integration/5 - delete endpoints/Delete VmWare endpoint.js
  19. 0 38
      private/cypress/integration/migration/4 - Cancel first running migration.js
  20. 0 37
      private/cypress/integration/migration/6 - Delete first migration.js
  21. 0 38
      private/cypress/integration/replica/4 - Cancel first running replica.js
  22. 0 32
      private/cypress/integration/replica/5 - Cannot delete used endpoint.js
  23. 2 1
      src/components/molecules/EndpointField/EndpointField.jsx
  24. 2 1
      src/components/molecules/EndpointListItem/EndpointListItem.jsx
  25. 150 45
      yarn.lock

+ 2 - 2
package.json

@@ -37,7 +37,7 @@
     "@storybook/react": "^3.2.15",
     "babel-eslint": "^8.0.1",
     "babel-jest": "^21.2.0",
-    "cypress": "^2.1.0",
+    "cypress": "3.0.1",
     "enzyme": "^3.1.0",
     "enzyme-adapter-react-16": "^1.0.4",
     "eslint": "^4.8.0",
@@ -103,4 +103,4 @@
     "webpack-blocks-happypack": "^0.1.3",
     "webpack-blocks-split-vendor": "^0.2.1"
   }
-}
+}

+ 25 - 6
private/cypress/config.template.js

@@ -17,7 +17,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 export default {
   nodeServer: 'http://localhost:3000/',
   coriolisUrl: '',
-  username: 'admin',
+  username: 'cypress',
   password: '',
   endpoints: {
     azure: {
@@ -40,16 +40,35 @@ export default {
       glanceApiVersion: 2,
       identityVersion: 3,
     },
+    oci: {
+      privateKeyData: '',
+      region: '',
+      tenancy: '',
+      user: '',
+      privateKeyPassphrase: '',
+    },
   },
   wizard: {
     azure: {
-      location: { label: 'West US', value: 'westus' },
-      resourceGroup: { label: 'Coriolis', value: 'coriolis' },
+      resourceGroup: { label: '', value: '' },
     },
     openstack: {
-      network: 'private',
+      network: '',
+    },
+    oci: {
+      compartment: {
+        label: '', value: '',
+      },
+      migrSubnetId: {
+        label: '', value: '',
+      },
+      availabilityDomain: '',
+    },
+    instancesSearch: {
+      vmwareSearchText: 'ubuntu 14.04',
+      vmwareItemIndex: 1,
+      ociSearchText: 'ubuntu',
+      ociItemIndex: 0,
     },
-    instancesSearch: 'ubuntu',
-    instancesSelectItem: 2,
   },
 }

+ 0 - 0
private/cypress/integration/login/Invalid Login.js → private/cypress/integration/1 - login/Invalid Login.js


+ 1 - 1
private/cypress/integration/replica/1 - Create Azure Endpoint.js → private/cypress/integration/2 - create endpoints/Create Azure Endpoint.js

@@ -46,7 +46,7 @@ describe('Create Azure Endpoint', () => {
   })
 
   it('Added Endpoint to endpoint list', () => {
-    cy.visit(`${config.nodeServer}endpoints/`)
+    cy.get('a[data-test-id="navigation-item-endpoints"]').click()
     cy.get('div[data-test-id="endpointListItem-content-e2e-azure-test"]').should('contain', 'e2e-azure-test')
   })
 })

+ 12 - 11
private/cypress/integration/replica/2 - Create VmWare Endpoint.js → private/cypress/integration/2 - create endpoints/Create OCI Endpoint.js

@@ -16,7 +16,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import config from '../../config'
 
-describe('Create VmWare Endpoint', () => {
+describe('Create OCI Endpoint', () => {
   before(() => {
     cy.login()
   })
@@ -25,18 +25,19 @@ describe('Create VmWare Endpoint', () => {
     Cypress.Cookies.preserveOnce('token', 'projectId')
   })
 
-  it('Shows new VmWare endpoint dialog', () => {
+  it('Shows new OCI endpoint dialog', () => {
     cy.get('div').contains('New').click()
     cy.get('a').contains('Endpoint').click()
-    cy.get('div[data-test-id="cProvider-endpointLogo-vmware_vsphere"]').click()
+    cy.get('div[data-test-id="cProvider-endpointLogo-oci"]').click()
   })
 
-  it('Fills VmWare connection info', () => {
-    cy.get('input[placeholder="Name"]').type('e2e-vmware-test')
-    cy.get('input[placeholder="Username"]').type(config.endpoints.vmware.username)
-    cy.get('input[placeholder="Password"]').type(config.endpoints.vmware.password)
-    cy.get('input[placeholder="Host"]').type(config.endpoints.vmware.host)
-
+  it('Fills OCI connection info', () => {
+    cy.get('input[data-test-id="endpointField-textInput-name"]').type('e2e-oci-test')
+    cy.get('textarea[data-test-id="endpointField-textArea-private_key_data"]').type(config.endpoints.oci.privateKeyData, { delay: 0 })
+    cy.get('input[data-test-id="endpointField-textInput-region"]').type(config.endpoints.oci.region)
+    cy.get('input[data-test-id="endpointField-textInput-tenancy"]').type(config.endpoints.oci.tenancy)
+    cy.get('input[data-test-id="endpointField-textInput-user"]').type(config.endpoints.oci.user)
+    cy.get('input[data-test-id="endpointField-textInput-private_key_passphrase"]').type(config.endpoints.oci.privateKeyPassphrase)
     cy.server()
     cy.route({ url: '**/actions', method: 'POST' }).as('validate')
     cy.get('button').contains('Validate and save').click()
@@ -45,7 +46,7 @@ describe('Create VmWare Endpoint', () => {
   })
 
   it('Added Endpoint to endpoint list', () => {
-    cy.visit(`${config.nodeServer}endpoints/`)
-    cy.get('div[data-test-id="endpointListItem-content-e2e-vmware-test"]').should('contain', 'e2e-vmware-test')
+    cy.get('a[data-test-id="navigation-item-endpoints"]').click()
+    cy.get('div[data-test-id="endpointListItem-content-e2e-oci-test"]').should('contain', 'e2e-oci-test')
   })
 })

+ 1 - 1
private/cypress/integration/migration/1 - Create Openstack Endpoint.js → private/cypress/integration/2 - create endpoints/Create Openstack Endpoint.js

@@ -53,7 +53,7 @@ describe('Create Openstack Endpoint', () => {
   })
 
   it('Added Openstack to endpoint list', () => {
-    cy.visit(`${config.nodeServer}endpoints/`)
+    cy.get('a[data-test-id="navigation-item-endpoints"]').click()
     cy.get('div[data-test-id="endpointListItem-content-e2e-openstack-test"]').should('contain', 'e2e-openstack-test')
   })
 })

+ 1 - 1
private/cypress/integration/migration/2 - Create VmWare Endpoint.js → private/cypress/integration/2 - create endpoints/Create VmWare Endpoint.js

@@ -45,7 +45,7 @@ describe('Create VmWare Endpoint', () => {
   })
 
   it('Added Endpoint to endpoint list', () => {
-    cy.visit(`${config.nodeServer}endpoints/`)
+    cy.get('a[data-test-id="navigation-item-endpoints"]').click()
     cy.get('div[data-test-id="endpointListItem-content-e2e-vmware-test"]').should('contain', 'e2e-vmware-test')
   })
 })

+ 59 - 0
private/cypress/integration/3 - duplicate endpoints/Duplicate Azure Endpoint.js

@@ -0,0 +1,59 @@
+/*
+Copyright (C) 2018  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// @flow
+
+describe('Duplicate Azure Endpoint', () => {
+  before(() => {
+    cy.login()
+  })
+
+  beforeEach(() => {
+    Cypress.Cookies.preserveOnce('token', 'projectId')
+  })
+
+  it('Creates duplicate', () => {
+    cy.get('a[data-test-id="navigation-item-endpoints"]').click()
+    cy.get('div[data-test-id="endpointListItem-content-e2e-azure-test"]').should('contain', 'e2e-azure-test')
+    cy.get('div[data-test-id="endpointListItem-checkbox-e2e-azure-test"]').click()
+    cy.get('div[data-test-id="dropdown-dropdownButton"]').contains('Select an action').click()
+    cy.get('div[data-test-id="dropdownListItem"]').contains('Duplicate').click()
+    cy.server()
+    cy.route({ url: '**/endpoints', method: 'POST' }).as('duplicate')
+    cy.get('button').contains('Duplicate').click()
+    cy.wait('@duplicate')
+  })
+
+  it('Validates duplicated endpoint', () => {
+    cy.get('div[data-test-id="endpointListItem-content-e2e-azure-test (copy)"').click()
+    cy.server()
+    cy.route({ url: '**/actions', method: 'POST' }).as('validate')
+    cy.get('button[data-test-id="edContent-validateButton"]').click()
+    cy.wait('@validate')
+    cy.get('div[data-test-id="eValidation-title"]').should('contain', 'Endpoint is Valid')
+    cy.get('button').contains('Dismiss').click()
+  })
+
+  it('Deletes duplicated endpoint', () => {
+    cy.server()
+    cy.route({ url: '**/replicas/detail', method: 'GET' }).as('replicas')
+    cy.route({ url: '**/migrations/detail', method: 'GET' }).as('migrations')
+    cy.get('button[data-test-id="edContent-deleteButton"]').click()
+    cy.wait('@replicas')
+    cy.wait('@migrations')
+    cy.route({ url: '**/secrets/**', method: 'DELETE' }).as('delete')
+    cy.get('button[data-test-id="aModal-yesButton"]').click()
+    cy.wait('@delete')
+  })
+})

+ 59 - 0
private/cypress/integration/3 - duplicate endpoints/Duplicate OCI Endpoint.js

@@ -0,0 +1,59 @@
+/*
+Copyright (C) 2018  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// @flow
+
+describe('Duplicate OCI Endpoint', () => {
+  before(() => {
+    cy.login()
+  })
+
+  beforeEach(() => {
+    Cypress.Cookies.preserveOnce('token', 'projectId')
+  })
+
+  it('Creates duplicate', () => {
+    cy.get('a[data-test-id="navigation-item-endpoints"]').click()
+    cy.get('div[data-test-id="endpointListItem-content-e2e-oci-test"]').should('contain', 'e2e-oci-test')
+    cy.get('div[data-test-id="endpointListItem-checkbox-e2e-oci-test"]').click()
+    cy.get('div[data-test-id="dropdown-dropdownButton"]').contains('Select an action').click()
+    cy.get('div[data-test-id="dropdownListItem"]').contains('Duplicate').click()
+    cy.server()
+    cy.route({ url: '**/endpoints', method: 'POST' }).as('duplicate')
+    cy.get('button').contains('Duplicate').click()
+    cy.wait('@duplicate')
+  })
+
+  it('Validates duplicated endpoint', () => {
+    cy.get('div[data-test-id="endpointListItem-content-e2e-oci-test (copy)"').click()
+    cy.server()
+    cy.route({ url: '**/actions', method: 'POST' }).as('validate')
+    cy.get('button[data-test-id="edContent-validateButton"]').click()
+    cy.wait('@validate')
+    cy.get('div[data-test-id="eValidation-title"]').should('contain', 'Endpoint is Valid')
+    cy.get('button').contains('Dismiss').click()
+  })
+
+  it('Deletes duplicated endpoint', () => {
+    cy.server()
+    cy.route({ url: '**/replicas/detail', method: 'GET' }).as('replicas')
+    cy.route({ url: '**/migrations/detail', method: 'GET' }).as('migrations')
+    cy.get('button[data-test-id="edContent-deleteButton"]').click()
+    cy.wait('@replicas')
+    cy.wait('@migrations')
+    cy.route({ url: '**/secrets/**', method: 'DELETE' }).as('delete')
+    cy.get('button[data-test-id="aModal-yesButton"]').click()
+    cy.wait('@delete')
+  })
+})

+ 130 - 0
private/cypress/integration/4 - migrations and replicas/Openstack -> OCI Migration.js

@@ -0,0 +1,130 @@
+/*
+Copyright (C) 2018  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// @flow
+
+import config from '../../config'
+
+describe('Create Openstack to OCI Migration', () => {
+  before(() => {
+    cy.login()
+  })
+
+  beforeEach(() => {
+    Cypress.Cookies.preserveOnce('token', 'projectId')
+  })
+
+  it('Shows Wizard page', () => {
+    cy.get('div').contains('New').click()
+    cy.get('a').contains('Migration').click()
+    cy.get('#app').should('contain', 'New Migration')
+  })
+
+  it('Chooses Openstack as Source Cloud', () => {
+    cy.server()
+    cy.route({ url: '**/instances**', method: 'GET' }).as('sourceInstances')
+    cy.get('button').contains('Next').click()
+    cy.get('div[data-test-id="wEndpointList-dropdown-openstack"]').first().click()
+    cy.get('div').contains('e2e-openstack-test').click()
+    cy.wait('@sourceInstances')
+  })
+
+  it('Chooses OCI as Target Cloud', () => {
+    cy.server()
+    cy.get('button').contains('Next').click()
+    cy.get('div[data-test-id="wEndpointList-dropdown-oci"]').first().click()
+    cy.route({ url: '**/destination-options', method: 'GET' }).as('destOptions')
+    cy.get('div').contains('e2e-oci-test').click()
+    cy.wait('@destOptions')
+  })
+
+  it('Searches and selects instances', () => {
+    cy.get('button').contains('Next').click()
+    cy.server()
+    cy.route({ url: '**/instances**', method: 'GET' }).as('search')
+    cy.get('input[placeholder="Search VMs"]').type(config.wizard.instancesSearch.ociSearchText)
+    cy.wait('@search')
+    cy.get('div[data-test-id="wInstances-instanceItem"]').contains(config.wizard.instancesSearch.ociSearchText)
+    cy.get('div[data-test-id="wInstances-instanceItem"]').its('length').should('be.gt', 0)
+    cy.get('div[data-test-id="wInstances-instanceItem"]').eq(config.wizard.instancesSearch.ociItemIndex).click()
+  })
+
+  it('Fills OCI migration info', () => {
+    cy.get('button').contains('Next').click()
+    cy.get('div[data-test-id="wOptionsField-enumDropdown-compartment"]').click()
+    cy.get('div[data-test-id="dropdownListItem"]').contains(config.wizard.oci.compartment.label).click()
+    cy.get('div[data-test-id="wOptionsField-enumDropdown-availability_domain"]').click()
+    cy.server()
+    cy.route({ url: '**/destination-options**', method: 'GET' }).as('destOptions')
+    cy.get('div[data-test-id="dropdownListItem"]').contains(config.wizard.oci.availabilityDomain).click()
+    cy.wait('@destOptions')
+    cy.get('div[data-test-id="wOptionsField-enumDropdown-migr_subnet_id"]').click()
+    cy.get('div[data-test-id="dropdownListItem"]').contains(config.wizard.oci.migrSubnetId.label).click()
+  })
+
+  it('Selects first available network mapping', () => {
+    cy.server()
+    cy.route({ url: '**/networks**', method: 'GET' }).as('networks')
+    cy.route({ url: '**/instances/**', method: 'GET' }).as('instances')
+    cy.get('button').contains('Next').click()
+    cy.wait('@networks')
+    cy.wait('@instances')
+    cy.get('button').contains('Next').should('be.disabled')
+    cy.get('div[data-test-id="networkItem"]').its('length').should('be.gt', 0)
+    cy.get('div[value="Select ..."]').first().click()
+    cy.get('div[data-test-id="dropdownListItem"]').first().click()
+    cy.get('button').contains('Next').should('not.be.disabled')
+  })
+
+  it('Shows summary page', () => {
+    cy.get('button').contains('Next').click()
+    cy.get('#app').should('contain', 'Summary')
+    cy.get('#app').should('contain', 'e2e-openstack-test')
+    cy.get('#app').should('contain', 'e2e-oci-test')
+    cy.get('#app').should('contain', 'Coriolis Migration')
+    cy.get('#app').should('contain', 'Migration Options')
+    cy.get('div[data-test-id="wSummary-optionValue-compartment"]').should('contain', config.wizard.oci.compartment.value)
+    cy.get('div[data-test-id="wSummary-optionValue-availability_domain"]').should('contain', config.wizard.oci.availabilityDomain)
+    cy.get('div[data-test-id="wSummary-optionValue-migr_subnet_id"]').should('contain', config.wizard.oci.migrSubnetId.value)
+  })
+
+  it('Executes migration', () => {
+    cy.server()
+    cy.route({ url: '**/migrations', method: 'POST' }).as('migration')
+    cy.get('button').contains('Finish').click()
+    cy.wait('@migration')
+  })
+
+  it('Shows running migration page', () => {
+    cy.get('div[data-test-id="statusPill-RUNNING"]').should('exist')
+  })
+
+  it('Cancels migration', () => {
+    cy.server()
+    cy.get('button', { timeout: 10000 }).contains('Cancel').click()
+    cy.route({ url: '**/actions', method: 'POST' }).as('cancel')
+    cy.get('button').contains('Yes').click()
+    cy.wait('@cancel')
+    cy.get('div[data-test-id="dcHeader-statusPill-ERROR"]', { timeout: 120000 })
+  })
+
+  it('Deletes migration', () => {
+    cy.get('a[data-test-id="detailsNavigation-"]').click()
+    cy.get('button').contains('Delete Migration').click()
+    cy.server()
+    cy.route({ url: '**/migrations/**', method: 'DELETE' }).as('delete')
+    cy.get('button').contains('Yes').click()
+    cy.wait('@delete')
+  })
+})

+ 28 - 15
private/cypress/integration/replica/3 - Create VmWare Azure Replica.js → private/cypress/integration/4 - migrations and replicas/VmWare -> Azure Replica/1 - Create replica.js

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 // @flow
 
-import config from '../../config'
+import config from '../../../config'
 
 describe('Create VmWare to Azure Replica', () => {
   before(() => {
@@ -50,22 +50,20 @@ describe('Create VmWare to Azure Replica', () => {
     cy.get('button').contains('Next').click()
     cy.server()
     cy.route({ url: '**/instances**', method: 'GET' }).as('search')
-    cy.get('input[placeholder="Search VMs"]').type(config.wizard.instancesSearch)
+    cy.get('input[placeholder="Search VMs"]').type(config.wizard.instancesSearch.vmwareSearchText)
     cy.wait('@search')
-    cy.get('div[data-test-id="wInstances-instanceItem"]').contains(config.wizard.instancesSearch)
+    cy.get('div[data-test-id="wInstances-instanceItem"]').contains(config.wizard.instancesSearch.vmwareSearchText)
     cy.get('div[data-test-id="wInstances-instanceItem"]').its('length').should('be.gt', 0)
-    cy.get('div[data-test-id="wInstances-instanceItem"]').eq(config.wizard.instancesSelectItem).click()
+    cy.get('div[data-test-id="wInstances-instanceItem"]').eq(config.wizard.instancesSearch.vmwareItemIndex).click()
   })
 
   it('Fills Azure replica info', () => {
     cy.get('button').contains('Next').click()
-    cy.get('input[placeholder="Location"]').type(config.wizard.azure.location.value)
-    cy.get('input[placeholder="Resource Group"]').type(config.wizard.azure.resourceGroup.value)
-
-    // cy.get('div[data-test-id="wOptionsField-dropdown-location"]').first().click()
-    // cy.get('div[data-test-id="wOptionsField-dropdownListItem"]').contains(config.wizard.azure.location.label).click()
-    // cy.get('div[data-test-id="wOptionsField-dropdown-resource_group"]').first().click()
-    // cy.get('div[data-test-id="dropdownListItem"]').contains(config.wizard.azure.resourceGroup.label).click()
+    cy.get('div[data-test-id="wOptionsField-enumDropdown-resource_group"]').first().click()
+    cy.server()
+    cy.route({ url: '**/destination-options**', method: 'GET' }).as('dest-options')
+    cy.get('div[data-test-id="dropdownListItem"]').contains(config.wizard.azure.resourceGroup.label).click()
+    cy.wait('@dest-options')
   })
 
   it('Selects first available network mapping', () => {
@@ -94,10 +92,7 @@ describe('Create VmWare to Azure Replica', () => {
     cy.get('#app').should('contain', 'e2e-azure-test')
     cy.get('#app').should('contain', 'Coriolis Replica')
     cy.get('#app').should('contain', 'Replica Options')
-    cy.get('#app').should('contain', config.wizard.azure.location.value)
-    cy.get('#app').should('contain', config.wizard.azure.resourceGroup.value)
-    cy.get('#app').should('contain', 'Networks')
-    cy.get('#app').should('contain', 'Instances')
+    cy.get('div[data-test-id="wSummary-optionValue-resource_group"]').should('contain', config.wizard.azure.resourceGroup.value)
   })
 
   it('Executes replica', () => {
@@ -110,4 +105,22 @@ describe('Create VmWare to Azure Replica', () => {
   it('Shows running replica page', () => {
     cy.get('div[data-test-id="statusPill-RUNNING"]').should('exist')
   })
+
+  it('Cancels replica execution', () => {
+    cy.server()
+    cy.get('button').contains('Cancel Execution').click()
+    cy.route({ url: '**/actions', method: 'POST' }).as('cancel')
+    cy.get('button').contains('Yes').click()
+    cy.wait('@cancel')
+    cy.get('div[data-test-id="dcHeader-statusPill-ERROR"]', { timeout: 120000 })
+  })
+
+  it('Should show in usage message when trying to delete', () => {
+    cy.get('div[data-test-id="dcHeader-backButton"]').click()
+    cy.get('a[data-test-id="navigation-item-endpoints"]').click()
+    cy.get('div[data-test-id="endpointListItem-content-e2e-azure-test"]').click()
+    cy.get('button').contains('Delete Endpoint').click()
+    cy.get('div[data-test-id="alertModal"]').should('contain', 'The endpoint can\'t be deleted because it is in use by replicas or migrations.')
+    cy.get('button[data-test-id="aModal-dismissButton"]').click()
+  })
 })

+ 0 - 0
private/cypress/integration/scheduler/Scheduler Operations.js → private/cypress/integration/4 - migrations and replicas/VmWare -> Azure Replica/2 - Scheduler Operations.js


+ 9 - 5
private/cypress/integration/replica/6 - Delete first replica.js → private/cypress/integration/4 - migrations and replicas/VmWare -> Azure Replica/3 - Delete replica.js

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 // @flow
 
-describe('Delete the first replica', () => {
+describe('Scheduler Operations', () => {
   before(() => {
     cy.login()
   })
@@ -23,12 +23,16 @@ describe('Delete the first replica', () => {
     Cypress.Cookies.preserveOnce('token', 'projectId')
   })
 
-  it('Delete replica', () => {
+  it('Goes to replica page', () => {
     cy.server()
-    cy.route({ url: '**/executions/**', method: 'GET' }).as('executions')
+    cy.route('GET', '**/executions/detail').as('execution')
     cy.get('div[data-test-id="mainListItem-content"]').first().click()
-    cy.wait('@executions')
-    cy.get('button').last().should('contain', 'Delete Replica').click()
+    cy.wait('@execution')
+  })
+
+  it('Deletes replica', () => {
+    cy.server()
+    cy.get('button[data-test-id="rdContent-deleteButton"]').click()
     cy.route({ url: '**/replicas/**', method: 'DELETE' }).as('delete')
     cy.get('button').contains('Yes').click()
     cy.wait('@delete')

+ 22 - 4
private/cypress/integration/migration/3 - Create VmWare Openstack Migration.js → private/cypress/integration/4 - migrations and replicas/VmWare -> Openstack Migration.js

@@ -50,11 +50,11 @@ describe('Create VmWare to Openstack Migration', () => {
     cy.get('button').contains('Next').click()
     cy.server()
     cy.route({ url: '**/instances**', method: 'GET' }).as('search')
-    cy.get('input[placeholder="Search VMs"]').type(config.wizard.instancesSearch)
+    cy.get('input[placeholder="Search VMs"]').type(config.wizard.instancesSearch.vmwareSearchText)
     cy.wait('@search')
-    cy.get('div[data-test-id="wInstances-instanceItem"]').contains(config.wizard.instancesSearch)
+    cy.get('div[data-test-id="wInstances-instanceItem"]').contains(config.wizard.instancesSearch.vmwareSearchText)
     cy.get('div[data-test-id="wInstances-instanceItem"]').its('length').should('be.gt', 0)
-    cy.get('div[data-test-id="wInstances-instanceItem"]').eq(config.wizard.instancesSelectItem).click()
+    cy.get('div[data-test-id="wInstances-instanceItem"]').eq(config.wizard.instancesSearch.vmwareItemIndex).click()
   })
 
   it('Fills Openstack migration info', () => {
@@ -63,7 +63,7 @@ describe('Create VmWare to Openstack Migration', () => {
     cy.get('input[placeholder="Description"]').type('VmWare Openstack Migration')
   })
 
-  it('Selects first available network mapping', () => {
+  it('Selects network mapping', () => {
     cy.server()
     cy.route({ url: '**/networks**', method: 'GET' }).as('networks')
     cy.route({ url: '**/instances/**', method: 'GET' }).as('instances')
@@ -99,4 +99,22 @@ describe('Create VmWare to Openstack Migration', () => {
   it('Shows running migration page', () => {
     cy.get('div[data-test-id="statusPill-RUNNING"]').should('exist')
   })
+
+  it('Cancels migration', () => {
+    cy.server()
+    cy.get('button', { timeout: 10000 }).contains('Cancel').click()
+    cy.route({ url: '**/actions', method: 'POST' }).as('cancel')
+    cy.get('button').contains('Yes').click()
+    cy.wait('@cancel')
+    cy.get('div[data-test-id="dcHeader-statusPill-ERROR"]', { timeout: 120000 })
+  })
+
+  it('Deletes migration', () => {
+    cy.get('a[data-test-id="detailsNavigation-"]').click()
+    cy.get('button').contains('Delete Migration').click()
+    cy.server()
+    cy.route({ url: '**/migrations/**', method: 'DELETE' }).as('delete')
+    cy.get('button').contains('Yes').click()
+    cy.wait('@delete')
+  })
 })

+ 0 - 0
private/cypress/integration/replica/7 - Delete e2e Azure endpoint.js → private/cypress/integration/5 - delete endpoints/Delete Azure endpoint.js


+ 4 - 4
private/cypress/integration/replica/8 - Delete e2e VmWare endpoint.js → private/cypress/integration/5 - delete endpoints/Delete OCI endpoint.js

@@ -16,7 +16,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import config from '../../config'
 
-describe('Delete the VmWare endpoint created for e2e testing', () => {
+describe('Delete the OCI endpoint created for e2e testing', () => {
   before(() => {
     cy.login()
   })
@@ -31,9 +31,9 @@ describe('Delete the VmWare endpoint created for e2e testing', () => {
     cy.get('#app').should('contain', 'Coriolis Endpoints')
   })
 
-  it('Delete e2e VmWare endpoint', () => {
-    cy.get('div[data-test-id="endpointListItem-content-e2e-vmware-test"]').should('contain', 'e2e-vmware-test')
-    cy.get('div[data-test-id="endpointListItem-content-e2e-vmware-test"]').first().click()
+  it('Delete e2e OCI endpoint', () => {
+    cy.get('div[data-test-id="endpointListItem-content-e2e-oci-test"]').should('contain', 'e2e-oci-test')
+    cy.get('div[data-test-id="endpointListItem-content-e2e-oci-test"]').first().click()
     cy.server()
     cy.route({ url: '**/migrations/**', method: 'GET' }).as('migrations')
     cy.route({ url: '**/replicas/**', method: 'GET' }).as('replicas')

+ 0 - 0
private/cypress/integration/migration/7 - Delete e2e Openstack endpoint.js → private/cypress/integration/5 - delete endpoints/Delete Openstack endpoint.js


+ 0 - 0
private/cypress/integration/migration/8 - Delete e2e VmWare endpoint.js → private/cypress/integration/5 - delete endpoints/Delete VmWare endpoint.js


+ 0 - 38
private/cypress/integration/migration/4 - Cancel first running migration.js

@@ -1,38 +0,0 @@
-/*
-Copyright (C) 2018  Cloudbase Solutions SRL
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-// @flow
-
-describe('Cancel a running migration', () => {
-  before(() => {
-    cy.login()
-  })
-
-  beforeEach(() => {
-    Cypress.Cookies.preserveOnce('token', 'projectId')
-  })
-
-  it('Cancels migration', () => {
-    cy.server()
-    cy.route({ url: '**/replicas/**', method: 'GET' }).as('replicas')
-    cy.wait('@replicas')
-    cy.get('a').contains('Migrations').click()
-    cy.get('div[data-test-id="mainListItem-statusPill-RUNNING"]').eq(0).click()
-    cy.get('button').contains('Cancel').click()
-    cy.route({ url: '**/actions', method: 'POST' }).as('cancel')
-    cy.get('button').contains('Yes').click()
-    cy.wait('@cancel')
-    cy.get('div[data-test-id="dcHeader-statusPill-ERROR"]', { timeout: 120000 })
-  })
-})

+ 0 - 37
private/cypress/integration/migration/6 - Delete first migration.js

@@ -1,37 +0,0 @@
-/*
-Copyright (C) 2018  Cloudbase Solutions SRL
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-// @flow
-
-describe('Delete the first migration', () => {
-  before(() => {
-    cy.login()
-  })
-
-  beforeEach(() => {
-    Cypress.Cookies.preserveOnce('token', 'projectId')
-  })
-
-  it('Deletes migration', () => {
-    cy.server()
-    cy.route({ url: '**/replicas/**', method: 'GET' }).as('replicas')
-    cy.wait('@replicas')
-    cy.get('a').contains('Migrations').click()
-    cy.get('div[data-test-id="mainListItem-content"]').first().click()
-    cy.get('button').last().should('contain', 'Delete Migration').click()
-    cy.route({ url: '**/migrations/**', method: 'DELETE' }).as('delete')
-    cy.get('button').contains('Yes').click()
-    cy.wait('@delete')
-  })
-})

+ 0 - 38
private/cypress/integration/replica/4 - Cancel first running replica.js

@@ -1,38 +0,0 @@
-/*
-Copyright (C) 2018  Cloudbase Solutions SRL
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-// @flow
-
-describe('Cancel a running replica', () => {
-  before(() => {
-    cy.login()
-  })
-
-  beforeEach(() => {
-    Cypress.Cookies.preserveOnce('token', 'projectId')
-  })
-
-  it('Cancels replica execution', () => {
-    cy.server()
-    cy.route({ url: '**/executions/detail', method: 'GET' }).as('execution')
-    cy.get('div[data-test-id="mainListItem-statusPill-RUNNING"]').eq(0).click()
-    cy.wait('@execution')
-    cy.get('a').contains('Executions').click()
-    cy.get('button').contains('Cancel Execution').click()
-    cy.route({ url: '**/actions', method: 'POST' }).as('cancel')
-    cy.get('button').contains('Yes').click()
-    cy.wait('@cancel')
-    cy.get('div[data-test-id="dcHeader-statusPill-ERROR"]', { timeout: 120000 })
-  })
-})

+ 0 - 32
private/cypress/integration/replica/5 - Cannot delete used endpoint.js

@@ -1,32 +0,0 @@
-/*
-Copyright (C) 2018  Cloudbase Solutions SRL
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-// @flow
-
-describe('Cannot delete used endpoint', () => {
-  before(() => {
-    cy.login()
-  })
-
-  beforeEach(() => {
-    Cypress.Cookies.preserveOnce('token', 'projectId')
-  })
-
-  it('Should show in usage message when trying to delete', () => {
-    cy.get('div').contains('Cloud Endpoints').first().click()
-    cy.get('div[data-test-id="endpointListItem-content-e2e-azure-test"]').first().click()
-    cy.get('button').contains('Delete Endpoint').click()
-    cy.get('div[data-test-id="alertModal"]').should('contain', 'The endpoint can\'t be deleted because it is in use by replicas or migrations.')
-  })
-})

+ 2 - 1
src/components/molecules/EndpointField/EndpointField.jsx

@@ -108,10 +108,11 @@ class Field extends React.Component<Props> {
   renderTextArea() {
     return (
       <TextArea
+        data-test-id={`endpointField-textArea-${this.props.name}`}
         style={{ width: '100%' }}
         highlight={this.props.highlight}
         value={this.props.value}
-        onChange={e => { if (this.props.onChange) this.props.onChange(e.target.value) }}
+        onChange={e => { console.log('changing', e); if (this.props.onChange) this.props.onChange(e.target.value) }}
         placeholder={LabelDictionary.get(this.props.name)}
         disabled={this.props.disabled}
       />

+ 2 - 1
src/components/molecules/EndpointListItem/EndpointListItem.jsx

@@ -27,7 +27,7 @@ import DateUtils from '../../../utils/DateUtils'
 
 import endpointImage from './images/endpoint.svg'
 
-const CheckboxStyled = styled(Checkbox) `
+const CheckboxStyled = styled(Checkbox)`
   opacity: ${props => props.checked ? 1 : 0};
   transition: all ${StyleProps.animations.swift};
 `
@@ -106,6 +106,7 @@ class EndpointListItem extends React.Component<Props> {
     return (
       <Wrapper>
         <CheckboxStyled
+          data-test-id={`endpointListItem-checkbox-${this.props.item.name}`}
           checked={this.props.selected}
           onChange={this.props.onSelectedChange}
         />

+ 150 - 45
yarn.lock

@@ -11,10 +11,11 @@
     date-fns "^1.27.2"
     figures "^1.7.0"
 
-"@cypress/xvfb@1.1.3":
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/@cypress/xvfb/-/xvfb-1.1.3.tgz#6294a7d1feb751f12302248f2089fc534c4acb7f"
+"@cypress/xvfb@1.2.3":
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/@cypress/xvfb/-/xvfb-1.2.3.tgz#6319afdcdcff7d1505daeeaa84484d0596189860"
   dependencies:
+    debug "^3.1.0"
     lodash.once "^4.1.1"
 
 "@hypnosphi/fuse.js@^3.0.9":
@@ -171,8 +172,8 @@
     "@types/jquery" "*"
 
 "@types/chai@*":
-  version "4.1.2"
-  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.2.tgz#f1af664769cfb50af805431c407425ed619daa21"
+  version "4.1.4"
+  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.4.tgz#5ca073b330d90b4066d6ce18f60d57f2084ce8ca"
 
 "@types/chai@4.0.8":
   version "4.0.8"
@@ -189,8 +190,8 @@
   resolved "https://registry.yarnpkg.com/@types/inline-style-prefixer/-/inline-style-prefixer-3.0.1.tgz#8541e636b029124b747952e9a28848286d2b5bf6"
 
 "@types/jquery@*":
-  version "3.3.1"
-  resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.1.tgz#55758d44d422756d6329cbf54e6d41931d7ba28f"
+  version "3.3.3"
+  resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.3.tgz#8d1dc5a11be6e22b14d36536d306d34b6ac8de41"
 
 "@types/jquery@3.2.16":
   version "3.2.16"
@@ -235,8 +236,8 @@
     "@types/sinon" "*"
 
 "@types/sinon@*":
-  version "4.3.0"
-  resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-4.3.0.tgz#7f53915994a00ccea24f4e0c24709822ed11a3b1"
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-5.0.1.tgz#a15b36ec42f1f53166617491feabd1734cb03e21"
 
 "@types/sinon@4.0.0":
   version "4.0.0"
@@ -631,7 +632,11 @@ aws-sign2@~0.7.0:
   version "0.7.0"
   resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
 
-aws4@^1.2.1, aws4@^1.6.0:
+aws4@^1.2.1:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289"
+
+aws4@^1.6.0:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
 
@@ -1973,6 +1978,12 @@ bytes@3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
 
+cachedir@1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-1.2.0.tgz#e9a0a25bb21a2b7a0f766f07c41eb7a311919b97"
+  dependencies:
+    os-homedir "^1.0.1"
+
 caller-path@^0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
@@ -2052,13 +2063,13 @@ chainsaw@~0.1.0:
   dependencies:
     traverse ">=0.3.0 <0.4"
 
-chalk@2.1.0, chalk@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e"
+chalk@2.4.1:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
   dependencies:
-    ansi-styles "^3.1.0"
+    ansi-styles "^3.2.1"
     escape-string-regexp "^1.0.5"
-    supports-color "^4.0.0"
+    supports-color "^5.3.0"
 
 chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
   version "1.1.3"
@@ -2070,6 +2081,14 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
     strip-ansi "^3.0.0"
     supports-color "^2.0.0"
 
+chalk@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e"
+  dependencies:
+    ansi-styles "^3.1.0"
+    escape-string-regexp "^1.0.5"
+    supports-color "^4.0.0"
+
 chalk@^2.0.1, chalk@^2.3.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba"
@@ -2121,8 +2140,8 @@ chokidar@^1.7.0:
     fsevents "^1.0.0"
 
 ci-info@^1.0.0:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.1.tgz#47b44df118c48d2597b56d342e7e25791060171a"
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2"
 
 cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
   version "1.0.4"
@@ -2219,10 +2238,14 @@ color-convert@^1.3.0:
     color-name "^1.1.1"
 
 color-convert@^1.9.0:
-  version "1.9.1"
-  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed"
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147"
   dependencies:
-    color-name "^1.1.1"
+    color-name "1.1.1"
+
+color-name@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689"
 
 color-name@^1.0.0, color-name@^1.1.1:
   version "1.1.3"
@@ -2263,8 +2286,8 @@ colors@~1.1.2:
   resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
 
 combined-stream@^1.0.5, combined-stream@~1.0.5:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
   dependencies:
     delayed-stream "~1.0.0"
 
@@ -2366,14 +2389,18 @@ core-js@^1.0.0:
   version "1.2.7"
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
 
-core-js@^2.4.0, core-js@^2.5.0:
-  version "2.5.5"
-  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.5.tgz#b14dde936c640c0579a6b50cabcc132dd6127e3b"
+core-js@^2.4.0:
+  version "2.5.7"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
 
 core-js@^2.4.1, core-js@^2.5.1:
   version "2.5.1"
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b"
 
+core-js@^2.5.0:
+  version "2.5.5"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.5.tgz#b14dde936c640c0579a6b50cabcc132dd6127e3b"
+
 core-util-is@1.0.2, core-util-is@~1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -2620,12 +2647,12 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
   dependencies:
     cssom "0.3.x"
 
-cypress@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/cypress/-/cypress-2.1.0.tgz#a8bd7d9b89c38a1e380db83b57d9bba0dbb95ba4"
+cypress@3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.0.1.tgz#6a8938ce8a551e4ae1bd5fb2ceab038d4ad39c4d"
   dependencies:
     "@cypress/listr-verbose-renderer" "0.4.1"
-    "@cypress/xvfb" "1.1.3"
+    "@cypress/xvfb" "1.2.3"
     "@types/blob-util" "1.3.3"
     "@types/bluebird" "3.5.18"
     "@types/chai" "4.0.8"
@@ -2637,11 +2664,13 @@ cypress@^2.1.0:
     "@types/sinon" "4.0.0"
     "@types/sinon-chai" "2.7.29"
     bluebird "3.5.0"
-    chalk "2.1.0"
+    cachedir "1.2.0"
+    chalk "2.4.1"
     check-more-types "2.24.0"
     commander "2.11.0"
     common-tags "1.4.0"
     debug "3.1.0"
+    executable "4.1.1"
     extract-zip "1.6.6"
     fs-extra "4.0.1"
     getos "2.8.4"
@@ -2651,6 +2680,7 @@ cypress@^2.1.0:
     lazy-ass "1.6.0"
     listr "0.12.0"
     lodash "4.17.4"
+    log-symbols "2.2.0"
     minimist "1.2.0"
     progress "1.1.8"
     ramda "0.24.1"
@@ -3337,6 +3367,12 @@ execa@^0.7.0:
     signal-exit "^3.0.0"
     strip-eof "^1.0.0"
 
+executable@4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c"
+  dependencies:
+    pify "^2.2.0"
+
 exenv@^1.2.0, exenv@^1.2.1:
   version "1.2.2"
   resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
@@ -3465,10 +3501,14 @@ extract-zip@1.6.6:
     mkdirp "0.5.0"
     yauzl "2.4.1"
 
-extsprintf@1.3.0, extsprintf@^1.2.0:
+extsprintf@1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
 
+extsprintf@^1.2.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
+
 fast-deep-equal@^1.0.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
@@ -4438,8 +4478,8 @@ is-path-in-cwd@^1.0.0:
     is-path-inside "^1.0.0"
 
 is-path-inside@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f"
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
   dependencies:
     path-is-inside "^1.0.1"
 
@@ -5252,7 +5292,7 @@ lodash.words@^3.0.0:
   dependencies:
     lodash._root "^3.0.0"
 
-lodash@4.17.4, lodash@4.x.x, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1:
+lodash@4.17.4, lodash@4.x.x, lodash@^4.15.0, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1:
   version "4.17.4"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
 
@@ -5260,6 +5300,16 @@ lodash@^3.10.1:
   version "3.10.1"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
 
+lodash@^4.14.0:
+  version "4.17.10"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
+
+log-symbols@2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
+  dependencies:
+    chalk "^2.0.1"
+
 log-symbols@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
@@ -5411,7 +5461,17 @@ mime-db@~1.30.0:
   version "1.30.0"
   resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01"
 
-mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.7:
+mime-db@~1.33.0:
+  version "1.33.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+  version "2.1.18"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
+  dependencies:
+    mime-db "~1.33.0"
+
+mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17:
   version "2.1.17"
   resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a"
   dependencies:
@@ -6046,7 +6106,7 @@ performance-now@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
 
-pify@^2.0.0, pify@^2.3.0:
+pify@^2.0.0, pify@^2.2.0, pify@^2.3.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
 
@@ -6417,6 +6477,10 @@ process-nextick-args@~1.0.6:
   version "1.0.7"
   resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
 
+process-nextick-args@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
+
 process@^0.11.0, process@^0.11.1:
   version "0.11.10"
   resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
@@ -6865,7 +6929,7 @@ readable-stream@1.0, readable-stream@~1.0.31:
     isarray "0.0.1"
     string_decoder "~0.10.x"
 
-readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.6:
+readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.6:
   version "2.3.3"
   resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c"
   dependencies:
@@ -6877,6 +6941,18 @@ readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable
     string_decoder "~1.0.3"
     util-deprecate "~1.0.1"
 
+readable-stream@^2.2.2:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.3"
+    isarray "~1.0.0"
+    process-nextick-args "~2.0.0"
+    safe-buffer "~5.1.1"
+    string_decoder "~1.1.1"
+    util-deprecate "~1.0.1"
+
 readable-stream@~2.1.5:
   version "2.1.5"
   resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0"
@@ -7194,15 +7270,23 @@ rx-lite@*, rx-lite@^4.0.8:
   resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
 
 rxjs@^5.0.0-beta.11:
-  version "5.5.7"
-  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.7.tgz#afb3d1642b069b2fbf203903d6501d1acb4cda27"
+  version "5.5.11"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.11.tgz#f733027ca43e3bec6b994473be4ab98ad43ced87"
   dependencies:
     symbol-observable "1.0.1"
 
-safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+safe-buffer@5.1.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1:
   version "5.1.1"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
 
+safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+
+safer-buffer@^2.0.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+
 samsam@1.x:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50"
@@ -7448,13 +7532,14 @@ sprintf-js@~1.0.2:
   resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
 
 sshpk@^1.7.0:
-  version "1.13.1"
-  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3"
+  version "1.14.2"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98"
   dependencies:
     asn1 "~0.2.3"
     assert-plus "^1.0.0"
     dashdash "^1.12.0"
     getpass "^0.1.1"
+    safer-buffer "^2.0.2"
   optionalDependencies:
     bcrypt-pbkdf "^1.0.0"
     ecc-jsbn "~0.1.1"
@@ -7542,7 +7627,17 @@ string_decoder@~1.0.3:
   dependencies:
     safe-buffer "~5.1.0"
 
-stringstream@~0.0.4, stringstream@~0.0.5:
+string_decoder@~1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+  dependencies:
+    safe-buffer "~5.1.0"
+
+stringstream@~0.0.4:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72"
+
+stringstream@~0.0.5:
   version "0.0.5"
   resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
 
@@ -7805,12 +7900,18 @@ toposort@^1.0.0:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.6.tgz#c31748e55d210effc00fdcdc7d6e68d7d7bb9cec"
 
-tough-cookie@^2.3.2, tough-cookie@~2.3.0, tough-cookie@~2.3.3:
+tough-cookie@^2.3.2, tough-cookie@~2.3.3:
   version "2.3.3"
   resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561"
   dependencies:
     punycode "^1.4.1"
 
+tough-cookie@~2.3.0:
+  version "2.3.4"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
+  dependencies:
+    punycode "^1.4.1"
+
 tr46@~0.0.3:
   version "0.0.3"
   resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
@@ -8016,7 +8117,11 @@ utils-merge@1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
 
-uuid@^3.0.0, uuid@^3.1.0:
+uuid@^3.0.0:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
+
+uuid@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"