Skip to content

Commit f92dee5

Browse files
authored
Users/mordvinx/testplane 404.new UI error boundaries (#630)
* feat(css): add min-width and min-height to app In the future, it will help to render ErrorBoundary to the full screen. * refactor(visual-checks): extract VisualCheckStickyHeader FC * refactor(test-steps): raise CollapsibleSection, extract TestStep FC * feat(error-handling): add ErrorHandling components * style(suite-title): remove unused interface * feat(test-step): add corrupted style for test step item * feat(error-handling): add usages of ErrorHandler component * refactor(error-handler): rename file * refactor(error-handler): reorganize components * feat(error-handler): add top level error handler * feat(error-handler): additional message * fix(icons): add new icons Не добавил сразу, потому что они под gitignore * feat(error-handler): change error font size from 15px to 13px * feat(error-handler): fallback components will take 100% of width * feat(error-handler): change data corruption fallback style * feat(error-handler): raise AssertViewResult error handling * feat(error-handler): reorganize fallbacks and add styling * feat(error-handling): clip stack if length is more than 50 lines * fix(imports): remove unused import * feat(error-handling): change icon * fix(styles): pretty width limitation for separator * refactor(error-info): remove stack clipping * feat(corrupted-test-step): update warning colors * refactor(error-actions): do not use internals * refactor(naming): rename ErrorHandler Root to Boundary * feat(error-handler): add recommended action for CardCrash * feat(error-boundary): add handling for any typed values * feat(error-handling): change data corrution fallback align * feat(error-handling): add handling for broken pages * feat(error-handling): full width buttons * fix(error-info): fix weird borders * feat(error-handling): set code block max height * fix(error-handling): fix mistypes * feat(tests): add svg import stub --------- Co-authored-by: = <=>
1 parent d057ffc commit f92dee5

File tree

24 files changed

+776
-249
lines changed

24 files changed

+776
-249
lines changed
Lines changed: 5 additions & 0 deletions
Loading

lib/static/icons/github-icon.svg

Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 5 additions & 0 deletions
Loading

lib/static/new-ui.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,18 @@ body {
2323
}
2424

2525
.report {
26+
min-width: 100%;
27+
min-height: 100%;
2628
font-family: var(--g-font-family-sans), sans-serif !important;
2729
margin-bottom: 0 !important;;
2830
}
2931

32+
#app {
33+
position: relative;
34+
min-width: 100%;
35+
min-height: 100%;
36+
}
37+
3038
/* Aside header styles */
3139
:root {
3240
--gn-aside-header-item-current-background-color: #1f2937;

lib/static/new-ui/app/App.tsx

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {CustomScripts} from '@/static/new-ui/components/CustomScripts';
1717
import {State} from '@/static/new-ui/types/store';
1818
import {AnalyticsProvider} from '@/static/new-ui/providers/analytics';
1919
import {MetrikaScript} from '@/static/new-ui/components/MetrikaScript';
20+
import {ErrorHandler} from '../features/error-handling/components/ErrorHandling';
2021

2122
export function App(): ReactNode {
2223
const pages = [
@@ -33,26 +34,38 @@ export function App(): ReactNode {
3334
const customScripts = (store.getState() as State).config.customScripts;
3435

3536
return <StrictMode>
36-
<CustomScripts scripts={customScripts} />
37-
<ThemeProvider theme='light'>
38-
<ToasterProvider>
39-
<Provider store={store}>
40-
<MetrikaScript/>
41-
<AnalyticsProvider>
42-
<HashRouter>
43-
<MainLayout menuItems={pages}>
44-
<LoadingBar/>
45-
<Routes>
46-
<Route element={<Navigate to={'/suites'}/>} path={'/'}/>
47-
{pages.map(page => <Route element={page.element} path={page.url} key={page.url}>{page.children}</Route>)}
48-
</Routes>
49-
<GuiniToolbarOverlay/>
50-
<ToasterComponent />
51-
</MainLayout>
52-
</HashRouter>
53-
</AnalyticsProvider>
54-
</Provider>
55-
</ToasterProvider>
56-
</ThemeProvider>
37+
<ErrorHandler.Boundary fallback={<ErrorHandler.FallbackAppCrash />}>
38+
<CustomScripts scripts={customScripts} />
39+
<ThemeProvider theme='light'>
40+
<ToasterProvider>
41+
<Provider store={store}>
42+
<MetrikaScript/>
43+
<AnalyticsProvider>
44+
<HashRouter>
45+
<ErrorHandler.Boundary fallback={<ErrorHandler.FallbackAppCrash />}>
46+
<MainLayout menuItems={pages}>
47+
<LoadingBar/>
48+
<Routes>
49+
<Route element={<Navigate to={'/suites'}/>} path={'/'}/>
50+
{pages.map(page => (
51+
<Route element={
52+
<ErrorHandler.Boundary watchFor={[page.url]} fallback={<ErrorHandler.FallbackAppCrash />}>
53+
{ page.element}
54+
</ErrorHandler.Boundary>
55+
} path={page.url} key={page.url}>
56+
{page.children}
57+
</Route>
58+
))}
59+
</Routes>
60+
<GuiniToolbarOverlay/>
61+
<ToasterComponent />
62+
</MainLayout>
63+
</ErrorHandler.Boundary>
64+
</HashRouter>
65+
</AnalyticsProvider>
66+
</Provider>
67+
</ToasterProvider>
68+
</ThemeProvider>
69+
</ErrorHandler.Boundary>
5770
</StrictMode>;
5871
}

lib/static/new-ui/components/AssertViewResult/index.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,30 @@ interface AssertViewResultProps {
1818
function AssertViewResultInternal({result, diffMode, style}: AssertViewResultProps): ReactNode {
1919
if (result.status === TestStatus.FAIL) {
2020
return <DiffViewer diffMode={diffMode} {...result} />;
21-
} else if (result.status === TestStatus.ERROR) {
21+
}
22+
23+
if (result.status === TestStatus.ERROR) {
2224
return <div className={styles.screenshotContainer}>
2325
<ImageLabel title={'Actual'} subtitle={getImageDisplayedSize(result.actualImg)} />
2426
<Screenshot containerStyle={style} containerClassName={styles.screenshot} image={result.actualImg} />
2527
</div>;
26-
} else if (result.status === TestStatus.SUCCESS || result.status === TestStatus.UPDATED) {
28+
}
29+
30+
if (result.status === TestStatus.SUCCESS || result.status === TestStatus.UPDATED) {
2731
return <div className={styles.screenshotContainer}>
2832
<ImageLabel title={'Expected'} subtitle={getImageDisplayedSize(result.expectedImg)} />
2933
<Screenshot containerStyle={style} containerClassName={styles.screenshot} image={result.expectedImg} />
3034
</div>;
31-
} else if (result.status === TestStatus.STAGED) {
35+
}
36+
37+
if (result.status === TestStatus.STAGED) {
3238
return <div className={styles.screenshotContainer}>
3339
<ImageLabel title={'Staged'} subtitle={getImageDisplayedSize(result.actualImg)} />
3440
<Screenshot containerStyle={style} containerClassName={styles.screenshot} image={result.actualImg} />
3541
</div>;
36-
} else if (result.status === TestStatus.COMMITED) {
42+
}
43+
44+
if (result.status === TestStatus.COMMITED) {
3745
return <div className={styles.screenshotContainer}>
3846
<ImageLabel title={'Committed'} subtitle={getImageDisplayedSize(result.actualImg)} />
3947
<Screenshot containerStyle={style} containerClassName={styles.screenshot} image={result.actualImg} />

lib/static/new-ui/components/ErrorInfo/index.module.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
overflow-y: hidden;
66
background: #101827;
77
border-radius: 5px;
8-
border: 12px solid #101827;
8+
padding: 12px;
99
box-shadow: rgba(0, 0, 0, 0) 0 0 0 0, rgba(0, 0, 0, 0) 0 0 0 0, rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.1) 0 4px 6px -4px;
1010
}

lib/static/new-ui/components/SuiteTitle/index.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ import styles from './index.module.css';
77

88
interface SuiteTitleProps {
99
className?: string;
10-
}
11-
12-
interface SuiteTitlePropsInternal extends SuiteTitleProps {
1310
suitePath: string[];
1411
browserName: string;
1512
stateName?: string;
@@ -19,7 +16,7 @@ interface SuiteTitlePropsInternal extends SuiteTitleProps {
1916
onNext: () => void;
2017
}
2118

22-
export function SuiteTitle(props: SuiteTitlePropsInternal): ReactNode {
19+
export function SuiteTitle(props: SuiteTitleProps): ReactNode {
2320
const suiteName = props.suitePath[props.suitePath.length - 1];
2421
const suitePath = props.suitePath.slice(0, -1);
2522

lib/static/new-ui/components/TreeViewItem/index.module.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,20 @@
1616
cursor: pointer;
1717

1818
padding-left: calc(var(--indent) * 24px);
19+
20+
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out;
1921
}
2022

2123
.tree-view-item--error {
2224
--g-color-base-simple-hover: var(--g-color-private-red-50);
2325
background: var(--g-color-private-red-100);
2426
color: var(--g-color-private-red-600-solid);
2527
}
28+
29+
.tree-view-item--corrupted {
30+
--g-color-base-simple-hover: hsl(32deg 100% 48% / 20%);
31+
background-color: rgba(255, 235, 206, 1);
32+
color: hsl(32 100% 48% / 1);
33+
--box-shadow-color: hsl(32deg 100% 48% / 42%);
34+
--g-button-text-color-hover: hsl(32 100% 48% / 1);
35+
}

lib/static/new-ui/components/TreeViewItem/index.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ interface TreeListItemProps<T> {
2121
id: string;
2222
list: UseListResult<T>;
2323
mapItemDataToContentProps: (data: T) => ListItemViewContentType;
24-
isFailed?: boolean;
24+
status?: 'error' | 'corrupted';
2525
onItemClick?: (data: {id: string}) => unknown;
2626
}
2727

@@ -34,7 +34,8 @@ export function TreeViewItem<T>(props: TreeListItemProps<T>): ReactNode {
3434
>
3535
<ListItemView
3636
className={classNames([styles.treeViewItem, {
37-
[styles['tree-view-item--error']]: props.isFailed
37+
[styles['tree-view-item--corrupted']]: props.status === 'corrupted',
38+
[styles['tree-view-item--error']]: props.status === 'error'
3839
}])}
3940
activeOnHover={true}
4041
style={{'--indent': indent + Number(!hasChildren)} as React.CSSProperties}

0 commit comments

Comments
 (0)