Fix tests to support window.matchMedia & add tests for responsiveness

Signed-off-by: Philipp Hugenroth <philipph@spotify.com>
This commit is contained in:
Philipp Hugenroth
2021-07-09 11:51:19 +02:00
parent 9cf8779dda
commit db935a4c10
3 changed files with 55 additions and 34 deletions
@@ -18,6 +18,8 @@ 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',
@@ -26,14 +28,17 @@ const queryToBreakpoint = {
'(min-width:0px)': 'xs',
} as Record<string, Breakpoint>;
function toBreakpoint(query: string) {
const breakpoint = queryToBreakpoint[query];
if (!breakpoint) {
throw new Error(
`received unknown media query in breakpoint mock: '${query}'`,
);
}
return breakpoint;
/**
* Converts media query string to Breakpoint.
* Chooses the default breakpoint if no breakpoint is set in the media query.
*
* @param query media query string
* @returns Breakpoint
*/
function toBreakpoint(query: string): Breakpoint {
return queryToBreakpoint[query]
? queryToBreakpoint[query]
: defaultBreakpoint;
}
type Listener = (event: { matches: boolean }) => void;
@@ -41,6 +46,8 @@ 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;
}
@@ -50,12 +57,15 @@ interface Query {
listeners: Set<Listener>;
}
export default function mockBreakpoint(initialBreakpoint: Breakpoint = 'xl') {
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>();
@@ -66,6 +76,12 @@ export default function mockBreakpoint(initialBreakpoint: Breakpoint = 'xl') {
removeListener(listener) {
listeners.delete(listener);
},
addEventListener(listener) {
listeners.add(listener);
},
removeEventListener(listener) {
listeners.delete(listener);
},
matches: toBreakpoint(query) === currentBreakpoint,
};
@@ -26,6 +26,7 @@ import {
MockStorageApi,
renderWithEffects,
wrapInTestApp,
mockBreakpoint,
} from '@backstage/test-utils';
import { fireEvent, screen } from '@testing-library/react';
import React from 'react';
@@ -111,6 +112,8 @@ describe('CatalogPage', () => {
getProfile: () => testProfile,
};
const { set: setBreakpoint } = mockBreakpoint();
const renderWrapped = (children: React.ReactNode) =>
renderWithEffects(
wrapInTestApp(
@@ -244,4 +247,10 @@ describe('CatalogPage', () => {
screen.findByText(/Starred \(1\)/),
).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();
});
});
@@ -43,28 +43,24 @@ export type CatalogPageProps = {
export const CatalogPage = ({
columns,
actions,
initiallySelectedFilter,
}: CatalogPageProps) => {
return (
<CatalogLayout>
<Content>
<ContentHeader title="Components">
<CreateComponentButton />
<SupportButton>All your software catalog entities</SupportButton>
</ContentHeader>
<Grid container spacing={2}>
<EntityListProvider>
<Grid item xs={12} sm={12} lg={2}>
<CatalogFilter
initiallySelectedFilter={initiallySelectedFilter}
/>
</Grid>
<Grid item xs={12} sm={12} lg={10}>
<CatalogTable columns={columns} actions={actions} />
</Grid>
</EntityListProvider>
</Grid>
</Content>
</CatalogLayout>
);
};
initiallySelectedFilter = 'owned',
}: CatalogPageProps) => (
<CatalogLayout>
<Content>
<ContentHeader title="Components">
<CreateComponentButton />
<SupportButton>All your software catalog entities</SupportButton>
</ContentHeader>
<Grid container spacing={2}>
<EntityListProvider>
<Grid item xs={12} sm={12} lg={2}>
<CatalogFilter initiallySelectedFilter={initiallySelectedFilter} />
</Grid>
<Grid item xs={12} sm={12} lg={10}>
<CatalogTable columns={columns} actions={actions} />
</Grid>
</EntityListProvider>
</Grid>
</Content>
</CatalogLayout>
);