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); 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));

View file

@ -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>

View file

@ -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 {

View file

@ -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}
/> />
}, },
{ {

View file

@ -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/,
]); ]);
}); });