(page, section)
| 152 | } |
| 153 | |
| 154 | async function ensureNavigationSection(page, section) { |
| 155 | const configs = { |
| 156 | reports: { |
| 157 | sectionList: '#section-reports', |
| 158 | toggle: 'li[data-section-id="section-reports"] > .app-navigation-entry > a', |
| 159 | fallbacks: ['#section-reports a', 'a:has-text("Reports")'], |
| 160 | }, |
| 161 | datasets: { |
| 162 | sectionList: '#section-datasets', |
| 163 | toggle: 'li[data-section-id="section-datasets"] > .app-navigation-entry > a', |
| 164 | fallbacks: ['#section-datasets a', 'a:has-text("Datasets")'], |
| 165 | }, |
| 166 | panoramas: { |
| 167 | sectionList: '#section-panoramas', |
| 168 | toggle: 'li[data-section-id="section-panoramas"] > .app-navigation-entry > a', |
| 169 | fallbacks: ['#section-panoramas a', 'a:has-text("Panoramas")'], |
| 170 | }, |
| 171 | }; |
| 172 | const config = configs[section]; |
| 173 | if (!config) { |
| 174 | throw new Error(`Unknown navigation section: ${section}`); |
| 175 | } |
| 176 | |
| 177 | const sectionList = page.locator(config.sectionList).first(); |
| 178 | if (await sectionList.count().catch(() => 0)) { |
| 179 | const isOpen = await sectionList.evaluate((node) => node.closest('li.collapsible')?.classList.contains('open') ?? true).catch(() => false); |
| 180 | if (!isOpen) { |
| 181 | const toggle = page.locator(config.toggle).first(); |
| 182 | if (await toggle.count().catch(() => 0)) { |
| 183 | await toggle.click().catch(() => {}); |
| 184 | } |
| 185 | } |
| 186 | } else { |
| 187 | await clickFirst(page, [config.toggle, ...config.fallbacks], `${section} navigation`, { throwOnMissing: false }); |
| 188 | } |
| 189 | |
| 190 | await waitForIdle(page, 10000); |
| 191 | } |
| 192 | |
| 193 | function navigationEntryLink(page, name) { |
| 194 | return page.locator(`#app-navigation .app-navigation-entry > a[data-name="${name.replace(/"/g, '\\"')}"]`).first(); |
no test coverage detected