feat: allow installing browsers from ui (#26628)
This commit is contained in:
parent
f41c862ac6
commit
46e33cd384
|
|
@ -28,7 +28,7 @@ import type { BrowserType } from '../../browserType';
|
||||||
|
|
||||||
export type Transport = {
|
export type Transport = {
|
||||||
sendEvent?: (method: string, params: any) => void;
|
sendEvent?: (method: string, params: any) => void;
|
||||||
dispatch: (method: string, params: any) => Promise<void>;
|
dispatch: (method: string, params: any) => Promise<any>;
|
||||||
close?: () => void;
|
close?: () => void;
|
||||||
onclose: () => void;
|
onclose: () => void;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { openTraceViewerApp, openTraceInBrowser } from 'playwright-core/lib/server';
|
import { openTraceViewerApp, openTraceInBrowser, registry } from 'playwright-core/lib/server';
|
||||||
import { isUnderTest, ManualPromise } from 'playwright-core/lib/utils';
|
import { isUnderTest, ManualPromise } from 'playwright-core/lib/utils';
|
||||||
import type { FullResult } from '../../reporter';
|
import type { FullResult } from '../../reporter';
|
||||||
import { clearCompilationCache, collectAffectedTestFiles, dependenciesForTestFile } from '../transform/compilationCache';
|
import { clearCompilationCache, collectAffectedTestFiles, dependenciesForTestFile } from '../transform/compilationCache';
|
||||||
|
|
@ -107,6 +107,13 @@ class UIMode {
|
||||||
void this._stopTests();
|
void this._stopTests();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (method === 'checkBrowsers')
|
||||||
|
return { hasBrowsers: hasSomeBrowsers() };
|
||||||
|
if (method === 'installBrowsers') {
|
||||||
|
await installBrowsers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
queue = queue.then(() => this._queueListOrRun(method, params));
|
queue = queue.then(() => this._queueListOrRun(method, params));
|
||||||
await queue;
|
await queue;
|
||||||
},
|
},
|
||||||
|
|
@ -297,3 +304,19 @@ class Watcher {
|
||||||
this._collector.length = 0;
|
this._collector.length = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasSomeBrowsers(): boolean {
|
||||||
|
for (const browserName of ['chromium', 'webkit', 'firefox']) {
|
||||||
|
try {
|
||||||
|
registry.findExecutable(browserName)!.executablePathOrDie('javascript');
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function installBrowsers() {
|
||||||
|
const executables = registry.defaultExecutables();
|
||||||
|
await registry.install(executables, false);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ export const UIModeView: React.FC<{}> = ({
|
||||||
const runTestBacklog = React.useRef<Set<string>>(new Set());
|
const runTestBacklog = React.useRef<Set<string>>(new Set());
|
||||||
const [collapseAllCount, setCollapseAllCount] = React.useState(0);
|
const [collapseAllCount, setCollapseAllCount] = React.useState(0);
|
||||||
const [isDisconnected, setIsDisconnected] = React.useState(false);
|
const [isDisconnected, setIsDisconnected] = React.useState(false);
|
||||||
|
const [hasBrowsers, setHasBrowsers] = React.useState(true);
|
||||||
|
|
||||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
|
@ -91,8 +92,10 @@ export const UIModeView: React.FC<{}> = ({
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setWatchedTreeIds({ value: new Set() });
|
setWatchedTreeIds({ value: new Set() });
|
||||||
updateRootSuite(baseFullConfig, new TeleSuite('', 'root'), [], undefined);
|
updateRootSuite(baseFullConfig, new TeleSuite('', 'root'), [], undefined);
|
||||||
refreshRootSuite(true).then(() => {
|
refreshRootSuite(true).then(async () => {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
const { hasBrowsers } = await sendMessage('checkBrowsers');
|
||||||
|
setHasBrowsers(hasBrowsers);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
@ -193,6 +196,14 @@ export const UIModeView: React.FC<{}> = ({
|
||||||
<ToolbarButton icon='color-mode' title='Toggle color mode' onClick={() => toggleTheme()} />
|
<ToolbarButton icon='color-mode' title='Toggle color mode' onClick={() => toggleTheme()} />
|
||||||
<ToolbarButton icon='refresh' title='Reload' onClick={() => reloadTests()} disabled={isRunningTest || isLoading}></ToolbarButton>
|
<ToolbarButton icon='refresh' title='Reload' onClick={() => reloadTests()} disabled={isRunningTest || isLoading}></ToolbarButton>
|
||||||
<ToolbarButton icon='terminal' title='Toggle output' toggled={isShowingOutput} onClick={() => { setIsShowingOutput(!isShowingOutput); }} />
|
<ToolbarButton icon='terminal' title='Toggle output' toggled={isShowingOutput} onClick={() => { setIsShowingOutput(!isShowingOutput); }} />
|
||||||
|
{!hasBrowsers && <ToolbarButton icon='lightbulb-autofix' style={{ color: 'var(--vscode-errorForeground)' }}title='Install browsers' toggled={isShowingOutput} onClick={() => {
|
||||||
|
setIsShowingOutput(true);
|
||||||
|
sendMessage('installBrowsers').then(async () => {
|
||||||
|
setIsShowingOutput(false);
|
||||||
|
const { hasBrowsers } = await sendMessage('checkBrowsers');
|
||||||
|
setHasBrowsers(hasBrowsers);
|
||||||
|
});
|
||||||
|
}} />}
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
<FiltersView
|
<FiltersView
|
||||||
filterText={filterText}
|
filterText={filterText}
|
||||||
|
|
|
||||||
|
|
@ -63,10 +63,7 @@ export function TreeView<T extends TreeItem>({
|
||||||
autoExpandDepth,
|
autoExpandDepth,
|
||||||
}: TreeViewProps<T>) {
|
}: TreeViewProps<T>) {
|
||||||
const treeItems = React.useMemo(() => {
|
const treeItems = React.useMemo(() => {
|
||||||
// Expand all ancestors of the selected item.
|
return flattenTree<T>(rootItem, selectedItem, treeState.expandedItems, autoExpandDepth || 0);
|
||||||
for (let item: TreeItem | undefined = selectedItem?.parent; item; item = item.parent)
|
|
||||||
treeState.expandedItems.set(item.id, true);
|
|
||||||
return flattenTree<T>(rootItem, treeState.expandedItems, autoExpandDepth || 0);
|
|
||||||
}, [rootItem, selectedItem, treeState, autoExpandDepth]);
|
}, [rootItem, selectedItem, treeState, autoExpandDepth]);
|
||||||
|
|
||||||
// Filter visible items.
|
// Filter visible items.
|
||||||
|
|
@ -160,11 +157,15 @@ type TreeItemData = {
|
||||||
parent: TreeItem | null,
|
parent: TreeItem | null,
|
||||||
};
|
};
|
||||||
|
|
||||||
function flattenTree<T extends TreeItem>(rootItem: T, expandedItems: Map<string, boolean | undefined>, autoExpandDepth: number): Map<T, TreeItemData> {
|
function flattenTree<T extends TreeItem>(rootItem: T, selectedItem: T | undefined, expandedItems: Map<string, boolean | undefined>, autoExpandDepth: number): Map<T, TreeItemData> {
|
||||||
const result = new Map<T, TreeItemData>();
|
const result = new Map<T, TreeItemData>();
|
||||||
|
const temporaryExpanded = new Map<string, boolean | undefined>();
|
||||||
|
for (let item: TreeItem | undefined = selectedItem?.parent; item; item = item.parent)
|
||||||
|
temporaryExpanded.set(item.id, true);
|
||||||
|
|
||||||
const appendChildren = (parent: T, depth: number) => {
|
const appendChildren = (parent: T, depth: number) => {
|
||||||
for (const item of parent.children as T[]) {
|
for (const item of parent.children as T[]) {
|
||||||
const expandState = expandedItems.get(item.id);
|
const expandState = expandedItems.get(item.id) ?? temporaryExpanded.get(item.id);
|
||||||
const autoExpandMatches = autoExpandDepth > depth && result.size < 25 && expandState !== false;
|
const autoExpandMatches = autoExpandDepth > depth && result.size < 25 && expandState !== false;
|
||||||
const expanded = item.children.length ? expandState || autoExpandMatches : undefined;
|
const expanded = item.children.length ? expandState || autoExpandMatches : undefined;
|
||||||
result.set(item, { depth, expanded, parent: rootItem === parent ? null : parent });
|
result.set(item, { depth, expanded, parent: rootItem === parent ? null : parent });
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue