mirror of
https://github.com/cypress-io/cypress.git
synced 2026-04-24 07:59:12 -05:00
929cac807a
* move snapshot-controls to shared package * share visit-failure component * share blank-contents * share message component * move message styling to shared * stub scss in unit tests * remove whitespace * make dup files match * share selector playground * share script error * share automation-disconnected * remove old file * share no-automation * share error messages * share errors * make iframe model files similar * share iframe-model * share selector playground * share style * share highlight in selector playground * share dom file * update import * share aut-iframe * wip: shared event manager * remove CT event manager * move studio to shared runner package * fix tests * use shared event manager in CT runner * comment back in code * rename viewporth width/height to width/height * fix ts errors * share viewport info * share header * revert changed test * remove old code * fix tests and move test to shared package * move tests to shared package * make container files similar * share container in runner * share container * move test * move spec * update tsconfig] * update headeR * fix styling * style * refactor * refactor * reduce public modules * Update packages/runner-shared/src/event-manager.js Co-authored-by: Zach Bloomquist <github@chary.us> * fix percy regression * fix regression in style * improve types, try reverting style * add runner-shared tests to pipeline Co-authored-by: Zach Bloomquist <github@chary.us> Co-authored-by: Barthélémy Ledoux <bart@cypress.io>
321 lines
11 KiB
React
321 lines
11 KiB
React
import _ from 'lodash'
|
|
import React from 'react'
|
|
import { mount, shallow } from 'enzyme'
|
|
import sinon from 'sinon'
|
|
import driver from '@packages/driver'
|
|
import Tooltip from '@cypress/react-tooltip'
|
|
|
|
import { eventManager } from '../event-manager'
|
|
import { Studio, studioRecorder } from '../studio'
|
|
import { selectorPlaygroundModel } from '../selector-playground'
|
|
import { Header } from '.'
|
|
|
|
const getState = (props) => _.extend({
|
|
defaults: {},
|
|
updateWindowDimensions: sinon.spy(),
|
|
}, props)
|
|
|
|
const propsWithState = (stateProps, configProps = {}) =>
|
|
({
|
|
state: getState(stateProps),
|
|
config: configProps,
|
|
runner: 'e2e',
|
|
})
|
|
|
|
describe('<Header />', () => {
|
|
beforeEach(() => {
|
|
driver.$.returns({ outerHeight: () => 42 })
|
|
|
|
sinon.stub(eventManager, 'emit')
|
|
|
|
sinon.stub(studioRecorder, 'removeListeners')
|
|
sinon.stub(studioRecorder, 'visitUrl')
|
|
})
|
|
|
|
afterEach(() => {
|
|
studioRecorder.cancel()
|
|
|
|
sinon.restore()
|
|
})
|
|
|
|
it('has showing-selector-playground class if selector playground is open', () => {
|
|
selectorPlaygroundModel.isOpen = true
|
|
expect(shallow(<Header {...propsWithState()} />)).to.have.className('showing-selector-playground')
|
|
})
|
|
|
|
it('does not showing-selector-playground class if selector playground is disabled', () => {
|
|
selectorPlaygroundModel.isOpen = false
|
|
expect(shallow(<Header {...propsWithState()} />)).not.to.have.className('showing-selector-playground')
|
|
})
|
|
|
|
describe('selector playground button', () => {
|
|
it('is disabled if tests are loading', () => {
|
|
const component = shallow(<Header {...propsWithState({ isLoading: true })} />)
|
|
|
|
expect(component.find('.selector-playground-toggle')).to.have.prop('disabled', true)
|
|
})
|
|
|
|
it('is disabled if tests are running', () => {
|
|
const component = shallow(<Header {...propsWithState({ isRunning: true })} />)
|
|
|
|
expect(component.find('.selector-playground-toggle')).to.have.prop('disabled', true)
|
|
})
|
|
|
|
it('is disabled if studio is loading', () => {
|
|
studioRecorder.isLoading = true
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find('.selector-playground-toggle')).to.have.prop('disabled', true)
|
|
})
|
|
|
|
it('is disabled if studio is active', () => {
|
|
studioRecorder.isActive = true
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find('.selector-playground-toggle')).to.have.prop('disabled', true)
|
|
})
|
|
|
|
it('toggles the selector playground on click', () => {
|
|
selectorPlaygroundModel.toggleOpen = sinon.spy()
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
component.find('.selector-playground-toggle').simulate('click')
|
|
expect(selectorPlaygroundModel.toggleOpen).to.be.called
|
|
})
|
|
|
|
it('updates window dimensions after selector playground is toggled', () => {
|
|
selectorPlaygroundModel.isOpen = false
|
|
const props = propsWithState()
|
|
|
|
mount(<Header {...props} />)
|
|
selectorPlaygroundModel.isOpen = true
|
|
expect(props.state.updateWindowDimensions).to.be.calledWith({ headerHeight: 42 })
|
|
})
|
|
|
|
it('does not show tooltip if selector playground is open', () => {
|
|
selectorPlaygroundModel.isOpen = true
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find(Tooltip)).to.have.prop('visible', false)
|
|
})
|
|
|
|
it('does not show tooltip if studio is loading', () => {
|
|
studioRecorder.isLoading = true
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find(Tooltip)).to.have.prop('visible', false)
|
|
})
|
|
|
|
it('does not show tooltip if studio is active', () => {
|
|
studioRecorder.isActive = true
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find(Tooltip)).to.have.prop('visible', false)
|
|
})
|
|
|
|
it('uses default tooltip visibility if selector playground is closed', () => {
|
|
selectorPlaygroundModel.isOpen = false
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find(Tooltip)).to.have.prop('visible', null)
|
|
})
|
|
})
|
|
|
|
describe('studio component', () => {
|
|
it('is hidden by default', () => {
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find('header')).not.to.have.className('showing-studio')
|
|
})
|
|
|
|
it('is visible when studio is loading', () => {
|
|
studioRecorder.isLoading = true
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find('header')).to.have.className('showing-studio')
|
|
})
|
|
|
|
it('is visible when studio is active', () => {
|
|
studioRecorder.isActive = true
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find('header')).to.have.className('showing-studio')
|
|
})
|
|
|
|
it('sets hasUrl to false when there is not a url in state', () => {
|
|
const component = shallow(<Header {...propsWithState({ url: '' })} />)
|
|
|
|
expect(component.find(Studio)).to.have.prop('hasUrl', false)
|
|
})
|
|
|
|
it('sets hasUrl to true when there is a url in state', () => {
|
|
const component = shallow(<Header {...propsWithState({ url: 'the://url' })} />)
|
|
|
|
expect(component.find(Studio)).to.have.prop('hasUrl', true)
|
|
})
|
|
})
|
|
|
|
describe('url', () => {
|
|
it('has loading class when loading url', () => {
|
|
const component = shallow(<Header {...propsWithState({ isLoadingUrl: true })} />)
|
|
|
|
expect(component.find('.url-container')).to.have.className('loading')
|
|
})
|
|
|
|
it('has highlighted class when url is highlighted', () => {
|
|
const component = shallow(<Header {...propsWithState({ highlightUrl: true })} />)
|
|
|
|
expect(component.find('.url-container')).to.have.className('highlighted')
|
|
})
|
|
|
|
it('displays url', () => {
|
|
const component = shallow(<Header {...propsWithState({ url: 'the://url' })} />)
|
|
|
|
expect(component.find('.url')).to.have.value('the://url')
|
|
})
|
|
|
|
it('opens url when clicked', () => {
|
|
sinon.stub(window, 'open')
|
|
const component = shallow(<Header {...propsWithState({ url: 'the://url' })} />)
|
|
|
|
component.find('.url').simulate('click')
|
|
expect(window.open).to.be.calledWith('the://url')
|
|
})
|
|
|
|
it('input is read only by default', () => {
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find('.url')).to.have.prop('readOnly', true)
|
|
})
|
|
|
|
it('does not display popup menu by default', () => {
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find('.url-container')).not.to.have.className('menu-open')
|
|
})
|
|
|
|
it('does not display menu cover by default', () => {
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find('.menu-cover')).not.to.have.className('menu-cover-display')
|
|
})
|
|
|
|
context('studio input', () => {
|
|
beforeEach(() => {
|
|
studioRecorder.isActive = true
|
|
})
|
|
|
|
it('input is active when studio is active and has no url', () => {
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find('.url')).to.have.prop('readOnly', false)
|
|
})
|
|
|
|
it('displays popup menu when studio is active and has no url', () => {
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find('.url-container')).to.have.className('menu-open')
|
|
})
|
|
|
|
it('displays menu cover when studio is active and has no url', () => {
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find('.menu-cover')).to.have.className('menu-cover-display')
|
|
})
|
|
|
|
it('is prefilled with the baseUrl', () => {
|
|
const component = shallow(<Header {...propsWithState({}, { baseUrl: 'the://url' })} />)
|
|
|
|
expect(component.find('.url')).to.have.prop('value', 'the://url/')
|
|
})
|
|
|
|
it('updates when typed into', () => {
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
component.find('.url').simulate('change', { target: { value: 'the://url' } })
|
|
|
|
expect(component.find('.url')).to.have.prop('value', 'the://url')
|
|
})
|
|
|
|
it('emits studio:cancel when cancel button is clicked', () => {
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
component.find('.btn-cancel').simulate('click')
|
|
|
|
expect(eventManager.emit).to.be.calledWith('studio:cancel')
|
|
})
|
|
|
|
it('disables submit button when there is no input', () => {
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
expect(component.find('.btn-submit')).to.have.prop('disabled', true)
|
|
})
|
|
|
|
it('does not disable submit button when there is a base url but no input', () => {
|
|
const component = shallow(<Header {...propsWithState({}, { baseUrl: 'the://url' })} />)
|
|
|
|
expect(component.find('.btn-submit')).to.have.prop('disabled', false)
|
|
})
|
|
|
|
it('does not disable submit button after user input', () => {
|
|
const component = shallow(<Header {...propsWithState()} />)
|
|
|
|
component.find('.url').simulate('change', { target: { value: 'the://url' } })
|
|
|
|
expect(component.find('.btn-submit')).to.have.prop('disabled', false)
|
|
})
|
|
|
|
it('visits fully formed http url on submit', () => {
|
|
const component = mount(<Header {...propsWithState()} />)
|
|
|
|
component.find('.url').simulate('change', { target: { value: 'http://cypress.io' } })
|
|
component.find('.url-container').simulate('submit')
|
|
|
|
expect(studioRecorder.visitUrl).to.be.calledWith('http://cypress.io')
|
|
})
|
|
|
|
it('visits fully formed https url on submit', () => {
|
|
const component = mount(<Header {...propsWithState()} />)
|
|
|
|
component.find('.url').simulate('change', { target: { value: 'https://cypress.io' } })
|
|
component.find('.url-container').simulate('submit')
|
|
|
|
expect(studioRecorder.visitUrl).to.be.calledWith('https://cypress.io')
|
|
})
|
|
|
|
it('resets url input after submit', () => {
|
|
const component = mount(<Header {...propsWithState()} />)
|
|
|
|
component.find('.url').simulate('change', { target: { value: 'cypress.io' } })
|
|
component.find('.url-container').simulate('submit')
|
|
|
|
expect(component.find('.url')).to.have.prop('value', '')
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('viewport info', () => {
|
|
it('has menu-open class on button click', () => {
|
|
const component = mount(<Header {...propsWithState()} />)
|
|
|
|
component.find('.viewport-info button').simulate('click')
|
|
expect(component.find('.viewport-info')).to.have.className('menu-open')
|
|
})
|
|
|
|
it('displays width, height, and display scale', () => {
|
|
const state = { width: 1, height: 2, displayScale: 3 }
|
|
const component = mount(<Header {...propsWithState(state)} />)
|
|
|
|
expect(component.find('.viewport-info button').text()).to.contain('1 x 2 (3%)')
|
|
})
|
|
|
|
it('displays default width and height in menu', () => {
|
|
const state = { defaults: { width: 4, height: 5 } }
|
|
const component = mount(<Header {...propsWithState(state)} />)
|
|
|
|
expect(component.find('.viewport-menu pre').text()).to.contain('"viewportWidth": 4')
|
|
expect(component.find('.viewport-menu pre').text()).to.contain('"viewportHeight": 5')
|
|
})
|
|
})
|
|
})
|