@revoloo/cypress6
Version:
Cypress.io end to end testing tool
979 lines (772 loc) • 33.9 kB
JavaScript
describe('Specs List', function () {
beforeEach(function () {
cy.fixture('user').as('user')
cy.fixture('config').as('config')
cy.fixture('specs_with_components').as('specs')
cy.fixture('specs_windows').as('specsWindows')
cy.visitIndex().then(function (win) {
let start = win.App.start
this.win = win
this.ipc = win.App.ipc
expect(this.specs.integration.length, 'has integration tests').to.be.gt(0)
expect(this.specs.component.length, 'has component tests').to.be.gt(0)
this.numSpecs = this.specs.integration.length + this.specs.component.length
cy.stub(this.ipc, 'getOptions').resolves({ projectRoot: '/foo/bar' })
cy.stub(this.ipc, 'getCurrentUser').resolves(this.user)
cy.stub(this.ipc, 'getSpecs').yields(null, this.specs)
cy.stub(this.ipc, 'getUserEditor').resolves({})
cy.stub(this.ipc, 'closeBrowser').resolves(null)
cy.stub(this.ipc, 'launchBrowser')
cy.stub(this.ipc, 'openFinder')
cy.stub(this.ipc, 'openFile')
cy.stub(this.ipc, 'externalOpen')
cy.stub(this.ipc, 'onboardingClosed')
cy.stub(this.ipc, 'onSpecChanged')
cy.stub(this.ipc, 'setUserEditor')
this.openProject = this.util.deferred()
cy.stub(this.ipc, 'openProject').returns(this.openProject.promise)
start()
})
})
describe('no specs', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, [])
this.openProject.resolve(this.config)
})
it('displays empty message', () => {
cy.contains('No files found')
cy.percySnapshot()
})
it('displays integration test folder path', function () {
cy.contains(this.config.integrationFolder)
})
it('triggers open:finder on click of text folder', function () {
cy.contains(this.config.integrationFolder).click().then(function () {
expect(this.ipc.openFinder).to.be.calledWith(this.config.integrationFolder)
})
})
it('displays help link', () => {
cy.contains('a', 'Need help?')
})
it('opens link to docs on click of help link', () => {
cy.contains('a', 'Need help?').click().then(function () {
expect(this.ipc.externalOpen).to.be.calledWith('https://on.cypress.io/writing-first-test')
})
})
})
describe('integration and component specs', function () {
beforeEach(function () {
cy.fixture('component_specs').as('componentSpecs')
})
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.componentSpecs)
this.openProject.resolve(this.config)
})
it('shows both types of specs', () => {
cy.get('.specs-list li.level-0').should('have.length', 2)
cy.contains('.folder.level-0', 'integration')
cy.contains('.folder.level-0', 'component')
// component specs should be visible
cy.get('.folder').eq(1).find('.file').should('be.visible')
cy.percySnapshot()
// let's check if the specs search works
cy.get('.filter').type('Nav')
cy.get('.file').should('have.length', 1)
cy.contains('.file', 'Navigation.spec.js').should('be.visible')
})
})
describe('first time onboarding specs', function () {
beforeEach(function () {
this.config.isNewProject = true
this.openProject.resolve(this.config)
})
context('modal', () => {
it('displays', () => {
cy.contains('.modal', 'To help you get started').should('be.visible')
cy.percySnapshot()
})
it('displays the scaffolded files', () => {
cy.get('.folder-preview-onboarding').within(function () {
cy.contains('span', 'fixtures').siblings('ul').within(function () {
})
cy.contains('example.json')
cy.contains('span', 'integration').siblings('ul').within(() => {
cy.contains('examples')
})
cy.contains('span', 'support').siblings('ul').within(function () {
cy.contains('commands.js')
cy.contains('defaults.js')
cy.contains('index.js')
})
cy.contains('span', 'plugins').siblings('ul').within(() => {
cy.contains('index.js')
})
})
})
it('lists folders and files alphabetically', () => {
cy.get('.folder-preview-onboarding').within(() => {
cy.contains('fixtures').parent().next()
.contains('integration')
})
})
it('truncates file lists with more than 3 items', () => {
cy.get('.folder-preview-onboarding').within(function () {
cy.contains('examples').closest('.new-item').find('li')
.should('have.length', 3)
cy.get('.is-more').should('have.text', ' ... 17 more files ...')
})
})
it('can dismiss the modal', function () {
cy.contains('OK, got it!').click()
cy.get('.modal').should('not.be.visible')
.then(function () {
expect(this.ipc.onboardingClosed).to.be.called
})
})
it('triggers open:finder on click of example folder', function () {
cy.get('.modal').contains('examples').click().then(() => {
expect(this.ipc.openFinder).to.be.calledWith(this.config.integrationExamplePath)
})
})
it('triggers open:finder on click of text folder', function () {
cy.get('.modal').contains('cypress/integration').click().then(() => {
expect(this.ipc.openFinder).to.be.calledWith(this.config.integrationFolder)
})
})
})
context('banner', function () {
beforeEach(function () {
cy.contains('.modal', 'OK, got it!').click()
})
it('displays', function () {
cy.get('.first-test-banner')
cy.percySnapshot()
})
it('is dismissable', function () {
cy.get('.first-test-banner').find('.close').click()
cy.get('.first-test-banner').should('not.exist')
})
it('opens link to docs on click of help link', function () {
cy.contains('a', 'How to write tests').click().then(function () {
expect(this.ipc.externalOpen).to.be.calledWith('https://on.cypress.io/writing-first-test')
})
})
})
})
describe('lists specs', function () {
context('Windows paths', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.specsWindows)
this.openProject.resolve(this.config)
})
context('displays list of specs', function () {
it('lists nested folders', () => {
cy.get('.folder .folder').contains('accounts')
})
it('lists test specs', function () {
cy.get('.file .file-name-wrapper').last().should('contain', 'last_list_spec.coffee')
cy.get('.file .file-name-wrapper').last().should('not.contain', 'admin_users')
})
})
})
context('Linux paths', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.specs)
this.openProject.resolve(this.config)
})
context('run all specs', function () {
const runAllIntegrationSpecsLabel = 'Run 5 integration specs'
it('displays run all specs button', () => {
cy.contains('.all-tests', runAllIntegrationSpecsLabel)
.should('have.attr', 'title', 'Run integration specs together')
})
it('has play icon', () => {
cy.contains('.all-tests', runAllIntegrationSpecsLabel)
.find('i').should('have.class', 'fa-play')
})
it('triggers browser launch on click of button', () => {
cy.contains('.all-tests', runAllIntegrationSpecsLabel).click()
.find('.fa-dot-circle')
.then(function () {
const launchArgs = this.ipc.launchBrowser.lastCall.args
expect(launchArgs[0].browser.name, 'browser name').to.eq('chrome')
expect(launchArgs[0].spec.name, 'spec name').to.eq('All Integration Specs')
expect(launchArgs[0].specFilter, 'spec filter').to.eq(null)
})
})
describe('all specs running in browser', function () {
beforeEach(() => {
cy.contains('.all-tests', runAllIntegrationSpecsLabel).as('allSpecs').click()
})
it('updates spec icon', function () {
cy.get('@allSpecs').find('i').should('have.class', 'fa-dot-circle')
cy.get('@allSpecs').find('i').should('not.have.class', 'fa-play')
cy.percySnapshot()
})
it('sets spec as active', () => {
cy.get('@allSpecs').should('have.class', 'active')
})
})
})
context('displays list of specs', function () {
it('lists main folders of specs', () => {
cy.get('.folder.level-0').should('have.length', 2)
cy.contains('.folder.level-0', 'integration')
cy.contains('.folder.level-0', 'component')
})
it('lists nested folders', () => {
cy.get('.folder.level-0 .folder.level-1').contains('accounts')
})
it('lists test specs', () => {
cy.get('.folder.level-0 .file.level-1 a').contains('app_spec.coffee')
})
it('lists folder with "."', function () {
cy.get('.file').should('have.length', this.numSpecs)
cy.get('.folder').should('have.length', 10)
})
it('lists files after folders when in same directory', () => {
// 📁 bar
// 📁 foo
// app
cy.get('.list-as-table.integration')
.find('li').first().should('contain', 'accounts')
cy.get('.list-as-table.integration')
.find('li').last().should('contain', 'app_spec')
})
})
context('collapsing specs', function () {
it('sets folder collapsed when clicked with correct icon', () => {
cy.get('.folder:first').should('have.class', 'folder-expanded')
cy.get('.folder-collapse-icon:first').should('have.class', 'fa-caret-down')
cy.get('.folder .folder-name:first').click()
cy.get('.folder-collapse-icon:first').should('have.class', 'fa-caret-right')
cy.get('.folder:first').should('have.class', 'folder-collapsed')
})
it('hides children when folder clicked', function () {
cy.get('.file').should('have.length', this.numSpecs)
cy.get('.folder .folder-name:first').click()
cy.get('.file').should('have.length', 8)
})
it('sets folder expanded when clicked twice', function () {
cy.get('.folder .folder-name:first').click()
cy.get('.folder:first').should('have.class', 'folder-collapsed')
cy.get('.folder .folder-name:first').click()
cy.get('.folder:first').should('have.class', 'folder-expanded')
})
it('hides children for every folder collapsed', function () {
const lastExpandedFolderSelector = '.folder-expanded:last > div > .folder-name:last'
cy.get('.file').should('have.length', this.numSpecs)
cy.get(lastExpandedFolderSelector).click()
cy.get('.file').should('have.length', 7)
cy.get(lastExpandedFolderSelector).click()
cy.get('.file').should('have.length', 7)
cy.get(lastExpandedFolderSelector).click()
cy.get('.file').should('have.length', 5)
cy.get(lastExpandedFolderSelector).click()
cy.get('.file').should('have.length', 5)
cy.get(lastExpandedFolderSelector).click()
cy.get('.file').should('have.length', 5)
cy.get(lastExpandedFolderSelector).click()
cy.get('.file').should('have.length', 5)
cy.get(lastExpandedFolderSelector).click()
cy.get('.file').should('have.length', 4)
cy.get(lastExpandedFolderSelector).click()
cy.get('.file').should('have.length', 3)
cy.get(lastExpandedFolderSelector).click()
cy.get('.file').should('have.length', 1)
cy.get(lastExpandedFolderSelector).click()
cy.get('.file').should('have.length', 0)
})
})
})
context('expand/collapse root specs', function () {
describe('with folders', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.specs)
this.openProject.resolve(this.config)
})
it('collapsing root spec will keep root itself expanded', function () {
cy.get('.level-0 .folder-name').find('a:first').click({ multiple: true })
cy.get('.folder.folder-collapsed').should('have.length', 3)
cy.get('.folder.folder-expanded').should('have.length', 2)
})
it('collapses all children folders', function () {
cy.get('.level-0 .folder-name').find('a:first').click({ multiple: true })
const lastCollapsedFolderSelector = '.folder-collapsed:last .folder-name'
const rootSpecCollapsedFoldersSelector = '.folder-collapsed'
cy.get(lastCollapsedFolderSelector).click()
cy.get(rootSpecCollapsedFoldersSelector).should('have.length', 3)
cy.get(lastCollapsedFolderSelector).click()
cy.get(rootSpecCollapsedFoldersSelector).should('have.length', 3)
cy.get(lastCollapsedFolderSelector).click()
cy.get(rootSpecCollapsedFoldersSelector).should('have.length', 3)
cy.get(lastCollapsedFolderSelector).click()
cy.get(rootSpecCollapsedFoldersSelector).should('have.length', 3)
cy.get(lastCollapsedFolderSelector).click()
cy.get(rootSpecCollapsedFoldersSelector).should('have.length', 2)
cy.get(lastCollapsedFolderSelector).click()
cy.get(rootSpecCollapsedFoldersSelector).should('have.length', 2)
cy.get(lastCollapsedFolderSelector).click()
cy.get(rootSpecCollapsedFoldersSelector).should('have.length', 1)
cy.get(lastCollapsedFolderSelector).click()
cy.get(rootSpecCollapsedFoldersSelector).should('have.length', 0)
})
it('expand all expands all sub folders', function () {
cy.get('.level-0 .folder-name').find('a:first').click({ multiple: true })
cy.get('.folder-expanded').should('have.length', 2)
cy.get('.folder-collapsed').should('have.length', 3)
cy.get('.level-0 .folder-name').find('a:last').click({ multiple: true })
cy.get('.folder-expanded').should('have.length', 10)
cy.get('.folder-collapsed').should('have.length', 0)
})
})
describe('without folders', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, {
integration: [
{
name: 'app_spec.coffee',
relative: 'app_spec.coffee',
},
{
name: 'account_new_spec.coffee',
relative: 'account_new_spec.coffee',
},
],
unit: [],
})
this.openProject.resolve(this.config)
})
it('hides expand/collapse buttons when there are no folders', function () {
cy.get('.level-0 .folder-name a').should('not.exist')
})
})
})
context('filtering specs', function () {
it('scrolls the specs and not the filter', function () {
this.ipc.getSpecs.yields(null, this.specs)
this.openProject.resolve(this.config)
cy.contains('last_list_spec').scrollIntoView()
cy.get('.filter').should('be.visible')
})
describe('typing the filter', function () {
const runAllIntegrationSpecsLabel = 'Run 5 integration specs'
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.specs)
this.openProject.resolve(this.config)
cy.contains('.all-tests', runAllIntegrationSpecsLabel)
cy.get('.filter').type('new')
})
it('displays only matching spec', function () {
cy.get('.specs-list .file')
.should('have.length', 1)
.and('contain', 'account_new_spec.coffee')
cy.contains('.all-tests', 'Run 1 integration spec').click()
.find('.fa-dot-circle')
.then(() => {
expect(this.ipc.launchBrowser).to.have.property('called').equal(true)
const launchArgs = this.ipc.launchBrowser.lastCall.args
expect(launchArgs[0].specFilter, 'spec filter').to.eq('new')
})
})
it('only shows matching folders', () => {
cy.get('.specs-list .folder')
.should('have.length', 2)
})
it('clears the filter on clear button click', function () {
cy.get('.clear-filter').click()
cy.get('.filter')
.should('have.value', '')
cy.get('.specs-list .file')
.should('have.length', this.numSpecs)
cy.contains('.all-tests', runAllIntegrationSpecsLabel)
})
it('clears the filter if the user press ESC key', function () {
cy.get('.filter').type('{esc}')
.should('have.value', '')
cy.get('.specs-list .file')
.should('have.length', this.numSpecs)
cy.contains('.all-tests', runAllIntegrationSpecsLabel)
.find('.fa-play')
})
it('shows empty message if no results', function () {
cy.get('.filter').clear().type('foobarbaz')
cy.get('.specs-list').should('not.exist')
cy.get('.empty-well').should('contain', 'No specs match your search: "foobarbaz"')
cy.percySnapshot()
})
it('removes run all tests buttons if no results', function () {
cy.get('.filter').clear().type('foobarbaz')
// the "Run ... tests" buttons should be gone
cy.get('.all-tests').should('not.exist')
})
it('clears and focuses the filter field when clear search is clicked', function () {
cy.get('.filter').clear().type('foobarbaz')
cy.get('.btn').contains('Clear search').click()
cy.focused().should('have.id', 'filter')
cy.get('.specs-list .file')
.should('have.length', this.numSpecs)
})
it('saves the filter to local storage for the project', function () {
cy.window().then((win) => {
expect(win.localStorage[`specsFilter-${this.config.projectId}-/foo/bar`]).to.be.a('string')
expect(JSON.parse(win.localStorage[`specsFilter-${this.config.projectId}-/foo/bar`])).to.equal('new')
})
})
it('does not update run button label while running', function () {
cy.contains('.all-tests', 'Run 1 integration spec').click()
// mock opened browser and running tests
// to force "Stop" button to show up
cy.window().its('__project').then((project) => {
project.browserOpened()
})
// the button has its its label reflect the running specs
cy.contains('.all-tests', 'Running integration tests')
.should('have.class', 'active')
// the button has its label unchanged while the specs are running
cy.get('.filter').clear()
cy.contains('.all-tests', 'Running integration tests')
.should('have.class', 'active')
// but once the project stops running tests, the button gets updated
cy.get('.close-browser').click()
cy.contains('.all-tests', 'Run 5 integration specs')
.should('not.have.class', 'active')
})
})
describe('when there\'s a saved filter', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.specs)
cy.window().then(function (win) {
win.localStorage[`specsFilter-${this.config.projectId}-/foo/bar`] = JSON.stringify('app')
})
})
it('applies it for the appropriate project', function () {
this.openProject.resolve(this.config)
cy.get('.filter').should('have.value', 'app')
cy.contains('.all-tests', 'Run 1 integration spec')
})
it('does not apply it for a different project', function () {
this.config.projectId = 'different'
this.openProject.resolve(this.config)
cy.get('.filter').should('have.value', '')
})
})
describe('when project has null id', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.specs)
this.config.projectId = null
})
it('saves the filter to local storage', function () {
this.openProject.resolve(this.config)
cy.get('.filter').type('my-filter')
cy.window().then((win) => {
expect(win.localStorage[`specsFilter-<no-id>-/foo/bar`]).to.be.a('string')
expect(JSON.parse(win.localStorage[`specsFilter-<no-id>-/foo/bar`])).to.equal('my-filter')
})
})
it('applies the saved filter when returning to the project', function () {
cy.window().then(function (win) {
win.localStorage[`specsFilter-<no-id>-/foo/bar`] = JSON.stringify('my-filter')
this.openProject.resolve(this.config)
})
cy.get('.filter').should('have.value', 'my-filter')
})
})
})
context('click on spec', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.specs)
this.openProject.resolve(this.config)
cy.contains('.file .file-name-wrapper', 'app_spec.coffee').as('firstSpec')
})
it('closes then launches browser on click of file', () => {
cy.get('@firstSpec')
.click()
.then(function () {
expect(this.ipc.closeBrowser).to.have.property('called', true)
const launchArgs = this.ipc.launchBrowser.lastCall.args
expect(launchArgs[0].browser.name).to.equal('chrome')
expect(launchArgs[0].spec.relative).to.equal('cypress/integration/app_spec.coffee')
})
})
it('adds \'active\' class on click', () => {
cy.get('@firstSpec').parent()
.should('not.have.class', 'active')
cy.get('@firstSpec').click()
.parent()
.should('have.class', 'active')
})
it('shows the running spec label', () => {
cy.get('@firstSpec').click()
cy.contains('.all-tests', 'Running 1 spec')
.find('.fa-dot-circle')
})
it('maintains active selection if specs change', function () {
cy.get('@firstSpec').click().then(() => {
this.ipc.getSpecs.yield(null, this.specs)
})
cy.get('@firstSpec').parent().should('have.class', 'active')
})
})
context('spec running in browser', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.specs)
this.openProject.resolve(this.config)
})
context('choose shallow spec', function () {
beforeEach(() => {
cy.get('.file .file-name-wrapper').contains('a', 'app_spec.coffee').as('firstSpec').click()
})
it('updates spec icon', function () {
cy.get('@firstSpec').find('i').should('have.class', 'fa-dot-circle')
cy.get('@firstSpec').find('i').should('not.have.class', 'fa-file-code')
})
it('sets spec as active', () => {
cy.get('@firstSpec').parent().should('have.class', 'active')
})
})
context('choose deeper nested spec', function () {
beforeEach(() => {
cy.get('.file .file-name-wrapper').contains('a', 'last_list_spec.coffee').as('deepSpec').click()
})
it('updates spec icon', () => {
cy.get('@deepSpec').find('i').should('have.class', 'fa-dot-circle')
})
it('sets spec as active', () => {
cy.get('@deepSpec').parent().should('have.class', 'active')
})
})
})
context('switching specs', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.specs)
this.openProject.resolve(this.config)
cy.get('.file').contains('a', 'app_spec.coffee').as('firstSpec')
.click()
cy.get('.file').contains('a', 'account_new_spec.coffee').as('secondSpec')
.click()
})
it('updates spec icon', function () {
cy.get('@firstSpec').find('i').should('not.have.class', 'fa-dot-circle')
cy.get('@secondSpec').find('i').should('have.class', 'fa-dot-circle')
})
it('updates active spec', function () {
cy.get('@firstSpec').parent().should('not.have.class', 'active')
cy.get('@secondSpec').parent().should('have.class', 'active')
})
})
context('with component tests', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.specs)
this.openProject.resolve(this.config)
})
it('shows separate run specs buttons', function () {
cy.get('.all-tests').should('have.length', 2)
cy.contains('.folder-name', 'integration tests')
.contains('.all-tests', 'Run 5 integration specs')
cy.contains('.folder-name', 'component tests')
.contains('.all-tests', 'Run 8 component specs')
})
it('runs all component tests together', function () {
cy.contains('.all-tests', 'Run 8 component specs').click()
// all other "Run .." buttons should disappear
cy.get('.all-tests').should('have.length', 1)
// and the label changes
cy.contains('.folder-name', 'component tests')
.contains('.all-tests', 'Running component tests').should('be.visible')
.and('have.class', 'active')
})
it('runs single component spec', function () {
cy.contains('bar_list_spec.coffee').click()
.parent()
.should('have.class', 'active')
// all other "Run .." buttons should disappear
cy.get('.all-tests').should('have.length', 1)
// and the label changes
cy.contains('.folder-name', 'component tests')
.contains('.all-tests', 'Running 1 spec').should('be.visible')
// the button does not get the class active, it stays with the file
.and('not.have.class', 'active')
})
it('filters all spec types using filter', function () {
cy.get('.filter').type('fo')
cy.contains('.all-tests', 'Run 1 integration spec')
cy.contains('.all-tests', 'Run 1 component spec')
cy.log('**clearing the search**')
cy.get('.filter').clear()
cy.contains('.all-tests', 'Run 5 integration specs')
cy.contains('.all-tests', 'Run 8 component specs')
})
})
context('returning to specs tab', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.specs)
this.openProject.resolve(this.config)
})
// https://github.com/cypress-io/cypress/issues/9151
it('does not crash when running', function () {
cy.contains('.file-name', 'app_spec.coffee').click()
.then(function () {
this.ipc.onSpecChanged.yield(null, 'integration/app_spec.coffee')
})
cy.contains('.all-tests', 'Running 1 spec')
cy.contains('.project-nav a', 'Settings').click()
cy.get('.settings').should('be.visible')
cy.contains('.project-nav a', 'Tests').click()
// the specs list renders again
cy.contains('.file-name', 'app_spec.coffee')
cy.contains('.all-tests', 'Running 1 spec')
})
})
})
describe('spec list updates', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.specs)
this.openProject.resolve(this.config)
})
it('updates spec list selected on specChanged', function () {
cy.get('.file a')
.contains('a', 'app_spec.coffee').as('firstSpec')
.then(function () {
this.ipc.onSpecChanged.yield(null, 'integration/app_spec.coffee')
})
cy.get('@firstSpec').parent().should('have.class', 'active')
.then(function () {
this.ipc.onSpecChanged.yield(null, 'integration/accounts/account_new_spec.coffee')
})
cy.get('@firstSpec').parent().should('not.have.class', 'active')
cy.contains('a', 'account_new_spec.coffee')
.parent()
.should('have.class', 'active')
})
})
describe('open in IDE', function () {
beforeEach(function () {
this.ipc.getSpecs.yields(null, this.specs)
this.openProject.resolve(this.config)
cy.get('.file').contains('a', 'app_spec.coffee').parent().as('spec')
cy.get('@spec').contains('Open in IDE').as('button')
})
it('does not display button without hover', function () {
cy.contains('Open in IDE').should('not.be.visible')
})
it('displays when spec is hovered over', function () {
cy.get('@spec').realHover()
cy.get('@button').should('be.visible')
// invoke show for snapshot since hover doesn't do it
cy.get('@button').invoke('show')
cy.percySnapshot()
})
it('displays when spec is active and hovered over', function () {
cy.get('@spec').click().should('have.class', 'active')
cy.get('@spec').realHover()
cy.get('@button').should('be.visible')
cy.get('@button').invoke('show')
cy.percySnapshot()
})
describe('opens files', function () {
beforeEach(function () {
this.availableEditors = [
{ id: 'computer', name: 'On Computer', isOther: false, openerId: 'computer' },
{ id: 'atom', name: 'Atom', isOther: false, openerId: 'atom' },
{ id: 'vim', name: 'Vim', isOther: false, openerId: 'vim' },
{ id: 'sublime', name: 'Sublime Text', isOther: false, openerId: 'sublime' },
{ id: 'vscode', name: 'Visual Studio Code', isOther: false, openerId: 'vscode' },
{ id: 'other', name: 'Other', isOther: true, openerId: '' },
]
cy.get('@spec').realHover()
})
context('when user has not already set opener and opens file', function () {
beforeEach(function () {
this.ipc.getUserEditor.resolves({
availableEditors: this.availableEditors,
preferredOpener: this.availableEditors[4],
})
})
it('opens in preferred opener', function () {
cy.get('@button').click()
.then(() => {
expect(this.ipc.openFile).to.be.calledWith({
where: this.availableEditors[4],
file: '/user/project/cypress/integration/app_spec.coffee',
line: 0,
column: 0,
})
})
})
})
context('when user has not already set opener and opens file', function () {
beforeEach(function () {
this.ipc.getUserEditor.resolves({
availableEditors: this.availableEditors,
})
cy.get('@button').click()
})
it('opens modal with available editors', function () {
this.availableEditors.forEach(({ name }) => {
cy.contains(name)
})
cy.contains('Set preference and open file')
cy.percySnapshot()
})
it('closes modal when cancel is clicked', function () {
cy.contains('Cancel').click()
cy.contains('Set preference and open file').should('not.exist')
})
describe('when editor is not selected', function () {
it('disables submit button', function () {
cy.contains('Set preference and open file')
.should('have.class', 'is-disabled')
.click()
.then(function () {
expect(this.ipc.setUserEditor).not.to.be.called
expect(this.ipc.openFile).not.to.be.called
})
})
it('shows validation message when hovering over submit button', function () {
cy.get('.editor-picker-modal .submit').trigger('mouseover')
cy.get('.cy-tooltip').should('have.text', 'Please select a preference')
})
})
describe('when Other is selected but path is not entered', function () {
beforeEach(function () {
cy.contains('Other').click()
})
it('disables submit button', function () {
cy.contains('Set preference and open file')
.should('have.class', 'is-disabled')
.click()
.then(function () {
expect(this.ipc.setUserEditor).not.to.be.called
expect(this.ipc.openFile).not.to.be.called
})
})
it('shows validation message when hovering over submit button', function () {
cy.get('.editor-picker-modal .submit').trigger('mouseover')
cy.get('.cy-tooltip').should('have.text', 'Please enter the path for the "Other" editor')
})
})
describe('when editor is set', function () {
beforeEach(function () {
cy.contains('Visual Studio Code').click()
cy.contains('Set preference and open file').click()
})
it('closes modal', function () {
cy.contains('Set preference and open file').should('not.exist')
})
it('sets user editor', function () {
expect(this.ipc.setUserEditor).to.be.calledWith(this.availableEditors[4])
})
it('opens file in selected editor', function () {
expect(this.ipc.openFile).to.be.calledWith({
where: this.availableEditors[4],
file: '/user/project/cypress/integration/app_spec.coffee',
line: 0,
column: 0,
})
})
})
})
})
})
})