diff --git a/package.json b/package.json index 022431c3..b19f06b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "impro", - "version": "0.20.33", + "version": "0.20.34", "type": "module", "scripts": { "start": "rm -rf \"${BUILD_DIR:-build}\" && NODE_ENV=development eleventy --serve", diff --git a/src/js/app.js b/src/js/app.js index 8f431630..8dfe6a6c 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -63,7 +63,10 @@ import { getAppViewConfig, handleAppViewResetQueryParam, } from "/js/appViewConfig.js"; -import { PluginService } from "/js/plugins/pluginService.js"; +import { + PluginService, + PLUGIN_PREVIEW_QUERY_PARAM, +} from "/js/plugins/pluginService.js"; import { HiddenFeedItemsStore } from "/js/dataLayer/hiddenFeedItemsStore.js"; import { Constellation } from "/js/constellation.js"; import { MainLayout } from "/js/mainLayout.js"; @@ -452,11 +455,16 @@ export async function main() { if (e.altKey) { return; } + const parsedUrl = new URL(anchor.href, window.location.href); + // The plugin preview param only takes effect at bootstrap, so these links + // need a full page load + if (parsedUrl.searchParams.has(PLUGIN_PREVIEW_QUERY_PARAM)) { + return; + } if (anchor.href.startsWith("/")) { e.preventDefault(); return router.go(anchor.href); } - const parsedUrl = new URL(anchor.href); // Handle direct .bsky.social links if (parsedUrl.hostname.endsWith(".bsky.social")) { const handle = parsedUrl.hostname; diff --git a/tests/e2e/specs/concerns/inAppLinks.test.js b/tests/e2e/specs/concerns/inAppLinks.test.js index 0e15b4f2..8cf3bb21 100644 --- a/tests/e2e/specs/concerns/inAppLinks.test.js +++ b/tests/e2e/specs/concerns/inAppLinks.test.js @@ -183,6 +183,34 @@ test.describe("In-app link interception", () => { expect(page.url()).toContain("example.com/some-page"); }); + test("should not intercept links with a plugin-preview query param", async ({ + page, + }) => { + await page.evaluate(() => { + window.__spaSessionMarker = true; + const anchor = document.createElement("a"); + anchor.href = "/?plugin-preview=example-plugin"; + anchor.textContent = "Plugin preview"; + anchor.id = "test-plugin-preview-link"; + document.body.appendChild(anchor); + }); + + await page.locator("#test-plugin-preview-link").click(); + + await expect(page).toHaveURL(/\?plugin-preview=example-plugin$/); + await expect(page.locator("#home-view")).toBeVisible({ timeout: 10000 }); + + // A full document navigation resets window state; an SPA transition would + // have kept the marker + const marker = await page.evaluate(() => window.__spaSessionMarker); + expect(marker).toBe(undefined); + + // Logged in, bootstrap shows the preview-links warning toast + await expect(page.locator('[data-testid="toast"]')).toBeVisible({ + timeout: 10000, + }); + }); + test("should not intercept modifier-key clicks on in-app links", async ({ page, }) => {