Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion packages/dom/src/lib/ElementAssertion.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Assertion, AssertionError } from "@assertive-ts/core";
import equal from "fast-deep-equal";

import { getExpectedAndReceivedStyles } from "./helpers/helpers";
import { getExpectedAndReceivedStyles, isElementEmpty } from "./helpers/helpers";

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

Expand Down Expand Up @@ -260,6 +260,38 @@ export class ElementAssertion<T extends Element> extends Assertion<T> {
});
}

/**
* Asserts that the element does not contain child nodes, excluding comments.
*
* @example
* ```
* expect(component).toBeEmpty();
* ```
*
* @returns the assertion instance.
*/

public toBeEmpty(): this {

const isEmpty = isElementEmpty(this.actual);

const error = new AssertionError({
actual: this.actual,
message: "Expected the element to be empty.",
});

const invertedError = new AssertionError({
actual: this.actual,
message: "Expected the element NOT to be empty.",
});

return this.execute({
assertWhen: isEmpty,
error,
invertedError,
});
}

/**
* Helper method to assert the presence or absence of class names.
*
Expand Down
11 changes: 8 additions & 3 deletions packages/dom/src/lib/helpers/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ function getReceivedStyle (props: string[], received: CSSStyleDeclaration): Styl
}, {} as StyleDeclaration);
}

export const getExpectedAndReceivedStyles =
(actual: Element, expected: Partial<CSSStyleDeclaration>): StyleDeclaration[] => {
export function getExpectedAndReceivedStyles
(actual: Element, expected: Partial<CSSStyleDeclaration>): StyleDeclaration[] {
if (!actual.ownerDocument.defaultView) {
throw new Error("The element is not attached to a document with a default view.");
}
Expand All @@ -72,4 +72,9 @@ export const getExpectedAndReceivedStyles =
expectedStyle,
elementProcessedStyle,
];
};
}

export function isElementEmpty (element: Element): boolean {
Copy link
Contributor Author

@SbsCruz SbsCruz Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a little comment about this function team, this is a helper indeed, but since we have a lot of helpers for the styles matchers in this file, should we rename it to something like helpers/style.ts? causing the isElementEmpty function to be moved to another file? or are we ok with what we have now, thanks!

const nonCommentChildNodes = [...element.childNodes].filter(child => child.nodeType !== 8);
return nonCommentChildNodes.length === 0;
}
54 changes: 54 additions & 0 deletions packages/dom/test/unit/lib/ElementAssertion.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -411,4 +411,58 @@ describe("[Unit] ElementAssertion.test.ts", () => {
});
});
});

describe(".toBeEmpty", () => {
context("when the element does not contain any child node", () => {
it("returns the assertion instance", () => {
const { getByTestId } = render(<div data-testid="test-div" />);
const divTest = getByTestId("test-div");
const test = new ElementAssertion(divTest);

expect(test.toBeEmpty()).toBeEqual(test);

expect(() => test.not.toBeEmpty())
.toThrowError(AssertionError)
.toHaveMessage("Expected the element NOT to be empty.");

});
});

context("when the element contains a comment node", () => {
it("returns the assertion instance", () => {
const { getByTestId } = render(<div data-testid="test-div" />);
const divTest = getByTestId("test-div");
const comment = document.createComment("test comment");
divTest.appendChild(comment);
const test = new ElementAssertion(divTest);

expect(test.toBeEmpty()).toBeEqual(test);

expect(() => test.not.toBeEmpty())
.toThrowError(AssertionError)
.toHaveMessage("Expected the element NOT to be empty.");

});
});

context("when the element contains a child node", () => {
it("throws an assertion error", () => {
const { getByTestId } = render(<div data-testid="test-div" />);
const divTest = getByTestId("test-div");

const emptyDiv = document.createElement("div");
divTest.appendChild(emptyDiv);

const test = new ElementAssertion(divTest);

expect(() => test.toBeEmpty())
.toThrowError(AssertionError)
.toHaveMessage("Expected the element to be empty.");

expect(test.not.toBeEmpty()).toBeEqual(test);

});
});
});

});