mirror of
https://github.com/tuono-labs/tuono
synced 2026-07-25 12:52:47 -07:00
test(packages/tuono-router): improve test using mocks (#641)
This commit is contained in:
committed by
GitHub
parent
9f14689ca0
commit
bfd0041c6a
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { render, fireEvent, screen } from '@testing-library/react'
|
||||
import { render, fireEvent, screen, cleanup } from '@testing-library/react'
|
||||
|
||||
import { Link } from './Link'
|
||||
|
||||
@@ -33,8 +33,9 @@ vi.mock('react-intersection-observer', () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
describe('Link component', () => {
|
||||
describe('<Link />', () => {
|
||||
beforeEach(() => {
|
||||
cleanup()
|
||||
pushMock.mockReset()
|
||||
preloadMock.mockReset()
|
||||
intersectionObserverCallback = undefined
|
||||
|
||||
@@ -1,114 +1,93 @@
|
||||
import type { HTMLAttributes, JSX } from 'react'
|
||||
import type { JSX, ReactNode } from 'react'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { cleanup, render, screen } from '@testing-library/react'
|
||||
import { cleanup, render } from '@testing-library/react'
|
||||
|
||||
import { Route } from '../route'
|
||||
import type { RouteComponent, RouteProps } from '../types'
|
||||
import type { RouteComponent } from '../types'
|
||||
import type { RouterInstanceType } from '../router'
|
||||
|
||||
import { NotFound } from './NotFound'
|
||||
import { RouteMatch } from './RouteMatch'
|
||||
import { useRouterContext } from './RouterContext'
|
||||
import { NotFoundDefaultContent } from './NotFoundDefaultContent'
|
||||
|
||||
function createRouteComponent(
|
||||
routeType: string,
|
||||
RouteComponentFn: (props: RouteProps) => JSX.Element,
|
||||
): RouteComponent {
|
||||
const RootComponent = RouteComponentFn as RouteComponent
|
||||
RootComponent.preload = vi.fn()
|
||||
RootComponent.displayName = routeType
|
||||
return RootComponent
|
||||
vi.mock('../components/RouterContext', () => ({
|
||||
useRouterContext: vi.fn(),
|
||||
}))
|
||||
vi.mock('./RouteMatch', () => ({
|
||||
RouteMatch: vi.fn(),
|
||||
}))
|
||||
vi.mock('./NotFoundDefaultContent', () => ({
|
||||
NotFoundDefaultContent: vi.fn(),
|
||||
}))
|
||||
|
||||
interface RouterMock {
|
||||
router: Pick<RouterInstanceType, 'routesById'>
|
||||
}
|
||||
const useRouterContextMock = vi.mocked(useRouterContext as () => RouterMock)
|
||||
const RouteMatchMock = vi.mocked(RouteMatch)
|
||||
const NotFoundDefaultContentMock = vi.mocked(NotFoundDefaultContent)
|
||||
|
||||
const rootRouteComponentMock = vi
|
||||
.fn<(props: { children: ReactNode }) => JSX.Element>()
|
||||
.mockImplementation(({ children }) => <div>{children}</div>)
|
||||
|
||||
const root = new Route({
|
||||
isRoot: true,
|
||||
component: createRouteComponent('root', ({ children }) => (
|
||||
<div data-testid="root">{children}</div>
|
||||
)),
|
||||
component: rootRouteComponentMock as unknown as RouteComponent,
|
||||
})
|
||||
|
||||
vi.mock('./Link', () => ({
|
||||
Link: (props: HTMLAttributes<HTMLAnchorElement>): JSX.Element => (
|
||||
<a {...props} />
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('../hooks/useServerPayloadData.ts', () => ({
|
||||
useServerPayloadData: (): { data: unknown; isLoading: boolean } => {
|
||||
return {
|
||||
data: undefined,
|
||||
isLoading: false,
|
||||
}
|
||||
},
|
||||
}))
|
||||
|
||||
const { useRouterContext } = vi.hoisted(() => {
|
||||
return { useRouterContext: vi.fn() }
|
||||
})
|
||||
|
||||
vi.mock('../components/RouterContext', () => ({
|
||||
useRouterContext,
|
||||
}))
|
||||
|
||||
describe('<NotFound />', () => {
|
||||
afterEach(cleanup)
|
||||
afterEach(() => {
|
||||
cleanup()
|
||||
useRouterContextMock.mockReset()
|
||||
RouteMatchMock.mockReset()
|
||||
NotFoundDefaultContentMock.mockReset()
|
||||
rootRouteComponentMock.mockClear()
|
||||
})
|
||||
|
||||
describe('when a custom 404 page exists', () => {
|
||||
it('should render the custom 404 page', () => {
|
||||
useRouterContext.mockReturnValue({
|
||||
const customRoute404 = new Route({
|
||||
getParentRoute: (): Route => root,
|
||||
component: vi.fn() as unknown as RouteComponent,
|
||||
})
|
||||
|
||||
useRouterContextMock.mockReturnValue({
|
||||
router: {
|
||||
routesById: {
|
||||
'/404': new Route({
|
||||
getParentRoute: (): Route => root,
|
||||
component: createRouteComponent('404', () => (
|
||||
<div data-testid="404">custom 404</div>
|
||||
)),
|
||||
}),
|
||||
'/404': customRoute404,
|
||||
__root__: root,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
render(<NotFound />)
|
||||
expect(screen.getByTestId('root')).toMatchInlineSnapshot(
|
||||
`
|
||||
<div
|
||||
data-testid="root"
|
||||
>
|
||||
<div
|
||||
data-testid="404"
|
||||
>
|
||||
custom 404
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
|
||||
expect(RouteMatchMock).toHaveBeenCalledExactlyOnceWith(
|
||||
{ route: customRoute404, serverInitialData: {} },
|
||||
undefined, // deprecated react context parameter
|
||||
)
|
||||
expect(rootRouteComponentMock).not.toHaveBeenCalled()
|
||||
expect(NotFoundDefaultContentMock).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('when a custom 404 page does not exist', () => {
|
||||
it('should render the default 404 page, wrapped by the root __layout', () => {
|
||||
useRouterContext.mockReturnValue({
|
||||
useRouterContextMock.mockReturnValue({
|
||||
router: {
|
||||
routesById: {
|
||||
__root__: root,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
render(<NotFound />)
|
||||
expect(screen.getByTestId('root')).toMatchInlineSnapshot(
|
||||
`
|
||||
<div
|
||||
data-testid="root"
|
||||
>
|
||||
<h1>
|
||||
404 Not found
|
||||
</h1>
|
||||
<a
|
||||
href="/"
|
||||
>
|
||||
Return home
|
||||
</a>
|
||||
</div>
|
||||
`,
|
||||
)
|
||||
|
||||
expect(RouteMatchMock).not.toHaveBeenCalled()
|
||||
expect(rootRouteComponentMock).toHaveBeenCalled()
|
||||
expect(NotFoundDefaultContentMock).toHaveBeenCalledOnce()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useRouterContext } from '../components/RouterContext'
|
||||
import { ROOT_ROUTE_ID } from '../route'
|
||||
|
||||
import { RouteMatch } from './RouteMatch'
|
||||
import { Link } from './Link'
|
||||
import { NotFoundDefaultContent } from './NotFoundDefaultContent'
|
||||
|
||||
export function NotFound(): JSX.Element | null {
|
||||
const { router } = useRouterContext()
|
||||
@@ -22,8 +22,7 @@ export function NotFound(): JSX.Element | null {
|
||||
|
||||
return (
|
||||
<RootLayout data={null} isLoading={false}>
|
||||
<h1>404 Not found</h1>
|
||||
<Link href="/">Return home</Link>
|
||||
<NotFoundDefaultContent />
|
||||
</RootLayout>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import type { JSX } from 'react'
|
||||
|
||||
import { Link } from './Link'
|
||||
|
||||
export function NotFoundDefaultContent(): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<h1>Page Not Found</h1>
|
||||
<Link href="/">Return to Homepage</Link>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,18 +1,22 @@
|
||||
import type { JSX } from 'react'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { cleanup, render, screen } from '@testing-library/react'
|
||||
|
||||
import { Route } from '../route'
|
||||
import type { RouteComponent, RouteProps } from '../types'
|
||||
import { useServerPayloadData } from '../hooks/useServerPayloadData'
|
||||
|
||||
import { RouteMatch } from './RouteMatch'
|
||||
|
||||
function createRouteComponent(
|
||||
routeType: string,
|
||||
RouteComponentFn: (props: RouteProps) => JSX.Element,
|
||||
includeChildren: boolean,
|
||||
): RouteComponent {
|
||||
const RootComponent = RouteComponentFn as RouteComponent
|
||||
const RootComponent = (({ children }: RouteProps) => (
|
||||
<div data-testid={routeType}>
|
||||
{`${routeType} route`}
|
||||
{includeChildren ? children : null}
|
||||
</div>
|
||||
)) as RouteComponent
|
||||
RootComponent.preload = vi.fn()
|
||||
RootComponent.displayName = routeType
|
||||
return RootComponent
|
||||
@@ -20,35 +24,28 @@ function createRouteComponent(
|
||||
|
||||
const root = new Route({
|
||||
isRoot: true,
|
||||
component: createRouteComponent('root', ({ children }) => (
|
||||
<div data-testid="root">root route {children}</div>
|
||||
)),
|
||||
component: createRouteComponent('root', true),
|
||||
})
|
||||
|
||||
const parent = new Route({
|
||||
component: createRouteComponent('parent', ({ children }) => (
|
||||
<div data-testid="parent">parent route {children}</div>
|
||||
)),
|
||||
component: createRouteComponent('parent', true),
|
||||
getParentRoute: (): Route => root,
|
||||
})
|
||||
|
||||
const route = new Route({
|
||||
component: createRouteComponent('route', () => (
|
||||
<p data-testid="route">current route</p>
|
||||
)),
|
||||
component: createRouteComponent('current', false),
|
||||
getParentRoute: (): Route => parent,
|
||||
})
|
||||
|
||||
vi.mock('../hooks/useServerPayloadData.ts', () => ({
|
||||
useServerPayloadData: (): { data: unknown; isLoading: boolean } => {
|
||||
return {
|
||||
data: undefined,
|
||||
isLoading: false,
|
||||
}
|
||||
},
|
||||
vi.mock('../hooks/useServerPayloadData', () => ({
|
||||
useServerPayloadData: vi.fn(),
|
||||
}))
|
||||
vi.mocked(useServerPayloadData).mockReturnValue({
|
||||
data: undefined,
|
||||
isLoading: false,
|
||||
})
|
||||
|
||||
describe('Test RouteMatch component', () => {
|
||||
describe('<RouteMatch />', () => {
|
||||
afterEach(cleanup)
|
||||
|
||||
it('should correctly render nested routes', () => {
|
||||
@@ -59,26 +56,19 @@ describe('Test RouteMatch component', () => {
|
||||
<div
|
||||
data-testid="root"
|
||||
>
|
||||
root route
|
||||
root route
|
||||
<div
|
||||
data-testid="parent"
|
||||
>
|
||||
parent route
|
||||
<p
|
||||
data-testid="route"
|
||||
parent route
|
||||
<div
|
||||
data-testid="current"
|
||||
>
|
||||
current route
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
)
|
||||
expect(screen.getByTestId('route')).toMatchInlineSnapshot(`
|
||||
<p
|
||||
data-testid="route"
|
||||
>
|
||||
current route
|
||||
</p>
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { cleanup } from '@testing-library/react'
|
||||
|
||||
import { useRouterContext } from '../components/RouterContext'
|
||||
|
||||
import { useRoute } from './useRoute'
|
||||
|
||||
const { useRouterContextMock } = vi.hoisted(() => ({
|
||||
useRouterContextMock: vi.fn<
|
||||
() => {
|
||||
router: { routesById: Record<string, { id: string }> }
|
||||
}
|
||||
>(),
|
||||
vi.mock('../components/RouterContext.tsx', () => ({
|
||||
useRouterContext: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('../components/RouterContext.tsx', () => ({
|
||||
useRouterContext: useRouterContextMock,
|
||||
}))
|
||||
interface RouterMock {
|
||||
router: { routesById: Record<string, { id: string }> }
|
||||
}
|
||||
const useRouterContextMock = vi.mocked(useRouterContext as () => RouterMock)
|
||||
|
||||
describe('useRoute', () => {
|
||||
afterEach(() => {
|
||||
|
||||
Reference in New Issue
Block a user