From cb481eeccca9ebaeec9288ee32ac2ad5c3369075 Mon Sep 17 00:00:00 2001 From: Edwin Hernandez Date: Tue, 27 May 2025 17:11:51 -0500 Subject: [PATCH 1/2] Create to haveFocus assertion and tests --- packages/dom/src/lib/ElementAssertion.ts | 28 ++++++++++++++++ .../test/unit/lib/ElementAssertion.test.tsx | 33 +++++++++++++++++++ .../unit/lib/fixtures/focusTestComponent.tsx | 10 ++++++ 3 files changed, 71 insertions(+) create mode 100644 packages/dom/test/unit/lib/fixtures/focusTestComponent.tsx 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 ( +
+ + +
+ ); +} From 0c7968db2236a5554014868b15ae145d25a2283c Mon Sep 17 00:00:00 2001 From: Edwin Hernandez Date: Fri, 22 Aug 2025 16:02:02 -0500 Subject: [PATCH 2/2] Updated output messages --- packages/dom/src/lib/ElementAssertion.ts | 4 ++-- packages/dom/test/unit/lib/ElementAssertion.test.tsx | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/dom/src/lib/ElementAssertion.ts b/packages/dom/src/lib/ElementAssertion.ts index 32e464d..a0e51e9 100644 --- a/packages/dom/src/lib/ElementAssertion.ts +++ b/packages/dom/src/lib/ElementAssertion.ts @@ -154,13 +154,13 @@ export class ElementAssertion extends Assertion { const error = new AssertionError({ actual: this.actual, expected: document.activeElement, - message: "Expected the element to have focus.", + message: "Expected the element to be focused", }); const invertedError = new AssertionError({ actual: this.actual, expected: document.activeElement, - message: "Expected the element not to have focus.", + message: "Expected the element NOT to be focused", }); return this.execute({ diff --git a/packages/dom/test/unit/lib/ElementAssertion.test.tsx b/packages/dom/test/unit/lib/ElementAssertion.test.tsx index 105419c..7b0f46c 100644 --- a/packages/dom/test/unit/lib/ElementAssertion.test.tsx +++ b/packages/dom/test/unit/lib/ElementAssertion.test.tsx @@ -278,7 +278,7 @@ describe("[Unit] ElementAssertion.test.ts", () => { expect(() => test.not.toHaveFocus()) .toThrowError(AssertionError) - .toHaveMessage("Expected the element not to have focus."); + .toHaveMessage("Expected the element NOT to be focused"); }); }); @@ -286,13 +286,11 @@ describe("[Unit] ElementAssertion.test.ts", () => { it("throws an assertion error", () => { const { getByTestId } = render(); const input1 = getByTestId("input1"); - const input2 = getByTestId("input2"); - input1.focus(); - const test = new ElementAssertion(input2); + const test = new ElementAssertion(input1); expect(() => test.toHaveFocus()) .toThrowError(AssertionError) - .toHaveMessage("Expected the element to have focus."); + .toHaveMessage("Expected the element to be focused"); expect(test.not.toHaveFocus()).toBeEqual(test); });