diff --git a/packages/dom/src/lib/ElementAssertion.ts b/packages/dom/src/lib/ElementAssertion.ts index 537d808..32e464d 100644 --- a/packages/dom/src/lib/ElementAssertion.ts +++ b/packages/dom/src/lib/ElementAssertion.ts @@ -142,6 +142,34 @@ export class ElementAssertion extends Assertion { ); } + /** + * Check if the provided element is currently focused in the document. + * + * @returns The assertion instance. + */ + public toHaveFocus(): this { + + const hasFocus = this.actual === document.activeElement; + + const error = new AssertionError({ + actual: this.actual, + expected: document.activeElement, + message: "Expected the element to have focus.", + }); + + const invertedError = new AssertionError({ + actual: this.actual, + expected: document.activeElement, + message: "Expected the element not to have focus.", + }); + + return this.execute({ + assertWhen: hasFocus, + error, + invertedError, + }); + } + private getClassList(): string[] { return this.actual.className.split(/\s+/).filter(Boolean); } diff --git a/packages/dom/test/unit/lib/ElementAssertion.test.tsx b/packages/dom/test/unit/lib/ElementAssertion.test.tsx index 47bb167..105419c 100644 --- a/packages/dom/test/unit/lib/ElementAssertion.test.tsx +++ b/packages/dom/test/unit/lib/ElementAssertion.test.tsx @@ -3,6 +3,7 @@ import { render } from "@testing-library/react"; import { ElementAssertion } from "../../../src/lib/ElementAssertion"; +import { FocusTestComponent } from "./fixtures/focusTestComponent"; import { HaveClassTestComponent } from "./fixtures/haveClassTestComponent"; import { NestedElementsTestComponent } from "./fixtures/nestedElementsTestComponent"; import { SimpleTestComponent } from "./fixtures/simpleTestComponent"; @@ -265,4 +266,36 @@ describe("[Unit] ElementAssertion.test.ts", () => { }); }); + describe(".toHaveFocus", () => { + context("when the element has focus", () => { + it("returns the assertion instance", () => { + const { getByTestId } = render(); + const input1 = getByTestId("input1"); + input1.focus(); + const test = new ElementAssertion(input1); + + expect(test.toHaveFocus()).toBeEqual(test); + + expect(() => test.not.toHaveFocus()) + .toThrowError(AssertionError) + .toHaveMessage("Expected the element not to have focus."); + }); + }); + + context("when the element does not have focus", () => { + it("throws an assertion error", () => { + const { getByTestId } = render(); + const input1 = getByTestId("input1"); + const input2 = getByTestId("input2"); + input1.focus(); + const test = new ElementAssertion(input2); + + expect(() => test.toHaveFocus()) + .toThrowError(AssertionError) + .toHaveMessage("Expected the element to have focus."); + + expect(test.not.toHaveFocus()).toBeEqual(test); + }); + }); + }); }); diff --git a/packages/dom/test/unit/lib/fixtures/focusTestComponent.tsx b/packages/dom/test/unit/lib/fixtures/focusTestComponent.tsx new file mode 100644 index 0000000..91dd421 --- /dev/null +++ b/packages/dom/test/unit/lib/fixtures/focusTestComponent.tsx @@ -0,0 +1,10 @@ +import { ReactElement } from "react"; + +export function FocusTestComponent(): ReactElement { + return ( +
+ + +
+ ); +}