1import { jest } from '@jest/globals'; 2import { act, renderHook } from '@testing-library/react-hooks'; 3import mockRouter from 'next-router-mock'; 4import { MemoryRouterProvider } from 'next-router-mock/MemoryRouterProvider'; 5import { PropsWithChildren } from 'react'; 6 7import { 8 PageApiVersionProvider, 9 usePageApiVersion, 10 getVersionFromPath, 11 replaceVersionInPath, 12} from './page-api-version'; 13 14jest.mock('next/router', () => mockRouter); 15 16function renderContext(initialUrl: string, onPush?: any) { 17 return renderHook(usePageApiVersion, { 18 wrapper: (props: PropsWithChildren<object>) => ( 19 <MemoryRouterProvider url={initialUrl} onPush={onPush}> 20 <PageApiVersionProvider>{props.children}</PageApiVersionProvider> 21 </MemoryRouterProvider> 22 ), 23 }); 24} 25 26describe('PageApiVersionContext', () => { 27 it('defaults to latest version', () => { 28 const { result } = renderHook(usePageApiVersion); 29 expect(result.current).toMatchObject({ version: 'latest', hasVersion: false }); 30 }); 31 32 it('defaults to setVersion throwing error', () => { 33 const { result } = renderHook(usePageApiVersion); 34 expect(() => result.current.setVersion('v44.0.0')).toThrowError( 35 'PageApiVersionContext not found' 36 ); 37 }); 38}); 39 40describe(PageApiVersionProvider, () => { 41 it('uses sdk version from pathname', () => { 42 const { result } = renderContext('/versions/v44.0.0/sdk/notifications'); 43 expect(result.current).toMatchObject({ version: 'v44.0.0', hasVersion: true }); 44 }); 45 46 it('uses unversioned version from pathname', () => { 47 const { result } = renderContext('/versions/unversioned/react-native/view-props'); 48 expect(result.current).toMatchObject({ version: 'unversioned', hasVersion: true }); 49 }); 50 51 it('uses latest version from pathname', () => { 52 const { result } = renderContext('/versions/latest/sdk'); 53 expect(result.current).toMatchObject({ version: 'latest', hasVersion: true }); 54 }); 55 56 it('updates router and version when setting version', () => { 57 const onPush = jest.fn<typeof mockRouter.push>(); 58 const { result, rerender } = renderContext('/versions/latest/sdk', onPush); 59 expect(result.current).toMatchObject({ version: 'latest', hasVersion: true }); 60 act(() => result.current.setVersion('unversioned')); 61 rerender(); 62 expect(onPush).toBeCalledWith('/versions/unversioned/sdk', { shallow: false }); 63 }); 64}); 65 66describe(getVersionFromPath, () => { 67 it('returns unversioned from pathname', () => { 68 expect(getVersionFromPath('/versions/unversioned')).toBe('unversioned'); 69 }); 70 71 it('returns latest from sdk pathname', () => { 72 expect(getVersionFromPath('/versions/latest/sdk/notifications')).toBe('latest'); 73 }); 74 75 it('returns v44.0.0 from react-native pathname', () => { 76 expect(getVersionFromPath('/versions/v44.0.0/react-native/view-props')).toBe('v44.0.0'); 77 }); 78 79 it('returns null for non-versioned pathname', () => { 80 expect(getVersionFromPath('/guides/monorepos/')).toBeNull(); 81 }); 82}); 83 84describe(replaceVersionInPath, () => { 85 it('returns same pathname for non-versioned pathname', () => { 86 expect(replaceVersionInPath('/build-reference/how-tos/', 'latest')).toBe( 87 '/build-reference/how-tos/' 88 ); 89 }); 90 91 it('returns new pathname for unversioned pathname', () => { 92 expect(replaceVersionInPath('/versions/unversioned', 'latest')).toBe('/versions/latest'); 93 }); 94 95 it('returns new pathname for sdk pathname', () => { 96 expect(replaceVersionInPath('/versions/latest/sdk/notifications', 'v44.0.0')).toBe( 97 '/versions/v44.0.0/sdk/notifications' 98 ); 99 }); 100 101 it('returns new pathname for react-native pathname', () => { 102 expect(replaceVersionInPath('/versions/v44.0.0/react-native/stylesheet/', 'v43.0.0')).toBe( 103 '/versions/v43.0.0/react-native/stylesheet/' 104 ); 105 }); 106}); 107