Skip to content

Commit 7400e37

Browse files
authored
Auto-scroll to the last failed test step (#10595)
1 parent 36a460f commit 7400e37

File tree

5 files changed

+30
-9
lines changed

5 files changed

+30
-9
lines changed

packages/e2e-tests/tests/react_devtools-02-integrations.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ test("react_devtools-02: RDT integrations (Chromium)", async ({
140140
await searchComponents(page, "Anonymous"); // Search and select 1st result
141141
await verifySearchResults(page, {
142142
currentNumber: 1,
143-
totalNumber: 16,
143+
totalNumber: 17,
144144
});
145145

146146
await componentSearchInput.focus();
@@ -149,7 +149,7 @@ test("react_devtools-02: RDT integrations (Chromium)", async ({
149149
await componentSearchInput.press("Enter");
150150
await verifySearchResults(page, {
151151
currentNumber: 4,
152-
totalNumber: 16,
152+
totalNumber: 17,
153153
});
154154

155155
await viewSourceButton.click();

src/ui/components/TestSuite/views/TestRecording/Panel.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import assert from "assert";
2+
import findLast from "lodash/findLast";
23
import { useCallback, useContext, useEffect, useRef, useState } from "react";
34
import {
45
ImperativePanelHandle,
@@ -115,12 +116,8 @@ export default function Panel() {
115116
// Select first failed event by default
116117
if (testRecording.result === "failed") {
117118
chosenTestEvent =
118-
main.find(testEvent => {
119-
switch (testEvent.type) {
120-
case "user-action":
121-
return testEvent.data.error != null;
122-
}
123-
}) ?? null;
119+
findLast(main, testEvent => testEvent.type === "user-action" && !!testEvent.data.error) ??
120+
null;
124121
}
125122

126123
// Or just select first event

src/ui/components/TestSuite/views/TestRecording/TestRecordingEvents/UserActionEventRow.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import assert from "assert";
22
import { ExecutionPoint, Location, TimeStampedPoint } from "@replayio/protocol";
3-
import { Suspense, memo, useContext, useMemo, useState } from "react";
3+
import { Suspense, memo, useContext, useEffect, useMemo, useRef, useState } from "react";
44
import { Cache, STATUS_PENDING, STATUS_RESOLVED, useImperativeCacheValue } from "suspense";
55

66
import { getExecutionPoint } from "devtools/client/debugger/src/selectors";
@@ -47,12 +47,14 @@ const cypressStepTypesToEventTypes = {
4747
export default memo(function UserActionEventRow({
4848
groupedTestCases,
4949
isSelected,
50+
scrollIntoView,
5051
testEvents,
5152
testSectionName,
5253
userActionEvent,
5354
}: {
5455
groupedTestCases: RecordingTestMetadataV3.GroupedTestCases;
5556
isSelected: boolean;
57+
scrollIntoView?: boolean;
5658
testEvents: TestEvent[];
5759
testSectionName: TestSectionName;
5860
userActionEvent: UserActionEvent;
@@ -148,6 +150,16 @@ export default memo(function UserActionEventRow({
148150
return null;
149151
}, [parentId, testRecording, testSectionName, userActionEvent]);
150152

153+
const ref = useRef<HTMLDivElement>(null);
154+
useEffect(() => {
155+
if (scrollIntoView) {
156+
// Chrome sometimes ignores scrollIntoView here if it is called immediately
157+
setTimeout(() => {
158+
ref.current?.scrollIntoView({ behavior: "smooth", block: "center" });
159+
});
160+
}
161+
}, [scrollIntoView]);
162+
151163
return (
152164
<div
153165
className={styles.Row}
@@ -156,6 +168,7 @@ export default memo(function UserActionEventRow({
156168
onClick={jumpToTestSourceDisabled ? undefined : onClickJumpToTestSource}
157169
onMouseEnter={() => setIsHovered(true)}
158170
onMouseLeave={() => setIsHovered(false)}
171+
ref={ref}
159172
>
160173
<div className={styles.Text}>
161174
{eventNumber != null ? <div className={styles.Number}>{eventNumber}</div> : null}

src/ui/components/TestSuite/views/TestRecording/TestSection.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import findLast from "lodash/findLast";
2+
13
import {
24
TestEvent,
35
TestRunnerName,
@@ -22,6 +24,11 @@ export default function TestSection({
2224
return null;
2325
}
2426

27+
const scrollToEvent =
28+
testSectionName === "main"
29+
? findLast(testEvents, evt => evt.type === "user-action" && !!evt.data.error)
30+
: undefined;
31+
2532
return (
2633
<>
2734
<div className={styles.Title} data-test-name="TestSection">
@@ -30,6 +37,7 @@ export default function TestSection({
3037
{testEvents.map((testEvent, index) => (
3138
<TestSectionRow
3239
key={index}
40+
scrollIntoView={testEvent === scrollToEvent}
3341
testEvent={testEvent}
3442
testEvents={testEvents}
3543
testRunnerName={testRunnerName}

src/ui/components/TestSuite/views/TestRecording/TestSectionRow.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@ import { Position } from "./types";
3636
import styles from "./TestSectionRow.module.css";
3737

3838
export function TestSectionRow({
39+
scrollIntoView,
3940
testEvent,
4041
testEvents,
4142
testRunnerName,
4243
testSectionName,
4344
}: {
45+
scrollIntoView?: boolean;
4446
testEvent: TestEvent;
4547
testEvents: TestEvent[];
4648
testRunnerName: TestRunnerName | null;
@@ -118,6 +120,7 @@ export function TestSectionRow({
118120
testEvents={testEvents}
119121
testSectionName={testSectionName}
120122
userActionEvent={testEvent}
123+
scrollIntoView={scrollIntoView}
121124
/>
122125
);
123126
status = testEvent.data.error ? "error" : "success";

0 commit comments

Comments
 (0)