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

keepURL in pagenotfoundhandler #2598

Merged
merged 14 commits into from
Mar 10, 2022
9 changes: 7 additions & 2 deletions core/src/services/routing.js
Original file line number Diff line number Diff line change
Expand Up @@ -469,10 +469,15 @@ class RoutingClass {
}

async showPageNotFoundError(component, pathToRedirect, notFoundPath, isAnyPathMatched = false) {
const redirectPathFromNotFoundHandler = RoutingHelpers.getPageNotFoundRedirectPath(notFoundPath, isAnyPathMatched);
const redirectResult = RoutingHelpers.getPageNotFoundRedirectResult(notFoundPath, isAnyPathMatched);
const redirectPathFromNotFoundHandler = redirectResult.path;

if (redirectPathFromNotFoundHandler) {
this.navigateTo(redirectPathFromNotFoundHandler);
if (redirectResult.keepURL) {
this.handleRouteChange(redirectPathFromNotFoundHandler, component, IframeHelpers.getIframeContainer(), {});
} else {
this.navigateTo(redirectPathFromNotFoundHandler);
}
return;
}
RoutingHelpers.showRouteNotFoundAlert(component, notFoundPath, isAnyPathMatched);
Expand Down
13 changes: 8 additions & 5 deletions core/src/utilities/helpers/routing-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -545,18 +545,21 @@ class RoutingHelpersClass {
* Queries the pageNotFoundHandler configuration and returns redirect path if it exists
* If the there is no `pageNotFoundHandler` defined we return undefined.
* @param {*} notFoundPath the path to check
* @returns redirect path if it exists, else return undefined
* @returns an object optionally containing the path to redirect, the keepURL option or an empty object if handler is undefined
*/
getPageNotFoundRedirectPath(notFoundPath, isAnyPathMatched = false) {
getPageNotFoundRedirectResult(notFoundPath, isAnyPathMatched = false) {
const pageNotFoundHandler = LuigiConfig.getConfigValue('routing.pageNotFoundHandler');
if (typeof pageNotFoundHandler === 'function') {
// custom 404 handler is provided, use it
const result = pageNotFoundHandler(notFoundPath, isAnyPathMatched);
if (result && result.redirectTo) {
return result.redirectTo;
return {
path: result.redirectTo,
keepURL: result.keepURL
};
}
}
return undefined;
return {};
}

/**
Expand All @@ -572,7 +575,7 @@ class RoutingHelpersClass {
if (pathExists) {
return path;
}
const redirectPath = this.getPageNotFoundRedirectPath(path);
const redirectPath = this.getPageNotFoundRedirectResult(path).path;
if (redirectPath !== undefined) {
return redirectPath;
} else {
Expand Down
46 changes: 34 additions & 12 deletions core/test/utilities/helpers/routing-helpers.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -737,39 +737,61 @@ describe('Routing-helpers', () => {
});
});

describe('getPageNotFoundRedirectPath', () => {
describe('getPageNotFoundRedirectResult', () => {
afterEach(() => {
sinon.restore();
sinon.reset();
});

it('with custom pageNotFoundHandler defined', async () => {
it('with custom pageNotFoundHandler defined redirectTo path', async () => {
const customRedirect = 'somecustompath';
sinon
.stub(LuigiConfig, 'getConfigValue')
.withArgs('routing.pageNotFoundHandler')
.returns(() => {
return { redirectTo: customRedirect };
});
const expected = await RoutingHelpers.getPageNotFoundRedirectPath('notFoundPath');
const expected = await RoutingHelpers.getPageNotFoundRedirectResult('notFoundPath').path;
assert.equal(customRedirect, expected);
});

it('with custom pageNotFoundHandler defined keepURL', async () => {
const customKeepURL = true;
const somePath = 'somePath';
sinon
.stub(LuigiConfig, 'getConfigValue')
.withArgs('routing.pageNotFoundHandler')
.returns(() => {
return {
redirectTo: somePath,
keepURL: customKeepURL
};
});
const expected = await RoutingHelpers.getPageNotFoundRedirectResult('');
assert.deepEqual(
{
path: somePath,
keepURL: customKeepURL
},
expected
);
});

it('with custom pageNotFoundHandler not defined', async () => {
sinon
.stub(LuigiConfig, 'getConfigValue')
.withArgs('routing.pageNotFoundHandler')
.returns(undefined);
const expected = await RoutingHelpers.getPageNotFoundRedirectPath('notFoundPath');
assert.equal(undefined, expected);
.returns();
const expected = await RoutingHelpers.getPageNotFoundRedirectResult('notFoundPath');
assert.deepEqual({}, expected);
});

it('with custom pageNotFoundHandler not a function', async () => {
sinon
.stub(LuigiConfig, 'getConfigValue')
.withArgs('routing.pageNotFoundHandler')
.returns({ thisObject: 'should be function instead' });
const expected = await RoutingHelpers.getPageNotFoundRedirectPath('notFoundPath');
const expected = await RoutingHelpers.getPageNotFoundRedirectResult('notFoundPath').path;
assert.equal(undefined, expected);
});
});
Expand All @@ -782,7 +804,7 @@ describe('Routing-helpers', () => {
beforeEach(() => {
console.warn = sinon.spy();
sinon.stub(LuigiI18N, 'getTranslation');
sinon.stub(RoutingHelpers, 'getPageNotFoundRedirectPath');
sinon.stub(RoutingHelpers, 'getPageNotFoundRedirectResult');
sinon.stub(RoutingHelpers, 'showRouteNotFoundAlert');
sinon.stub(component, 'showAlert');
});
Expand All @@ -799,12 +821,12 @@ describe('Routing-helpers', () => {
});

it('with custom pageNotFoundHandler defined', async () => {
const redirectPath = 'somepathtoredirect';
const redirectPath = { path: 'somepathtoredirect' };
// define pageNotFoundHandler return value with stub
RoutingHelpers.getPageNotFoundRedirectPath.returns(redirectPath);
RoutingHelpers.getPageNotFoundRedirectResult.returns(redirectPath);
// call function being tested
const expected = await RoutingHelpers.handlePageNotFoundAndRetrieveRedirectPath(component, redirectPath, false);
assert.equal(redirectPath, expected);
assert.equal(redirectPath.path, expected);
});

it('with custom pageNotFoundHandler as not defined', async () => {
Expand All @@ -813,7 +835,7 @@ describe('Routing-helpers', () => {
.withArgs('luigi.requestedRouteNotFound', { route: path })
.returns('Could not find the requested route');
// set pageNotFoundHandler as undefined with stub
RoutingHelpers.getPageNotFoundRedirectPath.returns(undefined);
RoutingHelpers.getPageNotFoundRedirectResult.returns({});
// call function being tested
const expected = await RoutingHelpers.handlePageNotFoundAndRetrieveRedirectPath(component, path, false);
sinon.assert.calledWith(console.warn, `Could not find the requested route: ${path}`);
Expand Down
2 changes: 1 addition & 1 deletion docs/navigation-parameters-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ You can configure the way Luigi tackles routing in your application in the `rout

### pageNotFoundHandler
- **type**: any
- **description**: defines custom behavior when a `404` error occurs. Luigi handles it by default. Leave its body empty if you have an external `404` handling. You can return an Object with **redirectTo** parameter if you want Luigi to redirect to a specific navigation path after execution.
- **description**: defines custom behavior when a `404` error occurs. Luigi handles it by default. Leave its body empty if you have an external `404` handling. You can return an Object with **redirectTo** and **keepURL** as parameters. You can use the **redirectTo** parameter if you want Luigi to redirect to a specific navigation path after execution. Setting the **keepURL** parameter to true will keep the erroneous url onto the browsers address bar.
- **attributes**:
- **wrongPath** (string): the path that the user tried navigating to.
- **wasAnyPathFitted** (bool): it is true if Luigi managed to fit a valid path which means **wrongPath** was only partially wrong. Otherwise it is false.
Expand Down