react-router#MemoryRouter TypeScript Examples
The following examples show how to use
react-router#MemoryRouter.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.test.tsx From firebase-tools-ui with Apache License 2.0 | 6 votes |
it('renders all emulators as "off" when error loading config', () => {
// We don't need to show the error here because there is an app-wide
// disconnected overlay. Just keep the layout and show everything as "off".
const { getByTestId } = render(
<MemoryRouter>
<TestEmulatorConfigProvider config={null}>
<Home />
</TestEmulatorConfigProvider>
</MemoryRouter>
);
for (const emulator of ['database', 'firestore', 'functions', 'extensions']) {
const card = getByTestId(`emulator-info-${emulator}`);
expect(getByText(card, 'Off')).not.toBeNull();
expect(getByText(card, 'N/A')).not.toBeNull(); // Port is N/A
}
});
Example #2
Source File: DebuggingMemoryRouter.ts From json-schema-viewer with Apache License 2.0 | 6 votes |
export class DebuggingMemoryRouter extends MemoryRouter {
constructor(props: MemoryRouterProps) {
super(props);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(this as any).history.listen((location: any, action: any) => { // tslint:disable-line:no-any
console.log(
`The current URL is ${location.pathname}${location.search}${location.hash}`
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
console.log(`The last navigation action was ${action}`, JSON.stringify((this as any).history, null, 2));
});
}
}
Example #3
Source File: CompareApiBreadcrumbs.stories.tsx From substrate-api-explorer with Apache License 2.0 | 6 votes |
storiesOf('COMPONENTS|CompareApiBreadcrumbs', module)
.addDecorator(story => (
<MemoryRouter initialEntries={['/']}>{story()}</MemoryRouter>
))
.add('default', () => {
const apiNameKnob = text(
'apiName',
'wss://kusama-rpc.polkadot.io/',
'props'
)
const urlKnob = text(
'apiexplorer.polkalert.com/compare-api/',
'query/staking',
'other'
)
return (
<div style={{ padding: '24px' }}>
<CompareApiBreadcrumbs
apiName={apiNameKnob}
match={{ url: `/compare-api/${urlKnob}` }}
/>
</div>
)
})
Example #4
Source File: Layout.test.tsx From glific-frontend with GNU Affero General Public License v3.0 | 6 votes |
describe('layout testing', () => {
it('renders the appropriate components', async () => {
const { getByTestId } = render(
<MockedProvider mocks={mocks}>
<MemoryRouter>
<Layout>Default layout</Layout>
</MemoryRouter>
</MockedProvider>
);
await waitFor(async () => await new Promise((resolve) => setTimeout(resolve, 0)));
expect(getByTestId('navbar')).toBeInTheDocument();
expect(getByTestId('layout')).toBeInTheDocument();
});
});
Example #5
Source File: InfoCard.stories.tsx From backstage with Apache License 2.0 | 6 votes |
Wrapper = ({ children }: PropsWithChildren<{}>) => (
<MemoryRouter>
<Grid container spacing={4}>
<Grid item xs={4}>
{children}
</Grid>
</Grid>
</MemoryRouter>
)
Example #6
Source File: Trigger.test.tsx From glific-frontend with GNU Affero General Public License v3.0 | 6 votes |
describe('trigger with hourly frequency', () => {
const mocks = [hourlyTrigger(), ...LIST_ITEM_MOCKS, ...SearchMocks];
const wrapper = (
<MockedProvider mocks={mocks} addTypename={false}>
<MemoryRouter>
<Trigger match={{ params: { id: '1' } }} />
</MemoryRouter>
</MockedProvider>
);
test('should load trigger edit form', async () => {
const { getByText, getByTestId } = render(wrapper);
// loading is show initially
expect(getByText('Loading...')).toBeInTheDocument();
await waitFor(() => {
const formLayout = getByTestId('formLayout');
expect(formLayout).toHaveTextContent('hours');
});
await waitFor(() => {
expect(getByText('1 AM')).toBeInTheDocument();
expect(getByText('1 PM')).toBeInTheDocument();
});
});
});
Example #7
Source File: BuildTable.stories.tsx From backstage with Apache License 2.0 | 6 votes |
ErrorMessage = () => (
<MemoryRouter>
<BuildTable
items={[]}
loading={false}
error={new Error('Failed to load builds!')}
/>
</MemoryRouter>
)
Example #8
Source File: MainList.spec.tsx From che-dashboard-next with Eclipse Public License 2.0 | 6 votes |
describe('Navigation Main List', () => {
function renderComponent(): RenderResult {
return render(
<MemoryRouter>
<Nav
onSelect={() => jest.fn()}
theme="light"
>
<NavigationMainList activePath="" />
</Nav>
</MemoryRouter>
);
}
it('should have correct number of main navigation items', () => {
renderComponent();
const navLinks = screen.getAllByRole('link');
expect(navLinks.length).toEqual(2);
});
it('should have correct navigation item labels', () => {
renderComponent();
const navLinks = screen.getAllByRole('link');
expect(navLinks[0]).toHaveTextContent('Get Started Page');
expect(navLinks[1]).toHaveTextContent('Workspaces');
});
});
Example #9
Source File: CollectionContactList.test.tsx From glific-frontend with GNU Affero General Public License v3.0 | 5 votes |
wrapper = ( <MockedProvider mocks={mocks} addTypename={false}> <MemoryRouter> <CollectionContactList match={{ params: { id: 1 } }} title={'Default Collection'} /> </MemoryRouter> </MockedProvider> )
Example #10
Source File: GaugeCard.stories.tsx From backstage with Apache License 2.0 | 5 votes |
Wrapper = ({ children }: PropsWithChildren<{}>) => (
<MemoryRouter>
<Grid container spacing={2}>
{children}
</Grid>
</MemoryRouter>
)
Example #11
Source File: ResetPasswordPhone.test.tsx From glific-frontend with GNU Affero General Public License v3.0 | 5 votes |
wrapper = ( <MemoryRouter> <ResetPasswordPhone /> </MemoryRouter> )
Example #12
Source File: TabbedLayout.stories.tsx From backstage with Apache License 2.0 | 5 votes |
Wrapper = ({ children }: PropsWithChildren<{}>) => (
<MemoryRouter>
<Routes>
<Route path="/*" element={<>{children}</>} />
</Routes>
</MemoryRouter>
)
Example #13
Source File: MainItem.spec.tsx From che-dashboard-next with Eclipse Public License 2.0 | 5 votes |
describe('Navigation Item', () => {
let activeItem = '';
const item: NavigationItemObject = {
icon: <HomeIcon />,
label: 'Home',
to: '/home',
};
function renderComponent(): RenderResult {
return render(
<MemoryRouter>
<NavigationMainItem
item={item}
activePath={activeItem}
>
{item.icon}
</NavigationMainItem>
</MemoryRouter>
);
}
it('should have correct label', () => {
renderComponent();
const link = screen.getByRole('link');
expect(link).toHaveTextContent('Home');
});
describe('activation', () => {
it('should render not active navigation item', () => {
renderComponent();
const link = screen.getByRole('link');
expect(link).not.toHaveAttribute('aria-current');
});
it('should render active navigation item', () => {
activeItem = '/home';
renderComponent();
const link = screen.getByRole('link');
expect(link).toHaveAttribute('aria-current');
});
it('should activate navigation item on props change', () => {
activeItem = '';
const { rerender } = renderComponent();
activeItem = '/home';
rerender(
<MemoryRouter>
<NavigationMainItem
item={item}
activePath={activeItem}
>
{item.icon}
</NavigationMainItem>
</MemoryRouter>
);
const link = screen.getByRole('link');
expect(link).toHaveAttribute('aria-current');
});
});
});
Example #14
Source File: ResetPasswordConfirmOTP.test.tsx From glific-frontend with GNU Affero General Public License v3.0 | 5 votes |
wrapper = ( <MemoryRouter> <ResetPasswordConfirmOTP {...defaultProps} /> </MemoryRouter> )
Example #15
Source File: RecentWorkflowRunsCard.test.tsx From backstage with Apache License 2.0 | 4 votes |
describe('<RecentWorkflowRunsCard />', () => {
const entity = {
apiVersion: 'v1',
kind: 'Component',
metadata: {
name: 'software',
annotations: {
'github.com/project-slug': 'theorg/the-service',
},
},
spec: {
owner: 'guest',
type: 'service',
lifecycle: 'production',
},
};
const workflowRuns = [1, 2, 3, 4, 5].map(n => ({
id: `run-id-${n}`,
message: `Commit message for workflow ${n}`,
source: { branchName: `branch-${n}` },
status: 'completed',
}));
beforeEach(() => {
(useWorkflowRuns as jest.Mock).mockReturnValue([{ runs: workflowRuns }]);
});
afterEach(() => {
jest.resetAllMocks();
});
const renderSubject = (props: RecentWorkflowRunsCardProps = {}) =>
render(
<ThemeProvider theme={lightTheme}>
<MemoryRouter>
<TestApiProvider
apis={[
[errorApiRef, mockErrorApi],
[configApiRef, configApi],
]}
>
<EntityProvider entity={entity}>
<RecentWorkflowRunsCard {...props} />
</EntityProvider>
</TestApiProvider>
</MemoryRouter>
</ThemeProvider>,
);
it('renders a table with a row for each workflow', async () => {
const subject = renderSubject();
workflowRuns.forEach(run => {
expect(subject.getByText(run.message)).toBeInTheDocument();
});
});
it('renders a workflow row correctly', async () => {
const subject = renderSubject();
const [run] = workflowRuns;
expect(subject.getByText(run.message).closest('a')).toHaveAttribute(
'href',
`/ci-cd/${run.id}`,
);
expect(subject.getByText(run.source.branchName)).toBeInTheDocument();
});
it('requests only the required number of workflow runs', async () => {
const limit = 3;
renderSubject({ limit });
expect(useWorkflowRuns).toHaveBeenCalledWith(
expect.objectContaining({ initialPageSize: limit }),
);
});
it('uses the github repo and owner from the entity annotation', async () => {
renderSubject();
expect(useWorkflowRuns).toHaveBeenCalledWith(
expect.objectContaining({ owner: 'theorg', repo: 'the-service' }),
);
});
it('filters workflows by branch if one is specified', async () => {
const branch = 'master';
renderSubject({ branch });
expect(useWorkflowRuns).toHaveBeenCalledWith(
expect.objectContaining({ branch }),
);
});
describe('where there is an error fetching workflows', () => {
const error = 'error getting workflows';
beforeEach(() => {
(useWorkflowRuns as jest.Mock).mockReturnValue([{ runs: [], error }]);
});
it('sends the error to the errorApi', async () => {
renderSubject();
expect(mockErrorApi.post).toHaveBeenCalledWith(error);
});
});
});
Example #16
Source File: ContactBar.test.tsx From glific-frontend with GNU Affero General Public License v3.0 | 4 votes |
describe('Menu test', () => {
beforeEach(async () => {
render(component);
await waitFor(() => {
fireEvent.click(screen.getByTestId('dropdownIcon')?.querySelector('svg'));
});
});
test('it should open a menu when dropdown icon is clicked', async () => {
expect(screen.getByText('View contact profile')).toBeInTheDocument();
});
test('clicking on add to collection button should open up a dialog box', async () => {
fireEvent.click(screen.getByTestId('collectionButton'));
await waitFor(() => {
expect(screen.getByText('Add contact to collection')).toBeInTheDocument();
expect(screen.getAllByText('Search')[1]).toBeInTheDocument();
fireEvent.click(screen.getAllByText('Search')[1]);
const button = screen.getByText('Save');
fireEvent.click(button);
});
});
test('close add to collection popup on click of cancel button', async () => {
fireEvent.click(screen.getByTestId('collectionButton'));
await waitFor(() => {
expect(screen.getByText('Add contact to collection')).toBeInTheDocument();
const button = screen.getByText('Cancel');
fireEvent.click(button);
});
});
test('clicking on Start flow should open up a dialog box', async () => {
fireEvent.click(screen.getByTestId('flowButton'));
await waitFor(() => {
expect(screen.getAllByText('Select flow')[0]).toBeInTheDocument();
});
await waitFor(() => {
const button = screen.getByText('Start');
fireEvent.click(button);
});
});
test('close start a flow popup on click of cancel button', async () => {
fireEvent.click(screen.getByTestId('flowButton'));
await waitFor(() => {
const button = screen.getByText('Cancel');
fireEvent.click(button);
});
});
test('check Chats option is present if screen size is less than 768', async () => {
// // Change the viewport to 500px.
global.innerWidth = 500;
// // Trigger the window resize event.
global.dispatchEvent(new Event('resize'));
expect(screen.getByText('UnselectedDark.svg')).toBeInTheDocument();
});
test('clicking on clear chat button should open up a dialog box', async () => {
fireEvent.click(screen.getByTestId('clearChatButton'));
await waitFor(() => {
expect(
screen.getByText('Are you sure you want to clear all conversation for this contact?')
).toBeInTheDocument();
// click on cancel
fireEvent.click(screen.getByTestId('ok-button'));
});
});
test('close clear conversation popup on click of cancel', async () => {
fireEvent.click(screen.getByTestId('clearChatButton'));
await waitFor(() => {
expect(
screen.getByText('Are you sure you want to clear all conversation for this contact?')
).toBeInTheDocument();
});
// click on cancel
fireEvent.click(screen.getByTestId('cancel-button'));
});
test('clicking on block button should open up a dialog box', async () => {
fireEvent.click(screen.getByTestId('blockButton'));
await waitFor(() => {
expect(screen.getByText('Do you want to block this contact')).toBeInTheDocument();
});
fireEvent.click(screen.getByText('Cancel'));
});
test('block a contact', async () => {
fireEvent.click(screen.getByTestId('blockButton'));
await waitFor(() => {
expect(screen.getByText('Do you want to block this contact')).toBeInTheDocument();
});
fireEvent.click(screen.getByText('Confirm'));
});
test('view contact profile', async () => {
fireEvent.click(screen.getByTestId('viewProfile'));
});
const componentWithBspStatusNone = (
<MockedProvider mocks={mocks} addTypename={false}>
<MemoryRouter>
<ContactBar {...propsWithBspStatusNone} />
</MemoryRouter>
</MockedProvider>
);
test('select flow should be blocked when Bsp Status is none', async () => {
cleanup();
const { getByTestId } = render(componentWithBspStatusNone);
await waitFor(() => {
fireEvent.click(getByTestId('dropdownIcon')?.querySelector('svg'));
});
await waitFor(() => {
expect(getByTestId('disabledFlowButton')).toBeInTheDocument();
});
});
});
Example #17
Source File: RecentList.spec.tsx From che-dashboard-next with Eclipse Public License 2.0 | 4 votes |
describe('Navigation Recent List', () => {
const workspaces: che.Workspace[] = [
{
id: 'wksp-1',
devfile: {
metadata: {
name: 'wksp-1'
}
},
attributes: {
updated: 1,
} as any,
} as che.Workspace,
{
id: 'wksp-2',
devfile: {
metadata: {
name: 'wksp-2'
}
},
attributes: {
updated: 2,
} as any,
} as che.Workspace,
{
id: 'wksp-3',
devfile: {
metadata: {
name: 'wksp-3'
}
},
attributes: {
updated: 3,
} as any,
} as che.Workspace,
];
function renderComponent(store: Store, workspaces: che.Workspace[]): RenderResult {
return render(
<Provider store={store}>
<MemoryRouter>
<Nav
onSelect={() => jest.fn()}
theme="light"
>
<NavigationRecentList workspaces={workspaces} activePath="" />
</Nav>
</MemoryRouter>
</Provider>
);
}
it('should have correct number of main navigation items', () => {
const store = createFakeStore(workspaces);
renderComponent(store, workspaces);
const navLinks = screen.getAllByRole('link');
expect(navLinks.length).toEqual(workspaces.length + 1);
});
it('should have correct navigation item labels', () => {
const store = createFakeStore(workspaces);
renderComponent(store, workspaces);
const navLinks = screen.getAllByRole('link');
expect(navLinks[0]).toHaveTextContent('Create Workspace');
expect(navLinks[1]).toHaveTextContent('wksp-1');
expect(navLinks[2]).toHaveTextContent('wksp-2');
expect(navLinks[3]).toHaveTextContent('wksp-3');
});
it('should correctly handle workspaces order', () => {
const store = createFakeStore(workspaces);
const { rerender } = renderComponent(store, workspaces);
// change workspaces order
[workspaces[0], workspaces[2]] = [workspaces[2], workspaces[0]];
rerender(
<Provider store={store}>
<MemoryRouter>
<Nav
onSelect={() => jest.fn()}
theme="light"
>
<NavigationRecentList workspaces={workspaces} activePath="" />
</Nav>
</MemoryRouter>
</Provider>
);
const navLinks = screen.getAllByRole('link');
expect(navLinks[0]).toHaveTextContent('Create Workspace');
expect(navLinks[1]).toHaveTextContent('wksp-3');
expect(navLinks[2]).toHaveTextContent('wksp-2');
expect(navLinks[3]).toHaveTextContent('wksp-1');
});
});
Example #18
Source File: appWrappers.tsx From backstage with Apache License 2.0 | 4 votes |
/**
* Creates a Wrapper component that wraps a component inside a Backstage test app,
* providing a mocked theme and app context, along with mocked APIs.
*
* @param options - Additional options for the rendering.
* @public
*/
export function createTestAppWrapper(
options: TestAppOptions = {},
): (props: { children: ReactNode }) => JSX.Element {
const { routeEntries = ['/'] } = options;
const boundRoutes = new Map<ExternalRouteRef, RouteRef>();
const app = createSpecializedApp({
apis: mockApis,
defaultApis,
// Bit of a hack to make sure that the default config loader isn't used
// as that would force every single test to wait for config loading.
configLoader: false as unknown as undefined,
components: {
Progress,
BootErrorPage,
NotFoundErrorPage,
ErrorBoundaryFallback,
Router: ({ children }) => (
<MemoryRouter initialEntries={routeEntries} children={children} />
),
},
icons: mockIcons,
plugins: [],
themes: [
{
id: 'light',
title: 'Test App Theme',
variant: 'light',
Provider: ({ children }) => (
<ThemeProvider theme={lightTheme}>
<CssBaseline>{children}</CssBaseline>
</ThemeProvider>
),
},
],
bindRoutes: ({ bind }) => {
for (const [externalRef, absoluteRef] of boundRoutes) {
bind(
{ ref: externalRef },
{
ref: absoluteRef,
},
);
}
},
});
const routeElements = Object.entries(options.mountedRoutes ?? {}).map(
([path, routeRef]) => {
const Page = () => <div>Mounted at {path}</div>;
// Allow external route refs to be bound to paths as well, for convenience.
// We work around it by creating and binding an absolute ref to the external one.
if (isExternalRouteRef(routeRef)) {
const absoluteRef = createRouteRef({ id: 'id' });
boundRoutes.set(routeRef, absoluteRef);
attachComponentData(Page, 'core.mountPoint', absoluteRef);
} else {
attachComponentData(Page, 'core.mountPoint', routeRef);
}
return <Route key={path} path={path} element={<Page />} />;
},
);
const AppProvider = app.getProvider();
const AppRouter = app.getRouter();
const TestAppWrapper = ({ children }: { children: ReactNode }) => (
<AppProvider>
<AppRouter>
<NoRender>{routeElements}</NoRender>
{/* The path of * here is needed to be set as a catch all, so it will render the wrapper element
* and work with nested routes if they exist too */}
<Routes>
<Route path="/*" element={<>{children}</>} />
</Routes>
</AppRouter>
</AppProvider>
);
return TestAppWrapper;
}
Example #19
Source File: SideNav.test.tsx From kfp-tekton-backend with Apache License 2.0 | 4 votes |
describe('SideNav', () => {
let tree: ReactWrapper | ShallowWrapper;
const consoleErrorSpy = jest.spyOn(console, 'error');
const buildInfoSpy = jest.spyOn(Apis, 'getBuildInfo');
const checkHubSpy = jest.spyOn(Apis, 'isJupyterHubAvailable');
const clusterNameSpy = jest.spyOn(Apis, 'getClusterName');
const projectIdSpy = jest.spyOn(Apis, 'getProjectId');
const localStorageHasKeySpy = jest.spyOn(LocalStorage, 'hasKey');
const localStorageIsCollapsedSpy = jest.spyOn(LocalStorage, 'isNavbarCollapsed');
beforeEach(() => {
jest.clearAllMocks();
consoleErrorSpy.mockImplementation(() => null);
buildInfoSpy.mockImplementation(() => ({
apiServerCommitHash: 'd3c4add0a95e930c70a330466d0923827784eb9a',
apiServerReady: true,
buildDate: 'Wed Jan 9 19:40:24 UTC 2019',
frontendCommitHash: '8efb2fcff9f666ba5b101647e909dc9c6889cecb',
}));
checkHubSpy.mockImplementation(() => ({ ok: true }));
clusterNameSpy.mockImplementation(() => Promise.reject('Error when fetching cluster name'));
projectIdSpy.mockImplementation(() => Promise.reject('Error when fetching project ID'));
localStorageHasKeySpy.mockImplementation(() => false);
localStorageIsCollapsedSpy.mockImplementation(() => false);
});
afterEach(async () => {
// unmount() should be called before resetAllMocks() in case any part of the unmount life cycle
// depends on mocks/spies
await tree.unmount();
jest.resetAllMocks();
(window as any).innerWidth = wideWidth;
});
it('renders expanded state', () => {
localStorageHasKeySpy.mockImplementationOnce(() => false);
(window as any).innerWidth = wideWidth;
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});
it('renders collapsed state', () => {
localStorageHasKeySpy.mockImplementationOnce(() => false);
(window as any).innerWidth = narrowWidth;
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});
it('renders Pipelines as active page', () => {
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});
it('renders Pipelines as active when on PipelineDetails page', () => {
tree = shallow(<SideNav page={RoutePage.PIPELINE_DETAILS} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});
it('renders experiments as active page', () => {
tree = shallow(<SideNav page={RoutePage.EXPERIMENTS} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});
it('renders experiments as active when on ExperimentDetails page', () => {
tree = shallow(<SideNav page={RoutePage.EXPERIMENT_DETAILS} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});
it('renders experiments as active page when on NewExperiment page', () => {
tree = shallow(<SideNav page={RoutePage.NEW_EXPERIMENT} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});
it('renders experiments as active page when on Compare page', () => {
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});
it('renders experiments as active page when on AllRuns page', () => {
tree = shallow(<SideNav page={RoutePage.RUNS} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});
it('renders experiments as active page when on RunDetails page', () => {
tree = shallow(<SideNav page={RoutePage.RUN_DETAILS} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});
it('renders experiments as active page when on RecurringRunDetails page', () => {
tree = shallow(<SideNav page={RoutePage.RECURRING_RUN} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});
it('renders experiments as active page when on NewRun page', () => {
tree = shallow(<SideNav page={RoutePage.NEW_RUN} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});
it('show jupyterhub link if accessible', () => {
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
tree.setState({ jupyterHubAvailable: true });
expect(tree).toMatchSnapshot();
});
it('collapses if collapse state is true localStorage', () => {
localStorageIsCollapsedSpy.mockImplementationOnce(() => true);
localStorageHasKeySpy.mockImplementationOnce(() => true);
(window as any).innerWidth = wideWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(true);
});
it('expands if collapse state is false in localStorage', () => {
localStorageIsCollapsedSpy.mockImplementationOnce(() => false);
localStorageHasKeySpy.mockImplementationOnce(() => true);
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(false);
});
it('collapses if no collapse state in localStorage, and window is too narrow', () => {
localStorageIsCollapsedSpy.mockImplementationOnce(() => false);
localStorageHasKeySpy.mockImplementationOnce(() => false);
(window as any).innerWidth = narrowWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(true);
});
it('expands if no collapse state in localStorage, and window is wide', () => {
localStorageIsCollapsedSpy.mockImplementationOnce(() => false);
localStorageHasKeySpy.mockImplementationOnce(() => false);
(window as any).innerWidth = wideWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(false);
});
it('collapses if no collapse state in localStorage, and window goes from wide to narrow', () => {
localStorageIsCollapsedSpy.mockImplementationOnce(() => false);
localStorageHasKeySpy.mockImplementationOnce(() => false);
(window as any).innerWidth = wideWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(false);
(window as any).innerWidth = narrowWidth;
const resizeEvent = new Event('resize');
window.dispatchEvent(resizeEvent);
expect(isCollapsed(tree)).toBe(true);
});
it('expands if no collapse state in localStorage, and window goes from narrow to wide', () => {
localStorageIsCollapsedSpy.mockImplementationOnce(() => false);
localStorageHasKeySpy.mockImplementationOnce(() => false);
(window as any).innerWidth = narrowWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(true);
(window as any).innerWidth = wideWidth;
const resizeEvent = new Event('resize');
window.dispatchEvent(resizeEvent);
expect(isCollapsed(tree)).toBe(false);
});
it('saves state in localStorage if chevron is clicked', () => {
localStorageIsCollapsedSpy.mockImplementationOnce(() => false);
localStorageHasKeySpy.mockImplementationOnce(() => false);
const spy = jest.spyOn(LocalStorage, 'saveNavbarCollapsed');
(window as any).innerWidth = narrowWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(true);
tree.find('WithStyles(IconButton)').simulate('click');
expect(spy).toHaveBeenCalledWith(false);
});
it('does not collapse if collapse state is saved in localStorage, and window resizes', () => {
localStorageIsCollapsedSpy.mockImplementationOnce(() => false);
localStorageHasKeySpy.mockImplementationOnce(() => true);
(window as any).innerWidth = wideWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(false);
(window as any).innerWidth = narrowWidth;
const resizeEvent = new Event('resize');
window.dispatchEvent(resizeEvent);
expect(isCollapsed(tree)).toBe(false);
});
it('populates the display build information using the response from the healthz endpoint', async () => {
const buildInfo = {
apiServerCommitHash: '0a7b9e38f2b9bcdef4bbf3234d971e1635b50cd5',
apiServerTagName: '1.0.0',
apiServerReady: true,
buildDate: 'Tue Oct 23 14:23:53 UTC 2018',
frontendCommitHash: '302e93ce99099173f387c7e0635476fe1b69ea98',
frontendTagName: '1.0.0-rc1',
};
buildInfoSpy.mockImplementationOnce(() => buildInfo);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();
expect(tree).toMatchSnapshot();
expect(tree.state('displayBuildInfo')).toEqual({
tagName: buildInfo.apiServerTagName,
commitHash: buildInfo.apiServerCommitHash.substring(0, 7),
commitUrl:
'https://www.github.com/kubeflow/pipelines/commit/' + buildInfo.apiServerCommitHash,
date: new Date(buildInfo.buildDate).toLocaleDateString(),
});
});
it('populates the cluster information from context', async () => {
const clusterName = 'some-cluster-name';
const projectId = 'some-project-id';
clusterNameSpy.mockImplementationOnce(() => Promise.resolve(clusterName));
projectIdSpy.mockImplementationOnce(() => Promise.resolve(projectId));
buildInfoSpy.mockImplementationOnce(() => Promise.reject('Error when fetching build info'));
tree = mount(
<GkeMetadataProvider>
<MemoryRouter>
<EnhancedSideNav page={RoutePage.PIPELINES} {...routerProps} />
</MemoryRouter>
</GkeMetadataProvider>,
);
const base = tree.html();
await TestUtils.flushPromises();
expect(
diffHTML({
base,
baseAnnotation: 'base',
update: tree.html(),
updateAnnotation: 'after GKE metadata loaded',
}),
).toMatchInlineSnapshot(`
Snapshot Diff:
- base
+ after GKE metadata loaded
@@ --- --- @@
<path fill="none" d="M0 0h24v24H0z"></path></svg></span
><span class="MuiTouchRipple-root-53"></span>
</button>
</div>
<div class="infoVisible">
+ <div
+ class="envMetadata"
+ title="Cluster name: some-cluster-name, Project ID: some-project-id"
+ >
+ <span>Cluster name: </span
+ ><a
+ href="https://console.cloud.google.com/kubernetes/list?project=some-project-id&filter=name:some-cluster-name"
+ class="link unstyled"
+ rel="noopener"
+ target="_blank"
+ >some-cluster-name</a
+ >
+ </div>
<div class="envMetadata" title="Report an Issue">
<a
href="https://github.com/kubeflow/pipelines/issues/new?template=BUG_REPORT.md"
class="link unstyled"
rel="noopener"
`);
});
it('displays the frontend tag name if the api server hash is not returned', async () => {
const buildInfo = {
apiServerReady: true,
// No apiServerCommitHash or apiServerTagName
buildDate: 'Tue Oct 23 14:23:53 UTC 2018',
frontendCommitHash: '302e93ce99099173f387c7e0635476fe1b69ea98',
frontendTagName: '1.0.0',
};
buildInfoSpy.mockImplementationOnce(() => buildInfo);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();
expect(tree.state('displayBuildInfo')).toEqual(
expect.objectContaining({
commitHash: buildInfo.frontendCommitHash.substring(0, 7),
tagName: buildInfo.frontendTagName,
}),
);
});
it('uses the frontend commit hash for the link URL if the api server hash is not returned', async () => {
const buildInfo = {
apiServerReady: true,
// No apiServerCommitHash
buildDate: 'Tue Oct 23 14:23:53 UTC 2018',
frontendCommitHash: '302e93ce99099173f387c7e0635476fe1b69ea98',
};
buildInfoSpy.mockImplementationOnce(() => buildInfo);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();
expect(tree.state('displayBuildInfo')).toEqual(
expect.objectContaining({
commitUrl:
'https://www.github.com/kubeflow/pipelines/commit/' + buildInfo.frontendCommitHash,
}),
);
});
it("displays 'unknown' if the frontend and api server tag names/commit hashes are not returned", async () => {
const buildInfo = {
apiServerReady: true,
// No apiServerCommitHash
buildDate: 'Tue Oct 23 14:23:53 UTC 2018',
// No frontendCommitHash
};
buildInfoSpy.mockImplementationOnce(() => buildInfo);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();
expect(tree.state('displayBuildInfo')).toEqual(
expect.objectContaining({
commitHash: 'unknown',
tagName: 'unknown',
}),
);
});
it('links to the github repo root if the frontend and api server commit hashes are not returned', async () => {
const buildInfo = {
apiServerReady: true,
// No apiServerCommitHash
buildDate: 'Tue Oct 23 14:23:53 UTC 2018',
// No frontendCommitHash
};
buildInfoSpy.mockImplementationOnce(() => buildInfo);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();
expect(tree.state('displayBuildInfo')).toEqual(
expect.objectContaining({
commitUrl: 'https://www.github.com/kubeflow/pipelines',
}),
);
});
it("displays 'unknown' if the date is not returned", async () => {
const buildInfo = {
apiServerCommitHash: '0a7b9e38f2b9bcdef4bbf3234d971e1635b50cd5',
apiServerReady: true,
// No buildDate
frontendCommitHash: '302e93ce99099173f387c7e0635476fe1b69ea98',
};
buildInfoSpy.mockImplementationOnce(() => buildInfo);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();
expect(tree.state('displayBuildInfo')).toEqual(
expect.objectContaining({
date: 'unknown',
}),
);
});
it('logs an error if the call getBuildInfo fails', async () => {
TestUtils.makeErrorResponseOnce(buildInfoSpy, 'Uh oh!');
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();
expect(tree.state('displayBuildInfo')).toBeUndefined();
expect(consoleErrorSpy.mock.calls[0][0]).toBe('Failed to retrieve build info');
});
});