Skip to content

Commit

Permalink
chore(new-ui): basic test running implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
shadowusr committed Sep 29, 2024
1 parent f714354 commit 03d256d
Show file tree
Hide file tree
Showing 13 changed files with 100 additions and 11 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
5 changes: 5 additions & 0 deletions lib/static/new-ui.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,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
7 changes: 7 additions & 0 deletions lib/static/new-ui/components/AttemptPicker/index.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,10 @@
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);
}
26 changes: 23 additions & 3 deletions lib/static/new-ui/components/AttemptPicker/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
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 @@ -19,14 +24,26 @@ 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);
};

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}>
Expand All @@ -37,10 +54,13 @@ function AttemptPickerInternal(props: AttemptPickerInternalProps): ReactNode {
key={resultId}
resultId={resultId}
isActive={isActive}
onClick={(): unknown => onClickHandler(resultId, index)}
onClick={(): unknown => onAttemptPickHandler(resultId, index)}
/>;
})}
</div>
{isRunTestsAvailable && <Button view={'action'} className={styles.retryButton} onClick={onRetryTestHandler} disabled={isRunning}>
{isRunning ? <Spin size={'xs'} /> : <Icon data={ArrowRotateRight}/>}Retry
</Button>}
</div>;
}

Expand Down
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
7 changes: 4 additions & 3 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

0 comments on commit 03d256d

Please sign in to comment.