Skip to content

Commit

Permalink
@W-17062545@ Add support for non-302 redirects (#2173)
Browse files Browse the repository at this point in the history
* Add support for non-302 redirects

* Changelog

* Add javadoc

* Code coverage

* Alternate implementaiton

* Apply feedback

* Add rendering test

* lint
  • Loading branch information
vcua-mobify authored Dec 17, 2024
1 parent 3725c0f commit 50c0f74
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/pwa-kit-react-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## v3.9.0-dev (Oct 29, 2024)
- Add RedirectWithStatus component, allowing finer grained control of rediriects and their status code [#2173](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2173)

## v3.8.0 (Oct 28, 2024)
- [Server Affinity] - Attach dwsid to SCAPI request headers [#2090](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2090)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export const render = async (req, res, next) => {
}

if (redirectUrl) {
res.redirect(302, redirectUrl)
res.redirect(routerContext.status || 302, redirectUrl)
} else {
res.status(status).send(html)
}
Expand Down
22 changes: 22 additions & 0 deletions packages/pwa-kit-react-sdk/src/ssr/server/react-rendering.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ jest.mock('../universal/routes', () => {
const React = require('react')
const PropTypes = require('prop-types')
const errors = require('../universal/errors')
const RedirectWithStatus = require('../universal/components/redirect-with-status').default
const {Redirect} = require('react-router-dom')
const {Helmet} = require('react-helmet')
const {useQuery} = require('@tanstack/react-query')
Expand Down Expand Up @@ -183,6 +184,16 @@ jest.mock('../universal/routes', () => {
}
}

class RedirectWithStatusPage extends React.Component {
static getProps() {
return Promise.resolve()
}

render() {
return <RedirectWithStatus to="/elsewhere/" status={301} />
}
}

class HelmetPage extends React.Component {
static getProps() {
return Promise.resolve()
Expand Down Expand Up @@ -305,6 +316,10 @@ jest.mock('../universal/routes', () => {
path: '/redirect/',
component: RedirectPage
},
{
path: '/redirectWithStatus/',
component: RedirectWithStatusPage
},
{
path: '/init-sets-status/',
component: InitSetsStatusPage
Expand Down Expand Up @@ -538,6 +553,13 @@ describe('The Node SSR Environment', () => {
expect(res.statusCode).toBe(302)
}
},
{
description: `can redirect with HTTP 301 status`,
req: {url: '/redirectWithStatus/'},
assertions: (res) => {
expect(res.statusCode).toBe(301)
}
},
{
description: `500 on unknown errors in getProps`,
req: {url: '/unknown-error/'},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2024, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

import React from 'react'
import {Redirect, withRouter} from 'react-router-dom'
import PropTypes from 'prop-types'

/**
* The `RedirectWithStatus` component is used to specify a different status code when redirecting via
* the Redirect component.
* The default redirect behavior when this component is not used is to set a 302 status.
*
* @param {number} status - The HTTP status code. Defaults to 302 if not specified
* @param {object} staticContext - The router context
* @param {string} to - The redirect's target path
*/
const RedirectWithStatus = ({status = 302, staticContext, ...props}) => {
// Handle server-side rendering
if (staticContext) {
staticContext.status = status
}

return <Redirect {...props} />
}

RedirectWithStatus.propTypes = {
status: PropTypes.number,
staticContext: PropTypes.object,
to: PropTypes.oneOfType([PropTypes.string, PropTypes.object])
}

export default withRouter(RedirectWithStatus)
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2024, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

import React from 'react'
import {render} from '@testing-library/react'
import {Router, StaticRouter, Route} from 'react-router-dom'
import {createMemoryHistory} from 'history'
import RedirectWithStatus from './index'

describe('RedirectWithStatus', () => {
test('Redirects if no status or context is provided', () => {
const targetUrl = '/target'
const history = createMemoryHistory()
history.push('/redirect')
render(
<Router history={history}>
<Route path="/redirect">
<RedirectWithStatus to={targetUrl} />
</Route>
</Router>
)
expect(history.location.pathname).toBe(targetUrl)
})
test('Redirect renders with correct status', async () => {
const context = {}
const status = 303
const targetUrl = '/target'

render(
<StaticRouter location="/redirect" context={context}>
<Route path="/redirect">
<RedirectWithStatus status={status} to={targetUrl} />
</Route>
</StaticRouter>
)

expect(context.status).toBe(status)
expect(context.url).toBe(targetUrl)
})
})

0 comments on commit 50c0f74

Please sign in to comment.