diff --git a/libs/eslint-plugin-mte/index.js b/libs/eslint-plugin-mte/index.js index 1ea249c9d..ad00d0e08 100644 --- a/libs/eslint-plugin-mte/index.js +++ b/libs/eslint-plugin-mte/index.js @@ -22,12 +22,11 @@ export default [ reportUnusedDisableDirectives: 'error', }, rules: { + eqeqeq: 'error', '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', '@typescript-eslint/consistent-type-imports': 'error', - // Not useful for a lot of stuff, but mainly `.shadowRoot` - '@typescript-eslint/no-non-null-assertion': 'off', }, }, { diff --git a/package-lock.json b/package-lock.json index c7e59a1f0..cb02c403d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7924,6 +7924,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/fuzzysort": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-3.1.0.tgz", + "integrity": "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==", + "dev": true, + "license": "MIT" + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -16514,6 +16521,7 @@ "esbuild": "0.24.0", "eslint-config-mte": "*", "express": "4.21.1", + "fuzzysort": "3.1.0", "lit": "3.2.1", "mutation-testing-metrics": "3.3.0", "mutation-testing-real-time": "3.3.0", diff --git a/packages/elements/.vscode/launch.json b/packages/elements/.vscode/launch.json index 8708ae224..41851823c 100644 --- a/packages/elements/.vscode/launch.json +++ b/packages/elements/.vscode/launch.json @@ -18,6 +18,29 @@ "url": "http://localhost:5173", "webRoot": "${workspaceFolder}", "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "Run unit tests", + "program": "${workspaceFolder:parent}/node_modules/vitest/vitest.mjs", + "console": "integratedTerminal", + "skipFiles": ["/**"], + "args": ["--inspect-brk", "--browser", "--no-file-parallelism"] + }, + { + "type": "chrome", + "request": "attach", + "name": "Attach to unit test browser", + "skipFiles": ["/**"], + "port": 9229 + } + ], + "compounds": [ + { + "name": "Debug unit tests", + "configurations": ["Attach to unit test browser", "Run unit tests"], + "stopAll": true } ] } diff --git a/packages/elements/package.json b/packages/elements/package.json index 5a0105e96..165e16c13 100644 --- a/packages/elements/package.json +++ b/packages/elements/package.json @@ -59,6 +59,7 @@ "esbuild": "0.24.0", "eslint-config-mte": "*", "express": "4.21.1", + "fuzzysort": "3.1.0", "lit": "3.2.1", "mutation-testing-metrics": "3.3.0", "mutation-testing-real-time": "3.3.0", diff --git a/packages/elements/src/components/app/app.component.ts b/packages/elements/src/components/app/app.component.ts index bb043404c..e865c6f13 100644 --- a/packages/elements/src/components/app/app.component.ts +++ b/packages/elements/src/components/app/app.component.ts @@ -2,6 +2,7 @@ import type { PropertyValues } from 'lit'; import { html, isServer, nothing, unsafeCSS } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; import type { FileUnderTestModel, Metrics, @@ -370,11 +371,11 @@ export class MutationTestReportAppComponent extends RealTimeElement { .path="${this.context.path}" > ${this.context.view === 'mutant' && this.context.result ? html`${searchIcon} `; + return html` + + `; } #dispatchFilePickerOpenEvent() { diff --git a/packages/elements/src/components/file-picker/file-picker.component.ts b/packages/elements/src/components/file-picker/file-picker.component.ts index 1fb1fa231..c18b3b4b0 100644 --- a/packages/elements/src/components/file-picker/file-picker.component.ts +++ b/packages/elements/src/components/file-picker/file-picker.component.ts @@ -1,30 +1,37 @@ +import fuzzysort from 'fuzzysort'; +import type { TemplateResult } from 'lit'; import { html, LitElement, nothing, type PropertyValues } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; - -import { TestFileModel } from 'mutation-testing-metrics'; import type { FileUnderTestModel, Metrics, MetricsResult, MutationTestMetricsResult, TestMetrics } from 'mutation-testing-metrics'; +import { TestFileModel } from 'mutation-testing-metrics'; -import { mutantFileIcon, searchIcon, testFileIcon } from '../../lib/svg-icons.js'; import { renderIf, toAbsoluteUrl } from '../../lib/html-helpers.js'; -import { tailwind } from '../../style/index.js'; import { View } from '../../lib/router.js'; +import { mutantFileIcon, searchIcon, testFileIcon } from '../../lib/svg-icons.js'; +import { tailwind } from '../../style/index.js'; + +interface ModelEntry { + name: string; + file: FileUnderTestModel | TestFileModel; +} @customElement('mte-file-picker') export class MutationTestReportFilePickerComponent extends LitElement { static styles = [tailwind]; #abortController = new AbortController(); - #searchMap = new Map(); + #searchTargets: (ModelEntry & { prepared: Fuzzysort.Prepared })[] = []; + #originalDocumentOverflow = ''; - @property({ type: Object }) - public declare rootModel: MutationTestMetricsResult; + @property({ attribute: false }) + public declare rootModel: MutationTestMetricsResult | undefined; @state() public declare openPicker: boolean; @state() - public declare filteredFiles: { name: string; file: FileUnderTestModel | TestFileModel }[]; + public declare filteredFiles: (ModelEntry & { template?: (string | TemplateResult)[] })[]; @state() public declare fileIndex: number; @@ -38,29 +45,38 @@ export class MutationTestReportFilePickerComponent extends LitElement { connectedCallback(): void { super.connectedCallback(); + this.#originalDocumentOverflow = document.body.style.overflow; - window.addEventListener('keydown', (e) => this.#handleKeyDown(e), { signal: this.#abortController.signal }); + window.addEventListener('keydown', this.#handleKeyDown, { signal: this.#abortController.signal }); } disconnectedCallback(): void { super.disconnectedCallback(); + fuzzysort.cleanup(); this.#abortController.abort(); } willUpdate(changedProperties: PropertyValues): void { - super.willUpdate(changedProperties); - if (changedProperties.has('rootModel')) { this.#prepareMap(); this.#filter(''); } } + updated(changedProperties: PropertyValues): void { + if (changedProperties.has('openPicker')) { + if (this.openPicker) { + document.body.style.overflow = 'hidden'; + this.#focusInput(); + } else { + document.body.style.overflow = this.#originalDocumentOverflow; + } + } + } + open() { this.openPicker = true; - - void this.updateComplete.then(() => this.#focusInput()); } render() { @@ -71,28 +87,31 @@ export class MutationTestReportFilePickerComponent extends LitElement { return html`
`; @@ -100,27 +119,37 @@ export class MutationTestReportFilePickerComponent extends LitElement { #renderFoundFiles() { return html` -
    +
      ${renderIf(this.filteredFiles.length === 0, () => html`
    • No files found
    • `)} ${repeat( this.filteredFiles, (item) => item.name, - ({ name, file }, index) => { + ({ name, file, template }, index) => { const view = this.#getView(file); return html` -
    • +
    • ${this.#renderTestOrMutantIndication(view)} ${file.result?.name} - ${name} + ${template ?? name}
    • `; @@ -131,39 +160,34 @@ export class MutationTestReportFilePickerComponent extends LitElement { } #renderTestOrMutantIndication(view: View) { - return html`${view === View.mutant ? mutantFileIcon : testFileIcon}`; - } - - #handleFocus() { - this.shadowRoot?.querySelector('input')?.focus(); + return view === View.mutant ? mutantFileIcon : testFileIcon; } #prepareMap() { - if (this.rootModel == null) { + if (!this.rootModel) { return; } + // Clear previous search targets + this.#searchTargets = []; const prepareFiles = ( result: MetricsResult | undefined, parentPath: string | null = null, allFilesKey: string, ) => { - if (result === undefined) { + if (!result) { return; } - if (result.file !== undefined && result.file !== null && result.name !== allFilesKey) { - this.#searchMap.set(parentPath == null ? result.name : `${parentPath}/${result.name}`, result.file); - } - - if (result.childResults.length === 0) { - return; + if (result.file && result.name !== allFilesKey) { + const name = !parentPath ? result.name : `${parentPath}/${result.name}`; + this.#searchTargets.push({ name, file: result.file, prepared: fuzzysort.prepare(name) }); } result.childResults.forEach((child) => { - if (parentPath !== allFilesKey && parentPath !== null && result.name !== null) { + if (parentPath !== allFilesKey && parentPath && result.name) { prepareFiles(child, `${parentPath}/${result.name}`, allFilesKey); - } else if ((parentPath === allFilesKey || parentPath === null) && result.name !== allFilesKey) { + } else if ((parentPath === allFilesKey || !parentPath) && result.name !== allFilesKey) { prepareFiles(child, result.name, allFilesKey); } else { prepareFiles(child, null, allFilesKey); @@ -175,7 +199,7 @@ export class MutationTestReportFilePickerComponent extends LitElement { prepareFiles(this.rootModel.testMetrics, null, 'All tests'); } - #handleKeyDown(event: KeyboardEvent) { + #handleKeyDown = (event: KeyboardEvent) => { if ((event.ctrlKey || event.metaKey) && event.key === 'k') { this.#togglePicker(event); } else if (!this.openPicker && event.key === '/') { @@ -189,7 +213,7 @@ export class MutationTestReportFilePickerComponent extends LitElement { } if (event.key === 'ArrowUp' || event.key === 'ArrowDown') { - setTimeout(() => { + void this.updateComplete.then(() => { this.#scrollActiveLinkInView(); }); } @@ -197,10 +221,10 @@ export class MutationTestReportFilePickerComponent extends LitElement { if (event.key === 'Enter') { this.#handleEnter(); } - } + }; #scrollActiveLinkInView() { - const activeLink = this.shadowRoot?.querySelector('a[data-active]'); + const activeLink = this.renderRoot.querySelector('[aria-selected="true"] a'); activeLink?.scrollIntoView({ block: 'nearest' }); } @@ -232,49 +256,44 @@ export class MutationTestReportFilePickerComponent extends LitElement { this.#closePicker(); } - #togglePicker(event: KeyboardEvent | null = null) { + #togglePicker = (event: KeyboardEvent | null = null) => { event?.preventDefault(); event?.stopPropagation(); this.openPicker = !this.openPicker; + }; - if (!this.openPicker) { - document.body.style.overflow = 'auto'; - } else { - document.body.style.overflow = 'hidden'; - } - - void this.updateComplete.then(() => this.#focusInput()); - } - - #focusInput() { - this.shadowRoot?.querySelector('input')?.focus(); - } + #focusInput = () => { + this.renderRoot.querySelector('input')?.focus(); + }; - #closePicker() { - document.body.style.overflow = 'auto'; + #closePicker = () => { this.openPicker = false; this.fileIndex = 0; this.#filter(''); - } + }; - #handleSearch(event: KeyboardEvent) { + #handleSearch = (event: InputEvent) => { if (!this.openPicker) { return; } - if (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'Tab') { - return; - } - this.#filter((event.target as HTMLInputElement).value); this.fileIndex = 0; - } + }; #filter(filterKey: string) { - this.filteredFiles = Array.from(this.#searchMap.keys()) - .filter((file) => file.toLowerCase().includes(filterKey.toLowerCase())) - .map((file) => ({ name: file, file: this.#searchMap.get(file)! })); + if (!filterKey) { + this.filteredFiles = this.#searchTargets; + } else { + this.filteredFiles = fuzzysort.go(filterKey, this.#searchTargets, { key: 'prepared', threshold: 0.3, limit: 500 }).map((result) => ({ + file: result.obj.file, + name: result.obj.name, + template: result.highlight( + (m) => html`${m}`, + ), + })); + } } #getView(file: FileUnderTestModel | TestFileModel): View { diff --git a/packages/elements/src/components/metrics-table/metrics-table.component.ts b/packages/elements/src/components/metrics-table/metrics-table.component.ts index 92994393b..3e3ac896f 100644 --- a/packages/elements/src/components/metrics-table/metrics-table.component.ts +++ b/packages/elements/src/components/metrics-table/metrics-table.component.ts @@ -61,11 +61,11 @@ export class MutationTestReportTestMetricsTable extends RealTime } public render() { - return html`${this.model + return this.model ? html`
      ${this.renderTableHeadRow()}${this.renderTableBody(this.model)}
      ` - : nothing}`; + : nothing; } private renderTableHeadRow() { diff --git a/packages/elements/src/components/result-status-bar/result-status-bar.ts b/packages/elements/src/components/result-status-bar/result-status-bar.ts index cd4a7f664..b7bee45b6 100644 --- a/packages/elements/src/components/result-status-bar/result-status-bar.ts +++ b/packages/elements/src/components/result-status-bar/result-status-bar.ts @@ -1,5 +1,6 @@ -import { LitElement, html } from 'lit'; -import { customElement, property, state } from 'lit/decorators.js'; +import { IntersectionController } from '@lit-labs/observers/intersection-controller.js'; +import { LitElement, html, nothing } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; import { tailwind } from '../../style/index.js'; type ProgressType = 'detected' | 'survived' | 'no coverage' | 'pending'; @@ -14,25 +15,22 @@ interface ProgressMetric { export class ResultStatusBar extends LitElement { public static styles = [tailwind]; - @property({ attribute: false }) - public declare detected; + @property({ type: Number }) + public declare detected: number; - @property({ attribute: false }) - public declare noCoverage; + @property({ type: Number }) + public declare noCoverage: number; - @property({ attribute: false }) - public declare pending; + @property({ type: Number }) + public declare pending: number; - @property({ attribute: false }) - public declare survived; + @property({ type: Number }) + public declare survived: number; - @property({ attribute: false }) - public declare total; + @property({ type: Number }) + public declare total: number; - @state() - private declare shouldBeSmall; - - #observer: IntersectionObserver | undefined; + #shouldBeSmallController: IntersectionController; public constructor() { super(); @@ -41,75 +39,49 @@ export class ResultStatusBar extends LitElement { this.pending = 0; this.survived = 0; this.total = 0; - this.shouldBeSmall = false; - } - - public connectedCallback(): void { - super.connectedCallback(); // This code is responsible for making the small progress-bar show up. // Once this element (the standard progress-bar) is no longer intersecting (visible) the viewable window, // the smaller progress-bar will show up at the top if the window. // If this element is visible, the smaller progress-bar will fade out and it will no longer be visible. - this.#observer = new window.IntersectionObserver(([entry]) => { - if (entry.isIntersecting) { - this.shouldBeSmall = false; - } else { - this.shouldBeSmall = true; - } - - this.requestUpdate(); + this.#shouldBeSmallController = new IntersectionController(this, { + callback: ([entry]) => { + return !entry.isIntersecting; + }, }); - this.#observer.observe(this); - } - - public disconnectedCallback(): void { - super.disconnectedCallback(); - - this.#observer?.disconnect(); } public render() { return html` ${this.#renderSmallParts()}
      -
      -
      ${this.#renderParts()}
      -
      +
      ${this.#renderParts()}
      `; } #renderSmallParts() { return html`
      -
      ${this.#getMetrics().map((metric) => this.#renderSmallPart(metric))}
      +
      ${this.#getMetrics().map((metric) => this.#renderPart(metric, true))}
      `; } - #renderSmallPart(metric: ProgressMetric) { - return html`
      `; - } - #renderParts() { - return html`${this.#getMetrics().map((metric) => this.#renderPart(metric))}`; + return this.#getMetrics().map((metric) => this.#renderPart(metric, false)); } - #renderPart(metric: ProgressMetric) { + #renderPart(metric: ProgressMetric, shouldBeSmall: boolean) { return html`
      - ${metric.amount} + class="${this.#colorFromMetric(metric.type)} ${metric.amount === 0 ? 'opacity-0' : 'opacity-1'} relative flex items-center overflow-hidden" + >${shouldBeSmall ? nothing : html`${metric.amount}`}
      `; } diff --git a/packages/elements/src/components/test-file/test-file.component.ts b/packages/elements/src/components/test-file/test-file.component.ts index 4dd84e501..64d04f13a 100644 --- a/packages/elements/src/components/test-file/test-file.component.ts +++ b/packages/elements/src/components/test-file/test-file.component.ts @@ -85,7 +85,7 @@ export class TestFileComponent extends RealTimeElement { } this.selectedTest = test; this.dispatchEvent(createCustomEvent('test-selected', { selected: true, test })); - scrollToCodeFragmentIfNeeded(this.shadowRoot!.querySelector(`[test-id="${test.id}"]`)); + scrollToCodeFragmentIfNeeded(this.renderRoot.querySelector(`[test-id="${test.id}"]`)); } } @@ -229,8 +229,6 @@ export class TestFileComponent extends RealTimeElement { } }); } - - super.willUpdate(changes); } private updateFileRepresentation() { @@ -254,7 +252,7 @@ export class TestFileComponent extends RealTimeElement { } #animateTestToggle(test: TestModel) { - beginElementAnimation(this.shadowRoot!, 'test-id', test.id); + beginElementAnimation(this.renderRoot, 'test-id', test.id); } } function title(test: TestModel): string { diff --git a/packages/elements/src/components/theme-switch/theme-switch.component.ts b/packages/elements/src/components/theme-switch/theme-switch.component.ts index 1903d68c2..a15f3f6d7 100644 --- a/packages/elements/src/components/theme-switch/theme-switch.component.ts +++ b/packages/elements/src/components/theme-switch/theme-switch.component.ts @@ -19,7 +19,7 @@ export class MutationTestReportThemeSwitchComponent extends LitElement { public render() { return html`
      - +
      `; diff --git a/packages/elements/test/integration/po/Breadcrumb.po.ts b/packages/elements/test/integration/po/Breadcrumb.po.ts index 7d61cb85b..7c29c5633 100644 --- a/packages/elements/test/integration/po/Breadcrumb.po.ts +++ b/packages/elements/test/integration/po/Breadcrumb.po.ts @@ -1,3 +1,4 @@ +import { FilePicker } from './FilePicker.po.js'; import { PageObject } from './PageObject.po.js'; export default class Breadcrumb extends PageObject { @@ -10,8 +11,10 @@ export default class Breadcrumb extends PageObject { await anchor.click(); } - public async clickOnSearchIcon(): Promise { + public async openFilePicker(): Promise { const button = this.$('button'); await button.click(); + + return new FilePicker(this.browser.locator('mutation-test-report-app >> mte-file-picker'), this.browser); } } diff --git a/packages/elements/test/integration/po/FilePicker.po.ts b/packages/elements/test/integration/po/FilePicker.po.ts new file mode 100644 index 000000000..05a371aba --- /dev/null +++ b/packages/elements/test/integration/po/FilePicker.po.ts @@ -0,0 +1,11 @@ +import { PageObject } from './PageObject.po.js'; + +export class FilePicker extends PageObject { + public async search(query: string) { + return this.$('input').fill(query); + } + + public async results() { + return this.$$('#files li'); + } +} diff --git a/packages/elements/test/integration/theming.it.spec.ts b/packages/elements/test/integration/theming.it.spec.ts index 284ef1fe3..d680eebbf 100644 --- a/packages/elements/test/integration/theming.it.spec.ts +++ b/packages/elements/test/integration/theming.it.spec.ts @@ -1,6 +1,7 @@ -import { ReportPage } from './po/ReportPage.js'; +import { expect, test } from '@playwright/test'; import { itShouldMatchScreenshot } from './lib/helpers.js'; -import { test, expect } from '@playwright/test'; +import type { FilePicker } from './po/FilePicker.po.js'; +import { ReportPage } from './po/ReportPage.js'; test.describe('Theming', () => { let page: ReportPage; @@ -43,11 +44,20 @@ test.describe('Theming', () => { }); test.describe('when opening the file picker', () => { + let filePicker: FilePicker; test.beforeEach(async () => { - await page.breadcrumb().clickOnSearchIcon(); + filePicker = await page.breadcrumb().openFilePicker(); }); itShouldMatchScreenshot('should match the dark theme'); + + test.describe('and typing in the search box', () => { + test.beforeEach(async () => { + await filePicker.search('in'); + }); + + itShouldMatchScreenshot('should match the dark theme'); + }); }); }); @@ -77,11 +87,20 @@ test.describe('Theming', () => { }); test.describe('when opening the file picker', () => { + let filePicker: FilePicker; test.beforeEach(async () => { - await page.breadcrumb().clickOnSearchIcon(); + filePicker = await page.breadcrumb().openFilePicker(); }); itShouldMatchScreenshot('should match the light theme'); + + test.describe('and typing in the search box', () => { + test.beforeEach(async () => { + await filePicker.search('in'); + }); + + itShouldMatchScreenshot('should match the light theme'); + }); }); }); }); diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picke-6b805-in-the-search-box-should-match-the-dark-theme-1-chromium-linux.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picke-6b805-in-the-search-box-should-match-the-dark-theme-1-chromium-linux.png new file mode 100644 index 000000000..13527592f Binary files /dev/null and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picke-6b805-in-the-search-box-should-match-the-dark-theme-1-chromium-linux.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picke-6b805-in-the-search-box-should-match-the-dark-theme-1-chromium-win32.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picke-6b805-in-the-search-box-should-match-the-dark-theme-1-chromium-win32.png new file mode 100644 index 000000000..17418f1c0 Binary files /dev/null and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picke-6b805-in-the-search-box-should-match-the-dark-theme-1-chromium-win32.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picke-6b805-in-the-search-box-should-match-the-dark-theme-1-firefox-linux.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picke-6b805-in-the-search-box-should-match-the-dark-theme-1-firefox-linux.png new file mode 100644 index 000000000..57a0af618 Binary files /dev/null and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picke-6b805-in-the-search-box-should-match-the-dark-theme-1-firefox-linux.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picke-6b805-in-the-search-box-should-match-the-dark-theme-1-firefox-win32.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picke-6b805-in-the-search-box-should-match-the-dark-theme-1-firefox-win32.png new file mode 100644 index 000000000..3f963ca86 Binary files /dev/null and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picke-6b805-in-the-search-box-should-match-the-dark-theme-1-firefox-win32.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-chromium-linux.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-chromium-linux.png index 1897ded98..def15ea95 100644 Binary files a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-chromium-linux.png and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-chromium-linux.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-chromium-win32.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-chromium-win32.png index 2f2a82316..833ccf05e 100644 Binary files a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-chromium-win32.png and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-chromium-win32.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-firefox-linux.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-firefox-linux.png index 5bd25aea9..591ac7b71 100644 Binary files a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-firefox-linux.png and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-firefox-linux.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-firefox-win32.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-firefox-win32.png index 386cdd8af..2de4e9f01 100644 Binary files a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-firefox-win32.png and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-dark-theme-when-opening-the-file-picker-should-match-the-dark-theme-1-firefox-win32.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-pick-d5814-n-the-search-box-should-match-the-light-theme-1-chromium-linux.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-pick-d5814-n-the-search-box-should-match-the-light-theme-1-chromium-linux.png new file mode 100644 index 000000000..5c853ef7b Binary files /dev/null and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-pick-d5814-n-the-search-box-should-match-the-light-theme-1-chromium-linux.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-pick-d5814-n-the-search-box-should-match-the-light-theme-1-chromium-win32.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-pick-d5814-n-the-search-box-should-match-the-light-theme-1-chromium-win32.png new file mode 100644 index 000000000..bbc907661 Binary files /dev/null and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-pick-d5814-n-the-search-box-should-match-the-light-theme-1-chromium-win32.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-pick-d5814-n-the-search-box-should-match-the-light-theme-1-firefox-linux.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-pick-d5814-n-the-search-box-should-match-the-light-theme-1-firefox-linux.png new file mode 100644 index 000000000..5bcb510b6 Binary files /dev/null and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-pick-d5814-n-the-search-box-should-match-the-light-theme-1-firefox-linux.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-pick-d5814-n-the-search-box-should-match-the-light-theme-1-firefox-win32.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-pick-d5814-n-the-search-box-should-match-the-light-theme-1-firefox-win32.png new file mode 100644 index 000000000..9f94c3878 Binary files /dev/null and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-pick-d5814-n-the-search-box-should-match-the-light-theme-1-firefox-win32.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-chromium-linux.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-chromium-linux.png index 66c2afaf1..3d4a6b539 100644 Binary files a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-chromium-linux.png and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-chromium-linux.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-chromium-win32.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-chromium-win32.png index fa6fa1d5c..bbd314b90 100644 Binary files a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-chromium-win32.png and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-chromium-win32.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-firefox-linux.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-firefox-linux.png index a808c003d..f3519e8c5 100644 Binary files a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-firefox-linux.png and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-firefox-linux.png differ diff --git a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-firefox-win32.png b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-firefox-win32.png index e3d8eeb87..fca5a93a5 100644 Binary files a/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-firefox-win32.png and b/packages/elements/test/integration/theming.it.spec.ts-snapshots/Theming-light-theme-when-opening-the-file-picker-should-match-the-light-theme-1-firefox-win32.png differ diff --git a/packages/elements/test/unit/components/breadcrumb.component.spec.ts b/packages/elements/test/unit/components/breadcrumb.component.spec.ts index 3efc0f808..49d3b1e41 100644 --- a/packages/elements/test/unit/components/breadcrumb.component.spec.ts +++ b/packages/elements/test/unit/components/breadcrumb.component.spec.ts @@ -18,7 +18,7 @@ describe(MutationTestReportBreadcrumbComponent.name, () => { it('should show the root item as "All files" for the "mutant" view', () => { const elements = sut.$$('li'); expect(elements).lengthOf(1); - expect(elements[0].textContent?.trim()).eq('All files'); + expect(elements[0]).toHaveTextContent('All files'); expect(elements[0].querySelector('a')).eq(null); }); @@ -27,7 +27,7 @@ describe(MutationTestReportBreadcrumbComponent.name, () => { await sut.whenStable(); const elements = sut.$$('li'); expect(elements).lengthOf(1); - expect(elements[0].textContent?.trim()).eq('All tests'); + expect(elements[0]).toHaveTextContent('All tests'); expect(elements[0].querySelector('a')).eq(null); }); @@ -39,7 +39,7 @@ describe(MutationTestReportBreadcrumbComponent.name, () => { const anchor = elements[0].querySelector('a')!; expect(anchor).ok; expect(anchor.href).eq(href('#mutant')); - expect(elements[1].textContent?.trim()).eq('foo.js'); + expect(elements[1]).toHaveTextContent('foo.js'); expect(elements[1].querySelector('a')).null; }); @@ -51,17 +51,17 @@ describe(MutationTestReportBreadcrumbComponent.name, () => { const rootLink = elements[0].querySelector('a')!; expect(rootLink).ok; expect(rootLink.href).eq(href('#mutant')); - expect(elements[1].textContent?.trim()).eq('bar'); + expect(elements[1]).toHaveTextContent('bar'); const barAnchor = elements[1].querySelector('a')!; expect(barAnchor).ok; expect(barAnchor.href).eq(href('#mutant/bar')); - expect(elements[2].textContent?.trim()).eq('foo.js'); + expect(elements[2]).toHaveTextContent('foo.js'); expect(elements[2].querySelector('a')).null; }); it('should dispatch open-file-picker event', async () => { // Act - const event = await sut.catchCustomEvent('mte-file-picker-open', () => sut.element.shadowRoot?.querySelector('button')?.click()); + const event = await sut.catchCustomEvent('mte-file-picker-open', () => sut.element.renderRoot.querySelector('button')?.click()); // Assert expect(event).ok; diff --git a/packages/elements/test/unit/components/drawer-mutant.component.spec.ts b/packages/elements/test/unit/components/drawer-mutant.component.spec.ts index ac0ae0a50..f3257747d 100644 --- a/packages/elements/test/unit/components/drawer-mutant.component.spec.ts +++ b/packages/elements/test/unit/components/drawer-mutant.component.spec.ts @@ -149,9 +149,9 @@ describe(MutationTestReportDrawerMutant.name, () => { await sut.whenStable(); const listItems = sut.$$('[slot="detail"] ul li'); expect(listItems).lengthOf(3); - expect(listItems[0].textContent).eq('🎯 foo should bar'); - expect(listItems[1].textContent).eq('🎯 baz should qux'); - expect(listItems[2].textContent).eq('☂️ quux should corge'); + expect(listItems[0]).toHaveTextContent('🎯 foo should bar'); + expect(listItems[1]).toHaveTextContent('🎯 baz should qux'); + expect(listItems[2]).toHaveTextContent('☂️ quux should corge'); }); function detailText() { diff --git a/packages/elements/test/unit/components/drawer-test.component.spec.ts b/packages/elements/test/unit/components/drawer-test.component.spec.ts index f9748e0b7..d172d7d9b 100644 --- a/packages/elements/test/unit/components/drawer-test.component.spec.ts +++ b/packages/elements/test/unit/components/drawer-test.component.spec.ts @@ -47,8 +47,7 @@ describe(MutationTestReportDrawerTestComponent.name, () => { it('should render the header correctly', async () => { sut.element.test = test; await sut.whenStable(); - const headerText = sut.$('[slot="header"]').textContent; - expect(headerText).contains('🌧 foo should bar [NotCovering]'); + expect(sut.$('[slot="header"]')).toHaveTextContent('🌧 foo should bar [NotCovering]'); }); it('should render closed by default', () => { @@ -131,9 +130,9 @@ describe(MutationTestReportDrawerTestComponent.name, () => { await sut.whenStable(); const listItems = sut.$$('[slot="detail"] ul li'); expect(listItems).lengthOf(3); - expect(listItems[0].textContent).contains('🎯 const a = false'); - expect(listItems[1].textContent).contains('🎯 const b = true'); - expect(listItems[2].textContent).contains('☂️ if(1 <= 5)'); + expect(listItems[0]).toHaveTextContent('🎯 const a = false'); + expect(listItems[1]).toHaveTextContent('🎯 const b = true'); + expect(listItems[2]).toHaveTextContent('☂️ if(1 <= 5)'); }); function detailText() { diff --git a/packages/elements/test/unit/components/drawer.component.spec.ts b/packages/elements/test/unit/components/drawer.component.spec.ts index 6a027d677..1435e989e 100644 --- a/packages/elements/test/unit/components/drawer.component.spec.ts +++ b/packages/elements/test/unit/components/drawer.component.spec.ts @@ -45,7 +45,7 @@ describe(MutationTestReportDrawer.name, () => { it('should render the read-more toggle', async () => { sut.element.mode = 'half'; await sut.whenStable(); - expect(readMoreToggle().textContent).eq('🔼 More'); + expect(readMoreToggle()).toHaveTextContent('🔼 More'); }); it('should expand to full size when read-more is clicked', async () => { @@ -58,7 +58,7 @@ describe(MutationTestReportDrawer.name, () => { it('should change the label of the read-more toggle when fully expanded', async () => { sut.element.mode = 'open'; await sut.whenStable(); - expect(readMoreToggle().textContent).eq('🔽 Less'); + expect(readMoreToggle()).toHaveTextContent('🔽 Less'); }); it('should show the detail when opened', async () => { diff --git a/packages/elements/test/unit/components/file-picker.component.spec.ts b/packages/elements/test/unit/components/file-picker.component.spec.ts index 01acbe0fc..bf6157310 100644 --- a/packages/elements/test/unit/components/file-picker.component.spec.ts +++ b/packages/elements/test/unit/components/file-picker.component.spec.ts @@ -1,10 +1,9 @@ import { userEvent } from '@vitest/browser/context'; import { calculateMutationTestMetrics } from 'mutation-testing-metrics'; +import { MutationTestReportFilePickerComponent } from '../../../src/components/file-picker/file-picker.component.js'; import { CustomElementFixture } from '../helpers/CustomElementFixture.js'; import { createReport } from '../helpers/factory.js'; -import { tick } from '../helpers/tick.js'; -import { MutationTestReportFilePickerComponent } from '../../../src/components/file-picker/file-picker.component.js'; describe(MutationTestReportFilePickerComponent.name, () => { let sut: CustomElementFixture; @@ -22,7 +21,7 @@ describe(MutationTestReportFilePickerComponent.name, () => { await sut.whenStable(); // Assert - expect(sut.element.shadowRoot?.querySelector('#picker')).to.eq(null); + expect(getPicker()).not.toBeInTheDocument(); }); it('should show the picker when keycombo is pressed', async () => { @@ -35,7 +34,7 @@ describe(MutationTestReportFilePickerComponent.name, () => { await openPicker(); // Assert - expect(sut.element.shadowRoot?.querySelector('#picker')).toBeVisible(); + expect(getPicker()).toBeVisible(); }); it('should show the picker when macos keycombo is pressed', async () => { @@ -49,7 +48,20 @@ describe(MutationTestReportFilePickerComponent.name, () => { await sut.whenStable(); // Assert - expect(sut.element.shadowRoot?.querySelector('#picker')).toBeVisible(); + expect(getPicker()).toBeVisible(); + }); + + it('should show the picker when / is pressed', async () => { + // Arrange + sut.element.rootModel = calculateMutationTestMetrics(createReport()); + + // Act + sut.connect(); + await userEvent.keyboard('/'); + await sut.whenStable(); + + // Assert + expect(getPicker()).toBeVisible(); }); describe('when the picker is open', () => { @@ -73,7 +85,7 @@ describe(MutationTestReportFilePickerComponent.name, () => { await openPicker(); // Assert - expect(sut.element.shadowRoot?.querySelector('#picker')).to.eq(null); + expect(getPicker()).not.toBeInTheDocument(); }); it('should close the picker when the escape key is pressed', async () => { @@ -82,17 +94,17 @@ describe(MutationTestReportFilePickerComponent.name, () => { await sut.whenStable(); // Assert - expect(sut.element.shadowRoot?.querySelector('#picker')).to.eq(null); + expect(getPicker()).not.toBeInTheDocument(); }); it('should close the picker when clicking outside the dialog', async () => { // Act - const backdrop = sut.element.shadowRoot?.querySelector('#backdrop'); - (backdrop as HTMLElement).click(); + const backdrop = sut.$('#backdrop'); + backdrop.click(); await sut.whenStable(); // Assert - expect(sut.element.shadowRoot?.querySelector('#picker')).to.eq(null); + expect(getPicker()).not.toBeInTheDocument(); }); describe('when not typing in the search box', () => { @@ -101,29 +113,29 @@ describe(MutationTestReportFilePickerComponent.name, () => { await sut.whenStable(); // Assert - expect(sut.element.shadowRoot?.querySelector('a[data-active]')?.textContent?.trim()).include('append.js'); + expect(getActiveItem()).toHaveTextContent('append.js'); + expect(sut.$$('#files li')).toHaveLength(3); + expect(sut.$('#files')).not.toHaveTextContent('No files found'); }); }); describe('when typing in the search box', () => { it('should select the first item when searching with the letter "i"', async () => { // Arrange - const input = sut.element.shadowRoot?.querySelector('#file-picker-input'); + const input = getFilePickerInput(); // Act - (input as HTMLInputElement).value = 'i'; - await userEvent.type(input as HTMLInputElement, 'i'); + await userEvent.fill(input, 'i'); await sut.whenStable(); // Assert - expect(sut.element.shadowRoot?.querySelector('a[data-active]')?.textContent?.trim()).include('index.html'); + expect(getActiveItem()).toHaveTextContent('index.ts'); }); it('should redirect to mutant when pressing enter', async () => { // Arrange - const input = sut.element.shadowRoot?.querySelector('#file-picker-input'); - (input as HTMLInputElement).value = 'index.html'; - await userEvent.type(input as HTMLInputElement, 'l'); + const input = getFilePickerInput(); + await userEvent.fill(input, 'l'); await sut.whenStable(); // Act @@ -133,22 +145,42 @@ describe(MutationTestReportFilePickerComponent.name, () => { // Assert expect(window.location.hash).to.eq('#mutant/index.html'); }); - }); - describe('when pressing the arrow keys', () => { - beforeEach(() => { - const input = sut.element.shadowRoot?.querySelector('#file-picker-input'); - (input as HTMLInputElement).value = ''; + it('should support fuzzy-search', async () => { + // Arrange + const input = getFilePickerInput(); + + // Ac + await userEvent.fill(input, 'indx.hml'); + await sut.whenStable(); + + // Assert + expect(getActiveItem()).toHaveTextContent('index.html'); }); + it('should show when no files are found', async () => { + // Arrange + const input = getFilePickerInput(); + + // Act + await userEvent.fill(input, 'non-existing-file'); + await sut.whenStable(); + + // Assert + expect(getActiveItem()).not.toBeInTheDocument(); + expect(sut.$('#files')).toHaveTextContent('No files found'); + expect(sut.$$('#files')).toHaveLength(1); + }); + }); + + describe('when pressing the arrow keys', () => { it('should move active item to the next item when pressing down', async () => { // Arrange & Act await userEvent.keyboard('{arrowdown}'); await sut.whenStable(); - await tick(); // Assert - expect(sut.element.shadowRoot?.querySelector('a[data-active]')?.textContent?.trim()).include('index.html'); + expect(getActiveItem()).toHaveTextContent('index.html'); }); it('should move to the first item when pressing down on the last item', async () => { @@ -159,7 +191,7 @@ describe(MutationTestReportFilePickerComponent.name, () => { await sut.whenStable(); // Assert - expect(sut.element.shadowRoot?.querySelector('a[data-active]')?.textContent?.trim()).include('append.js'); + expect(getActiveItem()).toHaveTextContent('append.js'); }); it('should move active item to the previous item when pressing up', async () => { @@ -171,7 +203,7 @@ describe(MutationTestReportFilePickerComponent.name, () => { await sut.whenStable(); // Assert - expect(sut.element.shadowRoot?.querySelector('a[data-active]')?.textContent?.trim()).include('index.html'); + expect(getActiveItem()).toHaveTextContent('index.html'); }); it('should move to the last item when pressing up on the first item', async () => { @@ -183,7 +215,7 @@ describe(MutationTestReportFilePickerComponent.name, () => { await sut.whenStable(); // Assert - expect(sut.element.shadowRoot?.querySelector('a[data-active]')?.textContent?.trim()).include('index.ts'); + expect(getActiveItem()).toHaveTextContent('index.ts'); }); }); }); @@ -192,4 +224,16 @@ describe(MutationTestReportFilePickerComponent.name, () => { await userEvent.keyboard('{Control>}{k}'); await sut.whenStable(); } + + function getPicker() { + return sut.$('#picker'); + } + + function getActiveItem() { + return sut.$('[aria-selected="true"] a'); + } + + function getFilePickerInput() { + return sut.$('#file-picker-input'); + } }); diff --git a/packages/elements/test/unit/components/file.component.spec.ts b/packages/elements/test/unit/components/file.component.spec.ts index 7f98ecc5b..6c14953d4 100644 --- a/packages/elements/test/unit/components/file.component.spec.ts +++ b/packages/elements/test/unit/components/file.component.spec.ts @@ -25,7 +25,7 @@ describe(FileComponent.name, () => { }); it('should show the code', () => { - expect(sut.$('code').textContent?.trim()).eq(fileResult.source); + expect(sut.$('code')).toHaveTextContent(fileResult.source); }); it('should highlight the code', () => { diff --git a/packages/elements/test/unit/components/totals.component.spec.ts b/packages/elements/test/unit/components/totals.component.spec.ts index 888adaa4c..2701251ef 100644 --- a/packages/elements/test/unit/components/totals.component.spec.ts +++ b/packages/elements/test/unit/components/totals.component.spec.ts @@ -96,7 +96,7 @@ describe(MutationTestReportTestMetricsTable.name, () => { expect(table).ok; const rows = table.querySelectorAll('tbody tr'); expect(rows).lengthOf(2); - expect((rows.item(1) as HTMLTableRowElement).cells.item(0)!.textContent).contains('baz/foo.js'); + expect((rows.item(1) as HTMLTableRowElement).cells.item(0)!).toHaveTextContent('baz/foo.js'); }); it('should show N/A when no mutation score is available', async () => { @@ -109,7 +109,7 @@ describe(MutationTestReportTestMetricsTable.name, () => { await sut.whenStable(); const table = sut.$('table'); expect(table).ok; - expect(table.querySelectorAll('td span.font-bold')[0].textContent).contains('N/A'); + expect(table.querySelectorAll('td span.font-bold')[0]).toHaveTextContent('N/A'); }); it('should show a progress bar when there is a score', async () => { @@ -124,7 +124,7 @@ describe(MutationTestReportTestMetricsTable.name, () => { const table = sut.$('table'); expect(table).ok; expect(table.querySelector('[role=progressbar]')!.getAttribute('aria-valuenow')).contains(mutationScore); - expect(table.querySelector('.text-red-700')!.textContent).contains(mutationScore); + expect(table.querySelector('.text-red-700')!).toHaveTextContent(mutationScore.toString()); }); it('should show no progress bar when score is NaN', async () => { diff --git a/packages/elements/test/unit/helpers/CustomElementFixture.ts b/packages/elements/test/unit/helpers/CustomElementFixture.ts index 840d9bca0..a57b5d7fe 100644 --- a/packages/elements/test/unit/helpers/CustomElementFixture.ts +++ b/packages/elements/test/unit/helpers/CustomElementFixture.ts @@ -61,14 +61,14 @@ export class CustomElementFixture { public $(selector: string, inShadow = true): TElement { if (inShadow) { - return this.element.shadowRoot!.querySelector(selector)!; + return this.element.renderRoot.querySelector(selector)!; } else { return this.element.querySelector(selector)!; } } public $$(selector: string): TElement[] { - return [...this.element.shadowRoot!.querySelectorAll(selector)]; + return [...this.element.renderRoot.querySelectorAll(selector)]; } public get style(): CSSStyleDeclaration {