From cb9b6117d4c69d8bd72d1185de2553fce3dd4155 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Thu, 7 Nov 2024 13:19:57 -0500 Subject: [PATCH] Support relative links (#45) * Support relative links * Update tests * dep * fix --- .../tests/acceptance/visit-all-links-test.ts | 15 ++++- test-app/tests/index.html | 1 - test-support/src/routing/visit-all.ts | 57 +++++++++++++------ 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/test-app/tests/acceptance/visit-all-links-test.ts b/test-app/tests/acceptance/visit-all-links-test.ts index 1a01bb7..161803e 100644 --- a/test-app/tests/acceptance/visit-all-links-test.ts +++ b/test-app/tests/acceptance/visit-all-links-test.ts @@ -6,7 +6,18 @@ import { visitAllLinks } from '@universal-ember/test-support'; module('All Links', function (hooks) { setupApplicationTest(hooks); - test('are visitable without error', async function () { - await visitAllLinks(); + test('are visitable without error', async function (assert) { + const size1 = await visitAllLinks(); + const size2 = await visitAllLinks((url) => { + assert.ok(url); + }); + + assert.ok(size1 > 0, 'The test app has links'); + assert.ok(size2 > 0, 'The test app has links'); + assert.strictEqual( + size1, + size2, + `multiple usages does not visit different numbers of links (${size1} === ${size2})`, + ); }); }); diff --git a/test-app/tests/index.html b/test-app/tests/index.html index e4b2e69..0fc6787 100644 --- a/test-app/tests/index.html +++ b/test-app/tests/index.html @@ -11,7 +11,6 @@ - {{content-for "head-footer"}} {{content-for "test-head-footer"}} diff --git a/test-support/src/routing/visit-all.ts b/test-support/src/routing/visit-all.ts index db551c6..6638def 100644 --- a/test-support/src/routing/visit-all.ts +++ b/test-support/src/routing/visit-all.ts @@ -11,11 +11,34 @@ import QUnit from 'qunit'; import type Owner from '@ember/owner'; import type RouterService from '@ember/routing/router-service'; -function findInAppLinks(): string[] { - return (findAll('a') - ?.map((link) => link.getAttribute('href')) - ?.filter((href) => !href?.startsWith('http')) - .filter(Boolean) || []) as string[]; +interface InAppLink { + href: string; + original: string; + selector: string; +} + +function findInAppLinks(): InAppLink[] { + const results: InAppLink[] = []; + + const allAnchorsOnThePage = findAll('a'); + + for (const a of allAnchorsOnThePage) { + const href = a.getAttribute('href'); + + if (!href) continue; + if (href.startsWith('http')) continue; + + const url = new URL(href, window.location.href); + const withoutDomain = `${url.pathname}${url.search}${url.hash}`; + + results.push({ + href: withoutDomain, + original: href, + selector: `a[href="${href}"]`, + }); + } + + return results; } const assert = QUnit.assert; @@ -32,7 +55,7 @@ export async function visitAllLinks( await visit(returnTo); const inAppLinks = findInAppLinks(); - const queue: (string | { changeReturnTo: string })[] = [...inAppLinks]; + const queue: (InAppLink | { changeReturnTo: string })[] = [...inAppLinks]; const ctx = getContext() as unknown as { owner: Owner }; const router = ctx?.owner?.lookup('service:router') as RouterService; @@ -44,7 +67,7 @@ export async function visitAllLinks( debugAssert(`Queue entries cannot be falsey`, toVisit); - if (typeof toVisit === 'object' && toVisit !== null) { + if ('changeReturnTo' in toVisit) { returnTo = toVisit.changeReturnTo; continue; } @@ -52,11 +75,11 @@ export async function visitAllLinks( // In-page links are on the page we're already on. // As long as we haven't already encountered an error, // this is silly to check. - if (toVisit.startsWith('#')) { + if (toVisit.original.startsWith('#')) { continue; } - const [nonHashPart] = toVisit.split('#'); + const [nonHashPart] = toVisit.href.split('#'); // This was our first page, we've already been here if (nonHashPart === '/') { @@ -67,31 +90,31 @@ export async function visitAllLinks( if (visited.has(key)) continue; - const result = router.recognize(toVisit); + const result = router.recognize(toVisit.href); if (!result) { assert.ok( true, - `${toVisit} on page ${returnTo} is not recognized by this app and will be skipped`, + `${toVisit.href} on page ${returnTo} is not recognized by this app and will be skipped`, ); continue; } await visit(returnTo); - const link = find(`a[href="${toVisit}"]`); + const link = find(toVisit.selector); - debugAssert(`link exists with ${toVisit}`, link); + debugAssert(`link exists via selector \`${toVisit.selector}\``, link); await click(link); assert.ok( - currentURL().startsWith(toVisit), - `Navigation was successful: to:${toVisit}, from:${returnTo}`, + currentURL().startsWith(toVisit.href), + `Navigation was successful: to:${toVisit.original}, from:${returnTo}`, ); visited.add(key); if (callback) { - await callback(toVisit); + await callback(toVisit.href); } const links = findInAppLinks(); @@ -99,4 +122,6 @@ export async function visitAllLinks( queue.push({ changeReturnTo: currentURL() }); queue.push(...links); } + + return visited.size; }