-
Notifications
You must be signed in to change notification settings - Fork 70
feat: retry tests with checkboxes #453
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| 'use strict'; | ||
|
|
||
| module.exports = { | ||
| UNCHECKED: 0, | ||
| INDETERMINATE: 0.5, | ||
| CHECKED: 1 | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import React from 'react'; | ||
| import classNames from 'classnames'; | ||
| import {Checkbox} from 'semantic-ui-react'; | ||
| import PropTypes from 'prop-types'; | ||
| import {isCheckboxChecked, isCheckboxIndeterminate} from '../../common-utils'; | ||
| import {CHECKED, INDETERMINATE, UNCHECKED} from '../../constants/checked-statuses'; | ||
| import useLocalStorage from '../hooks/useLocalStorage'; | ||
|
|
||
| const Bullet = ({status, onClick, className}) => { | ||
| const [isCheckbox] = useLocalStorage('showCheckboxes', false); | ||
|
|
||
| if (!isCheckbox) { | ||
| return <span className={classNames('bullet_type-simple', className)} />; | ||
| } | ||
|
|
||
| return <Checkbox | ||
KuznetsovRoman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| className={classNames('bullet_type-checkbox', className)} | ||
| checked={isCheckboxChecked(status)} | ||
| indeterminate={isCheckboxIndeterminate(status)} | ||
| onClick={onClick} | ||
| />; | ||
| }; | ||
|
|
||
| Bullet.propTypes = { | ||
| status: PropTypes.oneOf([CHECKED, UNCHECKED, INDETERMINATE]), | ||
| onClick: PropTypes.func, | ||
| bulletClassName: PropTypes.string | ||
| }; | ||
|
|
||
| export default Bullet; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,11 +6,12 @@ import {connect} from 'react-redux'; | |
| import * as actions from '../../modules/actions'; | ||
| import TestNameFilterInput from './test-name-filter-input'; | ||
| import StrictMatchFilterInput from './strict-match-filter-input'; | ||
| import ShowCheckboxesInput from './show-checkboxes-input'; | ||
| import BrowserList from './browser-list'; | ||
|
|
||
| class CommonFilters extends Component { | ||
| render() { | ||
| const {filteredBrowsers, browsers, actions} = this.props; | ||
| const {filteredBrowsers, browsers, gui, actions} = this.props; | ||
|
|
||
| return ( | ||
| <div className="control-container control-filters"> | ||
|
|
@@ -21,12 +22,13 @@ class CommonFilters extends Component { | |
| /> | ||
| <TestNameFilterInput/> | ||
| <StrictMatchFilterInput/> | ||
| {gui && <ShowCheckboxesInput/>} | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Затычка, чтобы убрать чекбоксы из статического отчета. Добавил, потому что пока от этих чекбоксов в статическом отчете никакого толку нет. Чтобы чекбоксы в статике заработали, достаточно просто убрать вот это вот условие |
||
| </div> | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| export default connect( | ||
| ({view, browsers}) => ({filteredBrowsers: view.filteredBrowsers, browsers}), | ||
| ({view, browsers, gui}) => ({filteredBrowsers: view.filteredBrowsers, browsers, gui}), | ||
| (dispatch) => ({actions: bindActionCreators(actions, dispatch)}) | ||
| )(CommonFilters); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,48 +9,23 @@ import ControlButton from './control-button'; | |
| import RunButton from './run-button'; | ||
| import AcceptOpenedButton from './accept-opened-button'; | ||
| import CommonFilters from './common-filters'; | ||
| import {getFailedTests} from '../../modules/selectors/tree'; | ||
|
|
||
| import './controls.less'; | ||
|
|
||
| class GuiControls extends Component { | ||
| static propTypes = { | ||
| // from store | ||
| running: PropTypes.bool.isRequired, | ||
| processing: PropTypes.bool.isRequired, | ||
| stopping: PropTypes.bool.isRequired, | ||
| autoRun: PropTypes.bool.isRequired, | ||
| allRootSuiteIds: PropTypes.arrayOf(PropTypes.string).isRequired, | ||
| failedRootSuiteIds: PropTypes.arrayOf(PropTypes.string).isRequired, | ||
| failedTests: PropTypes.arrayOf(PropTypes.shape({ | ||
| testName: PropTypes.string, | ||
| browserName: PropTypes.string | ||
| })).isRequired | ||
| } | ||
|
|
||
| _runFailedTests = () => { | ||
| const {actions, failedTests} = this.props; | ||
|
|
||
| return actions.runFailedTests(failedTests); | ||
|
Comment on lines
-20
to
-34
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Вот это вот все унес под кнопку |
||
| stopping: PropTypes.bool.isRequired | ||
| } | ||
|
|
||
| render() { | ||
| const {actions, allRootSuiteIds, failedRootSuiteIds, running, autoRun, processing, stopping} = this.props; | ||
| const {actions, running, stopping} = this.props; | ||
| return ( | ||
| <div className="main-menu container"> | ||
| <CustomGuiControls /> | ||
| <div className="control-container control-buttons"> | ||
| <RunButton | ||
| autoRun={autoRun} | ||
| isDisabled={!allRootSuiteIds.length || processing} | ||
| handler={actions.runAllTests} | ||
| isRunning={running} | ||
| /> | ||
| <ControlButton | ||
| label="Retry failed tests" | ||
| isDisabled={!failedRootSuiteIds.length || processing} | ||
| handler={this._runFailedTests} | ||
| /> | ||
| <RunButton /> | ||
| <ControlButton | ||
| label="Stop tests" | ||
| isDisabled={!running || stopping} | ||
|
|
@@ -66,16 +41,6 @@ class GuiControls extends Component { | |
| } | ||
|
|
||
| export default connect( | ||
| (state) => { | ||
| return { | ||
| running: state.running, | ||
| processing: state.processing, | ||
| stopping: state.stopping, | ||
| autoRun: state.autoRun, | ||
| allRootSuiteIds: state.tree.suites.allRootIds, | ||
| failedRootSuiteIds: state.tree.suites.failedRootIds, | ||
| failedTests: getFailedTests(state) | ||
| }; | ||
| }, | ||
| ({running, stopping}) => ({running, stopping}), | ||
| (dispatch) => ({actions: bindActionCreators(actions, dispatch)}) | ||
| )(GuiControls); | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| 'use strict'; | ||
|
|
||
| import React, {useEffect, useState} from 'react'; | ||
| import {bindActionCreators} from 'redux'; | ||
| import {isEmpty} from 'lodash'; | ||
| import {connect} from 'react-redux'; | ||
| import PropTypes from 'prop-types'; | ||
| import classNames from 'classnames'; | ||
| import * as actions from '../../../modules/actions'; | ||
| import Popup from '../../popup'; | ||
| import {getFailedTests, getCheckedTests} from '../../../modules/selectors/tree'; | ||
| import useLocalStorage from '../../../hooks/useLocalStorage'; | ||
|
|
||
| import './index.styl'; | ||
|
|
||
| const RunMode = Object.freeze({ | ||
| ALL: 'All', | ||
| FAILED: 'Failed', | ||
| CHECKED: 'Checked' | ||
| }); | ||
|
Comment on lines
+16
to
+20
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Что-то типа Enum |
||
|
|
||
| const RunButton = ({actions, autoRun, isDisabled, isRunning, failedTests, checkedTests}) => { | ||
| const [mode, setMode] = useState(RunMode.ALL); | ||
| const [showCheckboxes] = useLocalStorage('showCheckboxes', false); | ||
|
|
||
| const btnClassName = classNames('btn', {'button_blink': isRunning}); | ||
|
|
||
| const shouldDisableFailed = isEmpty(failedTests); | ||
| const shouldDisableChecked = !showCheckboxes || isEmpty(checkedTests); | ||
|
|
||
| const selectAllTests = () => setMode(RunMode.ALL); | ||
| const selectFailedTests = () => !shouldDisableFailed && setMode(RunMode.FAILED); | ||
| const selectCheckedTests = () => !shouldDisableChecked && setMode(RunMode.CHECKED); | ||
|
|
||
| const runAllTests = () => actions.runAllTests(); | ||
| const runFailedTests = () => actions.runFailedTests(failedTests); | ||
| const runCheckedTests = () => actions.retrySuite(checkedTests); | ||
|
|
||
| const handleRunClick = () => { | ||
| const action = { | ||
| [RunMode.ALL]: runAllTests, | ||
| [RunMode.FAILED]: runFailedTests, | ||
| [RunMode.CHECKED]: runCheckedTests | ||
| }[mode]; | ||
|
|
||
| action(); | ||
| }; | ||
|
|
||
| useEffect(() => { | ||
| if (autoRun) { | ||
| runAllTests(); | ||
| } | ||
| }, []); | ||
|
|
||
| useEffect(() => { | ||
| selectCheckedTests(); | ||
| }, [shouldDisableChecked]); | ||
|
|
||
| useEffect(() => { | ||
| const shouldResetFailedMode = mode === RunMode.FAILED && shouldDisableFailed; | ||
| const shouldResetCheckedMode = mode === RunMode.CHECKED && shouldDisableChecked; | ||
|
|
||
| if (shouldResetFailedMode || shouldResetCheckedMode) { | ||
| setMode(RunMode.ALL); | ||
| } | ||
| }, [shouldDisableFailed, shouldDisableChecked]); | ||
|
|
||
| return ( | ||
| <div className='run-button'> | ||
| <button disabled={isDisabled} onClick={handleRunClick} className={btnClassName}> | ||
| {isRunning ? 'Running' : `Run ${mode.toLowerCase()} tests`} | ||
| </button> | ||
| {!isDisabled && <Popup | ||
| action='hover' | ||
| hideOnClick={true} | ||
| target={<div className='run-button__dropdown' />} | ||
| > | ||
| <ul className='run-mode'> | ||
| <li | ||
| className='run-mode__item' | ||
| onClick={selectAllTests} | ||
| > | ||
| {RunMode.ALL} | ||
| </li> | ||
| <li | ||
| className={classNames('run-mode__item', {'run-mode__item_disabled': shouldDisableFailed})} | ||
| onClick={selectFailedTests}>{RunMode.FAILED} | ||
| </li> | ||
| <li | ||
| className={classNames('run-mode__item', {'run-mode__item_disabled': shouldDisableChecked})} | ||
| onClick={selectCheckedTests} | ||
| > | ||
| {RunMode.CHECKED} | ||
| </li> | ||
| </ul> | ||
| </Popup>} | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| RunButton.propTypes = { | ||
| // from store | ||
| autoRun: PropTypes.bool.isRequired, | ||
| isDisabled: PropTypes.bool, | ||
| isRunning: PropTypes.bool, | ||
| failedTests: PropTypes.arrayOf(PropTypes.shape({ | ||
| testName: PropTypes.string, | ||
| browserName: PropTypes.string | ||
| })).isRequired, | ||
| checkedTests: PropTypes.arrayOf(PropTypes.shape({ | ||
| testName: PropTypes.string, | ||
| browserName: PropTypes.string | ||
| })).isRequired | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. но ведь если у нас не включен режим чекбокса, то этого значения не будет. Или будет просто пустой массив?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| }; | ||
|
|
||
| export default connect( | ||
| (state) => { | ||
| const autoRun = state.autoRun; | ||
| const allRootSuiteIds = state.tree.suites.allRootIds; | ||
| const processing = state.processing; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. чем у нас processing отличается от running?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| const isDisabled = !allRootSuiteIds.length || processing; | ||
| const isRunning = state.running; | ||
| const failedTests = getFailedTests(state); | ||
| const checkedTests = getCheckedTests(state); | ||
|
|
||
| return {autoRun, isDisabled, isRunning, failedTests, checkedTests}; | ||
| }, | ||
| (dispatch) => ({actions: bindActionCreators(actions, dispatch)}) | ||
| )(RunButton); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| .run-button { | ||
| display: inline-flex; | ||
| align-items: center; | ||
| cursor: pointer; | ||
| width: 143px; | ||
| font-size: 11px; | ||
| line-height: 11px; | ||
| border: 1px solid #ccc; | ||
| border-radius: 2px; | ||
| background-color: #ffeba0; | ||
|
|
||
| .btn { | ||
| flex-grow: 1; | ||
| height: 100%; | ||
| background-color: #ffeba0; | ||
| cursor: pointer; | ||
| border: none; | ||
| } | ||
|
|
||
| .run-button__dropdown { | ||
| font-family: Dropdown; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. что это за ff такой?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| &::before { | ||
| content: '\f0d7'; | ||
| padding: 5px; | ||
| border-left: 1px solid #ccc; | ||
| } | ||
| } | ||
|
|
||
| .popup__content { | ||
| padding: 0; | ||
| } | ||
|
|
||
| .run-mode { | ||
| padding: 0; | ||
|
|
||
| .run-mode__item { | ||
| font-size: 13px; | ||
| padding: 5px 10px; | ||
| list-style: none; | ||
| user-select: none; | ||
|
|
||
| &.run-mode__item_disabled { | ||
| color: #939393; | ||
| cursor: auto; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| 'use strict'; | ||
|
|
||
| import React from 'react'; | ||
| import {Checkbox} from 'semantic-ui-react'; | ||
| import useLocalStorage from '../../hooks/useLocalStorage'; | ||
|
|
||
| const ShowCheckboxesInput = () => { | ||
| const [showCheckboxes, setShowCheckboxes] = useLocalStorage('showCheckboxes', false); | ||
|
|
||
| const onChange = () => setShowCheckboxes(!showCheckboxes); | ||
|
|
||
| return ( | ||
| <div className="toggle-control"> | ||
| <Checkbox | ||
| toggle | ||
| label="Checkboxes" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. почему это checkboxes, а не checkbox?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Лейбл. Это чекбокс с чекбоксАМИ. Будет как то странно видеть чекбокс с лейблом "чекбокс", а вот "чекбоксы" уже несколько понятнее) |
||
| onChange={onChange} | ||
| checked={showCheckboxes} | ||
| /> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default ShowCheckboxesInput; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,7 +17,7 @@ const StrictMatchFilterInput = ({strictMatchFilter, actions}) => { | |
| }; | ||
|
|
||
| return ( | ||
| <div className="strict-match-filter"> | ||
| <div className="toggle-control"> | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Заменил название класса, чтобы заюзать этот же класс для |
||
| <Checkbox | ||
| toggle | ||
| label="Strict match" | ||
|
|
||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Сначала были
checked/unchecked-true/false, соответственно. Потом появилисьindeterminate. Булевых значений всего два, поэтому и есть этотenum. Тип - число, потому что так удобнее считать.