๐Ÿ“ฆ mui / mui-x

๐Ÿ“„ TestViewer.tsx ยท 141 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141import * as React from 'react';
import { useLocation } from 'react-router';
import { styled } from '@mui/material/styles';
import GlobalStyles from '@mui/material/GlobalStyles';
// eslint-disable-next-line import/no-relative-packages
import { fakeClock, setupFakeClock } from '../utils/setupFakeClock';

const StyledBox = styled('div', {
  shouldForwardProp: (prop) => prop !== 'isDataGridTest' && prop !== 'isDataGridPivotTest',
})<{ isDataGridTest?: boolean; isDataGridPivotTest?: boolean }>(
  ({ theme, isDataGridTest, isDataGridPivotTest }) => ({
    backgroundColor: theme.palette.background.default,
    display: 'flex',
    padding: theme.spacing(1),
    justifyContent: 'center',
    ...(isDataGridTest && {
      width: isDataGridPivotTest ? 800 : 500,
      minHeight: 400,
      // Workaround the min-height limitation
      '& .grid-container': {
        position: 'relative',
        '& > .MuiDataGrid-root': {
          position: 'absolute',
          top: 0,
          right: 0,
          left: 0,
          bottom: 0,
        },
      },
    }),
  }),
);

function TestViewer(props: any) {
  const { children, isDataGridTest, isDataGridPivotTest, shouldAdvanceTime, path } = props;

  return (
    <React.Fragment>
      <GlobalStyles
        styles={{
          html: {
            WebkitFontSmoothing: 'antialiased', // Antialiasing.
            MozOsxFontSmoothing: 'grayscale', // Antialiasing.
            // Do the opposite of the docs in order to help catching issues.
            boxSizing: 'content-box',
          },
          '*, *::before, *::after': {
            boxSizing: 'inherit',
            // Disable transitions to avoid flaky screenshots
            transition: 'none !important',
            animation: 'none !important',
          },
          body: {
            margin: 0,
            overflowX: 'hidden',
          },
          '@media print': {
            '@page': {
              size: 'auto',
              margin: 0,
            },
          },
        }}
      />
      <MockTime shouldAdvanceTime={shouldAdvanceTime}>
        <LoadFont
          isDataGridTest={isDataGridTest}
          isDataGridPivotTest={isDataGridPivotTest}
          data-testpath={path}
        >
          {children}
        </LoadFont>
      </MockTime>
    </React.Fragment>
  );
}

function MockTime(props: React.PropsWithChildren<{ shouldAdvanceTime: boolean }>) {
  const [dispose, setDispose] = React.useState<(() => void) | null>(null);
  const [prevShouldAdvanceTime, setPrevShouldAdvanceTime] = React.useState(props.shouldAdvanceTime);

  if (!dispose || prevShouldAdvanceTime !== props.shouldAdvanceTime) {
    dispose?.();
    setDispose(() => setupFakeClock(props.shouldAdvanceTime));
    setPrevShouldAdvanceTime(props.shouldAdvanceTime);
  }

  return props.children;
}

function LoadFont(props: any) {
  const { children, ...other } = props;
  const location = useLocation();

  // We're simulating `act(() => ReactDOM.render(children))`
  // In the end children passive effects should've been flushed.
  // React doesn't have any such guarantee outside of `act()` so we're approximating it.
  const [ready, setReady] = React.useState(false);

  // In react-router v6, with multiple routes sharing the same element,
  // this effect will only run once if no dependency is passed.
  React.useEffect(() => {
    function handleFontsEvent(event: any) {
      if (event.type === 'loading') {
        setReady(false);
      } else if (event.type === 'loadingdone') {
        // Don't know if there could be multiple loaded events after we started loading multiple times.
        // So make sure we're only ready if fonts are actually ready.
        if (document.fonts.status === 'loaded') {
          setReady(true);
        }
      }
    }

    document.fonts.addEventListener('loading', handleFontsEvent);
    document.fonts.addEventListener('loadingdone', handleFontsEvent);

    // and wait `load-css` timeouts to be flushed
    fakeClock?.runToLast();

    // In case the child triggered font fetching we're not ready yet.
    // The fonts event handler will mark the test as ready on `loadingdone`
    if (document.fonts.status === 'loaded') {
      setReady(true);
    }

    return () => {
      document.fonts.removeEventListener('loading', handleFontsEvent);
      document.fonts.removeEventListener('loadingdone', handleFontsEvent);
    };
  }, [location]);

  return (
    <StyledBox aria-busy={!ready} data-testid="testcase" {...other}>
      {children}
    </StyledBox>
  );
}

export default TestViewer;