Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support ShadowRoot, add tests for rootElement, fixes #2089 #2090

Merged
merged 2 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 7 additions & 1 deletion API.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Once installed the DOM element assertions are available at `assert.dom(...).*`:
**Parameters**

* `target` **([string][114] | [HTMLElement][115])** A CSS selector that can be used to find elements using [`querySelector()`][116], or an \[HTMLElement]\[] (Not all assertions support both target types.) (optional, default `rootElement` or `document`)
* `rootElement` **[HTMLElement][115]?** The root element of the DOM in which to search for the `target` (optional, default `document`)
* `rootElement` **([HTMLElement][115] | [Document][152] | [ShadowRoot][153] | [null][154])?** The root element of the DOM in which to search for the `target` (optional, defaults `document` when `null` or not provided)

**Examples**

Expand Down Expand Up @@ -1194,3 +1194,9 @@ assert.dom('section#block').doesNotHaveTagName('div');
[150]: #hasValue

[151]: https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName

[152]: https://developer.mozilla.org/en-US/docs/Web/API/Document

[153]: https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot

[154]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/null
152 changes: 152 additions & 0 deletions packages/qunit-dom/lib/__tests__/root-element.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { describe, beforeEach, test, expect } from 'vitest';

import TestAssertions from '../helpers/test-assertions';

describe('assert.dom(..., rootElement)', () => {
let assert: TestAssertions;

beforeEach(() => {
assert = new TestAssertions();
});

test('passing an Element as rootElement', () => {
document.body.innerHTML = `
<span class="target">dedcoy<span>

<h1 class="parent">
<span class="target">real target<span>
</h1>
`;

const rootElement = document.querySelector('.parent');

assert.dom('.target', rootElement).exists({ count: 1 });
assert.dom('.target', rootElement).hasText('real target');

expect(assert.results).toEqual([
{
result: true,
actual: 'Element .target exists once',
expected: 'Element .target exists once',
message: 'Element .target exists once',
},
{
result: true,
actual: 'real target',
expected: 'real target',
message: 'Element .target has text "real target"',
},
]);
});

test('not passing anything as rootElement', () => {
document.body.innerHTML = `
<span class="target">decoy<span>

<h1 class="parent">
<span class="target">real target<span>
</h1>
`;

assert.dom('.target').exists({ count: 2 });

expect(assert.results).toEqual([
{
result: true,
actual: 'Element .target exists twice',
expected: 'Element .target exists twice',
message: 'Element .target exists twice',
},
]);
});

test('passing document as rootElement', () => {
document.body.innerHTML = `
<span class="target">decoy<span>

<h1 class="parent">
<span class="target">real target<span>
</h1>
`;

assert.dom('.target', document).exists({ count: 2 });

expect(assert.results).toEqual([
{
result: true,
actual: 'Element .target exists twice',
expected: 'Element .target exists twice',
message: 'Element .target exists twice',
},
]);
});

test('passing null as rootElement', () => {
document.body.innerHTML = `
<span class="target">decoy<span>

<h1 class="parent">
<span class="target">real target<span>
</h1>
`;

assert.dom('.target', null).exists({ count: 2 });

expect(assert.results).toEqual([
{
result: true,
actual: 'Element .target exists twice',
expected: 'Element .target exists twice',
message: 'Element .target exists twice',
},
]);
});

test('passing shadow root as rootElement', () => {
document.body.innerHTML = `
<div id="container">
<span class="target">decoy<span>
</div>
`;

const container = document.getElementById('container');
const shadowRoot = container.attachShadow({ mode: 'closed' });

shadowRoot.innerHTML = '<span class="target">real target<span>';

assert.dom('.target').exists({ count: 1 }, 'Only decoy element is found outside shadow root');
assert.dom('.target').hasText('real target', 'decoy element text');

assert.dom('.target', shadowRoot).exists({ count: 1 }, 'Only target found in shadow root');
assert.dom('.target', shadowRoot).hasText('real target', 'Target element text');

console.log(assert.results);

expect(assert.results).toEqual([
{
result: true,
actual: 'Element .target exists once',
expected: 'Element .target exists once',
message: 'Only decoy element is found outside shadow root',
},
{
result: false,
actual: 'decoy',
expected: 'real target',
message: 'decoy element text',
},
{
result: true,
actual: 'Element .target exists once',
expected: 'Element .target exists once',
message: 'Only target found in shadow root',
},
{
result: true,
actual: 'real target',
expected: 'real target',
message: 'Target element text',
},
]);
});
});
2 changes: 1 addition & 1 deletion packages/qunit-dom/lib/assertions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type ActualCSSStyleDeclaration = Partial<Record<CSSStyleDeclarationProperty, unk
export default class DOMAssertions {
constructor(
private target: string | Element | null,
private rootElement: Element | Document,
private rootElement: RootElement,
private testContext: Assert
) {}

Expand Down
2 changes: 1 addition & 1 deletion packages/qunit-dom/lib/helpers/test-assertions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import DOMAssertions, { type AssertionResult } from '../assertions.js';
export default class TestAssertions {
public results: AssertionResult[] = [];

dom(target: string | Element | null, rootElement?: Element) {
dom(target: string | Element | null, rootElement?: RootElement) {
return new DOMAssertions(target, rootElement || document, this as any);
}

Expand Down
9 changes: 7 additions & 2 deletions packages/qunit-dom/lib/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import DOMAssertions from './assertions.js';
import { getRootElement } from './root-element.js';

declare global {
type RootElement = Element | Document | ShadowRoot | null;

interface Assert {
dom(target?: string | Element | null, rootElement?: Element): DOMAssertions;
dom(target?: string | Element | null, rootElement?: RootElement): DOMAssertions;
}
}

export default function (assert: Assert) {
assert.dom = function (target?: string | Element | null, rootElement?: Element): DOMAssertions {
assert.dom = function (
target?: string | Element | null,
rootElement?: RootElement
): DOMAssertions {
if (!isValidRootElement(rootElement)) {
throw new Error(`${rootElement} is not a valid root element`);
}
Expand Down