|
| 1 | +import { makeLocaleOptional, stripLookahead } from '../packages/runtime/src/helpers/matchers' |
| 2 | + |
| 3 | +const makeDataPath = (path: string) => `/_next/data/build-id${path === '/' ? '/index' : path}.json` |
| 4 | + |
| 5 | +function checkPath(path: string, regex: string) { |
| 6 | + const re = new RegExp(regex) |
| 7 | + const dataPath = makeDataPath(path) |
| 8 | + const testPath = re.test(path) |
| 9 | + const testData = re.test(dataPath) |
| 10 | + // For easier debugging |
| 11 | + // console.log({ path, regex, dataPath, testPath, testData }) |
| 12 | + return testPath && testData |
| 13 | +} |
| 14 | + |
| 15 | +describe('the middleware path matcher', () => { |
| 16 | + it('makes the locale slug optional in the regex for the root', () => { |
| 17 | + // The regex generated by Next for the path "/" with i18n enabled |
| 18 | + const regex = |
| 19 | + '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))(|\\.json|\\/?index|\\/?index\\.json)?[\\/#\\?]?$' |
| 20 | + expect(checkPath('/', regex)).toBe(false) |
| 21 | + expect(checkPath('/', makeLocaleOptional(regex))).toBe(true) |
| 22 | + expect(checkPath('/en', makeLocaleOptional(regex))).toBe(true) |
| 23 | + }) |
| 24 | + |
| 25 | + it('makes the locale slug optional in the regex for a subpath', () => { |
| 26 | + // The regex generated by Next for the path "/static" with i18n enabled |
| 27 | + const regex = '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))\\/static(.json)?[\\/#\\?]?$' |
| 28 | + expect(checkPath('/static', regex)).toBe(false) |
| 29 | + expect(checkPath('/static', makeLocaleOptional(regex))).toBe(true) |
| 30 | + expect(checkPath('/en/static', makeLocaleOptional(regex))).toBe(true) |
| 31 | + }) |
| 32 | + |
| 33 | + it('does not change the regex when calling makeLocaleOptional with a regex that has no locale', () => { |
| 34 | + const regexes = [ |
| 35 | + '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/(\\/?index|\\/?index\\.json))?[\\/#\\?]?$', |
| 36 | + '^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/api(?:\\/((?:[^\\/#\\?]+?)(?:\\/(?:[^\\/#\\?]+?))*))?(.json)?[\\/#\\?]?$', |
| 37 | + '^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/shows(?:\\/((?!99|88).*))(.json)?[\\/#\\?]?$', |
| 38 | + ] |
| 39 | + for (const regex of regexes) { |
| 40 | + expect(makeLocaleOptional(regex)).toBe(regex) |
| 41 | + } |
| 42 | + }) |
| 43 | + |
| 44 | + it('removes lookaheads from the regex', () => { |
| 45 | + const regexes = [ |
| 46 | + '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))\\/shows(?:\\/((?!99|88).*))(.json)?[\\/#\\?]?$', |
| 47 | + '^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/shows(?:\\/((?!99|88).*))(.json)?[\\/#\\?]?$', |
| 48 | + ] |
| 49 | + for (const regex of regexes) { |
| 50 | + const stripped = stripLookahead(regex) |
| 51 | + expect(regex).toMatch(/\(\?!/) |
| 52 | + expect(stripped).not.toMatch(/\(\?!/) |
| 53 | + } |
| 54 | + }) |
| 55 | + it('converts regexes with lookaheads to stripped ones that still match at least the same paths', () => { |
| 56 | + const regex = '^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/shows(?:\\/((?!99|88).*))(.json)?[\\/#\\?]?$' |
| 57 | + expect(checkPath('/shows', regex)).toBe(false) |
| 58 | + expect(checkPath('/shows/11', regex)).toBe(true) |
| 59 | + expect(checkPath('/shows/99', regex)).toBe(false) |
| 60 | + expect(checkPath('/shows/888', regex)).toBe(false) |
| 61 | + |
| 62 | + const stripped = stripLookahead(regex) |
| 63 | + expect(checkPath('/shows', stripped)).toBe(false) |
| 64 | + expect(checkPath('/shows/11', stripped)).toBe(true) |
| 65 | + // These will be true because the regex is not as strict as the original one |
| 66 | + // The strict test will be done in the JS entrypoint |
| 67 | + expect(checkPath('/shows/99', stripped)).toBe(true) |
| 68 | + expect(checkPath('/shows/888', stripped)).toBe(true) |
| 69 | + }) |
| 70 | +}) |
| 71 | + |
| 72 | +// "regexp": "^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))\\/shows(?:\\/((?!99|88).*))(.json)?[\\/#\\?]?$" |
0 commit comments