Skip to content

Commit 8d7ffba

Browse files
authored
feat(dom): DOM - toContainElement (#132)
1 parent 975c8b2 commit 8d7ffba

File tree

5 files changed

+146
-23
lines changed

5 files changed

+146
-23
lines changed

packages/dom/src/lib/ElementAssertion.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,29 @@ export class ElementAssertion<T extends Element> extends Assertion<T> {
3131
});
3232
}
3333

34+
/**
35+
* Check if a given container element contains a specified child element.
36+
*
37+
* @param element the child expected to be contained.
38+
* @returns the assertion instance.
39+
*/
40+
public toContainElement(element: Element): this {
41+
const error = new AssertionError({
42+
actual: this.actual,
43+
message: "Expected the container to contain the element",
44+
});
45+
const invertedError = new AssertionError({
46+
actual: this.actual,
47+
message: "Expected the container to NOT contain the element",
48+
});
49+
50+
return this.execute({
51+
assertWhen: this.actual.contains(element),
52+
error,
53+
invertedError,
54+
});
55+
}
56+
3457
/**
3558
* Check if the element has a specific attribute.
3659
*
@@ -67,5 +90,4 @@ export class ElementAssertion<T extends Element> extends Assertion<T> {
6790
invertedError,
6891
});
6992
}
70-
7193
}

packages/dom/test/unit/lib/ElementAssertion.test.tsx

Lines changed: 85 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,17 @@
11
import { AssertionError, expect } from "@assertive-ts/core";
22
import { render } from "@testing-library/react";
3-
import { ReactElement } from "react";
43

54
import { ElementAssertion } from "../../../src/lib/ElementAssertion";
65

7-
function TestComponent(): ReactElement {
8-
return (
9-
<div>
10-
<button>click me</button>
11-
</div>
12-
);
13-
}
14-
15-
function TestComponentElement(): ReactElement {
16-
return (
17-
<button role="button" type="submit" className="btn primary" disabled>
18-
click me
19-
</button>
20-
);
21-
}
6+
import { NestedElementsTestComponent } from "./fixtures/nestedElementsTestComponent";
7+
import { SimpleTestComponent } from "./fixtures/simpleTestComponent";
8+
import { WithAttributesTestComponent } from "./fixtures/withAttributesTestComponent";
229

2310
describe("[Unit] ElementAssertion.test.ts", () => {
2411
describe(".toBeInTheDocument", () => {
2512
context("when the element is in the document", () => {
2613
it("returns the assertion instance", async () => {
27-
const { findByRole } = render(<TestComponent />);
14+
const { findByRole } = render(<SimpleTestComponent />);
2815
const button = await findByRole("button", { name: "click me" });
2916
const test = new ElementAssertion(button);
3017

@@ -39,7 +26,6 @@ describe("[Unit] ElementAssertion.test.ts", () => {
3926
context("when the element is not in the document", () => {
4027
it("throws an assertion error", () => {
4128
const detachedElement = document.createElement("div");
42-
4329
const test = new ElementAssertion(detachedElement);
4430

4531
expect(() => test.toBeInTheDocument())
@@ -51,10 +37,87 @@ describe("[Unit] ElementAssertion.test.ts", () => {
5137
});
5238
});
5339

40+
describe(".toContainElement", () => {
41+
context("when the descendant element is contained in the ancestor element", () => {
42+
context("and it is a direct child", () => {
43+
it("returns the assertion instance", async () => {
44+
const { findByTestId } = render(<NestedElementsTestComponent />);
45+
const grandparent = await findByTestId("grandparent");
46+
const parent = await findByTestId("parent");
47+
const child = await findByTestId("child");
48+
const svgElement = await findByTestId("svg-element");
49+
const grandparentTest = new ElementAssertion(grandparent);
50+
const parentTest = new ElementAssertion(parent);
51+
52+
expect(grandparentTest.toContainElement(parent));
53+
expect(grandparentTest.toContainElement(svgElement));
54+
expect(parentTest.toContainElement(child));
55+
56+
expect(() => grandparentTest.not.toContainElement(parent))
57+
.toThrowError(AssertionError)
58+
.toHaveMessage("Expected the container to NOT contain the element");
59+
60+
expect(() => grandparentTest.not.toContainElement(svgElement))
61+
.toThrowError(AssertionError)
62+
.toHaveMessage("Expected the container to NOT contain the element");
63+
64+
expect(() => parentTest.not.toContainElement(child))
65+
.toThrowError(AssertionError)
66+
.toHaveMessage("Expected the container to NOT contain the element");
67+
});
68+
});
69+
70+
context("and it is an indirect child", () => {
71+
it("returns the assertion instance", async () => {
72+
const { findByTestId } = render(<NestedElementsTestComponent/>);
73+
const grandparent = await findByTestId("grandparent");
74+
const child = await findByTestId("child");
75+
const grandparentTest = new ElementAssertion(grandparent);
76+
77+
expect(grandparentTest.toContainElement(child));
78+
79+
expect(() => grandparentTest.not.toContainElement(child))
80+
.toThrowError(AssertionError)
81+
.toHaveMessage("Expected the container to NOT contain the element");
82+
});
83+
});
84+
85+
context("and it is a deeply nested child", () => {
86+
it("returns the assertion instance", async () => {
87+
const { findByTestId } = render(<NestedElementsTestComponent/>);
88+
const grandparent = await findByTestId("grandparent");
89+
const deepChild = await findByTestId("deep-child");
90+
const grandparentTest = new ElementAssertion(grandparent);
91+
92+
expect(grandparentTest.toContainElement(deepChild));
93+
94+
expect(() => grandparentTest.not.toContainElement(deepChild))
95+
.toThrowError(AssertionError)
96+
.toHaveMessage("Expected the container to NOT contain the element");
97+
});
98+
});
99+
});
100+
101+
context("when element is NOT contained in ancestor element", () => {
102+
it("throws an assertion error", async () => {
103+
const notChildElement = document.createElement("span");
104+
const { findByTestId } = render(<NestedElementsTestComponent/>);
105+
const grandparent = await findByTestId("grandparent");
106+
const grandparentTest = new ElementAssertion(grandparent);
107+
108+
expect(() => grandparentTest.toContainElement(notChildElement))
109+
.toThrowError(AssertionError)
110+
.toHaveMessage("Expected the container to contain the element");
111+
112+
expect(grandparentTest.not.toContainElement(notChildElement)).toBeEqual(grandparentTest);
113+
});
114+
});
115+
});
116+
54117
describe(".toHaveAttribute", () => {
55118
context("when the element has the attribute with the expected value", () => {
56119
it("returns the assertion instance", async () => {
57-
const { findByRole } = render(<TestComponentElement />);
120+
const { findByRole } = render(<WithAttributesTestComponent />);
58121
const button = await findByRole("button", { name: "click me" });
59122
const test = new ElementAssertion(button);
60123

@@ -68,7 +131,7 @@ describe("[Unit] ElementAssertion.test.ts", () => {
68131

69132
context("when the element has the attribute with a not expected value", () => {
70133
it("throws an assertion error", async () => {
71-
const { findByRole } = render(<TestComponentElement />);
134+
const { findByRole } = render(<WithAttributesTestComponent />);
72135
const button = await findByRole("button", { name: "click me" });
73136
const test = new ElementAssertion(button);
74137

@@ -83,7 +146,7 @@ describe("[Unit] ElementAssertion.test.ts", () => {
83146

84147
context("when the element has the attribute without checking value", () => {
85148
it("returns the assertion instance", async () => {
86-
const { findByRole } = render(<TestComponentElement />);
149+
const { findByRole } = render(<WithAttributesTestComponent />);
87150
const button = await findByRole("button", { name: "click me" });
88151
const test = new ElementAssertion(button);
89152

@@ -97,7 +160,7 @@ describe("[Unit] ElementAssertion.test.ts", () => {
97160

98161
context("when the element does not have the attribute", () => {
99162
it("throws an assertion error", async () => {
100-
const { findByRole } = render(<TestComponentElement />);
163+
const { findByRole } = render(<WithAttributesTestComponent />);
101164
const button = await findByRole("button", { name: "click me" });
102165
const test = new ElementAssertion(button);
103166

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { ReactElement } from "react";
2+
3+
export function NestedElementsTestComponent(): ReactElement {
4+
return (
5+
<span data-testid="grandparent">
6+
<span data-testid="parent">
7+
<span data-testid="child">
8+
<span>
9+
<span>
10+
<span>
11+
<span data-testid="deep-child"></span>
12+
</span>
13+
</span>
14+
</span>
15+
</span>
16+
</span>
17+
<svg data-testid="svg-element"></svg>
18+
</span>
19+
);
20+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { ReactElement } from "react";
2+
3+
export function SimpleTestComponent(): ReactElement {
4+
return (
5+
<div>
6+
<button>click me</button>
7+
</div>
8+
);
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { ReactElement } from "react";
2+
3+
export function WithAttributesTestComponent(): ReactElement {
4+
return (
5+
<button role="button" type="submit" className="btn primary" disabled={true}>
6+
click me
7+
</button>
8+
);
9+
}

0 commit comments

Comments
 (0)