UNPKG

@revoloo/cypress6

Version:

Cypress.io end to end testing tool

238 lines (205 loc) 7.17 kB
import _ from 'lodash' import cs from 'classnames' import { action, observable } from 'mobx' import { observer } from 'mobx-react' import React, { Component } from 'react' import Tooltip from '@cypress/react-tooltip' import eventManager from '../lib/event-manager' const defaultCopyText = 'Copy to clipboard' const defaultPrintText = 'Print to console' // mouseleave fires when entering a child element, so make sure we're // actually leaving the button and not just hovering over a child const fixMouseOut = (fn, getTarget) => (e) => { if ( !e.relatedTarget || e.relatedTarget.parentNode === getTarget() || e.relatedTarget === getTarget() ) return fn(e) } @observer class SelectorPlayground extends Component { @observable copyText = defaultCopyText @observable printText = defaultPrintText @observable showingMethodPicker = false render () { const { model } = this.props const selectorText = `cy.${model.method}('${model.selector}')` return ( <div className={cs('header-popup selector-playground', `method-${model.method}`, { 'no-elements': !model.numElements, 'invalid-selector': !model.isValid, })}> <div className='selector'> <Tooltip title='Click an element to see a suggested selector' className='cy-tooltip' > <button className={`highlight-toggle ${model.isEnabled ? 'active' : ''}`} onClick={this._toggleEnablingSelectorPlayground}> <span className='fa-stack'> <i className='far fa-square fa-stack-1x'></i> <i className='fas fa-mouse-pointer fa-stack-1x'></i> </span> </button> </Tooltip> <div className='wrap' onMouseOver={this._setHighlight(true)} > {this._methodSelector()} <span>(</span> <span>{'\''}</span> <div className='selector-input'> <input ref={(node) => this._input = node} name={`${model.isEnabled}` /* fixes issue with not resizing when opening/closing selector playground */} value={model.selector} onChange={this._updateSelector} onFocus={this._setHighlight(true)} /> </div> <span>{'\''}</span> <span>)</span> <input ref='copyText' className='copy-backer' value={selectorText} readOnly /> <Tooltip title={model.infoHelp || ''} className='cy-tooltip'> <span className='info num-elements'> {model.isValid ? model.numElements : <i className='fas fa-exclamation-triangle'></i> } </span> </Tooltip> </div> <Tooltip title={this.copyText || ''} updateCue={`${selectorText}${this.copyText}`} className='cy-tooltip'> <button ref={(node) => this._copyButton = node} className='copy-to-clipboard' onClick={this._copyToClipboard} disabled={!model.numElements || !model.isValid} onMouseOut={fixMouseOut(this._resetCopyText, () => this._copyButton)} > <i className='far fa-copy' /> </button> </Tooltip> <Tooltip title={this.printText || ''} updateCue={`${selectorText}${this.printText}`} className='cy-tooltip'> <button ref={(node) => this._printButton = node} className='print-to-console' onClick={this._printToConsole} disabled={!model.numElements || !model.isValid} onMouseOut={fixMouseOut(this._resetPrintText, () => this._printButton)} > <i className='fas fa-terminal' /> </button> </Tooltip> </div> <a className='selector-info' href='https://on.cypress.io/selector-playground' target="_blank"> <i className='fas fa-question-circle'></i>{' '} Learn more </a> <button className='close' onClick={this._togglePlaygroundOpen}>x</button> </div> ) } componentDidMount () { this._previousIsEnabled = this.props.model.isEnabled this._previousMethod = this.props.model.method document.body.addEventListener('click', this._onOutsideClick, false) } componentDidUpdate () { if ( (this.props.model.isEnabled !== this._previousIsEnabled) || (this.props.model.method !== this._previousMethod) ) { if (this.props.model.isEnabled) { this._focusAndSelectInputText() } this._previousIsEnabled = this.props.model.isEnabled this._previousMethod = this.props.model.method } } componentWillUnmount () { document.body.removeEventListener('click', this._onOutsideClick) } _methodSelector () { const { model } = this.props const methods = _.filter(model.methods, (method) => method !== model.method) return ( <span className={cs('method', { 'is-showing': this.showingMethodPicker, })}> <button onClick={this._toggleMethodPicker}> <i className='fas fa-caret-down'></i>{' '} cy.{model.method} </button> <div className='method-picker'> {_.map(methods, (method) => ( <div key={method} onClick={() => this._setMethod(method)}> cy.{method} </div> ))} </div> </span> ) } _focusAndSelectInputText () { this._input.focus() this._input.select() } _onOutsideClick = () => { this._setShowingMethodPicker(false) } _toggleMethodPicker = () => { this._setShowingMethodPicker(!this.showingMethodPicker) } @action _setShowingMethodPicker (isShowing) { this.showingMethodPicker = isShowing } @action _setMethod (method) { if (method !== this.props.model.method) { this.props.model.setMethod(method) } } _setHighlight = (isShowing) => () => { this.props.model.setShowingHighlight(isShowing) } _copyToClipboard = () => { try { this.refs.copyText.select() const successful = document.execCommand('copy') this._setCopyText(successful ? 'Copied!' : 'Oops, unable to copy') } catch (err) { this._setCopyText('Oops, unable to copy') } } @action _setCopyText (text) { this.copyText = text } _resetCopyText = () => { this._setCopyText(defaultCopyText) } _printToConsole = () => { eventManager.emit('print:selector:elements:to:console') this._setPrintText('Printed!') } @action _setPrintText (text) { this.printText = text } _resetPrintText = () => { this._setPrintText(defaultPrintText) } _toggleEnablingSelectorPlayground = () => { this.props.model.toggleEnabled() } _togglePlaygroundOpen = () => { this.props.model.toggleOpen() } _updateSelector = (e) => { const { model } = this.props model.setSelector(e.target.value) model.setShowingHighlight(true) } } export default SelectorPlayground