import { makeLocaleOptional, stripLookahead } from '../packages/runtime/src/helpers/matchers' const makeDataPath = (path: string) => `/_next/data/build-id${path === '/' ? '/index' : path}.json` function checkPath(path: string, regex: string) { const re = new RegExp(regex) const dataPath = makeDataPath(path) const testPath = re.test(path) const testData = re.test(dataPath) // For easier debugging // console.log({ path, regex, dataPath, testPath, testData }) return testPath && testData } describe('the middleware path matcher', () => { it('makes the locale slug optional in the regex for the root', () => { // The regex generated by Next for the path "/" with i18n enabled const regex = '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))(|\\.json|\\/?index|\\/?index\\.json)?[\\/#\\?]?$' expect(checkPath('/', regex)).toBe(false) expect(checkPath('/', makeLocaleOptional(regex))).toBe(true) expect(checkPath('/en', makeLocaleOptional(regex))).toBe(true) }) it('makes the locale slug optional in the regex for a subpath', () => { // The regex generated by Next for the path "/static" with i18n enabled const regex = '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))\\/static(.json)?[\\/#\\?]?$' expect(checkPath('/static', regex)).toBe(false) expect(checkPath('/static', makeLocaleOptional(regex))).toBe(true) expect(checkPath('/en/static', makeLocaleOptional(regex))).toBe(true) }) it('does not change the regex when calling makeLocaleOptional with a regex that has no locale', () => { const regexes = [ '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/(\\/?index|\\/?index\\.json))?[\\/#\\?]?$', '^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/api(?:\\/((?:[^\\/#\\?]+?)(?:\\/(?:[^\\/#\\?]+?))*))?(.json)?[\\/#\\?]?$', '^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/shows(?:\\/((?!99|88).*))(.json)?[\\/#\\?]?$', ] for (const regex of regexes) { expect(makeLocaleOptional(regex)).toBe(regex) } }) it('removes lookaheads from the regex', () => { const regexes = [ '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))\\/shows(?:\\/((?!99|88).*))(.json)?[\\/#\\?]?$', '^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/shows(?:\\/((?!99|88).*))(.json)?[\\/#\\?]?$', ] for (const regex of regexes) { const stripped = stripLookahead(regex) expect(regex).toMatch(/\(\?!/) expect(stripped).not.toMatch(/\(\?!/) } }) it('converts regexes with lookaheads to stripped ones that still match at least the same paths', () => { const regex = '^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/shows(?:\\/((?!99|88).*))(.json)?[\\/#\\?]?$' expect(checkPath('/shows', regex)).toBe(false) expect(checkPath('/shows/11', regex)).toBe(true) expect(checkPath('/shows/99', regex)).toBe(false) expect(checkPath('/shows/888', regex)).toBe(false) const stripped = stripLookahead(regex) expect(checkPath('/shows', stripped)).toBe(false) expect(checkPath('/shows/11', stripped)).toBe(true) // These will be true because the regex is not as strict as the original one // The strict test will be done in the JS entrypoint expect(checkPath('/shows/99', stripped)).toBe(true) expect(checkPath('/shows/888', stripped)).toBe(true) }) })