diff --git a/core/src/services/routing.js b/core/src/services/routing.js index 6446af82d3..bc0c69955d 100644 --- a/core/src/services/routing.js +++ b/core/src/services/routing.js @@ -11,7 +11,7 @@ import { isEqual } from 'lodash'; class RoutingClass { getNodePath(node, params) { - return node ? RoutingHelpers.buildRoute(node, node.pathSegment ? '/' + node.pathSegment : '', params) : ''; + return RoutingHelpers.getNodePath(node, params); } normalizePath(path) { diff --git a/core/src/utilities/helpers/iframe-helpers.js b/core/src/utilities/helpers/iframe-helpers.js index 0431527216..324556332b 100644 --- a/core/src/utilities/helpers/iframe-helpers.js +++ b/core/src/utilities/helpers/iframe-helpers.js @@ -53,19 +53,18 @@ class IframeHelpersClass { }); } - isSameDomain(config, component) { - //TODO rename to reflect the fact that it checks for URL till hash (which is more than just domain) - if (config.iframe) { - const componentData = component.get(); - const previousUrl = GenericHelpers.getUrlWithoutHash(componentData.previousNodeValues.viewUrl); - const nextUrl = GenericHelpers.getUrlWithoutHash(componentData.viewUrl); - const previousViewGroup = componentData.previousNodeValues.viewGroup; - const nextViewGroup = componentData.viewGroup; - if (previousUrl === nextUrl && !previousViewGroup && !nextViewGroup) { - return true; - } + isSameUrl(config, component) { + if (!config.iframe) { + return false; } - return false; + + const componentData = component.get(); + const previousUrl = GenericHelpers.getUrlWithoutHash(componentData.previousNodeValues.viewUrl); + const nextUrl = GenericHelpers.getUrlWithoutHash(componentData.viewUrl); + const previousViewGroup = componentData.previousNodeValues.viewGroup; + const nextViewGroup = componentData.viewGroup; + + return !!(previousUrl === nextUrl && !previousViewGroup && !nextViewGroup); } isSameViewGroup(config, component) { @@ -87,7 +86,7 @@ class IframeHelpersClass { } canReuseIframe(config, component) { - return this.isSameDomain(config, component) || this.isSameViewGroup(config, component); + return this.isSameUrl(config, component) || this.isSameViewGroup(config, component); } getLocation(url) { diff --git a/core/src/utilities/helpers/navigation-helpers.js b/core/src/utilities/helpers/navigation-helpers.js index 6da687b8bb..752b280e87 100644 --- a/core/src/utilities/helpers/navigation-helpers.js +++ b/core/src/utilities/helpers/navigation-helpers.js @@ -1,10 +1,9 @@ // Helper methods for 'navigation.js' file. They don't require any method from 'navigation.js` but are required by them. +import { reject, get } from 'lodash'; import { LuigiAuth, LuigiConfig, LuigiFeatureToggles, LuigiI18N } from '../../core-api'; -import { AuthHelpers, GenericHelpers, RoutingHelpers } from './'; import { Navigation } from '../../navigation/services/navigation'; import { Routing } from '../../services/routing'; -import { reject, get } from 'lodash'; -import { IframeHelpers } from './'; +import { AuthHelpers, GenericHelpers, IframeHelpers, RoutingHelpers } from './'; class NavigationHelpersClass { constructor() { @@ -105,13 +104,8 @@ class NavigationHelpersClass { return context; } - // TODO: use one extracted generic helper function here and in routing.js getNodePath(node) { - if (node.parent) { - return this.getNodePath(node.parent) + '/' + node.pathSegment; - } else { - return node.pathSegment; - } + return RoutingHelpers.getNodePath(node, null); } groupNodesBy(nodes, property, useVirtualGroups) { diff --git a/core/src/utilities/helpers/routing-helpers.js b/core/src/utilities/helpers/routing-helpers.js index fbd23d89f9..b332a7f15e 100644 --- a/core/src/utilities/helpers/routing-helpers.js +++ b/core/src/utilities/helpers/routing-helpers.js @@ -243,6 +243,19 @@ class RoutingHelpersClass { return undefined; } + /** + * Returns the path from the passed node and params + * @param {*} node + * @param {*} params + */ + getNodePath(node, params) { + if (!node || params) { + return node ? this.buildRoute(node, node.pathSegment ? '/' + node.pathSegment : '', params) : ''; + } else { + return `${node.parent ? this.getNodePath(node.parent) : ''}/${node.pathSegment}`; + } + } + substituteDynamicParamsInObject(object, paramMap, paramPrefix = ':', contains = false) { return Object.entries(object) .map(([key, value]) => { diff --git a/core/test/utilities/helpers/iframe-helpers.spec.js b/core/test/utilities/helpers/iframe-helpers.spec.js index 143871af66..a5bb79f0e1 100644 --- a/core/test/utilities/helpers/iframe-helpers.spec.js +++ b/core/test/utilities/helpers/iframe-helpers.spec.js @@ -142,6 +142,76 @@ describe('Iframe-helpers', () => { }); }); + describe('isSameUrl', () => { + it('should return false when iframe is not set', () => { + const config = { iframe: null }; + + component.set({ + viewUrl: 'http://otherurl.de/app.html!#/someUrl', + viewGroup: 'test', + previousNodeValues: { viewUrl: null, viewGroup: null } + }); + + const result = IframeHelpers.isSameUrl(config, component); + + assert.equal(result, false); + }); + + it('should return false when iframe is set and previousUrl is different than nextUrl', () => { + const config = { + iframe: { + src: 'http://url.com/index.html!#/prevUrl' + } + }; + + component.set({ + viewUrl: 'http://otherurl.de/app.html!#/someUrl', + viewGroup: 'test', + previousNodeValues: { viewUrl: config.iframe.src, viewGroup: null } + }); + + const result = IframeHelpers.isSameUrl(config, component); + + assert.equal(result, false); + }); + + it('should return false when iframe is set and previousUrl equals nextUrl, but viewGroup is defined', () => { + const config = { + iframe: { + src: 'http://otherurl.de/app.html!#/someUrl' + } + }; + + component.set({ + viewUrl: 'http://otherurl.de/app.html!#/someUrl', + viewGroup: 'test', + previousNodeValues: { viewUrl: config.iframe.src, viewGroup: null } + }); + + const result = IframeHelpers.isSameUrl(config, component); + + assert.equal(result, false); + }); + + it('should return true when iframe is set and previousUrl equals nextUrl and viewGroup is not defined', () => { + const config = { + iframe: { + src: 'http://otherurl.de/app.html!#/someUrl' + } + }; + + component.set({ + viewUrl: 'http://otherurl.de/app.html!#/someUrl', + viewGroup: null, + previousNodeValues: { viewUrl: config.iframe.src, viewGroup: null } + }); + + const result = IframeHelpers.isSameUrl(config, component); + + assert.equal(result, true); + }); + }); + describe('canReuseIframe', () => { const config = { iframe: { diff --git a/core/test/utilities/helpers/navigation-helpers.spec.js b/core/test/utilities/helpers/navigation-helpers.spec.js index c1ab6f3d59..c05f319a37 100644 --- a/core/test/utilities/helpers/navigation-helpers.spec.js +++ b/core/test/utilities/helpers/navigation-helpers.spec.js @@ -1,12 +1,11 @@ -/* eslint-disable camelcase */ -//TODO: make some tests here +import { LuigiAuth, LuigiConfig, LuigiFeatureToggles, LuigiI18N } from '../../../src/core-api'; +import { Navigation } from '../../../src/navigation/services/navigation'; +import { Routing } from '../../../src/services'; +import { AuthHelpers, NavigationHelpers, RoutingHelpers } from '../../../src/utilities/helpers'; + const chai = require('chai'); const assert = chai.assert; const sinon = require('sinon'); -import { AuthHelpers, NavigationHelpers, RoutingHelpers } from '../../../src/utilities/helpers'; -import { LuigiAuth, LuigiConfig, LuigiFeatureToggles, LuigiI18N } from '../../../src/core-api'; -import { Routing } from '../../../src/services/routing'; -import { Navigation } from '../../../src/navigation/services/navigation'; describe('Navigation-helpers', () => { describe('isNodeAccessPermitted', () => { @@ -228,14 +227,25 @@ describe('Navigation-helpers', () => { }); }); - it('getNodePath', () => { - const node = { - parent: { - pathSegment: 'parent' - }, - pathSegment: 'pathSegment' - }; - assert.equal(NavigationHelpers.getNodePath(node), 'parent/pathSegment', 'path should match'); + describe('getNodePath', () => { + it('should return path built without parent segment', () => { + const node = { + pathSegment: 'pathSegment' + }; + + assert.equal(NavigationHelpers.getNodePath(node), '/pathSegment', 'path should match'); + }); + + it('should return path built from both parent and child segment', () => { + const node = { + parent: { + pathSegment: 'parent' + }, + pathSegment: 'pathSegment' + }; + + assert.equal(NavigationHelpers.getNodePath(node), '/parent/pathSegment', 'path should match'); + }); }); describe('handleUnresponsiveClient', () => { @@ -1006,4 +1016,130 @@ describe('Navigation-helpers', () => { assert.equal(sideNavAccordionMode, true); }); }); + + describe('getProductSwitcherConfig', () => { + beforeEach(() => { + sinon.stub(LuigiConfig, 'getConfigValue'); + }); + + afterEach(() => { + sinon.restore(); + }); + + it('should return product switcher config', () => { + const mockedConfig = { + icon: 'grid', + label: 'Products', + columns: 'auto', + items: () => { + return [{}, {}, {}]; + } + }; + + LuigiConfig.getConfigValue.returns(mockedConfig); + + const result = NavigationHelpers.getProductSwitcherConfig(); + + assert.deepEqual(result, mockedConfig); + }); + }); + + describe('applyContext', () => { + it('should return provided context when no additional data is present', () => { + const mockedContext = { data: 'store' }; + const result = NavigationHelpers.applyContext(mockedContext, null, null); + + assert.deepEqual(result, mockedContext); + }); + + it('should return provided context when additional data is present', () => { + const mockedContext = { data: 'store' }; + const mockedAddition = { foo: 'bar' }; + const result = NavigationHelpers.applyContext(mockedContext, mockedAddition, null); + + assert.deepEqual(result, { ...mockedContext, ...mockedAddition }); + }); + }); + + describe('stripNode', () => { + it('should return stripped node', () => { + const mockedNode = { children: [], data: 'store', navHeader: {}, parent: {} }; + const result = NavigationHelpers.stripNode(mockedNode); + + assert.deepEqual(result, { data: 'store' }); + }); + }); + + describe('getParentNode', () => { + it('should return node parent when it is present', () => { + const mockedNode = { children: [], data: 'store', navHeader: {}, parent: {} }; + const mockedPathData = [ + { + navigationPath: [ + { + pathSegment: 'groups', + children: [ + { + pathSegment: 'stakeholders', + viewUrl: '/sampleapp.html#/projects/1/users/groups/stakeholders' + }, + { + pathSegment: 'customers', + viewUrl: '/sampleapp.html#/projects/1/users/groups/customers' + } + ] + } + ], + context: {} + } + ]; + const result = NavigationHelpers.getParentNode(mockedNode, mockedPathData); + + assert.deepEqual(result, {}); + }); + + it('should return path data item when node parent is not present', () => { + const mockedNode = { children: [], data: 'store', navHeader: {}, parent: null }; + const mockedPathData = [ + { + navigationPath: [ + { + pathSegment: 'groups', + children: [ + { + pathSegment: 'stakeholders', + viewUrl: '/sampleapp.html#/projects/1/users/groups/stakeholders' + }, + { + pathSegment: 'customers', + viewUrl: '/sampleapp.html#/projects/1/users/groups/customers' + } + ] + } + ], + context: {} + }, + mockedNode + ]; + const result = NavigationHelpers.getParentNode(mockedNode, mockedPathData); + + assert.deepEqual(result, mockedPathData[0]); + }); + }); + + describe('getTestId', () => { + it('should return node testId when it is present', () => { + const mockedNode = { children: [], label: null, pathSegment: null, testId: 'ab_cd' }; + const result = NavigationHelpers.getTestId(mockedNode); + + assert.equal(result, 'ab_cd'); + }); + + it('should return generated testId when it is not present in node', () => { + const mockedNode = { children: [], label: 'cd', pathSegment: 'ab', testId: null }; + const result = NavigationHelpers.getTestId(mockedNode); + + assert.equal(result, 'ab_cd'); + }); + }); }); diff --git a/core/test/utilities/helpers/routing-helpers.spec.js b/core/test/utilities/helpers/routing-helpers.spec.js index ad0fed7085..57bc2f6492 100644 --- a/core/test/utilities/helpers/routing-helpers.spec.js +++ b/core/test/utilities/helpers/routing-helpers.spec.js @@ -503,6 +503,34 @@ describe('Routing-helpers', () => { sinon.assert.calledOnce(RoutingHelpers.getRouteLink); }); }); + + describe('getNodePath', () => { + const node = { + label: 'AAA', + pathSegment: 'projects', + viewUrl: '/aaa.html' + }; + const params = '~test=true&foo=bar'; + + it('should not fail if node is not defined', () => { + const result = Routing.getNodePath(undefined, params); + + assert.equal(result, ''); + }); + + it('should not fail if params are not defined', () => { + const result = Routing.getNodePath(node, undefined); + + assert.equal(result, '/projects'); + }); + + it('should return node path with params', () => { + const result = Routing.getNodePath(node, params); + + assert.equal(result, '/projects?~test=true&foo=bar'); + }); + }); + describe('getLastNodeObject', () => { let mockPathData;