cherry-pick(#23148): chore: do not annotate actions after failed ones as timed out

This commit is contained in:
Pavel Feldman 2023-05-18 15:52:44 -07:00
parent cd94a3f01d
commit 552cba8c05
5 changed files with 23 additions and 19 deletions

View file

@ -76,13 +76,6 @@ export class TraceModel {
unzipProgress(++done, total);
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');
if (stacks) {
const callMetadata = parseClientSideCallMetadata(JSON.parse(stacks));

View file

@ -31,6 +31,7 @@ export interface ActionListProps {
onSelected: (action: ActionTraceEvent) => void,
onHighlighted: (action: ActionTraceEvent | undefined) => void,
revealConsole: () => void,
isLive?: boolean,
}
type ActionTreeItem = {
@ -49,6 +50,7 @@ export const ActionList: React.FC<ActionListProps> = ({
onSelected,
onHighlighted,
revealConsole,
isLive,
}) => {
const [treeState, setTreeState] = React.useState<TreeState>({ expandedItems: new Map() });
const { rootItem, itemMap } = React.useMemo(() => {
@ -86,14 +88,15 @@ export const ActionList: React.FC<ActionListProps> = ({
onSelected={item => onSelected(item.action!)}
onHighlighted={item => onHighlighted(item?.action)}
isError={item => !!item.action?.error?.message}
render={item => renderAction(item.action!, sdkLanguage, revealConsole)}
render={item => renderAction(item.action!, sdkLanguage, revealConsole, isLive || false)}
/>;
};
const renderAction = (
action: ActionTraceEvent,
sdkLanguage: Language | undefined,
revealConsole: () => void
revealConsole: () => void,
isLive: boolean,
) => {
const { errors, warnings } = modelUtil.stats(action);
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);
else if (action.error)
time = 'Timed out';
else if (!isLive)
time = '-';
return <>
<div className='action-title'>
<span>{action.apiName}</span>

View file

@ -492,7 +492,7 @@ const TraceView: React.FC<{
item: { testFile?: SourceLocation, testCase?: TestCase },
rootDir?: string,
}> = ({ 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 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.
const [selectedActionId, setSelectedActionId] = React.useState<string | undefined>();
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(() => {
if (pollTimer.current)
@ -520,7 +520,7 @@ const TraceView: React.FC<{
// Test finished.
const attachment = result && result.duration >= 0 && result.attachments.find(a => a.name === 'trace');
if (attachment && attachment.path) {
loadSingleTraceFile(attachment.path).then(model => setModel(model));
loadSingleTraceFile(attachment.path).then(model => setModel({ model, isLive: false }));
return;
}
@ -534,7 +534,7 @@ const TraceView: React.FC<{
pollTimer.current = setTimeout(async () => {
try {
const model = await loadSingleTraceFile(traceLocation);
setModel(model);
setModel({ model, isLive: true });
} catch {
setModel(undefined);
} finally {
@ -549,14 +549,15 @@ const TraceView: React.FC<{
return <Workbench
key='workbench'
model={model}
model={model?.model}
hideTimelineBars={true}
hideStackFrames={true}
showSourcesFirst={true}
rootDir={rootDir}
initialSelection={initialSelection}
onSelectionChanged={onSelectionChanged}
fallbackLocation={item.testFile} />;
fallbackLocation={item.testFile}
isLive={model?.isLive} />;
};
declare global {

View file

@ -41,7 +41,8 @@ export const Workbench: React.FunctionComponent<{
fallbackLocation?: modelUtil.SourceLocation,
initialSelection?: ActionTraceEvent,
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 [highlightedAction, setHighlightedAction] = React.useState<ActionTraceEvent | undefined>();
const [selectedNavigatorTab, setSelectedNavigatorTab] = React.useState<string>('actions');
@ -142,6 +143,7 @@ export const Workbench: React.FunctionComponent<{
onSelected={onActionSelected}
onHighlighted={setHighlightedAction}
revealConsole={() => setSelectedPropertiesTab('console')}
isLive={isLive}
/>
},
{

View file

@ -98,9 +98,12 @@ test('should merge screenshot assertions', async ({ runUITest }, testInfo) => {
'action list'
).toHaveText([
/Before Hooks[\d.]+m?s/,
/page\.setContent[\d.]+m?s/,
/expect\.toHaveScreenshot[\d.]+m?s/,
/After Hooks/,
/page.setContent[\d.]+m?s/,
/expect.toHaveScreenshot[\d.]+m?s/,
/After Hooks-/,
/fixture: page[\d.]+m?s/,
/fixture: context[\d.]+m?s/,
/fixture: browser[\d.]+m?s/,
]);
});