Skip to content

Commit cfe0215

Browse files
author
rocketraccoon
committed
feat: refresh tests tree
1 parent a514340 commit cfe0215

9 files changed

Lines changed: 75 additions & 23 deletions

File tree

lib/gui/server.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,16 @@ export const start = async (args: ServerArgs): Promise<ServerReadyData> => {
180180
}
181181
});
182182

183+
server.post('/refresh', async (_, res) => {
184+
try {
185+
await app.initialize({refresh: true});
186+
187+
res.sendStatus(OK);
188+
} catch (e) {
189+
res.status(INTERNAL_SERVER_ERROR).send(`Error while trying to refresh tests: ${(e as Error).message}`);
190+
}
191+
});
192+
183193
server.post('/run-custom-gui-action', async ({body: payload}, res) => {
184194
try {
185195
if (toolAdapter.toolName === ToolName.Testplane) {

lib/gui/tool-runner/index.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ export interface RunParams {
6161
retry?: boolean;
6262
}
6363

64+
export interface InitializeParams {
65+
refresh: boolean;
66+
}
67+
6468
export class ToolRunner {
6569
private _testFiles: string[];
6670
private _toolAdapter: ToolAdapter;
@@ -119,7 +123,7 @@ export class ToolRunner {
119123
});
120124
}
121125

122-
async initialize(): Promise<void> {
126+
async initialize(params?: InitializeParams): Promise<void> {
123127
await mergeDatabasesForReuse(this._reportPath);
124128
await prepareLocalDatabase(this._reportPath);
125129

@@ -144,9 +148,13 @@ export class ToolRunner {
144148
this._collection = await this._readTests();
145149

146150
this._toolAdapter.htmlReporter.emit(PluginEvents.DATABASE_CREATED, dbClient.getRawConnection());
147-
await this._reportBuilder.saveStaticFiles();
148151

149-
this._reportBuilder.setApiValues(this._toolAdapter.htmlReporter.values);
152+
if (!params?.refresh) {
153+
await this._reportBuilder.saveStaticFiles();
154+
155+
this._reportBuilder.setApiValues(this._toolAdapter.htmlReporter.values);
156+
}
157+
150158
await this._handleRunnableCollection();
151159
}
152160

lib/static/modules/action-names.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,6 @@ export default {
8282
SNAPSHOTS_PLAYER_GO_TO_TIME: 'SNAPSHOTS_PLAYER_GO_TO_TIME',
8383
SNAPSHOTS_PLAYER_TOGGLE_VISIBILITY: 'SNAPSHOTS_PLAYER_TOGGLE_VISIBILITY',
8484
SET_BROWSER_FEATURES: 'SET_BROWSER_FEATURES',
85-
SET_SEARCH_LOADING: 'SET_SEARCH_LOADING'
85+
SET_SEARCH_LOADING: 'SET_SEARCH_LOADING',
86+
SET_REFRESH_LOADING: 'SET_REFRESH_LOADING'
8687
} as const;

lib/static/modules/actions/filters.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ export const setSearchLoading = (payload: boolean): SetSearchLoading => {
3636
return {type: actionNames.SET_SEARCH_LOADING, payload};
3737
};
3838

39+
export type SetRefreshLoading = Action<typeof actionNames.SET_REFRESH_LOADING, boolean>;
40+
export const setRefreshLoading = (payload: boolean): SetRefreshLoading => {
41+
return {type: actionNames.SET_REFRESH_LOADING, payload};
42+
};
43+
3944
export type ChangeViewModeAction = Action<typeof actionNames.CHANGE_VIEW_MODE, FilterPayload<ViewMode>>;
4045
export const changeViewMode = (payload: ChangeViewModeAction['payload']): ChangeViewModeAction => ({type: actionNames.CHANGE_VIEW_MODE, payload});
4146

@@ -44,5 +49,6 @@ export type FiltersAction =
4449
| SetMatchCaseFilterAction
4550
| SetUseRegexFilterAction
4651
| SelectBrowsersAction
52+
| SetRefreshLoading
4753
| ChangeViewModeAction
4854
| SetSearchLoading;

lib/static/modules/reducers/filters.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export default (state: State, action: FiltersAction | InitGuiReportAction | Init
4242
state,
4343
{
4444
app: {
45+
isRefreshLoading: false,
4546
[Page.suitesPage]: {
4647
viewMode: suitesPageViewMode
4748
},
@@ -114,6 +115,9 @@ export default (state: State, action: FiltersAction | InitGuiReportAction | Init
114115
case actionNames.SET_SEARCH_LOADING:
115116
return applyStateUpdate(state, {app: {isSearchLoading: action.payload}});
116117

118+
case actionNames.SET_REFRESH_LOADING:
119+
return applyStateUpdate(state, {app: {isRefreshLoading: action.payload}});
120+
117121
default:
118122
return state;
119123
}

lib/static/new-ui/components/TreeActionsToolbar/index.module.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@
1313
z-index: 1;
1414
}
1515

16+
@keyframes spin {
17+
from { transform: rotate(0deg); }
18+
to { transform: rotate(360deg); }
19+
}
20+
21+
.is-refresh-loading {
22+
animation: spin 0.8s linear infinite;
23+
}
24+
1625
.buttons-container {
1726
margin-left: auto;
1827
display: flex;

lib/static/new-ui/components/TreeActionsToolbar/index.tsx

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Hotkey, Icon, Popover, Spin} from '@gravity-ui/uikit';
1+
import {Hotkey, Icon, Popover} from '@gravity-ui/uikit';
22
import classNames from 'classnames';
33
import {
44
ArrowUturnCcwLeft,
@@ -13,7 +13,8 @@ import {
1313
SquareMinus,
1414
ListUl,
1515
Hierarchy,
16-
GearPlay
16+
GearPlay,
17+
ArrowsRotateRight
1718
} from '@gravity-ui/icons';
1819
import React, {ReactNode, useCallback, useMemo} from 'react';
1920
import {useDispatch, useSelector} from 'react-redux';
@@ -22,9 +23,9 @@ import styles from './index.module.css';
2223
import {
2324
deselectAll,
2425
selectAll,
25-
setAllTreeNodesState, setTreeViewMode,
26+
setAllTreeNodesState, setRefreshLoading, setTreeViewMode,
2627
staticAccepterStageScreenshot,
27-
staticAccepterUnstageScreenshot, thunkRunTests
28+
staticAccepterUnstageScreenshot, thunkInitGuiReport, thunkRunTests
2829
} from '@/static/modules/actions';
2930
import {ImageEntity, TreeViewMode} from '@/static/new-ui/types/store';
3031
import {CHECKED, INDETERMINATE} from '@/constants/checked-statuses';
@@ -74,6 +75,7 @@ export function TreeActionsToolbar({onHighlightCurrentTest, className}: TreeActi
7475
const selectedTests = useSelector(getCheckedTests);
7576
const visibleBrowserIds: string[] = useSelector(getVisibleBrowserIds);
7677
const isInitialized = useSelector(getIsInitialized);
78+
const isRefreshLoading = useSelector((state) => state.app.isRefreshLoading);
7779

7880
const isRunTestsAvailable = useSelector(state => state.app.availableFeatures)
7981
.find(feature => feature.name === RunTestsFeature.name);
@@ -139,6 +141,12 @@ export function TreeActionsToolbar({onHighlightCurrentTest, className}: TreeActi
139141
const selectedOrVisible = isSelectedAtLeastOne ? 'selected' : 'visible';
140142
const areActionsDisabled = isRunning || !isInitialized;
141143

144+
const handleRefresh = useCallback(async () => {
145+
dispatch(setRefreshLoading(true));
146+
await fetch('/refresh', {method: 'POST'});
147+
dispatch(thunkInitGuiReport({isNewUi: true}));
148+
}, []);
149+
142150
const handleRun = useCallback((): void => {
143151
analytics?.trackFeatureUsage({featureName: `${ANALYTICS_PREFIX} run tests`});
144152
if (isSelectedAtLeastOne) {
@@ -195,19 +203,24 @@ export function TreeActionsToolbar({onHighlightCurrentTest, className}: TreeActi
195203
const getViewButtons = (): ReactNode => (
196204
<>
197205
{isRunTestsAvailable && (
198-
isRunning
199-
? (
200-
<Spin size={'xs'} style={{marginRight: '6px'}}/>
201-
) : (
202-
<IconButton
203-
className={styles.iconButton}
204-
icon={<Icon data={Play} height={14}/>}
205-
tooltip={<>Run {selectedOrVisible}<Hotkey value="shift+r" view="light" /></>}
206-
view={'flat'}
207-
onClick={handleRun}
208-
disabled={isRunning || !isInitialized}
209-
/>
210-
)
206+
<IconButton
207+
className={styles.iconButton}
208+
icon={<Icon className={classNames({[styles.isRefreshLoading]: isRefreshLoading})} data={ArrowsRotateRight} height={14}/>}
209+
tooltip="Refresh tests tree"
210+
view="flat"
211+
onClick={handleRefresh}
212+
disabled={isRunning || !isInitialized || isRefreshLoading}
213+
/>
214+
)}
215+
{isRunTestsAvailable && (
216+
<IconButton
217+
className={styles.iconButton}
218+
icon={<Icon className={classNames({[styles.isRunning]: isRunning})} data={Play} height={14}/>}
219+
tooltip={<>Run {selectedOrVisible}<Hotkey value="shift+r" view="light" /></>}
220+
view={'flat'}
221+
onClick={handleRun}
222+
disabled={isRunning || !isInitialized}
223+
/>
211224
)}
212225
{isRunTestsAvailable && hasRunTestOptions && <Popover
213226
content={<div className={styles.runOptionsContainer}><ExtensionPoint name={ExtensionPointName.RunTestOptions}></ExtensionPoint></div>}

lib/static/new-ui/features/suites/selectors.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const getCurrentBrowser = (state: State): BrowserEntity | null => {
1414
export const getCurrentResultId = (state: State): string | null => {
1515
const browserId = state.app.suitesPage.currentBrowserId;
1616
const treeNodeId = state.app.suitesPage.currentTreeNodeId;
17-
if (!browserId || !treeNodeId) {
17+
if (!browserId || !treeNodeId || !state.tree.browsers.byId[browserId]) {
1818
return null;
1919
}
2020

@@ -89,7 +89,7 @@ export const isTimeTravelPlayerAvailable = (state: State): boolean => {
8989
export const getAttempt = (state: State): number | null => {
9090
const browserId = state.app.suitesPage.currentBrowserId;
9191

92-
if (browserId) {
92+
if (browserId && state.tree.browsers.stateById[browserId]) {
9393
return state.tree.browsers.stateById[browserId].retryIndex;
9494
}
9595

lib/static/new-ui/types/store.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ export interface State {
260260
isInitialized: boolean;
261261
availableFeatures: Feature[],
262262
isSearchLoading?: boolean;
263+
isRefreshLoading?: boolean;
263264
[Page.suitesPage]: {
264265
currentTreeNodeId: string | null;
265266
currentBrowserId: string | null;

0 commit comments

Comments
 (0)