From 6341ad707fbb5e87550a2882944b6f4aeeac5c4a Mon Sep 17 00:00:00 2001 From: Cody Foss Date: Mon, 15 Jun 2026 12:05:58 -0600 Subject: [PATCH 1/3] Initial commit with proof of concept --- .gitignore | 4 ++ _config.yml | 4 ++ e2e/README.md | 155 +++++++++++++++++++++++++++++++++++++++++++ e2e/qs-en.spec.js | 111 +++++++++++++++++++++++++++++++ e2e/srb-en.spec.js | 76 +++++++++++++++++++++ package-lock.json | 64 ++++++++++++++++++ package.json | 10 ++- playwright.config.js | 27 ++++++++ 8 files changed, 449 insertions(+), 2 deletions(-) create mode 100644 e2e/README.md create mode 100644 e2e/qs-en.spec.js create mode 100644 e2e/srb-en.spec.js create mode 100644 playwright.config.js diff --git a/.gitignore b/.gitignore index 57f582d..1207fcc 100644 --- a/.gitignore +++ b/.gitignore @@ -164,3 +164,7 @@ vendor Gemfile.lock _data/token.yml + +# Output from automated tests +/playwright-report +/test-results diff --git a/_config.yml b/_config.yml index 393f475..fd8daf2 100644 --- a/_config.yml +++ b/_config.yml @@ -25,8 +25,12 @@ exclude: - docker-compose.yml - Gruntfile.js - dist/ + - e2e/ + - playwright-report/ + - test-results/ - package.json - package-lock.json + - playwright.config.js - LICENSE - CONDE_OF_CONDUCT.md - CONTRIBUTING.md diff --git a/e2e/README.md b/e2e/README.md new file mode 100644 index 0000000..3f615da --- /dev/null +++ b/e2e/README.md @@ -0,0 +1,155 @@ +# Playwright end-to-end tests + +This folder contains automated browser tests for the Canada.ca Search UI. + +## Recommended file structure + +Keep test files organized by user workflow or page type. + +Suggested starting point: + +```text +e2e/ + README.md + search.spec.js + query-suggestions.spec.js + advanced-search.spec.js + contextual-search.spec.js + templates.spec.js + analytics.spec.js +``` + +If repeated setup becomes noisy, add small helper files under `e2e/support/`. Good helper candidates: + +- `goToTestPage(page, 'qs-en.html')`; +- `searchInput(page)`; +- `submitSearch(page)`; +- mock of Coveo requests/responses (if specific results are needed) + +Start simple and add as needed, when it removes meaningful repetition. + +## Writing tests + +Add `.spec.js` files to this directory. Playwright picks them up automatically. + +```js +// @ts-check +const { test, expect } = require('@playwright/test'); + +test('shows the search form', async ({ page }) => { + await page.goto('/tests/qs-en.html'); + + await expect(page.getByLabel('Search Government of Canada websites')).toBeVisible(); + await expect(page.getByRole('button', { name: 'Search' })).toBeVisible(); +}); +``` + +Prefer: + +- `getByRole`, `getByLabel`, `getByText`, and `getByPlaceholder`; +- web-first assertions such as `await expect(locator).toBeVisible()`; +- one user behaviour per test; +- test names that describe the expected behaviour; +- small setup repeated in each test when it makes the test clearer; +- `test.beforeEach` to reset the page state between tests. + +Avoid: + +- brittle CSS selectors when an accessible locator is available; +- testing internal functions from `src/connector.js`; +- use `page.waitForResponse` to wait for network requests to complete before performing tests. i.e., + - `await page.waitForResponse(res => res.url().includes('/querySuggest'), { timeout: 5000 }).catch(() => null);` +- for other fixed sleeps such as `waitForTimeout`; +- tests that depend on another test running first; +- broad tests that cover many behaviours at once; + +## Getting going + +### Install dependencies: + +```bash +npm install +npx playwright install chromium +``` + +### Start environment + +The README at the repo root explains how to start the Docker-based local environment, using a valid search token. + +The Playwright config expects: + +```text +http://localhost:4000 +``` + +## Running tests + +Most tests can be run via `npm`: + +Run all tests, silently: + +```bash +npm test +``` + +Run the interactive Playwright UI: + +```bash +npm run test:ui +``` + +Open the last HTML report: + +```bash +npm run test:report +``` + +Run one file: + +```bash +npx playwright test e2e/search.spec.js +``` + +Run one test by title: + +```bash +npx playwright test -g "renders the search form" +``` + +## Configuration + +The Playwright config lives at `playwright.config.js`. + +Current defaults: + +- tests are read from `e2e/` +- the base URL is `http://localhost:4000` +- tests are run in Chromium/Playwright UI +- generated artifacts such as `playwright-report/` have been excluded from version control and the Jekyll build process + +Optional configuration improvements: + +- add Firefox and WebKit projects once the Chromium suite is stable; + +## Debugging test failures + +Use the Playwright UI while writing, debugging, or to review actual browser results: + +```bash +npm run test:ui +``` + +Use trace mode when a failure needs a step-by-step replay: + +```bash +npx playwright test --trace on +npm run test:report +``` + +The trace viewer is useful for failures because it shows the DOM, console, network requests, actions, and assertions around the failure. + +## References + +- [Playwright best practices](https://playwright.dev/docs/best-practices) +- [Playwright configuration](https://playwright.dev/docs/test-configuration) +- [Playwright continuous integration](https://playwright.dev/docs/ci) diff --git a/e2e/qs-en.spec.js b/e2e/qs-en.spec.js new file mode 100644 index 0000000..2538448 --- /dev/null +++ b/e2e/qs-en.spec.js @@ -0,0 +1,111 @@ +import { test, expect } from '@playwright/test'; + +test.describe('QS EN page', () => { + test.beforeEach(async ({ page }) => { + // Mask the automation flag that Playwright sets — Coveo detects it and skips initialization. + await page.addInitScript(() => { + Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); + }); + + await page.goto('http://localhost:4000/tests/srb-en.html'); + // await page.goto('http://localhost:4000/tests/qs-en.html'); + }); + + test('query suggestion UI is initialized', async ({ page }) => { + await page.goto('http://localhost:4000/tests/srb-en.html'); + + const searchBox = page.locator('#sch-inp-ac'); + await expect(searchBox).toHaveAttribute('type', 'text'); + await expect(searchBox).toHaveAttribute('role', 'combobox'); + await expect(searchBox).toHaveAttribute('aria-expanded', 'false'); + await expect(searchBox).toHaveAttribute('aria-autocomplete', 'list'); + await expect(searchBox).toHaveAttribute('aria-controls', 'suggestions'); + + const suggestionsList = page.locator('form[role="search"] ul#suggestions'); + await expect(suggestionsList).toHaveAttribute('role', 'listbox'); + await expect(suggestionsList).toHaveClass(/query-suggestions/); + await expect(suggestionsList).toHaveAttribute('aria-describedby', 'sr-qs-hint'); + + const hint = page.locator('form[role="search"] p#sr-qs-hint'); + await expect(hint).toHaveClass(/hidden/); + }); + + test('query suggestions appear and update while typing, then disappear when input is too short', async ({ page }) => { + const searchBox = page.locator('#sch-inp-ac'); + const suggestionsList = page.locator('#suggestions'); + const suggestionItems = suggestionsList.locator('li.suggestion-item'); + + await searchBox.focus(); + + // Type "canada" one character at a time, asserting suggestions only appear at 3+ characters. + for (const [i, char] of [...'canada'].entries()) { + // Wait for the suggestions API response before asserting UI state. + const responsePromise = page.waitForResponse(res => res.url().includes('/querySuggest'), { timeout: 5000 }).catch(() => null); + await page.keyboard.type(char); + await responsePromise; + const typedSoFar = 'canada'.slice(0, i + 1); + + if (typedSoFar.length < 3) { + // Fewer than 3 characters — suggestions should not be shown. + await expect(searchBox).toHaveAttribute('aria-expanded', 'false'); + await expect(suggestionsList).toHaveAttribute('hidden'); + + } else { + // 3 or more characters — wait for suggestions to load and verify count. + await expect(searchBox).toHaveAttribute('aria-expanded', 'true'); + await expect(suggestionsList).not.toHaveAttribute('hidden'); + await expect(suggestionItems.first()).toBeVisible(); + const count = await suggestionItems.count(); + expect(count, `expected 1–10 suggestions for "${typedSoFar}"`).toBeGreaterThanOrEqual(1); + expect(count, `expected 1–10 suggestions for "${typedSoFar}"`).toBeLessThanOrEqual(10); + } + } + + // Backspace one character at a time. Suggestions should stay visible until input drops below 3 characters. + for (let remaining = 'canada'.length - 1; remaining >= 0; remaining--) { + const responsePromise = page.waitForResponse(res => res.url().includes('/querySuggest'), { timeout: 5000 }).catch(() => null); + await page.keyboard.press('Backspace'); + await responsePromise; + + if (remaining >= 3) { + await expect(searchBox).toHaveAttribute('aria-expanded', 'true'); + await expect(suggestionsList).not.toHaveAttribute('hidden'); + await expect(suggestionItems.first()).toBeVisible(); + } else { + // Input is now 0–2 characters — suggestions should be hidden. + await expect(searchBox).toHaveAttribute('aria-expanded', 'false'); + await expect(suggestionsList).toHaveAttribute('hidden'); + } + } + }); + + test('clicking a query suggestion submits a search for that suggestion', async ({ page }) => { + const searchBox = page.locator('#sch-inp-ac'); + const suggestionsList = page.locator('#suggestions'); + const suggestionItems = suggestionsList.locator('li.suggestion-item'); + + await searchBox.focus(); + + // Wait for suggestions to load before clicking. + const responsePromise = page.waitForResponse(res => res.url().includes('/querySuggest'), { timeout: 5000 }); + await page.keyboard.type('canada'); + await responsePromise; + + await expect(suggestionItems.first()).toBeVisible(); + const secondSuggestion = suggestionItems.nth(1); + const suggestionText = await secondSuggestion.innerText(); + await secondSuggestion.click(); + + // The suggestions box should close after clicking. + await expect(suggestionsList).toHaveAttribute('hidden'); + await expect(searchBox).toHaveAttribute('aria-expanded', 'false'); + + // The search field should show the clicked suggestion's text. + await expect(searchBox).toHaveValue(suggestionText); + + // Results should be returned for the selected suggestion. + const summary = page.locator('#wb-land h2'); + await expect(summary).toBeVisible(); + await expect(summary).toContainText(suggestionText); + }); +}); diff --git a/e2e/srb-en.spec.js b/e2e/srb-en.spec.js new file mode 100644 index 0000000..c2ef70b --- /dev/null +++ b/e2e/srb-en.spec.js @@ -0,0 +1,76 @@ +import { test, expect } from '@playwright/test'; + +test.describe('SRB EN page', () => { + test.beforeEach(async ({ page }) => { + // Mask the automation flag that Playwright sets — Coveo detects it and skips initialization. + await page.addInitScript(() => { + Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); + }); + + await page.goto('http://localhost:4000/tests/srb-en.html'); + }); + + test('search box and config are present', async ({ page }) => { + await expect(page.locator('#sch-inp-ac')).toBeVisible(); + + // connector.js reads the data-gc-search attribute to configure the Coveo search engine. + const configEl = page.locator('[data-gc-search]'); + await expect(configEl).toBeAttached(); + const attrValue = await configEl.getAttribute('data-gc-search'); + expect(attrValue).toBeTruthy(); + }); + + test('search library initializes successfully', async ({ page, context }) => { + // A query in the URL hash is required to trigger Coveo's first API call, + // which is what sets the tracking cookie and localStorage item. + await page.goto('http://localhost:4000/tests/srb-en.html#q=canada'); + + await page.waitForFunction( + () => document.cookie.includes('coveo_visitorId') || window.__coveoInitialized, + { timeout: 5000 } + ).catch(() => {}); + + // Fetch cookies via the browser context rather than JS so HttpOnly cookies are included. + const cookies = await context.cookies('http://localhost:4000'); + const visitorCookie = cookies.find(c => c.name === 'coveo_visitorId'); + expect(visitorCookie, 'coveo_visitorId cookie should exist').toBeTruthy(); + + await page.waitForFunction(() => localStorage.getItem('visitorId') !== null, { timeout: 5000 }); + const visitorId = await page.evaluate(() => localStorage.getItem('visitorId')); + expect(visitorId, 'visitorId localStorage item should exist').toBeTruthy(); + }); + + test('basic keyword search via keyboard submit', async ({ page }) => { + await page.locator('#sch-inp-ac').focus(); + await page.keyboard.type('Canada'); + await page.keyboard.press('Enter'); + + const summary = page.locator('#wb-land h2'); + await expect(summary).toBeFocused(); + await expect(summary).toBeVisible(); + await expect(summary).toContainText('Canada'); + + // After keyboard interaction, the browser shows a visible focus ring (:focus-visible is true). + const hasFocusRing = await summary.evaluate(el => el.matches(':focus-visible')); + expect(hasFocusRing, 'focus ring should be visible after keyboard submit').toBe(true); + + await expect(page.locator('#sch-inp-ac')).toHaveValue('Canada'); + }); + + test('basic keyword search via mouse submit', async ({ page }) => { + await page.locator('#sch-inp-ac').click(); + await page.keyboard.type('Canada'); + await page.locator('form[role="search"] button[type="submit"]').click(); + + const summary = page.locator('#wb-land h2'); + await expect(summary).toBeFocused(); + await expect(summary).toBeVisible(); + await expect(summary).toContainText('Canada'); + + // After mouse interaction, the browser suppresses the focus ring (:focus-visible is false). + const hasFocusRing = await summary.evaluate(el => el.matches(':focus-visible')); + expect(hasFocusRing, 'focus ring should not be visible after mouse submit').toBe(false); + + await expect(page.locator('#sch-inp-ac')).toHaveValue('Canada'); + }); +}); diff --git a/package-lock.json b/package-lock.json index 02b2899..51fafc2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "(MIT AND Apache-2.0)", "devDependencies": { "@lodder/grunt-postcss": "^3.0.1", + "@playwright/test": "^1.60.0", "grunt": "^1.6.1", "grunt-banner": "^0.6.0", "grunt-contrib-clean": "^2.0.1", @@ -1541,6 +1542,22 @@ "node": ">= 8" } }, + "node_modules/@playwright/test": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz", + "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.60.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", @@ -2737,6 +2754,21 @@ "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -4326,6 +4358,38 @@ "node": ">=6" } }, + "node_modules/playwright": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", + "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.60.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", + "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/postcss": { "version": "8.5.8", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", diff --git a/package.json b/package.json index 7c3649d..4fff163 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,14 @@ "author": "ServiceCanada", "license": "(MIT AND Apache-2.0)", "homepage": "https://servicecanada.github.io/search-ui/", + "scripts": { + "test": "playwright test", + "test:ui": "playwright test --ui", + "test:report": "playwright show-report" + }, "devDependencies": { + "@lodder/grunt-postcss": "^3.0.1", + "@playwright/test": "^1.60.0", "grunt": "^1.6.1", "grunt-banner": "^0.6.0", "grunt-contrib-clean": "^2.0.1", @@ -26,7 +33,6 @@ "grunt-eslint": "^24.3.0", "grunt-htmllint": "^0.3.0", "postcss": "^8.5.8", - "postcss-preset-env": "^11.2.0", - "@lodder/grunt-postcss": "^3.0.1" + "postcss-preset-env": "^11.2.0" } } diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 0000000..4bc6f21 --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,27 @@ +// @ts-check +const { defineConfig, devices } = require('@playwright/test'); + +module.exports = defineConfig({ + testDir: './e2e', + fullyParallel: true, + retries: process.env.CI ? 2 : 0, + reporter: 'html', + use: { + baseURL: 'http://localhost:4000', + trace: 'on-first-retry', + }, + projects: [ + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + launchOptions: { + args: [ + '--disable-features=ImprovedCookieControls,ImprovedCookieControlsForThirdPartyCookieBlocking,SameSiteByDefaultCookies,CookiesWithoutSameSiteMustBeSecure,CookiesWithoutSameSiteMustBeSecure,SameSiteByDefaultCookies', + '--disable-blink-features=AutomationControlled', + ], + }, + }, + }, + ], +}); From 2b51ff4a175498dc7db6d4b169e0fa1528647055 Mon Sep 17 00:00:00 2001 From: Cody Foss Date: Fri, 26 Jun 2026 08:41:14 -0600 Subject: [PATCH 2/3] Result mock and result template tests --- e2e/fixtures/result-template-results.json | 1140 +++++++++++++++++++++ e2e/result-templates.spec.js | 114 +++ e2e/srb-en.spec.js | 38 + 3 files changed, 1292 insertions(+) create mode 100644 e2e/fixtures/result-template-results.json create mode 100644 e2e/result-templates.spec.js diff --git a/e2e/fixtures/result-template-results.json b/e2e/fixtures/result-template-results.json new file mode 100644 index 0000000..42e4c41 --- /dev/null +++ b/e2e/fixtures/result-template-results.json @@ -0,0 +1,1140 @@ +{ + "advancedExpression": null, + "apiVersion": 2, + "basicExpression": "benefits", + "categoryFacets": [], + "constantExpression": "@declared_language==(eng,en,en-CA) OR (NOT @declared_language @language=english)", + "disjunctionExpression": "@permanentid=8474a65cdb75baf0af880228aaae5e8a374fff804e0d571fc41dce1734bb OR @permanentid=e0002bdd6d3c6f7ca8d2ecac1f81d3c3944b01cb0ca32e73838659ec443a OR @permanentid=ddd67756dd4fe0de6cf866d8fab51fa01909840c9b39a9ef76955d5bdc94 OR @permanentid=a79ff2303b93e98d68ed051a1e90c03332f7b962d15f2ac4c1d47ef13fbc", + "duration": 100, + "extendedResults": {}, + "facets": [], + "groupByResults": [], + "index": "employmentandsocialdevelopmentcanadanonproduction14o5d9wry-9di7prgj-Indexer-2-q4pnjkhqqifygbugofmiod2b5a", + "indexDuration": 51, + "indexRegion": "ca-central-1", + "indexToken": "ZW1wbG95bWVudGFuZHNvY2lhbGRldmVsb3BtZW50Y2FuYWRhbm9ucHJvZHVjdGlvbjE0bzVkOXdyeS05ZGk3cHJnai1JbmRleGVyLTItcTRwbmpraHFxaWZ5Z2J1Z29mbWlvZDJiNWE=", + "largeExpression": null, + "logicalIndex": "default", + "mandatoryExpression": null, + "phrasesToHighlight": {}, + "pipeline": "Canada public websites - Generic", + "queryCorrections": [], + "questionAnswer": { + "answerFound": false, + "answerSnippet": "", + "documentId": { + "contentIdKey": "", + "contentIdValue": "" + }, + "question": "", + "relatedQuestions": [], + "score": 0 + }, + "rankingExpressions": [ + { + "applyToEveryResult": true, + "expression": "@generator==gcnews ((@declared_type=\"media advisories\" @date Benefits", + "hostname": "canada.ca", + "language": [ + "English" + ], + "permanentid": "05e65251c3fa3635a1f0d778dd52a84d16f13cdf7cbea1d5283ffdcecffd", + "source": "priority_canada_ca_sitemap", + "sourcetype": "Sitemap", + "sysauthor": [ + "Employment and Social Development Canada" + ], + "syscollection": "default", + "sysdate": 1780617600000, + "syslanguage": [ + "English" + ], + "syssource": "priority_canada_ca_sitemap", + "syssourcetype": "Sitemap", + "sysurihash": "XKMFxwkOcw3dChmU", + "urihash": "XKMFxwkOcw3dChmU" + }, + "score": 7462, + "summary": null, + "summaryHighlights": [], + "title": "Disability benefits", + "titleHighlights": [], + "totalNumberOfChildResults": 0, + "uniqueId": "42.2001$https://www.canada.ca/en/services/benefits/disability.html", + "uri": "https://www.canada.ca/en/services/benefits/disability.html" + }, + { + "ClickUri": "https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html", + "Excerpt": "Canada Disability Benefit Important: Filing your tax return is required ... The Canada Disability Benefit provides direct financial support to people with disabilities who are between 18 and 64 years ... Related links Disability Tax Credit Benefits for people with disabilities Organizations providing disability benefits navigation services", + "FirstSentences": null, + "PrintableUri": "https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html", + "Title": "Canada Disability Benefit", + "UniqueId": "42.2001$https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html", + "Uri": "https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html", + "absentTerms": [], + "childResults": [], + "clickUri": "https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html", + "excerpt": "Canada Disability Benefit Important: Filing your tax return is required ... The Canada Disability Benefit provides direct financial support to people with disabilities who are between 18 and 64 years ... Related links Disability Tax Credit Benefits for people with disabilities Organizations providing disability benefits navigation services", + "excerptHighlights": [], + "firstSentences": null, + "firstSentencesHighlights": [], + "flags": "HasHtmlVersion;HasAllMetaDataStream", + "hasHtmlVersion": true, + "hasMobileHtmlVersion": false, + "isRecommendation": false, + "isTopResult": false, + "isUserActionView": false, + "parentResult": null, + "percentScore": 92.63505, + "primaryid": "IVQVSWODWA3VGS22JNGGRQ5RGNRGELRSGAYDCLTEMVTGC5LMOQ", + "printableUri": "https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html", + "printableUriHighlights": [ + { + "length": 84, + "offset": 0 + } + ], + "rankingInfo": null, + "rating": 0, + "raw": { + "author": [ + "Service Canada" + ], + "collection": "default", + "date": 1781827200000, + "description": "The Canada Disability Benefit is a monthly payment for working-age persons with disabilities who have low income", + "disp_declared_type": "service initiation", + "displaynavlabel": "www.canada.ca > Benefits > Disability benefits", + "hostname": "canada.ca", + "language": [ + "English" + ], + "permanentid": "9e54a36d38ac8cf2e6fdf9a525ce9a3ee27e1cdf385bc65b0bbb73d31863", + "source": "priority_canada_ca_sitemap", + "sourcetype": "Sitemap", + "sysauthor": [ + "Service Canada" + ], + "syscollection": "default", + "sysdate": 1781827200000, + "syslanguage": [ + "English" + ], + "syssource": "priority_canada_ca_sitemap", + "syssourcetype": "Sitemap", + "sysurihash": "EaYYð7SKZKLhñ3bb", + "urihash": "EaYYð7SKZKLhñ3bb" + }, + "score": 7488, + "summary": null, + "summaryHighlights": [], + "title": "Canada Disability Benefit", + "titleHighlights": [], + "totalNumberOfChildResults": 0, + "uniqueId": "42.2001$https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html", + "uri": "https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html" + }, + { + "ClickUri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "Excerpt": "Death benefit Death benefit The Canada Pension Plan (CPP) death benefit is a one-time payment, payable to the estate or other eligible individuals, on behalf of a deceased CPP contributor. ... complete the online CPP Death Benefit form ... the individual who receives it, refer to Death benefits - Prepare tax returns for someone who died.", + "FirstSentences": null, + "PrintableUri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "Title": "Death Benefit", + "UniqueId": "42.2001$https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "Uri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "absentTerms": [], + "childResults": [], + "clickUri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "excerpt": "Death benefit Death benefit The Canada Pension Plan (CPP) death benefit is a one-time payment, payable to the estate or other eligible individuals, on behalf of a deceased CPP contributor. ... complete the online CPP Death Benefit form ... the individual who receives it, refer to Death benefits - Prepare tax returns for someone who died.", + "excerptHighlights": [], + "firstSentences": null, + "firstSentencesHighlights": [], + "flags": "HasHtmlVersion;HasAllMetaDataStream", + "hasHtmlVersion": true, + "hasMobileHtmlVersion": false, + "isRecommendation": false, + "isTopResult": false, + "isUserActionView": false, + "parentResult": null, + "percentScore": 91.56495, + "primaryid": "JU3VS2RXLBQWQWBWO44G4NLTPAXDEMBQGEXGIZLGMF2WY5A", + "printableUri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "printableUriHighlights": [ + { + "length": 84, + "offset": 0 + } + ], + "rankingInfo": "Document weights:\nTitle: 184; Quality: 0; Date: 430; Adjacency: 1214; Source: 0; Custom: 0; QRE: 3000; Ranking functions: 0; \nQRE:\nExpression: \"@uri=veterans.gc.ca @uri=(remembrance/memorials/books/page,remembrance/memorials/canadian-virtual-war-memorial/detail)\" Score: 0\nExpression: \"@title=(\"Error 500\",\"Error 404\",archive,archivé,archivée)\" Score: 0\nExpression: \"@uri=canada.ca/en/news/archive/ OR @uri=canada.ca/fr/nouvelles/archive/ OR (@generator==gcnews ((@declared_type=\"news releases\" @date Canada Pension Plan retirement pension", + "hostname": "canada.ca", + "language": [ + "English" + ], + "permanentid": "846f42a8438a599f972379543a1b899d42ce71d8dc8ddeac5e3e21ac1350", + "source": "priority_canada_ca_sitemap", + "sourcetype": "Sitemap", + "sysauthor": [ + "Employment and Social Development Canada" + ], + "syscollection": "default", + "sysdate": 1779667200000, + "syslanguage": [ + "English" + ], + "syssource": "priority_canada_ca_sitemap", + "syssourcetype": "Sitemap", + "sysurihash": "M7Yj7XahX6w8n5sx", + "urihash": "M7Yj7XahX6w8n5sx" + }, + "score": 7316, + "summary": null, + "summaryHighlights": [], + "title": "Death Benefit", + "titleHighlights": [], + "totalNumberOfChildResults": 0, + "uniqueId": "42.2001$https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "uri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html" + }, + { + "ClickUri": "https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html", + "Excerpt": "Canada Disability Benefit Important: Filing your tax return is required ... The Canada Disability Benefit provides direct financial support to people with ... Disability Tax Credit Benefits for people with disabilities Organizations providing disability benefits navigation services ... About the Canada Disability Benefit program", + "FirstSentences": null, + "PrintableUri": "https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html", + "Title": "Canada Disability Benefit", + "UniqueId": "42.2001$https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html", + "Uri": "https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html", + "absentTerms": [], + "childResults": [], + "clickUri": "https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html", + "excerpt": "Canada Disability Benefit Important: Filing your tax return is required ... The Canada Disability Benefit provides direct financial support to people with ... Disability Tax Credit Benefits for people with disabilities Organizations providing disability benefits navigation services ... About the Canada Disability Benefit program", + "excerptHighlights": [ + { + "length": 7, + "offset": 18 + }, + { + "length": 7, + "offset": 315 + }, + { + "length": 7, + "offset": 98 + }, + { + "length": 8, + "offset": 181 + }, + { + "length": 8, + "offset": 254 + } + ], + "firstSentences": null, + "firstSentencesHighlights": [], + "flags": "HasHtmlVersion;HasAllMetaDataStream", + "hasHtmlVersion": true, + "hasMobileHtmlVersion": false, + "isRecommendation": false, + "isTopResult": false, + "isUserActionView": false, + "parentResult": null, + "percentScore": 99.31753, + "primaryid": "IVQVSWODWA3VGS22JNGGRQ5RGNRGELRSGAYDCLTEMVTGC5LMOQ", + "printableUri": "https://www.canada.ca/en/services/benefits/disability/canada-disability-benefit.html", + "printableUriHighlights": [ + { + "length": 7, + "offset": 72 + }, + { + "length": 8, + "offset": 34 + } + ], + "rankingInfo": "Document weights:\nTitle: 646; Quality: 0; Date: 614; Adjacency: 0; Source: 0; Custom: 0; QRE: 3000; Ranking functions: 0; \nQRE:\nExpression: \"@uri=veterans.gc.ca @uri=(remembrance/memorials/books/page,remembrance/memorials/canadian-virtual-war-memorial/detail)\" Score: 0\nExpression: \"@title=(\"Error 500\",\"Error 404\",archive,archivé,archivée)\" Score: 0\nExpression: \"@uri=canada.ca/en/news/archive/ OR @uri=canada.ca/fr/nouvelles/archive/ OR (@generator==gcnews ((@declared_type=\"news releases\" @date Benefits", + "hostname": "canada.ca", + "language": [ + "English" + ], + "permanentid": "43f4b25cb874cf7fb3f534fde77f94813f31953ee2fc3afaa79798df289d", + "source": "priority_canada_ca_sitemap", + "sourcetype": "Sitemap", + "sysauthor": [ + "Employment and Social Development Canada" + ], + "syscollection": "default", + "sysdate": 1780444800000, + "syslanguage": [ + "English" + ], + "syssource": "priority_canada_ca_sitemap", + "syssourcetype": "Sitemap", + "sysurihash": "m8ðkEaJñxNsVBZkd", + "urihash": "m8ðkEaJñxNsVBZkd" + }, + "score": 7809, + "summary": null, + "summaryHighlights": [], + "title": "Employment Insurance benefits", + "titleHighlights": [ + { + "length": 8, + "offset": 21 + } + ], + "totalNumberOfChildResults": 0, + "uniqueId": "42.2001$https://www.canada.ca/en/services/benefits/ei.html", + "uri": "https://www.canada.ca/en/services/benefits/ei.html" + }, + { + "ClickUri": "https://www.canada.ca/en/services/benefits/ei/ei-critically-ill-children/apply.html", + "Excerpt": "The EI program offers 3 types of caregiving benefits: Types of caregiving benefits Benefit name Maximum weeks payable Family caregiver benefit for children up to 35 weeks Family caregiver benefit for adults up to 15 weeks Compassionate care benefits up to 26 weeks Family caregiver benefits for children If you're away from work to ...", + "FirstSentences": null, + "PrintableUri": "https://www.canada.ca/en/services/benefits/ei/ei-critically-ill-children/apply.html", + "Title": "EI caregiving benefits", + "UniqueId": "42.2001$https://www.canada.ca/en/services/benefits/ei/ei-critically-ill-children/apply.html", + "Uri": "https://www.canada.ca/en/services/benefits/ei/ei-critically-ill-children/apply.html", + "absentTerms": [], + "childResults": [], + "clickUri": "https://www.canada.ca/en/services/benefits/ei/ei-critically-ill-children/apply.html", + "excerpt": "The EI program offers 3 types of caregiving benefits: Types of caregiving benefits Benefit name Maximum weeks payable Family caregiver benefit for children up to 35 weeks Family caregiver benefit for adults up to 15 weeks Compassionate care benefits up to 26 weeks Family caregiver benefits for children If you're away from work to ...", + "excerptHighlights": [ + { + "length": 7, + "offset": 135 + }, + { + "length": 7, + "offset": 188 + }, + { + "length": 7, + "offset": 83 + }, + { + "length": 8, + "offset": 241 + }, + { + "length": 8, + "offset": 282 + }, + { + "length": 8, + "offset": 44 + }, + { + "length": 8, + "offset": 74 + } + ], + "firstSentences": null, + "firstSentencesHighlights": [], + "flags": "HasHtmlVersion;HasAllMetaDataStream", + "hasHtmlVersion": true, + "hasMobileHtmlVersion": false, + "isRecommendation": false, + "isTopResult": false, + "isUserActionView": false, + "parentResult": null, + "percentScore": 98.337906, + "primaryid": "INMVUMCPIUZHQYSZNRYFIM2POMXDEMBQGEXGIZLGMF2WY5A", + "printableUri": "https://www.canada.ca/en/services/benefits/ei/ei-critically-ill-children/apply.html", + "printableUriHighlights": [ + { + "length": 8, + "offset": 34 + } + ], + "rankingInfo": "Document weights:\nTitle: 646; Quality: 0; Date: 462; Adjacency: 0; Source: 0; Custom: 0; QRE: 3000; Ranking functions: 0; \nQRE:\nExpression: \"@uri=veterans.gc.ca @uri=(remembrance/memorials/books/page,remembrance/memorials/canadian-virtual-war-memorial/detail)\" Score: 0\nExpression: \"@title=(\"Error 500\",\"Error 404\",archive,archivé,archivée)\" Score: 0\nExpression: \"@uri=canada.ca/en/news/archive/ OR @uri=canada.ca/fr/nouvelles/archive/ OR (@generator==gcnews ((@declared_type=\"news releases\" @date Employment Insurance benefits", + "hostname": "canada.ca", + "language": [ + "English" + ], + "permanentid": "e82e275da90ac399c8d4d0bd228d760f147623a9985035de34fb0650806e", + "source": "priority_canada_ca_sitemap", + "sourcetype": "Sitemap", + "sysauthor": [ + "Employment and Social Development Canada" + ], + "syscollection": "default", + "sysdate": 1780358400000, + "syslanguage": [ + "English" + ], + "syssource": "priority_canada_ca_sitemap", + "syssourcetype": "Sitemap", + "sysurihash": "CYZ0OE2xbYlpT3Os", + "urihash": "CYZ0OE2xbYlpT3Os" + }, + "score": 7891, + "summary": null, + "summaryHighlights": [], + "title": "EI caregiving benefits", + "titleHighlights": [ + { + "length": 8, + "offset": 14 + } + ], + "totalNumberOfChildResults": 0, + "uniqueId": "42.2001$https://www.canada.ca/en/services/benefits/ei/ei-critically-ill-children/apply.html", + "uri": "https://www.canada.ca/en/services/benefits/ei/ei-critically-ill-children/apply.html" + }, + { + "ClickUri": "https://www.canada.ca/en/services/benefits/ei/ei-fishing.html", + "Excerpt": "EI fishing benefits - Overview What these benefits offer Employment Insurance (EI) provides fishing benefits to qualifying, self-employed ... Unlike regular EI benefits, eligibility for EI fishing benefits is based on earnings, not insurable hours of ... may be eligible to receive regular fishing benefits as well as sickness, maternity, ...", + "FirstSentences": null, + "PrintableUri": "https://www.canada.ca/en/services/benefits/ei/ei-fishing.html", + "Title": "EI Fishing benefits - Overview", + "UniqueId": "42.2001$https://www.canada.ca/en/services/benefits/ei/ei-fishing.html", + "Uri": "https://www.canada.ca/en/services/benefits/ei/ei-fishing.html", + "absentTerms": [], + "childResults": [], + "clickUri": "https://www.canada.ca/en/services/benefits/ei/ei-fishing.html", + "excerpt": "EI fishing benefits - Overview What these benefits offer Employment Insurance (EI) provides fishing benefits to qualifying, self-employed ... Unlike regular EI benefits, eligibility for EI fishing benefits is based on earnings, not insurable hours of ... may be eligible to receive regular fishing benefits as well as sickness, maternity, ...", + "excerptHighlights": [ + { + "length": 8, + "offset": 100 + }, + { + "length": 8, + "offset": 11 + }, + { + "length": 8, + "offset": 160 + }, + { + "length": 8, + "offset": 197 + }, + { + "length": 8, + "offset": 298 + }, + { + "length": 8, + "offset": 42 + } + ], + "firstSentences": null, + "firstSentencesHighlights": [], + "flags": "HasHtmlVersion;HasAllMetaDataStream", + "hasHtmlVersion": true, + "hasMobileHtmlVersion": false, + "isRecommendation": false, + "isTopResult": false, + "isUserActionView": false, + "parentResult": null, + "percentScore": 97.8131, + "primaryid": "N5HUW4CGJFHVAQJROFXXQVDWJIXDEMBQGEXGIZLGMF2WY5A", + "printableUri": "https://www.canada.ca/en/services/benefits/ei/ei-fishing.html", + "printableUriHighlights": [ + { + "length": 8, + "offset": 34 + } + ], + "rankingInfo": "Document weights:\nTitle: 560; Quality: 0; Date: 462; Adjacency: 0; Source: 0; Custom: 0; QRE: 3000; Ranking functions: 0; \nQRE:\nExpression: \"@uri=veterans.gc.ca @uri=(remembrance/memorials/books/page,remembrance/memorials/canadian-virtual-war-memorial/detail)\" Score: 0\nExpression: \"@title=(\"Error 500\",\"Error 404\",archive,archivé,archivée)\" Score: 0\nExpression: \"@uri=canada.ca/en/news/archive/ OR @uri=canada.ca/fr/nouvelles/archive/ OR (@generator==gcnews ((@declared_type=\"news releases\" @date Employment Insurance benefits", + "hostname": "canada.ca", + "language": [ + "English" + ], + "permanentid": "0bdcf82331c5e443075d8d587061a2717b0372cb209ae41e450f3b38ec08", + "source": "priority_canada_ca_sitemap", + "sourcetype": "Sitemap", + "sysauthor": [ + "Employment and Social Development Canada" + ], + "syscollection": "default", + "sysdate": 1780358400000, + "syslanguage": [ + "English" + ], + "syssource": "priority_canada_ca_sitemap", + "syssourcetype": "Sitemap", + "sysurihash": "oOKpFIOPA1qoxTvJ", + "urihash": "oOKpFIOPA1qoxTvJ" + }, + "score": 7807, + "summary": null, + "summaryHighlights": [], + "title": "EI Fishing benefits - Overview", + "titleHighlights": [ + { + "length": 8, + "offset": 11 + } + ], + "totalNumberOfChildResults": 0, + "uniqueId": "42.2001$https://www.canada.ca/en/services/benefits/ei/ei-fishing.html", + "uri": "https://www.canada.ca/en/services/benefits/ei/ei-fishing.html" + }, + { + "ClickUri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "Excerpt": "Death benefit Death benefit The Canada Pension Plan (CPP) death benefit is a one-time payment, payable to the ... have never received a disability benefit, post-retirement disability benefit or retirement pension under the CPP or Quebec Pension Plan ( ... Survivor’s pension Benefits for children under 25 Step 2 How much could you receive", + "FirstSentences": null, + "PrintableUri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "Title": "Death Benefit", + "UniqueId": "42.2001$https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "Uri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "absentTerms": [], + "childResults": [], + "clickUri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "excerpt": "Death benefit Death benefit The Canada Pension Plan (CPP) death benefit is a one-time payment, payable to the ... have never received a disability benefit, post-retirement disability benefit or retirement pension under the CPP or Quebec Pension Plan ( ... Survivor’s pension Benefits for children under 25 Step 2 How much could you receive", + "excerptHighlights": [ + { + "length": 7, + "offset": 147 + }, + { + "length": 7, + "offset": 183 + }, + { + "length": 7, + "offset": 20 + }, + { + "length": 7, + "offset": 64 + }, + { + "length": 7, + "offset": 6 + }, + { + "length": 8, + "offset": 275 + } + ], + "firstSentences": null, + "firstSentencesHighlights": [], + "flags": "HasHtmlVersion;HasAllMetaDataStream", + "hasHtmlVersion": true, + "hasMobileHtmlVersion": false, + "isRecommendation": false, + "isTopResult": false, + "isUserActionView": false, + "parentResult": null, + "percentScore": 99.00857, + "primaryid": "JU3VS2RXLBQWQWBWO44G4NLTPAXDEMBQGEXGIZLGMF2WY5A", + "printableUri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "printableUriHighlights": [ + { + "length": 7, + "offset": 72 + }, + { + "length": 8, + "offset": 34 + } + ], + "rankingInfo": "Document weights:\nTitle: 791; Quality: 0; Date: 430; Adjacency: 0; Source: 0; Custom: 0; QRE: 3000; Ranking functions: 0; \nQRE:\nExpression: \"@uri=veterans.gc.ca @uri=(remembrance/memorials/books/page,remembrance/memorials/canadian-virtual-war-memorial/detail)\" Score: 0\nExpression: \"@title=(\"Error 500\",\"Error 404\",archive,archivé,archivée)\" Score: 0\nExpression: \"@uri=canada.ca/en/news/archive/ OR @uri=canada.ca/fr/nouvelles/archive/ OR (@generator==gcnews ((@declared_type=\"news releases\" @date Canada Pension Plan retirement pension", + "hostname": "canada.ca", + "language": [ + "English" + ], + "permanentid": "846f42a8438a599f972379543a1b899d42ce71d8dc8ddeac5e3e21ac1350", + "source": "priority_canada_ca_sitemap", + "sourcetype": "Sitemap", + "sysauthor": [ + "Employment and Social Development Canada" + ], + "syscollection": "default", + "sysdate": 1779667200000, + "syslanguage": [ + "English" + ], + "syssource": "priority_canada_ca_sitemap", + "syssourcetype": "Sitemap", + "sysurihash": "M7Yj7XahX6w8n5sx", + "urihash": "M7Yj7XahX6w8n5sx" + }, + "score": 7999, + "summary": null, + "summaryHighlights": [], + "title": "Death Benefit", + "titleHighlights": [ + { + "length": 7, + "offset": 6 + } + ], + "totalNumberOfChildResults": 0, + "uniqueId": "42.2001$https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html", + "uri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/cpp-death-benefit.html" + }, + { + "ClickUri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/receive-benefits.html", + "Excerpt": "Receive your benefits On this page ... To cancel your benefit, contact Service Canada. ... Death benefit: A one-time payment on behalf of the deceased contributor ... CPP children's benefit: A monthly benefit for a dependent child of a deceased CPP ... general questions about CPP retirement pension benefits or specific questions about your ...", + "FirstSentences": null, + "PrintableUri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/receive-benefits.html", + "Title": "Receive your benefits", + "UniqueId": "42.2001$https://www.canada.ca/en/services/benefits/publicpensions/cpp/receive-benefits.html", + "Uri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/receive-benefits.html", + "absentTerms": [], + "childResults": [], + "clickUri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/receive-benefits.html", + "excerpt": "Receive your benefits On this page ... To cancel your benefit, contact Service Canada. ... Death benefit: A one-time payment on behalf of the deceased contributor ... CPP children's benefit: A monthly benefit for a dependent child of a deceased CPP ... general questions about CPP retirement pension benefits or specific questions about your ...", + "excerptHighlights": [ + { + "length": 7, + "offset": 182 + }, + { + "length": 7, + "offset": 201 + }, + { + "length": 7, + "offset": 54 + }, + { + "length": 7, + "offset": 97 + }, + { + "length": 8, + "offset": 13 + }, + { + "length": 8, + "offset": 300 + } + ], + "firstSentences": null, + "firstSentencesHighlights": [], + "flags": "HasHtmlVersion;HasAllMetaDataStream", + "hasHtmlVersion": true, + "hasMobileHtmlVersion": false, + "isRecommendation": false, + "isTopResult": false, + "isUserActionView": false, + "parentResult": null, + "percentScore": 98.44377, + "primaryid": "OBEUQODTKVKVENRWKJXWUSLQMQXDEMBQGEXGIZLGMF2WY5A", + "printableUri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/receive-benefits.html", + "printableUriHighlights": [ + { + "length": 8, + "offset": 34 + }, + { + "length": 8, + "offset": 70 + } + ], + "rankingInfo": "Document weights:\nTitle: 646; Quality: 0; Date: 593; Adjacency: 0; Source: 0; Custom: 0; QRE: 3000; Ranking functions: 0; \nQRE:\nExpression: \"@uri=veterans.gc.ca @uri=(remembrance/memorials/books/page,remembrance/memorials/canadian-virtual-war-memorial/detail)\" Score: 0\nExpression: \"@title=(\"Error 500\",\"Error 404\",archive,archivé,archivée)\" Score: 0\nExpression: \"@uri=canada.ca/en/news/archive/ OR @uri=canada.ca/fr/nouvelles/archive/ OR (@generator==gcnews ((@declared_type=\"news releases\" @date Canada Pension Plan retirement pension", + "hostname": "canada.ca", + "language": [ + "English" + ], + "permanentid": "9472b4909e0543e71984a0fa7647560485e4e9596b0109cbfb5defd4d4a0", + "source": "priority_canada_ca_sitemap", + "sourcetype": "Sitemap", + "sysauthor": [ + "Service Canada" + ], + "syscollection": "default", + "sysdate": 1781740800000, + "syslanguage": [ + "English" + ], + "syssource": "priority_canada_ca_sitemap", + "syssourcetype": "Sitemap", + "sysurihash": "pIH8sUUR66RojIpd", + "urihash": "pIH8sUUR66RojIpd" + }, + "score": 7908, + "summary": null, + "summaryHighlights": [], + "title": "Receive your benefits", + "titleHighlights": [ + { + "length": 8, + "offset": 13 + } + ], + "totalNumberOfChildResults": 0, + "uniqueId": "42.2001$https://www.canada.ca/en/services/benefits/publicpensions/cpp/receive-benefits.html", + "uri": "https://www.canada.ca/en/services/benefits/publicpensions/cpp/receive-benefits.html" + } + ], + "searchUid": "ac01518d-3264-4aba-8b24-815a6f3e0a7f", + "splitTestRun": "Canada public websites - Gene...-mirror-1733855881", + "suggestedFacets": [], + "termsToHighlight": { + "benefits": [ + "benefit", + "benefited", + "benefitically", + "benefiting", + "benefitted", + "benefitting", + "benefıts", + "bénefit", + "bénéfition", + "bénéfits" + ] + }, + "topResults": [ + { + "applyToEveryResult": true, + "exclusive": false, + "expression": "@permanentid=8474a65cdb75baf0af880228aaae5e8a374fff804e0d571fc41dce1734bb", + "includeInFacets": true, + "isConstant": false, + "matchAdvancedQuery": true, + "matchQuery": false, + "modifier": 250 + }, + { + "applyToEveryResult": true, + "exclusive": false, + "expression": "@permanentid=a79ff2303b93e98d68ed051a1e90c03332f7b962d15f2ac4c1d47ef13fbc", + "includeInFacets": true, + "isConstant": false, + "matchAdvancedQuery": true, + "matchQuery": false, + "modifier": 159 + }, + { + "applyToEveryResult": true, + "exclusive": false, + "expression": "@permanentid=ddd67756dd4fe0de6cf866d8fab51fa01909840c9b39a9ef76955d5bdc94", + "includeInFacets": true, + "isConstant": false, + "matchAdvancedQuery": true, + "matchQuery": false, + "modifier": 250 + }, + { + "applyToEveryResult": true, + "exclusive": false, + "expression": "@permanentid=e0002bdd6d3c6f7ca8d2ecac1f81d3c3944b01cb0ca32e73838659ec443a", + "includeInFacets": true, + "isConstant": false, + "matchAdvancedQuery": true, + "matchQuery": false, + "modifier": 250 + } + ], + "totalCount": 193654, + "totalCountFiltered": 193653, + "triggers": [], + "userIdentities": [ + { + "name": "anonymous_user@anonymous.coveo.com", + "provider": "Email Security Provider", + "type": "User" + } + ] +} \ No newline at end of file diff --git a/e2e/result-templates.spec.js b/e2e/result-templates.spec.js new file mode 100644 index 0000000..f4f7d21 --- /dev/null +++ b/e2e/result-templates.spec.js @@ -0,0 +1,114 @@ +import { test, expect } from '@playwright/test'; +import searchFixture from './fixtures/result-template-results.json' assert { type: 'json' }; + +test.describe('Result templates', () => { + test.beforeEach(async ({ page }) => { + // Mask the automation flag that Playwright sets — Coveo detects it and skips initialization. + await page.addInitScript(() => { + Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); + }); + + // Intercept the Coveo search API and return the fixture so template assertions are deterministic. + await page.route('**/rest/search**', async route => { + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(searchFixture), + }); + }); + + await page.goto('http://localhost:4000/tests/srb-en.html#q=benefits'); + }); + + test('result template renders title, link, author, breadcrumb, time, and excerpt', async ({ page }) => { + const firstResult = page.locator('#wb-land #result-list section').first(); + await expect(firstResult).toBeVisible(); + + const firstResultData = searchFixture.results[0]; + + // Title links to the result's clickUri. + const titleLink = firstResult.locator('a.result-link'); + await expect(titleLink).toHaveText(firstResultData.title); + await expect(titleLink).toHaveAttribute('href', firstResultData.clickUri); + + // Author label comes from raw.author. + const author = Array.isArray(firstResultData.raw.author) + ? firstResultData.raw.author[0] + : firstResultData.raw.author; + await expect(firstResult.locator('ul.context-labels li')).toHaveText(author); + + // Excerpt is present and non-empty. + await expect(firstResult.locator('p')).toContainText(firstResultData.excerpt.slice(0, 30)); + + // Breadcrumb container is present. + await expect(firstResult.locator('.location')).toBeAttached(); + + // Date is rendered in a