diff --git a/news/changelog-1.9.md b/news/changelog-1.9.md index 0f61d281a9..cbf080fd90 100644 --- a/news/changelog-1.9.md +++ b/news/changelog-1.9.md @@ -119,6 +119,7 @@ All changes included in 1.9: - ([#13932](https://github.com/quarto-dev/quarto-cli/pull/13932)): Add `llms-txt: true` option to generate LLM-friendly content for websites. Creates `.llms.md` markdown files alongside HTML pages and a root `llms.txt` index file following the [llms.txt](https://llmstxt.org/) specification. - ([#13951](https://github.com/quarto-dev/quarto-cli/issues/13951)): Fix `image-lazy-loading` not applying `loading="lazy"` attribute to auto-detected listing images. - ([#14003](https://github.com/quarto-dev/quarto-cli/pull/14003)): Add text fragments to search result links so browsers scroll to and highlight the matched text on the target page. +- ([#9802](https://github.com/quarto-dev/quarto-cli/issues/9802), [#14047](https://github.com/quarto-dev/quarto-cli/issues/14047)): Fix search term highlighting disappearing on page scroll or layout events when navigating from search results. (author: @jtbayly, [#13442](https://github.com/quarto-dev/quarto-cli/pull/13442)) ### `book` diff --git a/tests/docs/playwright/html/.gitignore b/tests/docs/playwright/html/.gitignore index 2cca5373e9..76e53aa71b 100644 --- a/tests/docs/playwright/html/.gitignore +++ b/tests/docs/playwright/html/.gitignore @@ -1,2 +1,4 @@ *_files/ -*.html \ No newline at end of file +*.html +/.quarto/ +**/*.quarto_ipynb diff --git a/tests/docs/playwright/html/search-highlight/.gitignore b/tests/docs/playwright/html/search-highlight/.gitignore new file mode 100644 index 0000000000..91e4dc52c8 --- /dev/null +++ b/tests/docs/playwright/html/search-highlight/.gitignore @@ -0,0 +1,3 @@ +/.quarto/ +/_site/ +**/*.quarto_ipynb diff --git a/tests/docs/playwright/html/search-highlight/_quarto.yml b/tests/docs/playwright/html/search-highlight/_quarto.yml new file mode 100644 index 0000000000..5230178921 --- /dev/null +++ b/tests/docs/playwright/html/search-highlight/_quarto.yml @@ -0,0 +1,11 @@ +project: + type: website + +website: + title: "Search Highlight Test" + navbar: + left: + - href: index.qmd + text: Home + +format: html diff --git a/tests/docs/playwright/html/search-highlight/index.qmd b/tests/docs/playwright/html/search-highlight/index.qmd new file mode 100644 index 0000000000..42d90d0b6b --- /dev/null +++ b/tests/docs/playwright/html/search-highlight/index.qmd @@ -0,0 +1,7 @@ +--- +title: "Search Highlight Test" +--- + +This page contains a special keyword that we use for testing search highlighting. + +The word special appears multiple times on this page to ensure search highlighting works correctly. diff --git a/tests/integration/playwright/tests/html-search-highlight.spec.ts b/tests/integration/playwright/tests/html-search-highlight.spec.ts new file mode 100644 index 0000000000..5b326751f8 --- /dev/null +++ b/tests/integration/playwright/tests/html-search-highlight.spec.ts @@ -0,0 +1,43 @@ +import { test, expect } from "@playwright/test"; + +const BASE = './html/search-highlight/_site/index.html'; + +test('Search highlights persist after scrolling', async ({ page }) => { + await page.goto(`${BASE}?q=special`); + const marks = page.locator('mark'); + + await expect(marks.first()).toBeVisible({ timeout: 5000 }); + const initialCount = await marks.count(); + expect(initialCount).toBeGreaterThanOrEqual(2); + + // Scroll the page — marks should not be cleared + await page.evaluate(() => window.scrollBy(0, 300)); + await page.waitForTimeout(500); + await expect(marks).toHaveCount(initialCount); +}); + +test('Search highlights cleared when query changes', async ({ page }) => { + await page.goto(`${BASE}?q=special`); + const marks = page.locator('mark'); + + await expect(marks.first()).toBeVisible({ timeout: 5000 }); + + // Open the search overlay and type a different query + await page.locator('#quarto-search').getByRole('button').click(); + const input = page.getByRole('searchbox'); + await expect(input).toBeVisible({ timeout: 2000 }); + + // Typing a different query triggers onStateChange which clears marks + await input.fill('different'); + await expect(page.locator('main mark')).toHaveCount(0, { timeout: 2000 }); +}); + +test('No highlights without search query', async ({ page }) => { + await page.goto(BASE); + + // Wait for page to fully load + await expect(page.locator('main')).toBeVisible(); + + // No marks should exist without ?q= parameter + await expect(page.locator('mark')).toHaveCount(0); +});