|  | 
|  | 1 | +import type { NetlifyPluginOptions } from '@netlify/build' | 
|  | 2 | +import type { RoutesManifest } from 'next/dist/build/index.js' | 
|  | 3 | +import { beforeEach, describe, expect, test, type TestContext, vi } from 'vitest' | 
|  | 4 | + | 
|  | 5 | +import { PluginContext } from './plugin-context.js' | 
|  | 6 | +import { setRedirectsConfig } from './redirects.js' | 
|  | 7 | + | 
|  | 8 | +type RedirectsTestContext = TestContext & { | 
|  | 9 | +  pluginContext: PluginContext | 
|  | 10 | +  routesManifest: RoutesManifest | 
|  | 11 | +} | 
|  | 12 | + | 
|  | 13 | +describe('Redirects', () => { | 
|  | 14 | +  beforeEach<RedirectsTestContext>((ctx) => { | 
|  | 15 | +    ctx.routesManifest = { | 
|  | 16 | +      basePath: '', | 
|  | 17 | +      headers: [], | 
|  | 18 | +      rewrites: { | 
|  | 19 | +        beforeFiles: [], | 
|  | 20 | +        afterFiles: [], | 
|  | 21 | +        fallback: [], | 
|  | 22 | +      }, | 
|  | 23 | +      redirects: [ | 
|  | 24 | +        { | 
|  | 25 | +          source: '/old-page', | 
|  | 26 | +          destination: '/new-page', | 
|  | 27 | +          permanent: true, | 
|  | 28 | +        }, | 
|  | 29 | +        { | 
|  | 30 | +          source: '/another-old-page', | 
|  | 31 | +          destination: '/another-new-page', | 
|  | 32 | +          statusCode: 301, | 
|  | 33 | +        }, | 
|  | 34 | +        { | 
|  | 35 | +          source: '/external', | 
|  | 36 | +          destination: 'https://example.com', | 
|  | 37 | +          permanent: false, | 
|  | 38 | +        }, | 
|  | 39 | +        { | 
|  | 40 | +          source: '/with-params/:slug', | 
|  | 41 | +          destination: '/news/:slug', | 
|  | 42 | +          permanent: true, | 
|  | 43 | +        }, | 
|  | 44 | +        { | 
|  | 45 | +          source: '/splat/:path*', | 
|  | 46 | +          destination: '/new-splat/:path', | 
|  | 47 | +          permanent: true, | 
|  | 48 | +        }, | 
|  | 49 | +        { | 
|  | 50 | +          source: '/old-blog/:slug(\\d{1,})', | 
|  | 51 | +          destination: '/news/:slug', | 
|  | 52 | +          permanent: true, | 
|  | 53 | +        }, | 
|  | 54 | +        { | 
|  | 55 | +          source: '/missing', | 
|  | 56 | +          destination: '/somewhere', | 
|  | 57 | +          missing: [{ type: 'header', key: 'x-foo' }], | 
|  | 58 | +        }, | 
|  | 59 | +        { | 
|  | 60 | +          source: '/has', | 
|  | 61 | +          destination: '/somewhere-else', | 
|  | 62 | +          has: [{ type: 'header', key: 'x-bar', value: 'baz' }], | 
|  | 63 | +        }, | 
|  | 64 | +      ], | 
|  | 65 | +    } | 
|  | 66 | + | 
|  | 67 | +    ctx.pluginContext = new PluginContext({ | 
|  | 68 | +      netlifyConfig: { | 
|  | 69 | +        redirects: [], | 
|  | 70 | +      }, | 
|  | 71 | +    } as unknown as NetlifyPluginOptions) | 
|  | 72 | + | 
|  | 73 | +    vi.spyOn(ctx.pluginContext, 'getRoutesManifest').mockResolvedValue(ctx.routesManifest) | 
|  | 74 | +  }) | 
|  | 75 | + | 
|  | 76 | +  test<RedirectsTestContext>('creates redirects for simple cases', async (ctx) => { | 
|  | 77 | +    await setRedirectsConfig(ctx.pluginContext) | 
|  | 78 | +    expect(ctx.pluginContext.netlifyConfig.redirects).toEqual([ | 
|  | 79 | +      { | 
|  | 80 | +        from: '/old-page', | 
|  | 81 | +        to: '/new-page', | 
|  | 82 | +        status: 308, | 
|  | 83 | +      }, | 
|  | 84 | +      { | 
|  | 85 | +        from: '/another-old-page', | 
|  | 86 | +        to: '/another-new-page', | 
|  | 87 | +        status: 301, | 
|  | 88 | +      }, | 
|  | 89 | +      { | 
|  | 90 | +        from: '/external', | 
|  | 91 | +        to: 'https://example.com', | 
|  | 92 | +        status: 307, | 
|  | 93 | +      }, | 
|  | 94 | +      { | 
|  | 95 | +        from: '/with-params/:slug', | 
|  | 96 | +        to: '/news/:slug', | 
|  | 97 | +        status: 308, | 
|  | 98 | +      }, | 
|  | 99 | +      { | 
|  | 100 | +        from: '/splat/*', | 
|  | 101 | +        to: '/new-splat/:splat', | 
|  | 102 | +        status: 308, | 
|  | 103 | +      }, | 
|  | 104 | +    ]) | 
|  | 105 | +  }) | 
|  | 106 | + | 
|  | 107 | +  test<RedirectsTestContext>('prepends basePath to redirects', async (ctx) => { | 
|  | 108 | +    ctx.routesManifest.basePath = '/docs' | 
|  | 109 | +    await setRedirectsConfig(ctx.pluginContext) | 
|  | 110 | +    expect(ctx.pluginContext.netlifyConfig.redirects).toEqual([ | 
|  | 111 | +      { | 
|  | 112 | +        from: '/docs/old-page', | 
|  | 113 | +        to: '/docs/new-page', | 
|  | 114 | +        status: 308, | 
|  | 115 | +      }, | 
|  | 116 | +      { | 
|  | 117 | +        from: '/docs/another-old-page', | 
|  | 118 | +        to: '/docs/another-new-page', | 
|  | 119 | +        status: 301, | 
|  | 120 | +      }, | 
|  | 121 | +      { | 
|  | 122 | +        from: '/docs/external', | 
|  | 123 | +        to: 'https://example.com', | 
|  | 124 | +        status: 307, | 
|  | 125 | +      }, | 
|  | 126 | +      { | 
|  | 127 | +        from: '/docs/with-params/:slug', | 
|  | 128 | +        to: '/docs/news/:slug', | 
|  | 129 | +        status: 308, | 
|  | 130 | +      }, | 
|  | 131 | +      { | 
|  | 132 | +        from: '/docs/splat/*', | 
|  | 133 | +        to: '/docs/new-splat/:splat', | 
|  | 134 | +        status: 308, | 
|  | 135 | +      }, | 
|  | 136 | +    ]) | 
|  | 137 | +  }) | 
|  | 138 | +}) | 
0 commit comments