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