[Spaces] Added additional tests for space next route navigation (#189497)

## Summary

Added additional tests for space next route navigation with default
route, specifically:
- `defaultRoute` with and without hash
- `defaultRoute` with and without search
- `defaultRoute` check for not navigating outside of space base url


### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

__Fixes: https://github.com/elastic/kibana/issues/189481__
This commit is contained in:
elena-shostak 2024-08-02 13:23:52 +02:00 committed by GitHub
parent 02510bae9e
commit 4edcdef311
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 121 additions and 102 deletions

View file

@ -107,72 +107,63 @@ describe('Enter Space view routes', () => {
});
});
it('correctly enters space default route.', async () => {
const request = httpServerMock.createKibanaRequest();
const responseFactory = httpResourcesMock.createResponseFactory();
const contextMock = coreMock.createRequestHandlerContext();
const testCase = (
description: string,
{
query,
defaultRoute,
expectedLocation,
}: { query?: Record<string, string>; defaultRoute?: string; expectedLocation: string }
) => {
it(description, async () => {
const request = httpServerMock.createKibanaRequest({
query,
});
contextMock.uiSettings.client.get.mockResolvedValue('/home');
const responseFactory = httpResourcesMock.createResponseFactory();
const contextMock = coreMock.createRequestHandlerContext();
contextMock.uiSettings.client.get.mockResolvedValue(defaultRoute);
await routeHandler(
{ core: contextMock } as unknown as RequestHandlerContext,
request,
responseFactory
);
await routeHandler(
{ core: contextMock } as unknown as RequestHandlerContext,
request,
responseFactory
);
expect(responseFactory.redirected).toHaveBeenCalledWith({
headers: { location: '/mock-server-basepath/home' },
expect(responseFactory.redirected).toHaveBeenCalledWith({
headers: { location: expectedLocation },
});
});
};
testCase('correctly enters space default route.', {
defaultRoute: '/home',
expectedLocation: '/mock-server-basepath/home',
});
it('correctly enters space with specified route.', async () => {
const nextRoute = '/app/management/kibana/objects';
const request = httpServerMock.createKibanaRequest({
query: {
next: nextRoute,
},
});
const responseFactory = httpResourcesMock.createResponseFactory();
const contextMock = coreMock.createRequestHandlerContext();
await routeHandler(
{ core: contextMock } as unknown as RequestHandlerContext,
request,
responseFactory
);
expect(responseFactory.redirected).toHaveBeenCalledWith({
headers: { location: `/mock-server-basepath${nextRoute}` },
});
testCase('correctly enters space with specified route.', {
query: {
next: '/app/management/kibana/objects',
},
expectedLocation: '/mock-server-basepath/app/management/kibana/objects',
});
it('correctly enters space with specified route without leading slash.', async () => {
const nextRoute = 'app/management/kibana/objects';
const request = httpServerMock.createKibanaRequest({
query: {
next: nextRoute,
},
});
const responseFactory = httpResourcesMock.createResponseFactory();
const contextMock = coreMock.createRequestHandlerContext();
await routeHandler(
{ core: contextMock } as unknown as RequestHandlerContext,
request,
responseFactory
);
expect(responseFactory.redirected).toHaveBeenCalledWith({
headers: { location: `/mock-server-basepath/${nextRoute}` },
});
testCase('correctly enters space with specified route without leading slash.', {
query: {
next: 'app/management/kibana/objects',
},
expectedLocation: '/mock-server-basepath/app/management/kibana/objects',
});
it('correctly enters space and normalizes specified route.', async () => {
const responseFactory = httpResourcesMock.createResponseFactory();
const contextMock = coreMock.createRequestHandlerContext();
testCase('correctly enters space with default route if specified route is not relative.', {
query: {
next: 'http://evil.com/mock-server-basepath/app/kibana',
},
defaultRoute: '/home',
expectedLocation: '/mock-server-basepath/home',
});
describe('specified route normalization', () => {
for (const { query, expectedLocation } of [
{
query: {
@ -205,56 +196,47 @@ describe('Enter Space view routes', () => {
expectedLocation:
'/mock-server-basepath/app/management/kibana/objects?initialQuery=type:(visualization)',
},
{
query: {
next: '/app/discover#/view/uuid',
},
expectedLocation: '/mock-server-basepath/app/discover#/view/uuid',
},
{
query: {
next: '/app/discover?initialQuery=type:(visualization)#/view/uuid',
},
expectedLocation:
'/mock-server-basepath/app/discover?initialQuery=type:(visualization)#/view/uuid',
},
]) {
const request = httpServerMock.createKibanaRequest({
query,
});
await routeHandler(
{ core: contextMock } as unknown as RequestHandlerContext,
request,
responseFactory
);
expect(responseFactory.redirected).toHaveBeenCalledWith({
headers: { location: expectedLocation },
});
responseFactory.redirected.mockClear();
testCase(`url ${query.next}`, { query, expectedLocation });
}
});
it('correctly enters space with default route if specificed route is not relative.', async () => {
const request = httpServerMock.createKibanaRequest({
query: {
next: 'http://evil.com/mock-server-basepath/app/kibana',
describe('default route', () => {
for (const { defaultRoute, expectedLocation, query, testCaseName } of [
{
defaultRoute: '/home',
expectedLocation: '/mock-server-basepath/home',
testCaseName: 'correctly enters space with default route.',
},
});
const responseFactory = httpResourcesMock.createResponseFactory();
const contextMock = coreMock.createRequestHandlerContext();
contextMock.uiSettings.client.get.mockResolvedValue('/home');
await routeHandler(
{ core: contextMock } as unknown as RequestHandlerContext,
request,
responseFactory
);
expect(responseFactory.redirected).toHaveBeenCalledWith({
headers: { location: '/mock-server-basepath/home' },
});
{
defaultRoute: '/home',
expectedLocation: '/mock-server-basepath/home',
testCaseName: 'correctly enters space with default route if specified url is empty string.',
query: { next: '' },
},
{
defaultRoute: '/home/#view',
expectedLocation: '/mock-server-basepath/home/#view',
testCaseName: 'correctly enters space with default route preserving url hash.',
},
{
defaultRoute: '/home?initialQuery=type:(visualization)',
expectedLocation: '/mock-server-basepath/home?initialQuery=type:(visualization)',
testCaseName: 'correctly enters space with default route preserving url search.',
},
{
defaultRoute: '/app/discover?initialQuery=type:(visualization)#/view/uuid',
expectedLocation:
'/mock-server-basepath/app/discover?initialQuery=type:(visualization)#/view/uuid',
testCaseName: 'correctly enters space with default route preserving url search and hash.',
},
{
defaultRoute: '../../app/../app/management/kibana/objects',
expectedLocation: '/mock-server-basepath/app/management/kibana/objects',
testCaseName: 'correctly enters space with default route normalizing url.',
},
]) {
testCase(testCaseName, { query, defaultRoute, expectedLocation });
}
});
});

View file

@ -44,6 +44,7 @@ export function initSpacesViewsRoutes(deps: ViewRouteDeps) {
// need to get reed of ../../ to make sure we will not be out of space basePath
const normalizedRoute = new URL(route, 'https://localhost');
// preserving of the hash is important for the navigation to work correctly with default route
return response.redirected({
headers: {
location: `${basePath}${normalizedRoute.pathname}${normalizedRoute.search}${normalizedRoute.hash}`,

View file

@ -110,10 +110,37 @@ export default function enterSpaceFunctionalTests({
const anchorElement = await PageObjects.spaceSelector.getSpaceCardAnchor(spaceId);
const path = await anchorElement.getAttribute('href');
const pathWithNextRoute = `${path}?next=/app/management/kibana/objects?initialQuery=type:(visualization)#/view`;
const pathWithNextRoute = `${path}?next=/app/management/kibana/objects?initialQuery=type:(visualization)#/view/uuid`;
await browser.navigateTo(pathWithNextRoute);
await PageObjects.spaceSelector.expectRoute(
spaceId,
'/app/management/kibana/objects?initialQuery=type%3A(visualization)#/view/uuid'
);
});
it('allows user to navigate to different space with default route preserving url hash and search', async () => {
const spaceId = 'another-space';
await kibanaServer.uiSettings.replace(
{
defaultRoute: '/app/management/kibana/objects?initialQuery=type:(visualization)#/view',
buildNum: 8467,
'dateFormat:tz': 'UTC',
},
{ space: 'another-space' }
);
await PageObjects.security.login(undefined, undefined, {
expectSpaceSelector: true,
});
const anchorElement = await PageObjects.spaceSelector.getSpaceCardAnchor(spaceId);
const path = await anchorElement.getAttribute('href');
await browser.navigateTo(path!);
await PageObjects.spaceSelector.expectRoute(
spaceId,
'/app/management/kibana/objects?initialQuery=type%3A(visualization)#/view'
@ -142,6 +169,15 @@ export default function enterSpaceFunctionalTests({
it('falls back to the default home page if provided next route is malformed', async () => {
const spaceId = 'another-space';
await kibanaServer.uiSettings.replace(
{
defaultRoute: '/app/canvas',
buildNum: 8467,
'dateFormat:tz': 'UTC',
},
{ space: 'another-space' }
);
await PageObjects.security.login(undefined, undefined, {
expectSpaceSelector: true,
});