chore: pick locator tab (#26532)
This commit is contained in:
parent
14a57a788b
commit
8f31191637
59
packages/trace-viewer/src/ui/browserFrame.css
Normal file
59
packages/trace-viewer/src/ui/browserFrame.css
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) Microsoft Corporation.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.browser-frame-dot {
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
height: 12px;
|
||||||
|
margin-right: 6px;
|
||||||
|
margin-top: 4px;
|
||||||
|
width: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.browser-frame-address-bar {
|
||||||
|
background-color: var(--vscode-input-background);
|
||||||
|
border-radius: 12.5px;
|
||||||
|
color: var(--vscode-input-foreground);
|
||||||
|
flex: 1 0;
|
||||||
|
font: 400 16px Arial,sans-serif;
|
||||||
|
margin: 0 16px 0 8px;
|
||||||
|
padding: 5px 15px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.browser-frame-menu-bar {
|
||||||
|
background-color: #aaa;
|
||||||
|
display: block;
|
||||||
|
height: 3px;
|
||||||
|
margin: 3px 0;
|
||||||
|
width: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.browser-frame-header {
|
||||||
|
align-items: center;
|
||||||
|
background: #ebedf0;
|
||||||
|
display: flex;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-top-left-radius: 6px;
|
||||||
|
border-top-right-radius: 6px;
|
||||||
|
height: var(--browser-frame-header-height);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .browser-frame-header {
|
||||||
|
background: #444950;
|
||||||
|
}
|
||||||
38
packages/trace-viewer/src/ui/browserFrame.tsx
Normal file
38
packages/trace-viewer/src/ui/browserFrame.tsx
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import './browserFrame.css';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
export const BrowserFrame: React.FunctionComponent<{
|
||||||
|
url?: string,
|
||||||
|
}> = ({ url }) => {
|
||||||
|
return <div className='browser-frame-header'>
|
||||||
|
<div style={{ whiteSpace: 'nowrap' }}>
|
||||||
|
<span className='browser-frame-dot' style={{ backgroundColor: 'rgb(242, 95, 88)' }}></span>
|
||||||
|
<span className='browser-frame-dot' style={{ backgroundColor: 'rgb(251, 190, 60)' }}></span>
|
||||||
|
<span className='browser-frame-dot' style={{ backgroundColor: 'rgb(88, 203, 66)' }}></span>
|
||||||
|
</div>
|
||||||
|
<div className='browser-frame-address-bar' title={url || 'about:blank'}>{url || 'about:blank'}</div>
|
||||||
|
<div style={{ marginLeft: 'auto' }}>
|
||||||
|
<div>
|
||||||
|
<span className='browser-frame-menu-bar'></span>
|
||||||
|
<span className='browser-frame-menu-bar'></span>
|
||||||
|
<span className='browser-frame-menu-bar'></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
background-color: white;
|
background-color: var(--vscode-panel-background);
|
||||||
box-shadow: rgba(0, 0, 0, 0.133) 0px 1.6px 10px 0px, rgba(0, 0, 0, 0.11) 0px 0.3px 10px 0px;
|
box-shadow: rgba(0, 0, 0, 0.133) 0px 1.6px 10px 0px, rgba(0, 0, 0, 0.11) 0px 0.3px 10px 0px;
|
||||||
z-index: 200;
|
z-index: 200;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
@ -56,4 +56,5 @@
|
||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,10 +75,10 @@ export const FilmStrip: React.FunctionComponent<{
|
||||||
top: measure.bottom + 5,
|
top: measure.bottom + 5,
|
||||||
left: Math.min(previewPoint!.x, measure.width - previewSize.width - 10),
|
left: Math.min(previewPoint!.x, measure.width - previewSize.width - 10),
|
||||||
}}>
|
}}>
|
||||||
|
{previewPoint.action && <div className='film-strip-hover-title'>{renderAction(previewPoint.action, previewPoint.sdkLanguage)}</div>}
|
||||||
<div style={{ width: previewSize.width, height: previewSize.height }}>
|
<div style={{ width: previewSize.width, height: previewSize.height }}>
|
||||||
<img src={`sha1/${previewImage.sha1}`} width={previewSize.width} height={previewSize.height} />
|
<img src={`sha1/${previewImage.sha1}`} width={previewSize.width} height={previewSize.height} />
|
||||||
</div>
|
</div>
|
||||||
{previewPoint.action && <div className='film-strip-hover-title'>{renderAction(previewPoint.action, previewPoint.sdkLanguage)}</div>}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>;
|
</div>;
|
||||||
|
|
|
||||||
42
packages/trace-viewer/src/ui/inspectorTab.tsx
Normal file
42
packages/trace-viewer/src/ui/inspectorTab.tsx
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { CodeMirrorWrapper } from '@web/components/codeMirrorWrapper';
|
||||||
|
import type { Language } from '@web/components/codeMirrorWrapper';
|
||||||
|
import { ToolbarButton } from '@web/components/toolbarButton';
|
||||||
|
import { copy } from '@web/uiUtils';
|
||||||
|
import * as React from 'react';
|
||||||
|
import './sourceTab.css';
|
||||||
|
|
||||||
|
export const InspectorTab: React.FunctionComponent<{
|
||||||
|
sdkLanguage: Language,
|
||||||
|
setIsInspecting: (isInspecting: boolean) => void,
|
||||||
|
highlightedLocator: string,
|
||||||
|
setHighlightedLocator: (locator: string) => void,
|
||||||
|
}> = ({ sdkLanguage, setIsInspecting, highlightedLocator, setHighlightedLocator }) => {
|
||||||
|
return <div className='vbox'>
|
||||||
|
<CodeMirrorWrapper text={highlightedLocator} language={sdkLanguage} focusOnChange={true} wrapLines={true} onChange={text => {
|
||||||
|
// Updating text needs to go first - react can squeeze a render between the state updates.
|
||||||
|
setHighlightedLocator(text);
|
||||||
|
setIsInspecting(false);
|
||||||
|
}}></CodeMirrorWrapper>
|
||||||
|
<div style={{ position: 'absolute', right: '0', top: '0' }}>
|
||||||
|
<ToolbarButton icon='files' title='Copy locator' onClick={() => {
|
||||||
|
copy(highlightedLocator);
|
||||||
|
}}></ToolbarButton>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
|
@ -125,50 +125,6 @@ iframe.snapshot-visible[name=snapshot] {
|
||||||
opacity: var(--vscode-disabledForeground);
|
opacity: var(--vscode-disabledForeground);
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-dot {
|
|
||||||
border-radius: 50%;
|
|
||||||
display: inline-block;
|
|
||||||
height: 12px;
|
|
||||||
margin-right: 6px;
|
|
||||||
margin-top: 4px;
|
|
||||||
width: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-address-bar {
|
|
||||||
background-color: var(--vscode-input-background);
|
|
||||||
border-radius: 12.5px;
|
|
||||||
color: var(--vscode-input-foreground);
|
|
||||||
flex: 1 0;
|
|
||||||
font: 400 16px Arial,sans-serif;
|
|
||||||
margin: 0 16px 0 8px;
|
|
||||||
padding: 5px 15px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-menu-bar {
|
|
||||||
background-color: #aaa;
|
|
||||||
display: block;
|
|
||||||
height: 3px;
|
|
||||||
margin: 3px 0;
|
|
||||||
width: 17px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-header {
|
|
||||||
align-items: center;
|
|
||||||
background: #ebedf0;
|
|
||||||
display: flex;
|
|
||||||
padding: 8px 16px;
|
|
||||||
border-top-left-radius: 6px;
|
|
||||||
border-top-right-radius: 6px;
|
|
||||||
height: var(--window-header-height);
|
|
||||||
}
|
|
||||||
|
|
||||||
body.dark-mode .window-header {
|
|
||||||
background: #444950;
|
|
||||||
}
|
|
||||||
|
|
||||||
.snapshot-tab .cm-wrapper {
|
.snapshot-tab .cm-wrapper {
|
||||||
line-height: 23px;
|
line-height: 23px;
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,9 @@ import './snapshotTab.css';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import type { ActionTraceEvent } from '@trace/trace';
|
import type { ActionTraceEvent } from '@trace/trace';
|
||||||
import { context, prevInList } from './modelUtil';
|
import { context, prevInList } from './modelUtil';
|
||||||
import { CodeMirrorWrapper } from '@web/components/codeMirrorWrapper';
|
|
||||||
import { Toolbar } from '@web/components/toolbar';
|
import { Toolbar } from '@web/components/toolbar';
|
||||||
import { ToolbarButton } from '@web/components/toolbarButton';
|
import { ToolbarButton } from '@web/components/toolbarButton';
|
||||||
import { copy, useMeasure } from '@web/uiUtils';
|
import { useMeasure } from '@web/uiUtils';
|
||||||
import { InjectedScript } from '@injected/injectedScript';
|
import { InjectedScript } from '@injected/injectedScript';
|
||||||
import { Recorder } from '@injected/recorder';
|
import { Recorder } from '@injected/recorder';
|
||||||
import ConsoleAPI from '@injected/consoleApi';
|
import ConsoleAPI from '@injected/consoleApi';
|
||||||
|
|
@ -29,17 +28,19 @@ import { asLocator } from '@isomorphic/locatorGenerators';
|
||||||
import type { Language } from '@isomorphic/locatorGenerators';
|
import type { Language } from '@isomorphic/locatorGenerators';
|
||||||
import { locatorOrSelectorAsSelector } from '@isomorphic/locatorParser';
|
import { locatorOrSelectorAsSelector } from '@isomorphic/locatorParser';
|
||||||
import { TabbedPaneTab } from '@web/components/tabbedPane';
|
import { TabbedPaneTab } from '@web/components/tabbedPane';
|
||||||
|
import { BrowserFrame } from './browserFrame';
|
||||||
|
|
||||||
export const SnapshotTab: React.FunctionComponent<{
|
export const SnapshotTab: React.FunctionComponent<{
|
||||||
action: ActionTraceEvent | undefined,
|
action: ActionTraceEvent | undefined,
|
||||||
sdkLanguage: Language,
|
sdkLanguage: Language,
|
||||||
testIdAttributeName: string,
|
testIdAttributeName: string,
|
||||||
}> = ({ action, sdkLanguage, testIdAttributeName }) => {
|
isInspecting: boolean,
|
||||||
|
setIsInspecting: (isInspecting: boolean) => void,
|
||||||
|
highlightedLocator: string,
|
||||||
|
setHighlightedLocator: (locator: string) => void,
|
||||||
|
}> = ({ action, sdkLanguage, testIdAttributeName, isInspecting, setIsInspecting, highlightedLocator, setHighlightedLocator }) => {
|
||||||
const [measure, ref] = useMeasure<HTMLDivElement>();
|
const [measure, ref] = useMeasure<HTMLDivElement>();
|
||||||
const [snapshotTab, setSnapshotTab] = React.useState<'action'|'before'|'after'>('action');
|
const [snapshotTab, setSnapshotTab] = React.useState<'action'|'before'|'after'>('action');
|
||||||
const [isInspecting, setIsInspecting] = React.useState(false);
|
|
||||||
const [highlightedLocator, setHighlightedLocator] = React.useState<string>('');
|
|
||||||
const [pickerVisible, setPickerVisible] = React.useState(false);
|
|
||||||
|
|
||||||
const { snapshots } = React.useMemo(() => {
|
const { snapshots } = React.useMemo(() => {
|
||||||
if (!action)
|
if (!action)
|
||||||
|
|
@ -171,11 +172,6 @@ export const SnapshotTab: React.FunctionComponent<{
|
||||||
iframe={iframeRef1.current}
|
iframe={iframeRef1.current}
|
||||||
iteration={loadingRef.current.iteration} />
|
iteration={loadingRef.current.iteration} />
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<ToolbarButton title='Pick locator' disabled={!popoutUrl} toggled={pickerVisible} onClick={() => {
|
|
||||||
setPickerVisible(!pickerVisible);
|
|
||||||
setHighlightedLocator('');
|
|
||||||
setIsInspecting(!pickerVisible);
|
|
||||||
}}>Pick locator</ToolbarButton>
|
|
||||||
{['action', 'before', 'after'].map(tab => {
|
{['action', 'before', 'after'].map(tab => {
|
||||||
return <TabbedPaneTab
|
return <TabbedPaneTab
|
||||||
id={tab}
|
id={tab}
|
||||||
|
|
@ -193,40 +189,13 @@ export const SnapshotTab: React.FunctionComponent<{
|
||||||
});
|
});
|
||||||
}}></ToolbarButton>
|
}}></ToolbarButton>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
{pickerVisible && <Toolbar noMinHeight={true}>
|
|
||||||
<ToolbarButton icon='microscope' title='Pick locator' disabled={!popoutUrl} toggled={isInspecting} onClick={() => {
|
|
||||||
setIsInspecting(!isInspecting);
|
|
||||||
}}></ToolbarButton>
|
|
||||||
<CodeMirrorWrapper text={highlightedLocator} language={sdkLanguage} readOnly={!popoutUrl} focusOnChange={true} wrapLines={true} onChange={text => {
|
|
||||||
// Updating text needs to go first - react can squeeze a render between the state updates.
|
|
||||||
setHighlightedLocator(text);
|
|
||||||
setIsInspecting(false);
|
|
||||||
}}></CodeMirrorWrapper>
|
|
||||||
<ToolbarButton icon='files' title='Copy locator' disabled={!popoutUrl} onClick={() => {
|
|
||||||
copy(highlightedLocator);
|
|
||||||
}}></ToolbarButton>
|
|
||||||
</Toolbar>}
|
|
||||||
<div ref={ref} className='snapshot-wrapper'>
|
<div ref={ref} className='snapshot-wrapper'>
|
||||||
<div className='snapshot-container' style={{
|
<div className='snapshot-container' style={{
|
||||||
width: snapshotContainerSize.width + 'px',
|
width: snapshotContainerSize.width + 'px',
|
||||||
height: snapshotContainerSize.height + 'px',
|
height: snapshotContainerSize.height + 'px',
|
||||||
transform: `translate(${translate.x}px, ${translate.y}px) scale(${scale})`,
|
transform: `translate(${translate.x}px, ${translate.y}px) scale(${scale})`,
|
||||||
}}>
|
}}>
|
||||||
<div className='window-header'>
|
<BrowserFrame url={snapshotInfo.url} />
|
||||||
<div style={{ whiteSpace: 'nowrap' }}>
|
|
||||||
<span className='window-dot' style={{ backgroundColor: 'rgb(242, 95, 88)' }}></span>
|
|
||||||
<span className='window-dot' style={{ backgroundColor: 'rgb(251, 190, 60)' }}></span>
|
|
||||||
<span className='window-dot' style={{ backgroundColor: 'rgb(88, 203, 66)' }}></span>
|
|
||||||
</div>
|
|
||||||
<div className='window-address-bar' title={snapshotInfo.url || 'about:blank'}>{snapshotInfo.url || 'about:blank'}</div>
|
|
||||||
<div style={{ marginLeft: 'auto' }}>
|
|
||||||
<div>
|
|
||||||
<span className='window-menu-bar'></span>
|
|
||||||
<span className='window-menu-bar'></span>
|
|
||||||
<span className='window-menu-bar'></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='snapshot-switcher'>
|
<div className='snapshot-switcher'>
|
||||||
<iframe ref={iframeRef0} name='snapshot' className={loadingRef.current.visibleIframe === 0 ? 'snapshot-visible' : ''}></iframe>
|
<iframe ref={iframeRef0} name='snapshot' className={loadingRef.current.visibleIframe === 0 ? 'snapshot-visible' : ''}></iframe>
|
||||||
<iframe ref={iframeRef1} name='snapshot' className={loadingRef.current.visibleIframe === 1 ? 'snapshot-visible' : ''}></iframe>
|
<iframe ref={iframeRef1} name='snapshot' className={loadingRef.current.visibleIframe === 1 ? 'snapshot-visible' : ''}></iframe>
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ export const SourceTab: React.FunctionComponent<{
|
||||||
return { source, highlight, targetLine, fileName };
|
return { source, highlight, targetLine, fileName };
|
||||||
}, [action, selectedFrame, rootDir, fallbackLocation], { source: { errors: [], content: 'Loading\u2026' }, highlight: [] });
|
}, [action, selectedFrame, rootDir, fallbackLocation], { source: { errors: [], content: 'Loading\u2026' }, highlight: [] });
|
||||||
|
|
||||||
return <SplitView sidebarSize={200} orientation='vertical' sidebarHidden={hideStackFrames}>
|
return <SplitView sidebarSize={200} orientation='horizontal' sidebarHidden={hideStackFrames}>
|
||||||
<div className='vbox' data-testid='source-code'>
|
<div className='vbox' data-testid='source-code'>
|
||||||
{fileName && <div className='source-tab-file-name'>{fileName}</div>}
|
{fileName && <div className='source-tab-file-name'>{fileName}</div>}
|
||||||
<CodeMirrorWrapper text={source.content || ''} language='javascript' highlight={highlight} revealLine={targetLine} readOnly={true} lineNumbers={true} />
|
<CodeMirrorWrapper text={source.content || ''} language='javascript' highlight={highlight} revealLine={targetLine} readOnly={true} lineNumbers={true} />
|
||||||
|
|
|
||||||
|
|
@ -570,8 +570,7 @@ const TraceView: React.FC<{
|
||||||
initialSelection={initialSelection}
|
initialSelection={initialSelection}
|
||||||
onSelectionChanged={onSelectionChanged}
|
onSelectionChanged={onSelectionChanged}
|
||||||
fallbackLocation={item.testFile}
|
fallbackLocation={item.testFile}
|
||||||
isLive={model?.isLive}
|
isLive={model?.isLive} />;
|
||||||
drawer='bottom' />;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let receiver: TeleReporterReceiver | undefined;
|
let receiver: TeleReporterReceiver | undefined;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ import { Timeline } from './timeline';
|
||||||
import { MetadataView } from './metadataView';
|
import { MetadataView } from './metadataView';
|
||||||
import { AttachmentsTab } from './attachmentsTab';
|
import { AttachmentsTab } from './attachmentsTab';
|
||||||
import type { Boundaries } from '../geometry';
|
import type { Boundaries } from '../geometry';
|
||||||
|
import { InspectorTab } from './inspectorTab';
|
||||||
|
import { ToolbarButton } from '@web/components/toolbarButton';
|
||||||
|
|
||||||
export const Workbench: React.FunctionComponent<{
|
export const Workbench: React.FunctionComponent<{
|
||||||
model?: MultiTraceModel,
|
model?: MultiTraceModel,
|
||||||
|
|
@ -40,12 +42,13 @@ export const Workbench: React.FunctionComponent<{
|
||||||
initialSelection?: ActionTraceEventInContext,
|
initialSelection?: ActionTraceEventInContext,
|
||||||
onSelectionChanged?: (action: ActionTraceEventInContext) => void,
|
onSelectionChanged?: (action: ActionTraceEventInContext) => void,
|
||||||
isLive?: boolean,
|
isLive?: boolean,
|
||||||
drawer?: 'bottom' | 'right',
|
}> = ({ model, hideStackFrames, showSourcesFirst, rootDir, fallbackLocation, initialSelection, onSelectionChanged, isLive }) => {
|
||||||
}> = ({ model, hideStackFrames, showSourcesFirst, rootDir, fallbackLocation, initialSelection, onSelectionChanged, isLive, drawer }) => {
|
|
||||||
const [selectedAction, setSelectedAction] = React.useState<ActionTraceEventInContext | undefined>(undefined);
|
const [selectedAction, setSelectedAction] = React.useState<ActionTraceEventInContext | undefined>(undefined);
|
||||||
const [highlightedAction, setHighlightedAction] = React.useState<ActionTraceEventInContext | undefined>();
|
const [highlightedAction, setHighlightedAction] = React.useState<ActionTraceEventInContext | undefined>();
|
||||||
const [selectedNavigatorTab, setSelectedNavigatorTab] = React.useState<string>('actions');
|
const [selectedNavigatorTab, setSelectedNavigatorTab] = React.useState<string>('actions');
|
||||||
const [selectedPropertiesTab, setSelectedPropertiesTab] = React.useState<string>(showSourcesFirst ? 'source' : 'call');
|
const [selectedPropertiesTab, setSelectedPropertiesTab] = React.useState<string>(showSourcesFirst ? 'source' : 'call');
|
||||||
|
const [isInspecting, setIsInspecting] = React.useState(false);
|
||||||
|
const [highlightedLocator, setHighlightedLocator] = React.useState<string>('');
|
||||||
const activeAction = model ? highlightedAction || selectedAction : undefined;
|
const activeAction = model ? highlightedAction || selectedAction : undefined;
|
||||||
const [selectedTime, setSelectedTime] = React.useState<Boundaries | undefined>();
|
const [selectedTime, setSelectedTime] = React.useState<Boundaries | undefined>();
|
||||||
|
|
||||||
|
|
@ -68,8 +71,22 @@ export const Workbench: React.FunctionComponent<{
|
||||||
onSelectionChanged?.(action);
|
onSelectionChanged?.(action);
|
||||||
}, [setSelectedAction, onSelectionChanged]);
|
}, [setSelectedAction, onSelectionChanged]);
|
||||||
|
|
||||||
|
const locatorPicked = React.useCallback((locator: string) => {
|
||||||
|
setHighlightedLocator(locator);
|
||||||
|
setSelectedPropertiesTab('inspector');
|
||||||
|
}, []);
|
||||||
|
|
||||||
const sdkLanguage = model?.sdkLanguage || 'javascript';
|
const sdkLanguage = model?.sdkLanguage || 'javascript';
|
||||||
|
|
||||||
|
const inspectorTab: TabbedPaneTabModel = {
|
||||||
|
id: 'inspector',
|
||||||
|
title: 'Locator',
|
||||||
|
render: () => <InspectorTab
|
||||||
|
sdkLanguage={sdkLanguage}
|
||||||
|
setIsInspecting={setIsInspecting}
|
||||||
|
highlightedLocator={highlightedLocator}
|
||||||
|
setHighlightedLocator={setHighlightedLocator} />,
|
||||||
|
};
|
||||||
const callTab: TabbedPaneTabModel = {
|
const callTab: TabbedPaneTabModel = {
|
||||||
id: 'call',
|
id: 'call',
|
||||||
title: 'Call',
|
title: 'Call',
|
||||||
|
|
@ -102,12 +119,14 @@ export const Workbench: React.FunctionComponent<{
|
||||||
};
|
};
|
||||||
|
|
||||||
const tabs: TabbedPaneTabModel[] = showSourcesFirst ? [
|
const tabs: TabbedPaneTabModel[] = showSourcesFirst ? [
|
||||||
|
inspectorTab,
|
||||||
sourceTab,
|
sourceTab,
|
||||||
consoleTab,
|
consoleTab,
|
||||||
networkTab,
|
networkTab,
|
||||||
callTab,
|
callTab,
|
||||||
attachmentsTab,
|
attachmentsTab,
|
||||||
] : [
|
] : [
|
||||||
|
inspectorTab,
|
||||||
callTab,
|
callTab,
|
||||||
consoleTab,
|
consoleTab,
|
||||||
networkTab,
|
networkTab,
|
||||||
|
|
@ -135,34 +154,50 @@ export const Workbench: React.FunctionComponent<{
|
||||||
selectedTime={selectedTime}
|
selectedTime={selectedTime}
|
||||||
setSelectedTime={setSelectedTime}
|
setSelectedTime={setSelectedTime}
|
||||||
/>
|
/>
|
||||||
<SplitView sidebarSize={drawer === 'bottom' ? 250 : 400} orientation={drawer === 'bottom' ? 'vertical' : 'horizontal'}>
|
<SplitView sidebarSize={400} orientation='horizontal' sidebarIsFirst={true}>
|
||||||
<SplitView sidebarSize={250} orientation='horizontal' sidebarIsFirst={true}>
|
<SplitView sidebarSize={250} orientation='vertical'>
|
||||||
<SnapshotTab action={activeAction} sdkLanguage={sdkLanguage} testIdAttributeName={model?.testIdAttributeName || 'data-testid'} />
|
<SnapshotTab
|
||||||
<TabbedPane tabs={
|
action={activeAction}
|
||||||
[
|
sdkLanguage={sdkLanguage}
|
||||||
{
|
testIdAttributeName={model?.testIdAttributeName || 'data-testid'}
|
||||||
id: 'actions',
|
isInspecting={isInspecting}
|
||||||
title: 'Actions',
|
setIsInspecting={setIsInspecting}
|
||||||
component: <ActionList
|
highlightedLocator={highlightedLocator}
|
||||||
sdkLanguage={sdkLanguage}
|
setHighlightedLocator={locatorPicked} />
|
||||||
actions={model?.actions || []}
|
<TabbedPane
|
||||||
selectedAction={model ? selectedAction : undefined}
|
tabs={tabs}
|
||||||
selectedTime={selectedTime}
|
selectedTab={selectedPropertiesTab}
|
||||||
onSelected={onActionSelected}
|
setSelectedTab={setSelectedPropertiesTab}
|
||||||
onHighlighted={setHighlightedAction}
|
leftToolbar={[
|
||||||
revealConsole={() => setSelectedPropertiesTab('console')}
|
<ToolbarButton icon='microscope' title='Pick locator' toggled={isInspecting} onClick={() => {
|
||||||
isLive={isLive}
|
setIsInspecting(!isInspecting);
|
||||||
/>
|
}}></ToolbarButton>
|
||||||
},
|
]}
|
||||||
{
|
/>
|
||||||
id: 'metadata',
|
|
||||||
title: 'Metadata',
|
|
||||||
component: <MetadataView model={model}/>
|
|
||||||
},
|
|
||||||
]
|
|
||||||
} selectedTab={selectedNavigatorTab} setSelectedTab={setSelectedNavigatorTab}/>
|
|
||||||
</SplitView>
|
</SplitView>
|
||||||
<TabbedPane tabs={tabs} selectedTab={selectedPropertiesTab} setSelectedTab={setSelectedPropertiesTab} />
|
<TabbedPane
|
||||||
|
tabs={[
|
||||||
|
{
|
||||||
|
id: 'actions',
|
||||||
|
title: 'Actions',
|
||||||
|
component: <ActionList
|
||||||
|
sdkLanguage={sdkLanguage}
|
||||||
|
actions={model?.actions || []}
|
||||||
|
selectedAction={model ? selectedAction : undefined}
|
||||||
|
selectedTime={selectedTime}
|
||||||
|
onSelected={onActionSelected}
|
||||||
|
onHighlighted={setHighlightedAction}
|
||||||
|
revealConsole={() => setSelectedPropertiesTab('console')}
|
||||||
|
isLive={isLive}
|
||||||
|
/>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'metadata',
|
||||||
|
title: 'Metadata',
|
||||||
|
component: <MetadataView model={model}/>
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
selectedTab={selectedNavigatorTab} setSelectedTab={setSelectedNavigatorTab}/>
|
||||||
</SplitView>
|
</SplitView>
|
||||||
</div>;
|
</div>;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,7 @@ test('should show snapshot URL', async ({ page, runAndTrace, server }) => {
|
||||||
await page.evaluate('2+2');
|
await page.evaluate('2+2');
|
||||||
});
|
});
|
||||||
await traceViewer.snapshotFrame('page.evaluate');
|
await traceViewer.snapshotFrame('page.evaluate');
|
||||||
await expect(traceViewer.page.locator('.window-address-bar')).toHaveText(server.EMPTY_PAGE);
|
await expect(traceViewer.page.locator('.browser-frame-address-bar')).toHaveText(server.EMPTY_PAGE);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should popup snapshot', async ({ page, runAndTrace, server }) => {
|
test('should popup snapshot', async ({ page, runAndTrace, server }) => {
|
||||||
|
|
@ -862,7 +862,7 @@ test('should update highlight when typing', async ({ page, runAndTrace, server }
|
||||||
await page.setContent('<button>Submit</button>');
|
await page.setContent('<button>Submit</button>');
|
||||||
});
|
});
|
||||||
const snapshot = await traceViewer.snapshotFrame('page.setContent');
|
const snapshot = await traceViewer.snapshotFrame('page.setContent');
|
||||||
await traceViewer.page.getByTitle('Pick locator').click();
|
await traceViewer.page.getByText('Locator').click();
|
||||||
await traceViewer.page.locator('.CodeMirror').click();
|
await traceViewer.page.locator('.CodeMirror').click();
|
||||||
await traceViewer.page.keyboard.type('button');
|
await traceViewer.page.keyboard.type('button');
|
||||||
await expect(snapshot.locator('x-pw-glass')).toBeVisible();
|
await expect(snapshot.locator('x-pw-glass')).toBeVisible();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue