fix(techdocs): handle undefined defaultPath in techdocs initial redirect
When handling the initial redirect for techdocs deep linking an undefined value for defaultPath was being included in the url resulting in an error page. https://github.com/backstage/backstage/issues/30300 Signed-off-by: Chris Suich <csuich2@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': patch
|
||||
---
|
||||
|
||||
Handle undefined defaultPath in TechDocs initial redirect.
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
// We need to mock react-router-dom hooks used by useInitialRedirect
|
||||
import { useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
// Import the module from which the hook is defined
|
||||
import { useInitialRedirect } from './dom';
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
...jest.requireActual('react-router-dom'),
|
||||
useLocation: jest.fn(),
|
||||
useNavigate: jest.fn(),
|
||||
useParams: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('useInitialRedirect', () => {
|
||||
const mockNavigate = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset mocks before each test
|
||||
mockNavigate.mockReset();
|
||||
(useNavigate as jest.Mock).mockReturnValue(mockNavigate);
|
||||
(useLocation as jest.Mock).mockReturnValue({
|
||||
pathname: '/docs/default/Component/backstage-demo',
|
||||
});
|
||||
// Simulate that no current path is provided
|
||||
(useParams as jest.Mock).mockReturnValue({ '*': '' });
|
||||
});
|
||||
|
||||
const TestComponent: React.FC<{ defaultPath?: string }> = ({
|
||||
defaultPath,
|
||||
}) => {
|
||||
// Call hook that should trigger a redirect on mount only if defaultPath is a non-empty string.
|
||||
useInitialRedirect(defaultPath);
|
||||
return <div>Test</div>;
|
||||
};
|
||||
|
||||
it('should not navigate when defaultPath is undefined', () => {
|
||||
render(<TestComponent defaultPath={undefined} />);
|
||||
expect(mockNavigate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should navigate when defaultPath is a non-empty string', () => {
|
||||
render(<TestComponent defaultPath="/overview" />);
|
||||
expect(mockNavigate).toHaveBeenCalledWith(
|
||||
'/docs/default/Component/backstage-demo/overview',
|
||||
{ replace: true },
|
||||
);
|
||||
});
|
||||
|
||||
it('should not navigate if currPath is non-empty', () => {
|
||||
// Override useParams to simulate a non-empty currPath
|
||||
(useParams as jest.Mock).mockReturnValue({ '*': 'existing-path' });
|
||||
render(<TestComponent defaultPath={undefined} />);
|
||||
expect(mockNavigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -61,15 +61,13 @@ const MOBILE_MEDIA_QUERY = 'screen and (max-width: 76.1875em)';
|
||||
// If a defaultPath is specified then we should navigate to that path replacing the
|
||||
// current location in the history. This should only happen on the initial load so
|
||||
// navigating to the root of the docs doesn't also redirect.
|
||||
const useInitialRedirect = (defaultPath?: string) => {
|
||||
// const hasRun = useRef(false);
|
||||
|
||||
export const useInitialRedirect = (defaultPath?: string) => {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const { '*': currPath = '' } = useParams();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (currPath === '' && defaultPath !== '') {
|
||||
if (currPath === '' && defaultPath && defaultPath !== '') {
|
||||
navigate(`${location.pathname}${defaultPath}`, { replace: true });
|
||||
}
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
Reference in New Issue
Block a user