cherry-pick(#23148): chore: do not annotate actions after failed ones as timed out
This commit is contained in:
parent
cd94a3f01d
commit
552cba8c05
|
|
@ -76,13 +76,6 @@ export class TraceModel {
|
||||||
unzipProgress(++done, total);
|
unzipProgress(++done, total);
|
||||||
|
|
||||||
contextEntry.actions = [...actionMap.values()].sort((a1, a2) => a1.startTime - a2.startTime);
|
contextEntry.actions = [...actionMap.values()].sort((a1, a2) => a1.startTime - a2.startTime);
|
||||||
if (!backend.isLive()) {
|
|
||||||
for (const action of contextEntry.actions) {
|
|
||||||
if (!action.endTime && !action.error)
|
|
||||||
action.error = { name: 'Error', message: 'Timed out' };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const stacks = await this._backend.readText(ordinal + '.stacks');
|
const stacks = await this._backend.readText(ordinal + '.stacks');
|
||||||
if (stacks) {
|
if (stacks) {
|
||||||
const callMetadata = parseClientSideCallMetadata(JSON.parse(stacks));
|
const callMetadata = parseClientSideCallMetadata(JSON.parse(stacks));
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ export interface ActionListProps {
|
||||||
onSelected: (action: ActionTraceEvent) => void,
|
onSelected: (action: ActionTraceEvent) => void,
|
||||||
onHighlighted: (action: ActionTraceEvent | undefined) => void,
|
onHighlighted: (action: ActionTraceEvent | undefined) => void,
|
||||||
revealConsole: () => void,
|
revealConsole: () => void,
|
||||||
|
isLive?: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActionTreeItem = {
|
type ActionTreeItem = {
|
||||||
|
|
@ -49,6 +50,7 @@ export const ActionList: React.FC<ActionListProps> = ({
|
||||||
onSelected,
|
onSelected,
|
||||||
onHighlighted,
|
onHighlighted,
|
||||||
revealConsole,
|
revealConsole,
|
||||||
|
isLive,
|
||||||
}) => {
|
}) => {
|
||||||
const [treeState, setTreeState] = React.useState<TreeState>({ expandedItems: new Map() });
|
const [treeState, setTreeState] = React.useState<TreeState>({ expandedItems: new Map() });
|
||||||
const { rootItem, itemMap } = React.useMemo(() => {
|
const { rootItem, itemMap } = React.useMemo(() => {
|
||||||
|
|
@ -86,14 +88,15 @@ export const ActionList: React.FC<ActionListProps> = ({
|
||||||
onSelected={item => onSelected(item.action!)}
|
onSelected={item => onSelected(item.action!)}
|
||||||
onHighlighted={item => onHighlighted(item?.action)}
|
onHighlighted={item => onHighlighted(item?.action)}
|
||||||
isError={item => !!item.action?.error?.message}
|
isError={item => !!item.action?.error?.message}
|
||||||
render={item => renderAction(item.action!, sdkLanguage, revealConsole)}
|
render={item => renderAction(item.action!, sdkLanguage, revealConsole, isLive || false)}
|
||||||
/>;
|
/>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderAction = (
|
const renderAction = (
|
||||||
action: ActionTraceEvent,
|
action: ActionTraceEvent,
|
||||||
sdkLanguage: Language | undefined,
|
sdkLanguage: Language | undefined,
|
||||||
revealConsole: () => void
|
revealConsole: () => void,
|
||||||
|
isLive: boolean,
|
||||||
) => {
|
) => {
|
||||||
const { errors, warnings } = modelUtil.stats(action);
|
const { errors, warnings } = modelUtil.stats(action);
|
||||||
const locator = action.params.selector ? asLocator(sdkLanguage || 'javascript', action.params.selector, false /* isFrameLocator */, true /* playSafe */) : undefined;
|
const locator = action.params.selector ? asLocator(sdkLanguage || 'javascript', action.params.selector, false /* isFrameLocator */, true /* playSafe */) : undefined;
|
||||||
|
|
@ -103,6 +106,8 @@ const renderAction = (
|
||||||
time = msToString(action.endTime - action.startTime);
|
time = msToString(action.endTime - action.startTime);
|
||||||
else if (action.error)
|
else if (action.error)
|
||||||
time = 'Timed out';
|
time = 'Timed out';
|
||||||
|
else if (!isLive)
|
||||||
|
time = '-';
|
||||||
return <>
|
return <>
|
||||||
<div className='action-title'>
|
<div className='action-title'>
|
||||||
<span>{action.apiName}</span>
|
<span>{action.apiName}</span>
|
||||||
|
|
|
||||||
|
|
@ -492,7 +492,7 @@ const TraceView: React.FC<{
|
||||||
item: { testFile?: SourceLocation, testCase?: TestCase },
|
item: { testFile?: SourceLocation, testCase?: TestCase },
|
||||||
rootDir?: string,
|
rootDir?: string,
|
||||||
}> = ({ item, rootDir }) => {
|
}> = ({ item, rootDir }) => {
|
||||||
const [model, setModel] = React.useState<MultiTraceModel | undefined>();
|
const [model, setModel] = React.useState<{ model: MultiTraceModel, isLive: boolean } | undefined>();
|
||||||
const [counter, setCounter] = React.useState(0);
|
const [counter, setCounter] = React.useState(0);
|
||||||
const pollTimer = React.useRef<NodeJS.Timeout | null>(null);
|
const pollTimer = React.useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
|
|
@ -505,7 +505,7 @@ const TraceView: React.FC<{
|
||||||
// This avoids auto-selection of the last action every time we reload the model.
|
// This avoids auto-selection of the last action every time we reload the model.
|
||||||
const [selectedActionId, setSelectedActionId] = React.useState<string | undefined>();
|
const [selectedActionId, setSelectedActionId] = React.useState<string | undefined>();
|
||||||
const onSelectionChanged = React.useCallback((action: ActionTraceEvent) => setSelectedActionId(idForAction(action)), [setSelectedActionId]);
|
const onSelectionChanged = React.useCallback((action: ActionTraceEvent) => setSelectedActionId(idForAction(action)), [setSelectedActionId]);
|
||||||
const initialSelection = selectedActionId ? model?.actions.find(a => idForAction(a) === selectedActionId) : undefined;
|
const initialSelection = selectedActionId ? model?.model.actions.find(a => idForAction(a) === selectedActionId) : undefined;
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (pollTimer.current)
|
if (pollTimer.current)
|
||||||
|
|
@ -520,7 +520,7 @@ const TraceView: React.FC<{
|
||||||
// Test finished.
|
// Test finished.
|
||||||
const attachment = result && result.duration >= 0 && result.attachments.find(a => a.name === 'trace');
|
const attachment = result && result.duration >= 0 && result.attachments.find(a => a.name === 'trace');
|
||||||
if (attachment && attachment.path) {
|
if (attachment && attachment.path) {
|
||||||
loadSingleTraceFile(attachment.path).then(model => setModel(model));
|
loadSingleTraceFile(attachment.path).then(model => setModel({ model, isLive: false }));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -534,7 +534,7 @@ const TraceView: React.FC<{
|
||||||
pollTimer.current = setTimeout(async () => {
|
pollTimer.current = setTimeout(async () => {
|
||||||
try {
|
try {
|
||||||
const model = await loadSingleTraceFile(traceLocation);
|
const model = await loadSingleTraceFile(traceLocation);
|
||||||
setModel(model);
|
setModel({ model, isLive: true });
|
||||||
} catch {
|
} catch {
|
||||||
setModel(undefined);
|
setModel(undefined);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -549,14 +549,15 @@ const TraceView: React.FC<{
|
||||||
|
|
||||||
return <Workbench
|
return <Workbench
|
||||||
key='workbench'
|
key='workbench'
|
||||||
model={model}
|
model={model?.model}
|
||||||
hideTimelineBars={true}
|
hideTimelineBars={true}
|
||||||
hideStackFrames={true}
|
hideStackFrames={true}
|
||||||
showSourcesFirst={true}
|
showSourcesFirst={true}
|
||||||
rootDir={rootDir}
|
rootDir={rootDir}
|
||||||
initialSelection={initialSelection}
|
initialSelection={initialSelection}
|
||||||
onSelectionChanged={onSelectionChanged}
|
onSelectionChanged={onSelectionChanged}
|
||||||
fallbackLocation={item.testFile} />;
|
fallbackLocation={item.testFile}
|
||||||
|
isLive={model?.isLive} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,8 @@ export const Workbench: React.FunctionComponent<{
|
||||||
fallbackLocation?: modelUtil.SourceLocation,
|
fallbackLocation?: modelUtil.SourceLocation,
|
||||||
initialSelection?: ActionTraceEvent,
|
initialSelection?: ActionTraceEvent,
|
||||||
onSelectionChanged?: (action: ActionTraceEvent) => void,
|
onSelectionChanged?: (action: ActionTraceEvent) => void,
|
||||||
}> = ({ model, hideTimelineBars, hideStackFrames, showSourcesFirst, rootDir, fallbackLocation, initialSelection, onSelectionChanged }) => {
|
isLive?: boolean,
|
||||||
|
}> = ({ model, hideTimelineBars, hideStackFrames, showSourcesFirst, rootDir, fallbackLocation, initialSelection, onSelectionChanged, isLive }) => {
|
||||||
const [selectedAction, setSelectedAction] = React.useState<ActionTraceEvent | undefined>(undefined);
|
const [selectedAction, setSelectedAction] = React.useState<ActionTraceEvent | undefined>(undefined);
|
||||||
const [highlightedAction, setHighlightedAction] = React.useState<ActionTraceEvent | undefined>();
|
const [highlightedAction, setHighlightedAction] = React.useState<ActionTraceEvent | undefined>();
|
||||||
const [selectedNavigatorTab, setSelectedNavigatorTab] = React.useState<string>('actions');
|
const [selectedNavigatorTab, setSelectedNavigatorTab] = React.useState<string>('actions');
|
||||||
|
|
@ -142,6 +143,7 @@ export const Workbench: React.FunctionComponent<{
|
||||||
onSelected={onActionSelected}
|
onSelected={onActionSelected}
|
||||||
onHighlighted={setHighlightedAction}
|
onHighlighted={setHighlightedAction}
|
||||||
revealConsole={() => setSelectedPropertiesTab('console')}
|
revealConsole={() => setSelectedPropertiesTab('console')}
|
||||||
|
isLive={isLive}
|
||||||
/>
|
/>
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -98,9 +98,12 @@ test('should merge screenshot assertions', async ({ runUITest }, testInfo) => {
|
||||||
'action list'
|
'action list'
|
||||||
).toHaveText([
|
).toHaveText([
|
||||||
/Before Hooks[\d.]+m?s/,
|
/Before Hooks[\d.]+m?s/,
|
||||||
/page\.setContent[\d.]+m?s/,
|
/page.setContent[\d.]+m?s/,
|
||||||
/expect\.toHaveScreenshot[\d.]+m?s/,
|
/expect.toHaveScreenshot[\d.]+m?s/,
|
||||||
/After Hooks/,
|
/After Hooks-/,
|
||||||
|
/fixture: page[\d.]+m?s/,
|
||||||
|
/fixture: context[\d.]+m?s/,
|
||||||
|
/fixture: browser[\d.]+m?s/,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue