| import { safeCompile } from './route-match-utils' |
| import { |
| PARAM_SEPARATOR, |
| stripNormalizedSeparators, |
| } from '../../../../lib/route-pattern-normalizer' |
|
|
| describe('safeCompile', () => { |
| describe('interception route patterns', () => { |
| it('should strip _NEXTSEP_ from compiled output for (.) interception marker', () => { |
| |
| const pattern = '/photos/(.):author/:id' |
| const compile = safeCompile(pattern, { validate: false }) |
|
|
| |
| const result = compile({ '0': '(.)', author: 'next', id: '123' }) |
|
|
| |
| expect(result).toBe('/photos/(.)next/123') |
| }) |
|
|
| it('should strip _NEXTSEP_ from compiled output for (..) interception marker', () => { |
| const pattern = '/photos/(..):category/:id' |
| const compile = safeCompile(pattern, { validate: false }) |
|
|
| const result = compile({ '0': '(..)', category: 'blog', id: '456' }) |
|
|
| expect(result).toBe('/photos/(..)blog/456') |
| }) |
|
|
| it('should strip _NEXTSEP_ from compiled output for (...) interception marker', () => { |
| const pattern = '/photos/(...):path' |
| const compile = safeCompile(pattern, { validate: false }) |
|
|
| const result = compile({ '0': '(...)', path: 'deep/nested/route' }) |
|
|
| expect(result).toBe('/photos/(...)deep/nested/route') |
| }) |
|
|
| it('should strip _NEXTSEP_ from compiled output for (..)(..) interception marker', () => { |
| const pattern = '/photos/(.)(..)/:id' |
| const compile = safeCompile(pattern, { validate: false }) |
|
|
| |
| const result = compile({ '0': '(..)', '1': '(..)', id: '789' }) |
|
|
| expect(result).toBe('/photos/(..)(..)/789') |
| }) |
|
|
| it('should handle multiple interception markers in one pattern', () => { |
| const pattern = '/(.):author/photos/(.):id' |
| const compile = safeCompile(pattern, { validate: false }) |
|
|
| |
| const result = compile({ |
| '0': '(.)', |
| author: 'john', |
| '1': '(.)', |
| id: '999', |
| }) |
|
|
| expect(result).toBe('/(.)john/photos/(.)999') |
| }) |
|
|
| it('should work with the actual failing case from interception routes', () => { |
| |
| const pattern = |
| '/intercepting-routes-dynamic/photos/(.):nxtPauthor/:nxtPid' |
| const compile = safeCompile(pattern, { validate: false }) |
|
|
| const result = compile({ |
| '0': '(.)', |
| nxtPauthor: 'next', |
| nxtPid: '123', |
| }) |
|
|
| expect(result).toBe('/intercepting-routes-dynamic/photos/(.)next/123') |
| }) |
| }) |
|
|
| describe('patterns without normalization needs', () => { |
| it('should work normally for patterns without adjacent parameters', () => { |
| const pattern = '/photos/:author/:id' |
| const compile = safeCompile(pattern, { validate: false }) |
|
|
| const result = compile({ author: 'jane', id: '456' }) |
|
|
| expect(result).toBe('/photos/jane/456') |
| }) |
|
|
| it('should work with optional parameters', () => { |
| const pattern = '/photos/:author?/:id' |
| const compile = safeCompile(pattern, { validate: false }) |
|
|
| const result = compile({ id: '789' }) |
|
|
| expect(result).toBe('/photos/789') |
| }) |
|
|
| it('should work with catchall parameters', () => { |
| const pattern = '/files/:path*' |
| const compile = safeCompile(pattern, { validate: false }) |
|
|
| const result = compile({ path: ['folder', 'subfolder', 'file.txt'] }) |
|
|
| expect(result).toBe('/files/folder/subfolder/file.txt') |
| }) |
| }) |
|
|
| describe('edge cases', () => { |
| it('should handle patterns with path separators between parameters', () => { |
| |
| const pattern = '/:param1/separator/:param2' |
| const compile = safeCompile(pattern, { validate: false }) |
|
|
| const result = compile({ param1: 'value1', param2: 'value2' }) |
|
|
| expect(result).toBe('/value1/separator/value2') |
| }) |
|
|
| it('should not strip _NEXTSEP_ from user content outside interception markers', () => { |
| |
| |
| const pattern = '/:folder/:file' |
| const compile = safeCompile(pattern, { validate: false }) |
|
|
| |
| const result = compile({ |
| folder: 'my_NEXTSEP_folder', |
| file: 'my_NEXTSEP_file.txt', |
| }) |
|
|
| |
| expect(result).toBe('/my_NEXTSEP_folder/my_NEXTSEP_file.txt') |
| }) |
| }) |
| }) |
|
|
| describe('stripNormalizedSeparators', () => { |
| it('should strip _NEXTSEP_ after single dot interception marker', () => { |
| const input = `/photos/(.)${PARAM_SEPARATOR}next/123` |
| const result = stripNormalizedSeparators(input) |
| expect(result).toBe('/photos/(.)next/123') |
| }) |
|
|
| it('should strip _NEXTSEP_ after double dot interception marker', () => { |
| const input = `/photos/(..)${PARAM_SEPARATOR}blog/456` |
| const result = stripNormalizedSeparators(input) |
| expect(result).toBe('/photos/(..)blog/456') |
| }) |
|
|
| it('should strip _NEXTSEP_ after triple dot interception marker', () => { |
| const input = `/photos/(...)${PARAM_SEPARATOR}deep/nested/route` |
| const result = stripNormalizedSeparators(input) |
| expect(result).toBe('/photos/(...)deep/nested/route') |
| }) |
|
|
| it('should strip _NEXTSEP_ for adjacent interception markers with parameters', () => { |
| |
| |
| |
| const input = `/(.)${PARAM_SEPARATOR}first/(..)${PARAM_SEPARATOR}second` |
| const result = stripNormalizedSeparators(input) |
| expect(result).toBe('/(.)first/(..)second') |
| }) |
|
|
| it('should handle multiple interception markers in one path', () => { |
| const input = `/(.)${PARAM_SEPARATOR}john/photos/(.)${PARAM_SEPARATOR}999` |
| const result = stripNormalizedSeparators(input) |
| expect(result).toBe('/(.)john/photos/(.)999') |
| }) |
|
|
| it('should NOT strip _NEXTSEP_ from user content', () => { |
| |
| |
| const input = `/folder/my${PARAM_SEPARATOR}file/data${PARAM_SEPARATOR}value` |
| const result = stripNormalizedSeparators(input) |
| expect(result).toBe( |
| `/folder/my${PARAM_SEPARATOR}file/data${PARAM_SEPARATOR}value` |
| ) |
| }) |
|
|
| it('should only strip after closing paren, not before', () => { |
| const input = `/path${PARAM_SEPARATOR}(.)${PARAM_SEPARATOR}value` |
| const result = stripNormalizedSeparators(input) |
| |
| expect(result).toBe(`/path${PARAM_SEPARATOR}(.)value`) |
| }) |
| }) |
|
|