Skip to content

Commit 23f854f

Browse files
authored
feat(dom): DOM - toBeEmpty (#162)
1 parent c627ade commit 23f854f

File tree

3 files changed

+97
-4
lines changed

3 files changed

+97
-4
lines changed

packages/dom/src/lib/ElementAssertion.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Assertion, AssertionError } from "@assertive-ts/core";
22
import equal from "fast-deep-equal";
33

4-
import { getExpectedAndReceivedStyles } from "./helpers/helpers";
4+
import { getExpectedAndReceivedStyles, isElementEmpty } from "./helpers/helpers";
55

66
export class ElementAssertion<T extends Element> extends Assertion<T> {
77

@@ -260,6 +260,38 @@ export class ElementAssertion<T extends Element> extends Assertion<T> {
260260
});
261261
}
262262

263+
/**
264+
* Asserts that the element does not contain child nodes, excluding comments.
265+
*
266+
* @example
267+
* ```
268+
* expect(component).toBeEmpty();
269+
* ```
270+
*
271+
* @returns the assertion instance.
272+
*/
273+
274+
public toBeEmpty(): this {
275+
276+
const isEmpty = isElementEmpty(this.actual);
277+
278+
const error = new AssertionError({
279+
actual: this.actual,
280+
message: "Expected the element to be empty.",
281+
});
282+
283+
const invertedError = new AssertionError({
284+
actual: this.actual,
285+
message: "Expected the element NOT to be empty.",
286+
});
287+
288+
return this.execute({
289+
assertWhen: isEmpty,
290+
error,
291+
invertedError,
292+
});
293+
}
294+
263295
/**
264296
* Helper method to assert the presence or absence of class names.
265297
*

packages/dom/src/lib/helpers/helpers.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ interface StyleDeclaration extends Record<string, string> {
33
value: string;
44
}
55

6+
const COMMENT_NODE_TYPE = 8;
7+
68
function normalizeStyles(css: Partial<CSSStyleDeclaration>): StyleDeclaration {
79
const normalizer = document.createElement("div");
810
document.body.appendChild(normalizer);
@@ -49,8 +51,8 @@ function getReceivedStyle (props: string[], received: CSSStyleDeclaration): Styl
4951
}, {} as StyleDeclaration);
5052
}
5153

52-
export const getExpectedAndReceivedStyles =
53-
(actual: Element, expected: Partial<CSSStyleDeclaration>): StyleDeclaration[] => {
54+
export function getExpectedAndReceivedStyles
55+
(actual: Element, expected: Partial<CSSStyleDeclaration>): StyleDeclaration[] {
5456
if (!actual.ownerDocument.defaultView) {
5557
throw new Error("The element is not attached to a document with a default view.");
5658
}
@@ -72,4 +74,9 @@ export const getExpectedAndReceivedStyles =
7274
expectedStyle,
7375
elementProcessedStyle,
7476
];
75-
};
77+
}
78+
79+
export function isElementEmpty (element: Element): boolean {
80+
const nonCommentChildNodes = [...element.childNodes].filter(child => child.nodeType !== COMMENT_NODE_TYPE);
81+
return nonCommentChildNodes.length === 0;
82+
}

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,4 +411,58 @@ describe("[Unit] ElementAssertion.test.ts", () => {
411411
});
412412
});
413413
});
414+
415+
describe(".toBeEmpty", () => {
416+
context("when the element does not contain any child node", () => {
417+
it("returns the assertion instance", () => {
418+
const { getByTestId } = render(<div data-testid="test-div" />);
419+
const divTest = getByTestId("test-div");
420+
const test = new ElementAssertion(divTest);
421+
422+
expect(test.toBeEmpty()).toBeEqual(test);
423+
424+
expect(() => test.not.toBeEmpty())
425+
.toThrowError(AssertionError)
426+
.toHaveMessage("Expected the element NOT to be empty.");
427+
428+
});
429+
});
430+
431+
context("when the element contains a comment node", () => {
432+
it("returns the assertion instance", () => {
433+
const { getByTestId } = render(<div data-testid="test-div" />);
434+
const divTest = getByTestId("test-div");
435+
const comment = document.createComment("test comment");
436+
divTest.appendChild(comment);
437+
const test = new ElementAssertion(divTest);
438+
439+
expect(test.toBeEmpty()).toBeEqual(test);
440+
441+
expect(() => test.not.toBeEmpty())
442+
.toThrowError(AssertionError)
443+
.toHaveMessage("Expected the element NOT to be empty.");
444+
445+
});
446+
});
447+
448+
context("when the element contains a child node", () => {
449+
it("throws an assertion error", () => {
450+
const { getByTestId } = render(<div data-testid="test-div" />);
451+
const divTest = getByTestId("test-div");
452+
453+
const emptyDiv = document.createElement("div");
454+
divTest.appendChild(emptyDiv);
455+
456+
const test = new ElementAssertion(divTest);
457+
458+
expect(() => test.toBeEmpty())
459+
.toThrowError(AssertionError)
460+
.toHaveMessage("Expected the element to be empty.");
461+
462+
expect(test.not.toBeEmpty()).toBeEqual(test);
463+
464+
});
465+
});
466+
});
467+
414468
});

0 commit comments

Comments
 (0)