Fix testing for MUI breakpoints
Signed-off-by: Philipp Hugenroth <philipph@spotify.com>
This commit is contained in:
@@ -14,96 +14,30 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { act } from '@testing-library/react';
|
||||
|
||||
type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
||||
|
||||
const defaultBreakpoint: Breakpoint = 'xl';
|
||||
|
||||
const queryToBreakpoint = {
|
||||
'(min-width:1920px)': 'xl',
|
||||
'(min-width:1280px)': 'lg',
|
||||
'(min-width:960px)': 'md',
|
||||
'(min-width:600px)': 'sm',
|
||||
'(min-width:0px)': 'xs',
|
||||
} as Record<string, Breakpoint>;
|
||||
|
||||
/**
|
||||
* Converts media query string to Breakpoint.
|
||||
* Chooses the default breakpoint if no breakpoint is set in the media query.
|
||||
* This is a mocking method suggested in the Jest Doc's, as it is not implemented in JSDOM yet.
|
||||
* It can be used to mock values when the MUI `useMediaQuery` hook if it is used in a tested component.
|
||||
*
|
||||
* @param query media query string
|
||||
* @returns Breakpoint
|
||||
* For issues checkout the documentation:
|
||||
* https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
|
||||
*
|
||||
* If there are any updates from MUI React on testing `useMediaQuery` this mock should be replaced
|
||||
* https://material-ui.com/components/use-media-query/#testing
|
||||
*
|
||||
* @param matchMediaOptions
|
||||
*/
|
||||
function toBreakpoint(query: string): Breakpoint {
|
||||
return queryToBreakpoint[query]
|
||||
? queryToBreakpoint[query]
|
||||
: defaultBreakpoint;
|
||||
}
|
||||
|
||||
type Listener = (event: { matches: boolean }) => void;
|
||||
|
||||
interface QueryList {
|
||||
addListener(listener: Listener): void;
|
||||
removeListener(listener: Listener): void;
|
||||
addEventListener(listener: Listener): void;
|
||||
removeEventListener(listener: Listener): void;
|
||||
matches: boolean;
|
||||
}
|
||||
|
||||
interface Query {
|
||||
query: string;
|
||||
queryList: QueryList;
|
||||
listeners: Set<Listener>;
|
||||
}
|
||||
|
||||
export default function mockBreakpoint(
|
||||
initialBreakpoint: Breakpoint = defaultBreakpoint,
|
||||
) {
|
||||
let currentBreakpoint = initialBreakpoint;
|
||||
const queries = Array<Query>();
|
||||
|
||||
const previousMatchMedia: any = (window as any).matchMedia;
|
||||
|
||||
// https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
|
||||
(window as any).matchMedia = (query: string): QueryList => {
|
||||
const listeners = new Set<Listener>();
|
||||
|
||||
const queryList: QueryList = {
|
||||
addListener(listener) {
|
||||
listeners.add(listener);
|
||||
},
|
||||
removeListener(listener) {
|
||||
listeners.delete(listener);
|
||||
},
|
||||
addEventListener(listener) {
|
||||
listeners.add(listener);
|
||||
},
|
||||
removeEventListener(listener) {
|
||||
listeners.delete(listener);
|
||||
},
|
||||
matches: toBreakpoint(query) === currentBreakpoint,
|
||||
};
|
||||
|
||||
queries.push({ query, queryList, listeners });
|
||||
|
||||
return queryList;
|
||||
};
|
||||
|
||||
return {
|
||||
set(breakpoint: Breakpoint) {
|
||||
currentBreakpoint = breakpoint;
|
||||
|
||||
act(() => {
|
||||
queries.forEach(({ query, queryList, listeners }) => {
|
||||
const matches = toBreakpoint(query) === breakpoint;
|
||||
queryList.matches = matches;
|
||||
listeners.forEach(listener => listener({ matches }));
|
||||
});
|
||||
});
|
||||
},
|
||||
remove() {
|
||||
(window as any).matchMedia = previousMatchMedia;
|
||||
},
|
||||
};
|
||||
export default function mockBreakpoint({ matches = false }) {
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: jest.fn().mockImplementation(query => ({
|
||||
matches: matches,
|
||||
media: query,
|
||||
onchange: null,
|
||||
addListener: jest.fn(), // deprecated
|
||||
removeListener: jest.fn(), // deprecated
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
dispatchEvent: jest.fn(),
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -112,8 +112,6 @@ describe('CatalogPage', () => {
|
||||
getProfile: () => testProfile,
|
||||
};
|
||||
|
||||
const { set: setBreakpoint } = mockBreakpoint();
|
||||
|
||||
const renderWrapped = (children: React.ReactNode) =>
|
||||
renderWithEffects(
|
||||
wrapInTestApp(
|
||||
@@ -248,9 +246,16 @@ describe('CatalogPage', () => {
|
||||
).resolves.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should wrap filter in accordion on smaller screens', async () => {
|
||||
setBreakpoint('sm');
|
||||
const { findByText } = await renderWrapped(<CatalogPage />);
|
||||
await expect(findByText(/Filters/)).resolves.toBeInTheDocument();
|
||||
it('should wrap filter in drawer on smaller screens', async () => {
|
||||
mockBreakpoint({ matches: true });
|
||||
const { findByText, getByTestId } = await renderWrapped(<CatalogPage />);
|
||||
expect(getByTestId('entity-filters-drawer')).toBeInTheDocument();
|
||||
await expect(findByText('Filters')).resolves.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should wrap filter in grid on larger screens', async () => {
|
||||
mockBreakpoint({ matches: false });
|
||||
const { getByTestId } = await renderWrapped(<CatalogPage />);
|
||||
expect(getByTestId('entity-filters-grid')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,6 +27,7 @@ export const FilterContainer = ({ children }: React.PropsWithChildren<{}>) => {
|
||||
|
||||
return isMidSizeScreen ? (
|
||||
<Drawer
|
||||
data-testid="entity-filters-drawer"
|
||||
open={showFiltersDrawer}
|
||||
onClose={() => {
|
||||
toggleFiltersDrawer(false);
|
||||
@@ -43,7 +44,7 @@ export const FilterContainer = ({ children }: React.PropsWithChildren<{}>) => {
|
||||
<Box m={2}>{children}</Box>
|
||||
</Drawer>
|
||||
) : (
|
||||
<Grid item lg={2}>
|
||||
<Grid data-testid="entity-filters-grid" item lg={2}>
|
||||
{children}
|
||||
</Grid>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user