Skip to content

Commit

Permalink
chore(new-ui): basic test running implementation (#604)
Browse files Browse the repository at this point in the history
* chore(new-ui): tweak attempt picker design

* chore(new-ui): basic test running implementation

* test: update screenshots

* test: update screenshots
  • Loading branch information
shadowusr authored Oct 8, 2024
1 parent 2aba0dd commit eb131fd
Show file tree
Hide file tree
Showing 25 changed files with 139 additions and 21 deletions.
7 changes: 7 additions & 0 deletions lib/constants/features.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface Feature {
name: string;
}

export const RunTestsFeature = {
name: 'run-tests'
} as const satisfies Feature;
1 change: 1 addition & 0 deletions lib/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './database';
export * from './defaults';
export * from './diff-modes';
export * from './errors';
export * from './features';
export * from './group-tests';
export * from './paths';
export * from './tests';
Expand Down
1 change: 1 addition & 0 deletions lib/static/modules/default-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export default Object.assign({config: configDefaults}, {
},
app: {
isInitialized: false,
availableFeatures: [],
suitesPage: {
currentBrowserId: null
},
Expand Down
4 changes: 3 additions & 1 deletion lib/static/modules/reducers/gui.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import actionNames from '../action-names';
import {applyStateUpdate} from '@/static/modules/utils/state';
import {RunTestsFeature} from '@/constants';

export default (state, action) => {
switch (action.type) {
case actionNames.INIT_GUI_REPORT: {
return {...state, gui: true};
return applyStateUpdate(state, {gui: true, app: {availableFeatures: [RunTestsFeature]}});
}

case actionNames.INIT_STATIC_REPORT: {
Expand Down
6 changes: 6 additions & 0 deletions lib/static/new-ui.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
.g-root {
--g-font-family-sans: 'Jost', sans-serif;
--g-color-base-background: #eee;
--g-color-text-danger-heavy: #e9043a;
}

body {
Expand All @@ -37,3 +38,8 @@ body {
.gn-aside-header__header:after {
display: none;
}

.action-button {
font-size: 15px;
font-weight: 450;
}
30 changes: 29 additions & 1 deletion lib/static/new-ui/app/gui.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,43 @@
import React, {ReactNode, useEffect} from 'react';
import {createRoot} from 'react-dom/client';

import {ClientEvents} from '@/gui/constants';
import {App} from './App';
import store from '../../modules/store';
import {finGuiReport, initGuiReport} from '../../modules/actions';
import {finGuiReport, initGuiReport, suiteBegin, testBegin, testResult, testsEnd} from '../../modules/actions';

const rootEl = document.getElementById('app') as HTMLDivElement;
const root = createRoot(rootEl);

function Gui(): ReactNode {
const subscribeToEvents = (): void => {
const eventSource = new EventSource('/events');

eventSource.addEventListener(ClientEvents.BEGIN_SUITE, (e) => {
const data = JSON.parse(e.data);
store.dispatch(suiteBegin(data));
});

eventSource.addEventListener(ClientEvents.BEGIN_STATE, (e) => {
const data = JSON.parse(e.data);
store.dispatch(testBegin(data));
});

[ClientEvents.TEST_RESULT, ClientEvents.ERROR].forEach((eventName) => {
eventSource.addEventListener(eventName, (e) => {
const data = JSON.parse(e.data);
store.dispatch(testResult(data));
});
});

eventSource.addEventListener(ClientEvents.END, () => {
store.dispatch(testsEnd());
});
};

useEffect(() => {
store.dispatch(initGuiReport());
subscribeToEvents();

return () => {
store.dispatch(finGuiReport());
Expand Down
21 changes: 21 additions & 0 deletions lib/static/new-ui/components/AttemptPicker/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.container {
display: flex;
gap: 16px;
}

.heading {
line-height: 28px;
}

.attempts-container {
display: flex;
flex-wrap: wrap;
gap: 4px;
}

.retry-button {
composes: action-button from global;
margin-left: auto;
/* Sets spinner color */
--g-color-line-brand: var(--g-color-text-hint);
}
39 changes: 30 additions & 9 deletions lib/static/new-ui/components/AttemptPicker/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import {Flex} from '@gravity-ui/uikit';
import React, {ReactNode} from 'react';
import {connect} from 'react-redux';
import {connect, useDispatch, useSelector} from 'react-redux';
import {ArrowRotateRight} from '@gravity-ui/icons';

import {State} from '@/static/new-ui/types/store';
import {AttemptPickerItem} from '@/static/new-ui/components/AttemptPickerItem';
import styles from './index.module.css';
import classNames from 'classnames';
import {Button, Icon, Spin} from '@gravity-ui/uikit';
import {RunTestsFeature} from '@/constants';
import {retryTest} from '@/static/modules/actions';
import {getCurrentBrowser} from '@/static/new-ui/features/suites/selectors';

interface AttemptPickerProps {
onChange?: (browserId: string, resultId: string, attemptIndex: number) => unknown;
Expand All @@ -18,29 +24,44 @@ interface AttemptPickerInternalProps extends AttemptPickerProps {
function AttemptPickerInternal(props: AttemptPickerInternalProps): ReactNode {
const {resultIds, currentResultId} = props;

const onClickHandler = (resultId: string, attemptIndex: number): void => {
const dispatch = useDispatch();
const currentBrowser = useSelector(getCurrentBrowser);
const isRunTestsAvailable = useSelector((state: State) => state.app.availableFeatures)
.find(feature => feature.name === RunTestsFeature.name);
const isRunning = useSelector((state: State) => state.running);

const onAttemptPickHandler = (resultId: string, attemptIndex: number): void => {
if (!props.browserId || currentResultId === resultId) {
return;
}

props.onChange?.(props.browserId, resultId, attemptIndex);
};

return <Flex alignItems={'center'} gap={5}>
<h3 className='text-header-1'>Attempts</h3>
<Flex gap={0.5} wrap={'wrap'}>
const onRetryTestHandler = (): void => {
if (currentBrowser) {
dispatch(retryTest({testName: currentBrowser.parentId, browserName: currentBrowser.name}));
}
};

return <div className={styles.container}>
<h3 className={classNames('text-header-1', styles.heading)}>Attempts</h3>
<div className={styles.attemptsContainer}>
{resultIds.map((resultId, index) => {
const isActive = resultId === currentResultId;

return <AttemptPickerItem
key={resultId}
resultId={resultId}
isActive={isActive}
onClick={(): unknown => onClickHandler(resultId, index)}
onClick={(): unknown => onAttemptPickHandler(resultId, index)}
/>;
})}
</Flex>
</Flex>;
</div>
{isRunTestsAvailable && <Button view={'action'} className={styles.retryButton} onClick={onRetryTestHandler} disabled={isRunning}>
{isRunning ? <Spin size={'xs'} /> : <Icon data={ArrowRotateRight}/>}Retry
</Button>}
</div>;
}

export const AttemptPicker = connect((state: State) => {
Expand Down
14 changes: 13 additions & 1 deletion lib/static/new-ui/components/AttemptPickerItem/index.module.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
.attempt-picker-item {
--g-button-padding: 8px;
width: 28px;
}

.attempt-picker-item--active {
--g-button-border-width: 1px;
box-shadow: 0px 1px 3px 0px var(--box-shadow-color);
}

.attempt-picker-item--staged {
Expand All @@ -16,10 +17,21 @@
border-color: rgba(207, 231, 252, 1);
}

.attempt-picker-item--success {
--box-shadow-color: #21a95661;
}

.attempt-picker-item--error {
--box-shadow-color: #ff004b61;
}

.attempt-picker-item--fail {
--g-button-text-color-hover: #c522ff;
--g-button-background-color-hover: #cf49ff4f;
--g-button-background-color: var(--color-pink-100);
--g-button-text-color: var(--color-pink-600);
--g-button-border-color: var(--color-pink-600);
--box-shadow-color: #cf49ff61;
}

.attempt-picker-item--fail_error {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@
position: sticky;
top: 0;
z-index: 10;
padding-bottom: 4px;
padding-bottom: 8px;
border-bottom: 1px solid #eee;
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
.tree-view__item--current {
background: #a28aff !important;
color: #fff !important;
/* Sets spinner color */
--g-color-line-brand: #fff;
}

.tree-view__item__title--current {
Expand Down
11 changes: 10 additions & 1 deletion lib/static/new-ui/features/suites/selectors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import {ImageEntity, ResultEntity, State} from '@/static/new-ui/types/store';
import {BrowserEntity, ImageEntity, ResultEntity, State} from '@/static/new-ui/types/store';

export const getCurrentBrowser = (state: State): BrowserEntity | null => {
const browserId = state.app.suitesPage.currentBrowserId;
if (!browserId) {
return null;
}

return state.tree.browsers.byId[browserId];
};

export const getCurrentResultId = (state: State): string | null => {
const browserId = state.app.suitesPage.currentBrowserId;
Expand Down
4 changes: 3 additions & 1 deletion lib/static/new-ui/types/store.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {DiffModeId, TestStatus, ViewMode} from '@/constants';
import {DiffModeId, Feature, TestStatus, ViewMode} from '@/constants';
import {BrowserItem, ImageFile, ReporterConfig, TestError, TestStepCompressed} from '@/types';
import {HtmlReporterValues} from '@/plugin-api';
import {CoordBounds} from 'looks-same';
Expand Down Expand Up @@ -132,6 +132,7 @@ export interface TreeEntity {
export interface State {
app: {
isInitialized: boolean;
availableFeatures: Feature[],
suitesPage: {
currentBrowserId: string | null;
};
Expand All @@ -155,6 +156,7 @@ export interface State {
keyToGroupTestsBy: string;
baseHost: string;
};
running: boolean;
apiValues: HtmlReporterValues;
config: ReporterConfig;
}
6 changes: 5 additions & 1 deletion lib/static/new-ui/utils/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {TestStatus} from '@/constants';
import {ArrowRotateLeft, CircleCheck, CircleDashed, CircleMinus, CircleXmark, ArrowsRotateLeft} from '@gravity-ui/icons';
import {Spin} from '@gravity-ui/uikit';
import React from 'react';

import {TestStatus} from '@/constants';

export const getIconByStatus = (status: TestStatus): React.JSX.Element => {
if (status === TestStatus.FAIL || status === TestStatus.ERROR) {
return <CircleXmark className={'icon-fail'} />;
Expand All @@ -13,6 +15,8 @@ export const getIconByStatus = (status: TestStatus): React.JSX.Element => {
return <ArrowRotateLeft className={'icon-retry'}/>;
} else if (status === TestStatus.UPDATED) {
return <ArrowsRotateLeft className={'icon-updated'}/>;
} else if (status === TestStatus.RUNNING) {
return <Spin size={'xs'} />;
}

return <CircleDashed />;
Expand Down
11 changes: 6 additions & 5 deletions lib/static/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -858,15 +858,16 @@ a:active {
}

.g-root_theme_light {
--g-color-base-brand: var(--g-color-private-color-400);
--g-color-base-brand-hover: var(--g-color-private-color-150);
--g-color-base-brand: var(--g-color-private-color-550-solid);
--g-color-base-brand-hover: var(--g-color-private-color-450-solid);
--g-color-base-selection: var(--g-color-private-color-100);
--g-color-base-selection-hover: var(--g-color-private-color-150);
--g-color-line-brand: var(--g-color-private-color-200);
--g-color-line-brand: var(--g-color-private-color-500);
--g-color-text-brand: var(--g-color-private-color-300);
--g-color-text-link: var(--g-color-private-color-300);
--g-color-text-link-hover: var(--g-color-private-color-500);
--gn-aside-header-decoration-collapsed-background-color: var(--g-color-private-color-150);
--g-color-text-brand-contrast: var(--g-color-private-color-50-solid);

--g-color-private-color-50: rgba(108,71,255,0.1);
--g-color-private-color-100: rgba(108,71,255,0.15);
Expand Down Expand Up @@ -950,8 +951,8 @@ h1, h2, h3, h4, h5, h6 {

.text-header-1 {
font-family: Jost, sans-serif;
font-weight: 500;
font-size: var(--g-text-header-1-font-size);
font-weight: 450;
font-size: 18px;
line-height: var(--g-text-header-1-line-height);
}

Expand Down
Binary file modified test/func/tests/screens/0049570/chrome/retry-switcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/func/tests/screens/07c99c0/chrome/retry-switcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/func/tests/screens/1361a92/chrome/retry-selector.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/func/tests/screens/1bb949f/chrome/retry-switcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/func/tests/screens/42ea26d/chrome/retry-selector.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/func/tests/screens/45b9477/chrome/retry-switcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/func/tests/screens/67cd8d8/chrome/retry-switcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/func/tests/screens/bdf4a21/chrome/retry-switcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/func/tests/screens/d90f7de/chrome/retry-selector.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/func/tests/screens/ff4deba/chrome/retry-selector.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit eb131fd

Please sign in to comment.