From 2c10857eb8848aef04236a3ada94ad14bd3b9cd8 Mon Sep 17 00:00:00 2001 From: Sarah German Date: Tue, 26 Jul 2022 12:39:44 -0500 Subject: Ensure correct paths for Versions menu links --- .../frontend/default/components/versions_menu.vue | 20 ++++++- .../components/helpers/versions_menu_helper.js | 14 +++++ .../default/components/versions_menu_spec.js | 68 ++++++++++++++++++++-- 3 files changed, 95 insertions(+), 7 deletions(-) create mode 100644 spec/frontend/default/components/helpers/versions_menu_helper.js diff --git a/content/frontend/default/components/versions_menu.vue b/content/frontend/default/components/versions_menu.vue index 04d2b982..01773330 100644 --- a/content/frontend/default/components/versions_menu.vue +++ b/content/frontend/default/components/versions_menu.vue @@ -30,6 +30,14 @@ export default { methods: { getVersionPath(versionNumber) { let path = window.location.pathname; + + // If we're viewing an older version, drop its version prefix when creating links. + if (this.activeVersion !== this.versions.next) { + const pathArr = window.location.pathname.split('/').filter((n) => n); + pathArr.shift(); + path = `/${pathArr.join('/')}`; + } + if (versionNumber) { path = `/${versionNumber}${path}`; } @@ -41,9 +49,15 @@ export default { // Check if the first item in the URL path is a valid version. // If so, that should be the active menu item. const versionPath = window.location.pathname.split('/')[1]; - if (Object.values(this.versions).includes(versionPath)) { - activeVersion = versionPath; - } + + Object.keys(versions).forEach((key) => { + if ( + versions[key] === versionPath || + (versions[key].constructor === Array && versions[key].includes(versionPath)) + ) { + activeVersion = versionPath; + } + }); return activeVersion; }, }, diff --git a/spec/frontend/default/components/helpers/versions_menu_helper.js b/spec/frontend/default/components/helpers/versions_menu_helper.js new file mode 100644 index 00000000..bdc1fa88 --- /dev/null +++ b/spec/frontend/default/components/helpers/versions_menu_helper.js @@ -0,0 +1,14 @@ +/** + * Creates a mock browser window object with a given path. + * @param {String} pathname + */ +export const setWindowPath = (pathname) => { + const location = { + ...window.location, + pathname, + }; + Object.defineProperty(window, 'location', { + writable: true, + value: location, + }); +}; diff --git a/spec/frontend/default/components/versions_menu_spec.js b/spec/frontend/default/components/versions_menu_spec.js index e7cadd20..01bb43e2 100644 --- a/spec/frontend/default/components/versions_menu_spec.js +++ b/spec/frontend/default/components/versions_menu_spec.js @@ -6,22 +6,82 @@ import { mount } from '@vue/test-utils'; import flushPromises from 'flush-promises'; import VersionsMenu from '../../../../content/frontend/default/components/versions_menu.vue'; import { getVersions } from '../../../../content/frontend/services/fetch_versions'; +import { setWindowPath } from './helpers/versions_menu_helper'; jest.mock('../../../../content/frontend/services/fetch_versions'); +const mockVersions = { + next: '15.3', + current: '15.2', + last_minor: ['15.1', '15.0'], + last_major: ['14.10', '13.12'], +}; + beforeEach(() => { jest.clearAllMocks(); + getVersions.mockResolvedValueOnce(mockVersions); }); describe('component: Versions menu', () => { it('Fetches versions.json and displays current version', async () => { - const mockNextVersion = '15.2'; - getVersions.mockResolvedValueOnce({ next: mockNextVersion }); const wrapper = mount(VersionsMenu); - await flushPromises(); + expect(getVersions).toHaveBeenCalledTimes(1); const nextVersion = wrapper.find('[data-testid="next-version"]').element.textContent; - expect(nextVersion).toEqual(mockNextVersion); + expect(nextVersion).toEqual(mockVersions.next); + }); + + it('Generates correct menu links from the homepage', async () => { + setWindowPath('/'); + const wrapper = mount(VersionsMenu); + + expect(wrapper.vm.getVersionPath('')).toBe('/'); + expect(wrapper.vm.getVersionPath(mockVersions.current)).toBe(`/${mockVersions.current}/`); + + Object.values([...mockVersions.last_major, ...mockVersions.last_minor]).forEach( + function testLink(v) { + expect(wrapper.vm.getVersionPath(v)).toBe(`/${v}/`); + }, + ); + }); + + it('Generates correct menu links from an interior page', async () => { + setWindowPath('/ee/user/project/issue_board.html'); + const wrapper = mount(VersionsMenu); + await wrapper.setData({ activeVersion: '15.3', versions: mockVersions }); + + expect(wrapper.vm.getVersionPath('')).toBe('/ee/user/project/issue_board.html'); + expect(wrapper.vm.getVersionPath(mockVersions.current)).toBe( + `/${mockVersions.current}/ee/user/project/issue_board.html`, + ); + + Object.values([...mockVersions.last_major, ...mockVersions.last_minor]).forEach( + function testLink(v) { + expect(wrapper.vm.getVersionPath(v)).toBe(`/${v}/ee/user/project/issue_board.html`); + }, + ); + }); + + it('Generates correct menu links from an older version', async () => { + setWindowPath('/14.10/runner'); + const wrapper = mount(VersionsMenu); + await wrapper.setData({ activeVersion: '14.10', versions: mockVersions }); + + expect(wrapper.vm.getVersionPath('')).toBe('/runner'); + expect(wrapper.vm.getVersionPath(mockVersions.current)).toBe(`/${mockVersions.current}/runner`); + + Object.values([...mockVersions.last_major, ...mockVersions.last_minor]).forEach( + function testLink(v) { + expect(wrapper.vm.getVersionPath(v)).toBe(`/${v}/runner`); + }, + ); + }); + + it('Detects the active version from the page URL', async () => { + setWindowPath('/14.10/runner'); + const wrapper = mount(VersionsMenu); + await flushPromises(); + expect(wrapper.vm.getActiveVersion(mockVersions)).toBe('14.10'); }); }); -- cgit v1.2.3