chore: select files to watch explicitly (#21599)
This commit is contained in:
parent
08a5922c4d
commit
493171cb6b
|
|
@ -35,7 +35,6 @@ class UIMode {
|
||||||
private _testRun: { run: Promise<FullResult['status']>, stop: ManualPromise<void> } | undefined;
|
private _testRun: { run: Promise<FullResult['status']>, stop: ManualPromise<void> } | undefined;
|
||||||
globalCleanup: (() => Promise<FullResult['status']>) | undefined;
|
globalCleanup: (() => Promise<FullResult['status']>) | undefined;
|
||||||
private _testWatcher: FSWatcher | undefined;
|
private _testWatcher: FSWatcher | undefined;
|
||||||
private _watchTestFile: string | undefined;
|
|
||||||
private _originalStderr: (buffer: string | Uint8Array) => void;
|
private _originalStderr: (buffer: string | Uint8Array) => void;
|
||||||
|
|
||||||
constructor(config: FullConfigInternal) {
|
constructor(config: FullConfigInternal) {
|
||||||
|
|
@ -113,7 +112,7 @@ class UIMode {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (method === 'watch') {
|
if (method === 'watch') {
|
||||||
this._watchFile(params.fileName);
|
this._watchFiles(params.fileNames);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (method === 'open' && params.location) {
|
if (method === 'open' && params.location) {
|
||||||
|
|
@ -185,17 +184,19 @@ class UIMode {
|
||||||
await run;
|
await run;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _watchFile(fileName: string) {
|
private async _watchFiles(fileNames: string[]) {
|
||||||
if (this._watchTestFile === fileName)
|
|
||||||
return;
|
|
||||||
if (this._testWatcher)
|
if (this._testWatcher)
|
||||||
await this._testWatcher.close();
|
await this._testWatcher.close();
|
||||||
this._watchTestFile = fileName;
|
if (!fileNames.length)
|
||||||
if (!fileName)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const files = [fileName, ...dependenciesForTestFile(fileName)];
|
const files = new Set<string>();
|
||||||
this._testWatcher = chokidar.watch(files, { ignoreInitial: true }).on('all', async (event, file) => {
|
for (const fileName of fileNames) {
|
||||||
|
files.add(fileName);
|
||||||
|
dependenciesForTestFile(fileName).forEach(file => files.add(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
this._testWatcher = chokidar.watch([...files], { ignoreInitial: true }).on('all', async (event, file) => {
|
||||||
if (event !== 'add' && event !== 'change')
|
if (event !== 'add' && event !== 'change')
|
||||||
return;
|
return;
|
||||||
this._dispatchEvent({ method: 'fileChanged', params: { fileName: file } });
|
this._dispatchEvent({ method: 'fileChanged', params: { fileName: file } });
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-view-entry:not(.selected):not(.highlighted) .toolbar-button {
|
.list-view-entry:not(.highlighted) .toolbar-button:not(.toggled) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ import { Expandable } from '@web/components/expandable';
|
||||||
|
|
||||||
let updateRootSuite: (rootSuite: Suite, progress: Progress) => void = () => {};
|
let updateRootSuite: (rootSuite: Suite, progress: Progress) => void = () => {};
|
||||||
let updateStepsProgress: () => void = () => {};
|
let updateStepsProgress: () => void = () => {};
|
||||||
let runWatchedTests = () => {};
|
let runWatchedTests = (fileName: string) => {};
|
||||||
let xtermSize = { cols: 80, rows: 24 };
|
let xtermSize = { cols: 80, rows: 24 };
|
||||||
|
|
||||||
const xtermDataSource: XtermDataSource = {
|
const xtermDataSource: XtermDataSource = {
|
||||||
|
|
@ -52,7 +52,6 @@ const xtermDataSource: XtermDataSource = {
|
||||||
|
|
||||||
export const WatchModeView: React.FC<{}> = ({
|
export const WatchModeView: React.FC<{}> = ({
|
||||||
}) => {
|
}) => {
|
||||||
const [isWatchingFiles, setIsWatchingFiles] = useSetting<boolean>('test-ui-watch-files', false);
|
|
||||||
const [filterText, setFilterText] = useSetting<string>('test-ui-filter-text', '');
|
const [filterText, setFilterText] = useSetting<string>('test-ui-filter-text', '');
|
||||||
const [filterExpanded, setFilterExpanded] = useSetting<boolean>('test-ui-filter-expanded', false);
|
const [filterExpanded, setFilterExpanded] = useSetting<boolean>('test-ui-filter-expanded', false);
|
||||||
const [isShowingOutput, setIsShowingOutput] = useSetting<boolean>('test-ui-show-output', false);
|
const [isShowingOutput, setIsShowingOutput] = useSetting<boolean>('test-ui-show-output', false);
|
||||||
|
|
@ -64,6 +63,7 @@ export const WatchModeView: React.FC<{}> = ({
|
||||||
const [settingsVisible, setSettingsVisible] = React.useState<boolean>(false);
|
const [settingsVisible, setSettingsVisible] = React.useState<boolean>(false);
|
||||||
const [visibleTestIds, setVisibleTestIds] = React.useState<string[]>([]);
|
const [visibleTestIds, setVisibleTestIds] = React.useState<string[]>([]);
|
||||||
const [runningState, setRunningState] = React.useState<{ testIds: Set<string>, itemSelectedByUser?: boolean }>();
|
const [runningState, setRunningState] = React.useState<{ testIds: Set<string>, itemSelectedByUser?: boolean }>();
|
||||||
|
|
||||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|
@ -152,7 +152,6 @@ export const WatchModeView: React.FC<{}> = ({
|
||||||
<ToolbarButton icon='play' title='Run' onClick={() => runTests(visibleTestIds)} disabled={isRunningTest}></ToolbarButton>
|
<ToolbarButton icon='play' title='Run' onClick={() => runTests(visibleTestIds)} disabled={isRunningTest}></ToolbarButton>
|
||||||
<ToolbarButton icon='debug-stop' title='Stop' onClick={() => sendMessageNoReply('stop')} disabled={!isRunningTest}></ToolbarButton>
|
<ToolbarButton icon='debug-stop' title='Stop' onClick={() => sendMessageNoReply('stop')} disabled={!isRunningTest}></ToolbarButton>
|
||||||
<ToolbarButton icon='refresh' title='Reload' onClick={() => refreshRootSuite(true)} disabled={isRunningTest}></ToolbarButton>
|
<ToolbarButton icon='refresh' title='Reload' onClick={() => refreshRootSuite(true)} disabled={isRunningTest}></ToolbarButton>
|
||||||
<ToolbarButton icon='eye-watch' title='Watch' toggled={isWatchingFiles} onClick={() => setIsWatchingFiles(!isWatchingFiles)}></ToolbarButton>
|
|
||||||
<div className='spacer'></div>
|
<div className='spacer'></div>
|
||||||
<ToolbarButton icon='gear' title='Toggle color mode' toggled={settingsVisible} onClick={() => { setSettingsVisible(!settingsVisible); }}></ToolbarButton>
|
<ToolbarButton icon='gear' title='Toggle color mode' toggled={settingsVisible} onClick={() => { setSettingsVisible(!settingsVisible); }}></ToolbarButton>
|
||||||
<ToolbarButton icon='terminal' title='Toggle color mode' toggled={isShowingOutput} onClick={() => { setIsShowingOutput(!isShowingOutput); }}></ToolbarButton>
|
<ToolbarButton icon='terminal' title='Toggle color mode' toggled={isShowingOutput} onClick={() => { setIsShowingOutput(!isShowingOutput); }}></ToolbarButton>
|
||||||
|
|
@ -185,7 +184,6 @@ export const WatchModeView: React.FC<{}> = ({
|
||||||
filterText={filterText}
|
filterText={filterText}
|
||||||
rootSuite={rootSuite}
|
rootSuite={rootSuite}
|
||||||
runningState={runningState}
|
runningState={runningState}
|
||||||
isWatchingFiles={isWatchingFiles}
|
|
||||||
runTests={runTests}
|
runTests={runTests}
|
||||||
onTestSelected={setSelectedTest}
|
onTestSelected={setSelectedTest}
|
||||||
isVisible={!settingsVisible}
|
isVisible={!settingsVisible}
|
||||||
|
|
@ -212,13 +210,13 @@ export const TestList: React.FC<{
|
||||||
rootSuite: { value: Suite | undefined },
|
rootSuite: { value: Suite | undefined },
|
||||||
runTests: (testIds: string[]) => void,
|
runTests: (testIds: string[]) => void,
|
||||||
runningState?: { testIds: Set<string>, itemSelectedByUser?: boolean },
|
runningState?: { testIds: Set<string>, itemSelectedByUser?: boolean },
|
||||||
isWatchingFiles: boolean,
|
|
||||||
isVisible: boolean,
|
isVisible: boolean,
|
||||||
setVisibleTestIds: (testIds: string[]) => void,
|
setVisibleTestIds: (testIds: string[]) => void,
|
||||||
onTestSelected: (test: TestCase | undefined) => void,
|
onTestSelected: (test: TestCase | undefined) => void,
|
||||||
}> = ({ projects, filterText, rootSuite, runTests, runningState, isWatchingFiles, isVisible, onTestSelected, setVisibleTestIds }) => {
|
}> = ({ projects, filterText, rootSuite, runTests, runningState, isVisible, onTestSelected, setVisibleTestIds }) => {
|
||||||
const [treeState, setTreeState] = React.useState<TreeState>({ expandedItems: new Map() });
|
const [treeState, setTreeState] = React.useState<TreeState>({ expandedItems: new Map() });
|
||||||
const [selectedTreeItemId, setSelectedTreeItemId] = React.useState<string | undefined>();
|
const [selectedTreeItemId, setSelectedTreeItemId] = React.useState<string | undefined>();
|
||||||
|
const [watchedTreeIds] = React.useState<Set<string>>(new Set());
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
refreshRootSuite(true);
|
refreshRootSuite(true);
|
||||||
|
|
@ -274,17 +272,28 @@ export const TestList: React.FC<{
|
||||||
return { selectedTreeItem };
|
return { selectedTreeItem };
|
||||||
}, [onTestSelected, selectedTreeItemId, treeItemMap]);
|
}, [onTestSelected, selectedTreeItemId, treeItemMap]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
const setWatchedTreeIds = (watchedTreeIds: Set<string>) => {
|
||||||
sendMessageNoReply('watch', { fileName: isWatchingFiles ? fileName(selectedTreeItem) : undefined });
|
const fileNames = new Set<string>();
|
||||||
}, [selectedTreeItem, isWatchingFiles]);
|
for (const itemId of watchedTreeIds) {
|
||||||
|
const treeItem = treeItemMap.get(itemId)!;
|
||||||
|
fileNames.add(fileNameForTreeItem(treeItem)!);
|
||||||
|
}
|
||||||
|
sendMessageNoReply('watch', { fileNames: [...fileNames] });
|
||||||
|
};
|
||||||
|
|
||||||
const runTreeItem = (treeItem: TreeItem) => {
|
const runTreeItem = (treeItem: TreeItem) => {
|
||||||
setSelectedTreeItemId(treeItem.id);
|
setSelectedTreeItemId(treeItem.id);
|
||||||
runTests(collectTestIds(treeItem));
|
runTests(collectTestIds(treeItem));
|
||||||
};
|
};
|
||||||
|
|
||||||
runWatchedTests = () => {
|
runWatchedTests = (fileName: string) => {
|
||||||
runTests(collectTestIds(selectedTreeItem));
|
const testIds: string[] = [];
|
||||||
|
for (const treeId of watchedTreeIds) {
|
||||||
|
const treeItem = treeItemMap.get(treeId)!;
|
||||||
|
if (fileNameForTreeItem(treeItem) === fileName)
|
||||||
|
testIds.push(...collectTestIds(treeItem));
|
||||||
|
}
|
||||||
|
runTests(testIds);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isVisible)
|
if (!isVisible)
|
||||||
|
|
@ -299,6 +308,13 @@ export const TestList: React.FC<{
|
||||||
<div className='watch-mode-list-item-title'>{treeItem.title}</div>
|
<div className='watch-mode-list-item-title'>{treeItem.title}</div>
|
||||||
<ToolbarButton icon='play' title='Run' onClick={() => runTreeItem(treeItem)} disabled={!!runningState}></ToolbarButton>
|
<ToolbarButton icon='play' title='Run' onClick={() => runTreeItem(treeItem)} disabled={!!runningState}></ToolbarButton>
|
||||||
<ToolbarButton icon='go-to-file' title='Open in VS Code' onClick={() => sendMessageNoReply('open', { location: locationToOpen(treeItem) })}></ToolbarButton>
|
<ToolbarButton icon='go-to-file' title='Open in VS Code' onClick={() => sendMessageNoReply('open', { location: locationToOpen(treeItem) })}></ToolbarButton>
|
||||||
|
<ToolbarButton icon='eye' title='Watch' onClick={() => {
|
||||||
|
if (watchedTreeIds.has(treeItem.id))
|
||||||
|
watchedTreeIds.delete(treeItem.id);
|
||||||
|
else
|
||||||
|
watchedTreeIds.add(treeItem.id);
|
||||||
|
setWatchedTreeIds(watchedTreeIds);
|
||||||
|
}} toggled={watchedTreeIds.has(treeItem.id)}></ToolbarButton>
|
||||||
</div>;
|
</div>;
|
||||||
}}
|
}}
|
||||||
icon={treeItem => {
|
icon={treeItem => {
|
||||||
|
|
@ -469,7 +485,7 @@ const refreshRootSuite = (eraseResults: boolean) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.method === 'fileChanged') {
|
if (message.method === 'fileChanged') {
|
||||||
runWatchedTests();
|
runWatchedTests(message.params.fileName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -497,7 +513,7 @@ const sendMessageNoReply = (method: string, params?: any) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const fileName = (treeItem?: TreeItem): string | undefined => {
|
const fileNameForTreeItem = (treeItem?: TreeItem): string | undefined => {
|
||||||
return treeItem?.location.file;
|
return treeItem?.location.file;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,15 @@ export const ToolbarButton: React.FC<React.PropsWithChildren<ToolbarButtonProps>
|
||||||
let className = `toolbar-button ${icon}`;
|
let className = `toolbar-button ${icon}`;
|
||||||
if (toggled)
|
if (toggled)
|
||||||
className += ' toggled';
|
className += ' toggled';
|
||||||
return <button className={className} onClick={onClick} title={title} disabled={!!disabled}>
|
return <button
|
||||||
|
className={className}
|
||||||
|
onMouseDown={preventDefault}
|
||||||
|
onClick={onClick}
|
||||||
|
title={title}
|
||||||
|
disabled={!!disabled}>
|
||||||
{icon && <span className={`codicon codicon-${icon}`} style={children ? { marginRight: 5 } : {}}></span>}
|
{icon && <span className={`codicon codicon-${icon}`} style={children ? { marginRight: 5 } : {}}></span>}
|
||||||
{children}
|
{children}
|
||||||
</button>;
|
</button>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const preventDefault = (e: any) => e.preventDefault();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue