Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds failing test cases for Issue 5296 #5359

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 124 additions & 9 deletions packages/react-router/modules/__tests__/Route-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import expect from 'expect'
import React from 'react'
import ReactDOM from 'react-dom'
import MemoryRouter from '../MemoryRouter'
import StaticRouter from '../StaticRouter'
import Router from '../Router'
import createMemoryHistory from 'history/createMemoryHistory'
import Route from '../Route'
Expand Down Expand Up @@ -91,16 +92,130 @@ describe('A <Route>', () => {
})

describe('A <Route> with dynamic segments in the path', () => {
it('decodes them', () => {
const node = document.createElement('div')
ReactDOM.render((
<MemoryRouter initialEntries={[ '/a%20dynamic%20segment' ]}>
<Route path="/:id" render={({ match }) => <div>{match.params.id}</div>} />
</MemoryRouter>
), node)
// This test group also demonstrates that the param parsing and decoding behavior differs according to the containing
// router component.
//
// Rather than copy/paste the same tests for every containing router we might have, we'll loop through them
// and pass all potentially used props to each (extras are expected to be ignored)
//
// TODO: Getting HashRouter and BrowserRouter to work here is left as an exercise for the reader

[StaticRouter, MemoryRouter, Router].forEach((RouterComponent) =>
describe(`${`${RouterComponent}`.split('\n')[0]}...}`, () => {
let history, props
const node = document.createElement('div')

expect(node.innerHTML).toContain('a dynamic segment')
})
function prepHistoryAndGetProps(url) {
history.push(url)
return {
initialEntries: [ url ],
location: url,
history
}
}

beforeEach(() => {
history = createMemoryHistory()
})

afterEach(() => {
ReactDOM.unmountComponentAtNode(node)
})

it('decodes them', () => {
props = prepHistoryAndGetProps('/a%20dynamic%20segment')
ReactDOM.render((
<RouterComponent {...props}>
<Route path="/:id" render={({ match }) => <div>{match.params.id}</div>} />
</RouterComponent>
), node)

expect(node.innerText).toBe('a dynamic segment')
})

it('correctly finds multiple params', () => {
props = prepHistoryAndGetProps('/first/second')
ReactDOM.render((
<RouterComponent {...props}>
<Route path="/:param1/:param2"
render={({ match }) => <div>{match.params.param1}:{match.params.param2}</div>} />
</RouterComponent>
), node)

expect(node.innerText).toBe('first:second')
})

it('correctly finds and decodes params in the middle of a complex path rule', () => {
// This test case is modeled after a real-world case where we'd seen some inconsistent behavior
props = prepHistoryAndGetProps('/foo/some%20param/edit')
ReactDOM.render((
<RouterComponent {...props}>
<Route path="/foo/:param1/:param2(edit|view|history)?"
render={({ match }) => <div>{match.params.param1}:{match.params.param2}</div>} />
</RouterComponent>
), node)

expect(node.innerText).toBe('some param:edit')
})

it('correctly finds and decodes params in the middle of a complex path rule 2', () => {
// This test case is modeled after a real-world case where we'd seen some inconsistent behavior
props = prepHistoryAndGetProps('/foo/some%20param')
ReactDOM.render((
<RouterComponent {...props}>
<Route path="/foo/:param1/:param2(edit|view|history)?"
render={({ match }) => <div>{match.params.param1}:{match.params.param2}</div>} />
</RouterComponent>
), node)

expect(node.innerText).toBe('some param:')
})

it('correctly decodes params which have an encoded /', () => {
props = prepHistoryAndGetProps('/foo%2fbar/baz')
ReactDOM.render((
<RouterComponent {...props}>
<Route path="/:param1/baz" render={({ match }) => <div>{match.params.param1}</div>} />
</RouterComponent>
), node)

expect(node.innerText).toBe('foo/bar')
})

it('correctly decodes params which have an encoded :', () => {
props = prepHistoryAndGetProps('/%3abar/baz')
ReactDOM.render((
<RouterComponent {...props}>
<Route path="/:param1/baz" render={({ match }) => <div>{match.params.param1}</div>} />
</RouterComponent>
), node)

expect(node.innerText).toBe(':bar')
})

it('matches paths which themselves contain a percent-encoded slash', () => {
props = prepHistoryAndGetProps('/foo%2fbar/baz')
ReactDOM.render((
<RouterComponent {...props}>
<Route path="/foo%2fbar/:param1" render={({ match }) => <div>{match.params.param1}</div>} />
</RouterComponent>
), node)

expect(node.innerText).toBe('baz')
})

it('matches paths which themselves contain a percent-encoded colon', () => {
props = prepHistoryAndGetProps('/%3abar/baz')
ReactDOM.render((
<RouterComponent {...props}>
<Route path="/%3abar/:param1" render={({ match }) => <div>{match.params.param1}</div>} />
</RouterComponent>
), node)

expect(node.innerText).toBe('baz')
})
})
)
})

describe('A unicode <Route>', () => {
Expand Down
112 changes: 112 additions & 0 deletions packages/react-router/modules/__tests__/matchPath-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,116 @@ describe('matchPath', () => {
expect(!!falseTrue).toBe(false)
})
})

describe('with dynamic segments in the path', () => {
let url

it('decodes them', () => {
url = '/a%20dynamic%20segment'
const match = matchPath(url, {
path: '/:id',
exact: true,
strict: true
})

expect(match.isExact).toBe(true)
expect(match.params.id).toBe('a dynamic segment')
})

it('correctly finds multiple params', () => {
url = '/first/second'

const match = matchPath(url, {
path: '/:param1/:param2',
exact: true,
strict: true
})

expect(match.isExact).toBe(true)
expect(match.params.param1).toBe('first')
expect(match.params.param2).toBe('second')
})

it('correctly finds and decodes params in the middle of a complex path rule', () => {
// This test case is modeled after a real-world case where we'd seen some inconsistent behavior
url = '/foo/some%20param/edit'

const match = matchPath(url, {
path: '/foo/:param1/:param2(edit|view|history)?',
exact: true,
strict: false
})

expect(match.isExact).toBe(true)
expect(match.params.param1).toBe('some param')
expect(match.params.param2).toBe('edit')
})

it('correctly finds and decodes params in the middle of a complex path rule 2', () => {
// This test case is modeled after a real-world case where we'd seen some inconsistent behavior
url = '/foo/some%20param'

const match = matchPath(url, {
path: '/foo/:param1/:param2(edit|view|history)?',
exact: true,
strict: false
})

expect(match.isExact).toBe(true)
expect(match.params.param1).toBe('some param')
expect(match.params.param2).toBe(null)
})

it('correctly decodes params which have an encoded /', () => {
url = '/foo%2fbar/baz'

const match = matchPath(url, {
path: '/:param1/baz',
exact: true,
strict: true
})

expect(match.isExact).toBe(true)
expect(match.params.param1).toBe('foo/bar')
})

it('correctly decodes params which have an encoded :', () => {
url = '/%3abar/baz'

const match = matchPath(url, {
path: '/:param1/baz',
exact: true,
strict: true
})

expect(match.isExact).toBe(true)
expect(match.params.param1).toBe(':bar')
})

it('matches paths which themselves contain a percent-encoded slash', () => {
url = '/foo%2fbar/baz'

const match = matchPath(url, {
path: '/foo%2fbar/:param1',
exact: true,
strict: true
})

expect(match.isExact).toBe(true)
expect(match.params.param1).toBe('baz')
})

it('matches paths which themselves contain a percent-encoded colon', () => {
url = '/%3abar/baz'

const match = matchPath(url, {
path: '/%3abar/:param1',
exact: true,
strict: true
})

expect(match.isExact).toBe(true)
expect(match.params.param1).toBe('baz')
})
})
})