diff --git a/packages/dom/src/lib/ElementAssertion.ts b/packages/dom/src/lib/ElementAssertion.ts index 21b1faf..8e7692f 100644 --- a/packages/dom/src/lib/ElementAssertion.ts +++ b/packages/dom/src/lib/ElementAssertion.ts @@ -434,6 +434,46 @@ export class ElementAssertion extends Assertion { }); } + /** + * Asserts that the element contains the specified HTML. + * + * @example + * ``` + * expect(container).toContainHTML('Hello'); + * expect(container).toContainHTML('
Bar
'); + * ``` + * + * @param htmlText The HTML text that should be contained in the element + * @returns the assertion instance. + */ + public toContainHTML(htmlText: string): this { + if (typeof htmlText !== "string") { + throw new Error(`.toContainHTML() expects a string value, got ${typeof htmlText}`); + } + + if (htmlText === "") { + throw new Error(".toContainHTML() expects a non-empty string"); + } + + const error = new AssertionError({ + actual: this.actual, + expected: htmlText, + message: `Expected the element to contain HTML: ${htmlText}`, + }); + + const invertedError = new AssertionError({ + actual: this.actual, + expected: htmlText, + message: `Expected the element NOT to contain HTML: ${htmlText}`, + }); + + return this.execute({ + assertWhen: this.actual.outerHTML.includes(htmlText), + error, + invertedError, + }); + } + /** * Helper method to assert the presence or absence of class names. * diff --git a/packages/dom/test/unit/lib/ElementAssertion.test.tsx b/packages/dom/test/unit/lib/ElementAssertion.test.tsx index ec746b2..63472c5 100644 --- a/packages/dom/test/unit/lib/ElementAssertion.test.tsx +++ b/packages/dom/test/unit/lib/ElementAssertion.test.tsx @@ -8,6 +8,7 @@ import { NestedElementsTest } from "./fixtures/NestedElementsTest"; import { PressedTestComponent } from "./fixtures/PressedTestComponent"; import { SimpleTest } from "./fixtures/SimpleTest"; import { WithAttributesTest } from "./fixtures/WithAttributesTest"; +import { ContainHtmlTestComponent } from "./fixtures/containHtmlTestComponent"; import { DescriptionTestComponent } from "./fixtures/descriptionTestComponent"; import { FocusTestComponent } from "./fixtures/focusTestComponent"; @@ -823,4 +824,72 @@ describe("[Unit] ElementAssertion.test.ts", () => { }); }); }); + + describe(".toContainHTML", () => { + context("when the element contains the expected HTML", () => { + it("returns the assertion instance", () => { + const { getByTestId } = render(); + const container = getByTestId("container"); + const test = new ElementAssertion(container); + + expect(test.toContainHTML('Hello World')).toBeEqual(test); + + expect(() => test.not.toContainHTML('Hello World')) + .toThrowError(AssertionError) + .toHaveMessage('Expected the element NOT to contain HTML: Hello World'); + }); + }); + + context("when the element contains nested HTML", () => { + it("returns the assertion instance", () => { + const { getByTestId } = render(); + const container = getByTestId("container"); + const test = new ElementAssertion(container); + + expect(test.toContainHTML("

Nested content

")).toBeEqual(test); + + expect(() => test.not.toContainHTML("

Nested content

")) + .toThrowError(AssertionError) + .toHaveMessage("Expected the element NOT to contain HTML:

Nested content

"); + }); + }); + + context("when the element does not contain the expected HTML", () => { + it("throws an assertion error", () => { + const { getByTestId } = render(); + const container = getByTestId("container"); + const test = new ElementAssertion(container); + + expect(() => test.toContainHTML("
Not present
")) + .toThrowError(AssertionError) + .toHaveMessage("Expected the element to contain HTML:
Not present
"); + + expect(test.not.toContainHTML("
Not present
")).toBeEqual(test); + }); + }); + + context("when a non-string value is passed", () => { + it("throws an error", () => { + const { getByTestId } = render(); + const container = getByTestId("container"); + const test = new ElementAssertion(container); + + expect(() => test.toContainHTML(123 as unknown as string)) + .toThrowError(Error) + .toHaveMessage(".toContainHTML() expects a string value, got number"); + }); + }); + + context("when an empty string is passed", () => { + it("throws an error", () => { + const { getByTestId } = render(); + const container = getByTestId("container"); + const test = new ElementAssertion(container); + + expect(() => test.toContainHTML("")) + .toThrowError(Error) + .toHaveMessage(".toContainHTML() expects a non-empty string"); + }); + }); + }); }); diff --git a/packages/dom/test/unit/lib/fixtures/containHtmlTestComponent.tsx b/packages/dom/test/unit/lib/fixtures/containHtmlTestComponent.tsx new file mode 100644 index 0000000..6e07da3 --- /dev/null +++ b/packages/dom/test/unit/lib/fixtures/containHtmlTestComponent.tsx @@ -0,0 +1,12 @@ +import type { ReactElement } from "react"; + +export function ContainHtmlTestComponent(): ReactElement { + return ( +
+ {"Hello World"} +
+

{"Nested content"}

+
+
+ ); +}