diff --git a/client/src/includes/tabs.js b/client/src/includes/tabs.js
index b621caccb8..2631c75c9d 100644
--- a/client/src/includes/tabs.js
+++ b/client/src/includes/tabs.js
@@ -270,10 +270,10 @@ class Tabs {
selectTabByURLHash() {
if (window.location.hash) {
- const cleanedHash = window.location.hash.replace(/[^\w\-#]/g, '');
+ const anchorId = window.location.hash.slice(1);
// Support linking straight to a tab, or to an element within a tab.
const tabID = document
- .querySelector(cleanedHash)
+ .getElementById(anchorId)
?.closest('[role="tabpanel"]')
?.getAttribute('aria-labelledby');
const tab = document.getElementById(tabID);
diff --git a/client/src/includes/tabs.test.js b/client/src/includes/tabs.test.js
new file mode 100644
index 0000000000..1644af84a1
--- /dev/null
+++ b/client/src/includes/tabs.test.js
@@ -0,0 +1,158 @@
+import { validateCreationForm } from './chooserModal';
+import { initTabs } from './tabs';
+
+describe('tabs', () => {
+ beforeEach(() => {
+ document.body.innerHTML = /* html */ `
+
+ `;
+ });
+
+ describe('initialize selected tab', () => {
+ afterEach(() => {
+ window.location.hash = '';
+ });
+
+ it('should select the first tab by default', async () => {
+ initTabs();
+ await Promise.resolve();
+
+ const contentTab = document.getElementById('tab-content');
+ const promoteTab = document.getElementById('tab-promote');
+ const contentTabLabel = document.getElementById('tab-label-content');
+ const promoteTabLabel = document.getElementById('tab-label-promote');
+
+ expect(contentTab.hasAttribute('hidden')).toBe(false);
+ expect(promoteTab.hasAttribute('hidden')).toBe(true);
+
+ expect(contentTabLabel.getAttribute('aria-selected')).toEqual('true');
+ expect(promoteTabLabel.getAttribute('aria-selected')).toEqual('false');
+ });
+
+ it('should select the correct tab where the anchored element lives', async () => {
+ window.location.hash = '#id_search_description';
+ initTabs();
+ await Promise.resolve();
+
+ const contentTab = document.getElementById('tab-content');
+ const promoteTab = document.getElementById('tab-promote');
+ const contentTabLabel = document.getElementById('tab-label-content');
+ const promoteTabLabel = document.getElementById('tab-label-promote');
+
+ expect(contentTab.hasAttribute('hidden')).toBe(true);
+ expect(promoteTab.hasAttribute('hidden')).toBe(false);
+
+ expect(contentTabLabel.getAttribute('aria-selected')).toEqual('false');
+ expect(promoteTabLabel.getAttribute('aria-selected')).toEqual('true');
+ });
+
+ it('should not throw an error if the URL hash begins with a number', async () => {
+ window.location.hash = '#123abcd';
+ initTabs();
+ await Promise.resolve();
+
+ const contentTab = document.getElementById('tab-content');
+ const promoteTab = document.getElementById('tab-promote');
+ const contentTabLabel = document.getElementById('tab-label-content');
+ const promoteTabLabel = document.getElementById('tab-label-promote');
+
+ expect(contentTab.hasAttribute('hidden')).toBe(false);
+ expect(promoteTab.hasAttribute('hidden')).toBe(true);
+
+ expect(contentTabLabel.getAttribute('aria-selected')).toEqual('true');
+ expect(promoteTabLabel.getAttribute('aria-selected')).toEqual('false');
+ });
+ });
+
+ describe('switching tabs', () => {
+ it('should allow switching to a different tab by clicking on the label', async () => {
+ initTabs();
+ await Promise.resolve();
+
+ const contentTab = document.getElementById('tab-content');
+ const promoteTab = document.getElementById('tab-promote');
+ const contentTabLabel = document.getElementById('tab-label-content');
+ const promoteTabLabel = document.getElementById('tab-label-promote');
+
+ promoteTabLabel.click();
+
+ expect(contentTab.hasAttribute('hidden')).toBe(true);
+ expect(promoteTab.hasAttribute('hidden')).toBe(false);
+
+ expect(contentTabLabel.getAttribute('aria-selected')).toEqual('false');
+ expect(promoteTabLabel.getAttribute('aria-selected')).toEqual('true');
+ });
+ });
+});