From 41d0f97fc51a080ed60576c335e8927a02378ff6 Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Mon, 17 Mar 2025 10:47:13 -0500 Subject: [PATCH 01/16] WIP: toBeEmpty function --- .../src/lib/ToBeEmptyElementAssertion.ts | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 packages/native/src/lib/ToBeEmptyElementAssertion.ts diff --git a/packages/native/src/lib/ToBeEmptyElementAssertion.ts b/packages/native/src/lib/ToBeEmptyElementAssertion.ts new file mode 100644 index 00000000..3b59632c --- /dev/null +++ b/packages/native/src/lib/ToBeEmptyElementAssertion.ts @@ -0,0 +1,51 @@ +import { Assertion, AssertionError } from "@assertive-ts/core"; +import { ReactTestInstance } from "react-test-renderer"; + +export class ToBeEmptyElementAssertion extends Assertion { + public constructor(actual: ReactTestInstance) { + super(actual); + } + + public override toString = (): string => { + if (this.actual === null) { + return "null"; + } + + return `<${this.actual.type.toString()} ... />`; + }; + + /** + * Check if the element is empty. + * + * @example + * ``` + * expect(element).toBeEmptyElement(); + * ``` + * + * @returns the assertion instance + */ + public toBeEmptyElement(): this { + const error = new AssertionError({ + actual: this.actual, + message: `Expected element ${this.toString()} to be empty.`, + }); + const invertedError = new AssertionError({ + actual: this.actual, + message: `Expected element ${this.toString()} to NOT be empty.`, + }); + + return this.execute({ + assertWhen: this.isEmpty(this.actual), + error, + invertedError, + }); + } + + private isEmpty(element: ReactTestInstance): boolean { + if(!element?.props?.children) { + return true; + } + + return element?.props?.children.length === 0; + } +} \ No newline at end of file From 6dfdd21db7f766971de9024499f662ca890d4443 Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Mon, 17 Mar 2025 10:47:33 -0500 Subject: [PATCH 02/16] toBeEmpty tests --- .../lib/ToBeEmptyElementAssertion.test.tsx | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 packages/native/test/lib/ToBeEmptyElementAssertion.test.tsx diff --git a/packages/native/test/lib/ToBeEmptyElementAssertion.test.tsx b/packages/native/test/lib/ToBeEmptyElementAssertion.test.tsx new file mode 100644 index 00000000..e28a680d --- /dev/null +++ b/packages/native/test/lib/ToBeEmptyElementAssertion.test.tsx @@ -0,0 +1,37 @@ +import { AssertionError, expect } from "@assertive-ts/core"; +import { render } from "@testing-library/react-native"; +import { View, Text } from "react-native"; + +import { ToBeEmptyElementAssertion } from "../../src/lib/ToBeEmptyElementAssertion"; + +describe("[Unit] ToBeEmptyElementAssertion.test.ts", () => { + describe(".toBeEmptyElement", () => { + context("when the element is empty", () => { + it("returns the assertion instance", () => { + const element = render(); + const test = new ToBeEmptyElementAssertion(element.getByTestId("id")); + + expect(test.toBeEmptyElement()).toBe(test); + expect(() => test.not.toBeEmptyElement()) + .toThrowError(AssertionError) + .toHaveMessage("Expected element to NOT be empty."); + }); + }); + + context("when the element is NOT empty", () => { + it("throws an error", () => { + const element = render( + + {"Not empty"} + , + ); + const test = new ToBeEmptyElementAssertion(element.getByTestId("id")); + + expect(test.not.toBeEmptyElement()).toBeEqual(test); + expect(() => test.toBeEmptyElement()) + .toThrowError(AssertionError) + .toHaveMessage("Expected element to be empty."); + }); + }); + }); +}); From debfd8ae11f4eb9277c0626354a4274d697539f6 Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Mon, 17 Mar 2025 13:01:15 -0500 Subject: [PATCH 03/16] Fix: use element 'children' --- packages/native/src/lib/ToBeEmptyElementAssertion.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/native/src/lib/ToBeEmptyElementAssertion.ts b/packages/native/src/lib/ToBeEmptyElementAssertion.ts index 3b59632c..ab0f2fd4 100644 --- a/packages/native/src/lib/ToBeEmptyElementAssertion.ts +++ b/packages/native/src/lib/ToBeEmptyElementAssertion.ts @@ -42,10 +42,16 @@ export class ToBeEmptyElementAssertion extends Assertion { } private isEmpty(element: ReactTestInstance): boolean { - if(!element?.props?.children) { + const children = element?.children; + + if (!children) { return true; } - return element?.props?.children.length === 0; + if (Array.isArray(children)) { + return children.length === 0; + } + + return false; } -} \ No newline at end of file +} From 496edc59a1a507808cb2f6429cc6542dad361354 Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Mon, 17 Mar 2025 15:45:03 -0500 Subject: [PATCH 04/16] CR: Move isEmpty to a helper file --- .../src/lib/ToBeEmptyElementAssertion.ts | 21 ++++++------------- packages/native/src/lib/helpers/helpers.ts | 15 +++++++++++++ 2 files changed, 21 insertions(+), 15 deletions(-) create mode 100644 packages/native/src/lib/helpers/helpers.ts diff --git a/packages/native/src/lib/ToBeEmptyElementAssertion.ts b/packages/native/src/lib/ToBeEmptyElementAssertion.ts index ab0f2fd4..b6bede40 100644 --- a/packages/native/src/lib/ToBeEmptyElementAssertion.ts +++ b/packages/native/src/lib/ToBeEmptyElementAssertion.ts @@ -1,6 +1,11 @@ import { Assertion, AssertionError } from "@assertive-ts/core"; import { ReactTestInstance } from "react-test-renderer"; +import { isEmpty } from "./helpers/helpers"; + +/** + * Assertion for checking if a React element is empty. + */ export class ToBeEmptyElementAssertion extends Assertion { public constructor(actual: ReactTestInstance) { super(actual); @@ -35,23 +40,9 @@ export class ToBeEmptyElementAssertion extends Assertion { }); return this.execute({ - assertWhen: this.isEmpty(this.actual), + assertWhen: isEmpty(this.actual), error, invertedError, }); } - - private isEmpty(element: ReactTestInstance): boolean { - const children = element?.children; - - if (!children) { - return true; - } - - if (Array.isArray(children)) { - return children.length === 0; - } - - return false; - } } diff --git a/packages/native/src/lib/helpers/helpers.ts b/packages/native/src/lib/helpers/helpers.ts new file mode 100644 index 00000000..afaf4d05 --- /dev/null +++ b/packages/native/src/lib/helpers/helpers.ts @@ -0,0 +1,15 @@ +import { ReactTestInstance } from "react-test-renderer"; + +export function isEmpty(element: ReactTestInstance): boolean { + const children = element?.children; + + if (!children) { + return true; + } + + if (Array.isArray(children)) { + return children.length === 0; + } + + return false; +} From 1f782720dc31584f1393299a46601fc39da39a9a Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Mon, 17 Mar 2025 15:55:33 -0500 Subject: [PATCH 05/16] Add isEmpty doc. --- .../src/lib/ToBeEmptyElementAssertion.ts | 2 +- packages/native/src/lib/helpers/helpers.ts | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/native/src/lib/ToBeEmptyElementAssertion.ts b/packages/native/src/lib/ToBeEmptyElementAssertion.ts index b6bede40..43d71b22 100644 --- a/packages/native/src/lib/ToBeEmptyElementAssertion.ts +++ b/packages/native/src/lib/ToBeEmptyElementAssertion.ts @@ -40,7 +40,7 @@ export class ToBeEmptyElementAssertion extends Assertion { }); return this.execute({ - assertWhen: isEmpty(this.actual), + assertWhen: isEmpty(this.actual.children), error, invertedError, }); diff --git a/packages/native/src/lib/helpers/helpers.ts b/packages/native/src/lib/helpers/helpers.ts index afaf4d05..76e6f2a6 100644 --- a/packages/native/src/lib/helpers/helpers.ts +++ b/packages/native/src/lib/helpers/helpers.ts @@ -1,14 +1,16 @@ -import { ReactTestInstance } from "react-test-renderer"; - -export function isEmpty(element: ReactTestInstance): boolean { - const children = element?.children; - - if (!children) { +/** + * Checks if a value is empty. + * + * @param value - The value to check. + * @returns `true` if the value is empty, `false` otherwise. + */ +export function isEmpty(value: unknown): boolean { + if (!value) { return true; } - if (Array.isArray(children)) { - return children.length === 0; + if (Array.isArray(value)) { + return value.length === 0; } return false; From f305bb4cf72237a2e321a472fc620fec508b37db Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Tue, 18 Mar 2025 13:01:54 -0500 Subject: [PATCH 06/16] Update: CR comments --- packages/native/src/lib/ElementAssertion.ts | 12 +++++------ ...mentAssertion.ts => ToBeEmptyAssertion.ts} | 16 ++++++--------- packages/native/src/lib/helpers/helpers.ts | 16 +++++++++++++++ .../native/test/lib/ElementAssertion.test.tsx | 12 +++++------ .../lib/ToBeEmptyElementAssertion.test.tsx | 20 +++++++++---------- 5 files changed, 43 insertions(+), 33 deletions(-) rename packages/native/src/lib/{ToBeEmptyElementAssertion.ts => ToBeEmptyAssertion.ts} (67%) diff --git a/packages/native/src/lib/ElementAssertion.ts b/packages/native/src/lib/ElementAssertion.ts index d1350b95..aa9d6804 100644 --- a/packages/native/src/lib/ElementAssertion.ts +++ b/packages/native/src/lib/ElementAssertion.ts @@ -2,17 +2,15 @@ import { Assertion, AssertionError } from "@assertive-ts/core"; import { get } from "dot-prop-immutable"; import { ReactTestInstance } from "react-test-renderer"; +import { instanceToString } from "./helpers/helpers"; + export class ElementAssertion extends Assertion { public constructor(actual: ReactTestInstance) { super(actual); } public override toString = (): string => { - if (this.actual === null) { - return "null"; - } - - return `<${this.actual.type.toString()} ... />`; + return instanceToString(this.actual); }; /** @@ -32,7 +30,7 @@ export class ElementAssertion extends Assertion { }); const invertedError = new AssertionError({ actual: this.actual, - message: `Expected element ${this.toString()} to NOT be disabled.`, + message: `Expected element ${this.toString()} NOT to be disabled.`, }); return this.execute({ @@ -58,7 +56,7 @@ export class ElementAssertion extends Assertion { }); const invertedError = new AssertionError({ actual: this.actual, - message: `Expected element ${this.toString()} to NOT be enabled.`, + message: `Expected element ${this.toString()} NOT to be enabled.`, }); return this.execute({ diff --git a/packages/native/src/lib/ToBeEmptyElementAssertion.ts b/packages/native/src/lib/ToBeEmptyAssertion.ts similarity index 67% rename from packages/native/src/lib/ToBeEmptyElementAssertion.ts rename to packages/native/src/lib/ToBeEmptyAssertion.ts index 43d71b22..b6bd6030 100644 --- a/packages/native/src/lib/ToBeEmptyElementAssertion.ts +++ b/packages/native/src/lib/ToBeEmptyAssertion.ts @@ -1,22 +1,18 @@ import { Assertion, AssertionError } from "@assertive-ts/core"; import { ReactTestInstance } from "react-test-renderer"; -import { isEmpty } from "./helpers/helpers"; +import { instanceToString, isEmpty } from "./helpers/helpers"; /** * Assertion for checking if a React element is empty. */ -export class ToBeEmptyElementAssertion extends Assertion { +export class ToBeEmptyAssertion extends Assertion { public constructor(actual: ReactTestInstance) { super(actual); } public override toString = (): string => { - if (this.actual === null) { - return "null"; - } - - return `<${this.actual.type.toString()} ... />`; + return instanceToString(this.actual); }; /** @@ -24,19 +20,19 @@ export class ToBeEmptyElementAssertion extends Assertion { * * @example * ``` - * expect(element).toBeEmptyElement(); + * expect(element).toBeEmpty(); * ``` * * @returns the assertion instance */ - public toBeEmptyElement(): this { + public toBeEmpty(): this { const error = new AssertionError({ actual: this.actual, message: `Expected element ${this.toString()} to be empty.`, }); const invertedError = new AssertionError({ actual: this.actual, - message: `Expected element ${this.toString()} to NOT be empty.`, + message: `Expected element ${this.toString()} NOT to be empty.`, }); return this.execute({ diff --git a/packages/native/src/lib/helpers/helpers.ts b/packages/native/src/lib/helpers/helpers.ts index 76e6f2a6..6ab4db1e 100644 --- a/packages/native/src/lib/helpers/helpers.ts +++ b/packages/native/src/lib/helpers/helpers.ts @@ -1,3 +1,5 @@ +import { ReactTestInstance } from "react-test-renderer"; + /** * Checks if a value is empty. * @@ -15,3 +17,17 @@ export function isEmpty(value: unknown): boolean { return false; } + +/** + * Converts a ReactTestInstance to a string representation. + * + * @param instance - The ReactTestInstance to convert. + * @returns A string representation of the instance. + */ +export function instanceToString(instance: ReactTestInstance | null): string { + if (instance === null) { + return "null"; + } + + return `<${instance.type.toString()} ... />`; +} diff --git a/packages/native/test/lib/ElementAssertion.test.tsx b/packages/native/test/lib/ElementAssertion.test.tsx index 6db8aba7..bdaabb40 100644 --- a/packages/native/test/lib/ElementAssertion.test.tsx +++ b/packages/native/test/lib/ElementAssertion.test.tsx @@ -34,7 +34,7 @@ describe("[Unit] ElementAssertion.test.ts", () => { .toHaveMessage("Expected element to be disabled."); expect(() => test.not.toBeEnabled()) .toThrowError(AssertionError) - .toHaveMessage("Expected element to NOT be enabled."); + .toHaveMessage("Expected element NOT to be enabled."); }); }); }); @@ -59,7 +59,7 @@ describe("[Unit] ElementAssertion.test.ts", () => { .toHaveMessage("Expected element to be enabled."); expect(() => parent.not.toBeDisabled()) .toThrowError(AssertionError) - .toHaveMessage("Expected element to NOT be disabled."); + .toHaveMessage("Expected element NOT to be disabled."); }); }); @@ -83,13 +83,13 @@ describe("[Unit] ElementAssertion.test.ts", () => { .toHaveMessage("Expected element to be disabled."); expect(() => parent.not.toBeEnabled()) .toThrowError(AssertionError) - .toHaveMessage("Expected element to NOT be enabled."); + .toHaveMessage("Expected element NOT to be enabled."); expect(() => child.toBeDisabled()) .toThrowError(AssertionError) .toHaveMessage("Expected element to be disabled."); expect(() => child.not.toBeEnabled()) .toThrowError(AssertionError) - .toHaveMessage("Expected element to NOT be enabled."); + .toHaveMessage("Expected element NOT to be enabled."); }); }); }); @@ -114,7 +114,7 @@ describe("[Unit] ElementAssertion.test.ts", () => { .toHaveMessage("Expected element to be enabled."); expect(() => child.not.toBeDisabled()) .toThrowError(AssertionError) - .toHaveMessage("Expected element to NOT be disabled."); + .toHaveMessage("Expected element NOT to be disabled."); }); it("returns error for parent element", () => { @@ -124,7 +124,7 @@ describe("[Unit] ElementAssertion.test.ts", () => { .toHaveMessage("Expected element to be disabled."); expect(() => parent.not.toBeEnabled()) .toThrowError(AssertionError) - .toHaveMessage("Expected element to NOT be enabled."); + .toHaveMessage("Expected element NOT to be enabled."); }); }); }); diff --git a/packages/native/test/lib/ToBeEmptyElementAssertion.test.tsx b/packages/native/test/lib/ToBeEmptyElementAssertion.test.tsx index e28a680d..86fcb218 100644 --- a/packages/native/test/lib/ToBeEmptyElementAssertion.test.tsx +++ b/packages/native/test/lib/ToBeEmptyElementAssertion.test.tsx @@ -2,19 +2,19 @@ import { AssertionError, expect } from "@assertive-ts/core"; import { render } from "@testing-library/react-native"; import { View, Text } from "react-native"; -import { ToBeEmptyElementAssertion } from "../../src/lib/ToBeEmptyElementAssertion"; +import { ToBeEmptyAssertion } from "../../src/lib/ToBeEmptyAssertion"; -describe("[Unit] ToBeEmptyElementAssertion.test.ts", () => { - describe(".toBeEmptyElement", () => { +describe("[Unit] toBeEmptyAssertion.test.ts", () => { + describe(".toBeEmpty", () => { context("when the element is empty", () => { it("returns the assertion instance", () => { const element = render(); - const test = new ToBeEmptyElementAssertion(element.getByTestId("id")); + const test = new ToBeEmptyAssertion(element.getByTestId("id")); - expect(test.toBeEmptyElement()).toBe(test); - expect(() => test.not.toBeEmptyElement()) + expect(test.toBeEmpty()).toBe(test); + expect(() => test.not.toBeEmpty()) .toThrowError(AssertionError) - .toHaveMessage("Expected element to NOT be empty."); + .toHaveMessage("Expected element NOT to be empty."); }); }); @@ -25,10 +25,10 @@ describe("[Unit] ToBeEmptyElementAssertion.test.ts", () => { {"Not empty"} , ); - const test = new ToBeEmptyElementAssertion(element.getByTestId("id")); + const test = new ToBeEmptyAssertion(element.getByTestId("id")); - expect(test.not.toBeEmptyElement()).toBeEqual(test); - expect(() => test.toBeEmptyElement()) + expect(test.not.toBeEmpty()).toBeEqual(test); + expect(() => test.toBeEmpty()) .toThrowError(AssertionError) .toHaveMessage("Expected element to be empty."); }); From aed8344bb10a1626210ab13fbff4808067322f13 Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Thu, 20 Mar 2025 12:53:04 -0500 Subject: [PATCH 07/16] Move toBeEmptyAssertion to the element assertions --- packages/native/src/lib/ElementAssertion.ts | 29 +++++++++++- packages/native/src/lib/ToBeEmptyAssertion.ts | 44 ------------------- .../native/test/lib/ElementAssertion.test.tsx | 31 +++++++++++++ .../lib/ToBeEmptyElementAssertion.test.tsx | 37 ---------------- 4 files changed, 59 insertions(+), 82 deletions(-) delete mode 100644 packages/native/src/lib/ToBeEmptyAssertion.ts delete mode 100644 packages/native/test/lib/ToBeEmptyElementAssertion.test.tsx diff --git a/packages/native/src/lib/ElementAssertion.ts b/packages/native/src/lib/ElementAssertion.ts index aa9d6804..283516c8 100644 --- a/packages/native/src/lib/ElementAssertion.ts +++ b/packages/native/src/lib/ElementAssertion.ts @@ -2,7 +2,7 @@ import { Assertion, AssertionError } from "@assertive-ts/core"; import { get } from "dot-prop-immutable"; import { ReactTestInstance } from "react-test-renderer"; -import { instanceToString } from "./helpers/helpers"; +import { instanceToString, isEmpty } from "./helpers/helpers"; export class ElementAssertion extends Assertion { public constructor(actual: ReactTestInstance) { @@ -66,6 +66,33 @@ export class ElementAssertion extends Assertion { }); } + /** + * Check if the element is empty. + * + * @example + * ``` + * expect(element).toBeEmpty(); + * ``` + * + * @returns the assertion instance + */ + public toBeEmpty(): this { + const error = new AssertionError({ + actual: this.actual, + message: `Expected element ${this.toString()} to be empty.`, + }); + const invertedError = new AssertionError({ + actual: this.actual, + message: `Expected element ${this.toString()} NOT to be empty.`, + }); + + return this.execute({ + assertWhen: isEmpty(this.actual.children), + error, + invertedError, + }); + } + private isElementDisabled(element: ReactTestInstance): boolean { const { type } = element; const elementType = type.toString(); diff --git a/packages/native/src/lib/ToBeEmptyAssertion.ts b/packages/native/src/lib/ToBeEmptyAssertion.ts deleted file mode 100644 index b6bd6030..00000000 --- a/packages/native/src/lib/ToBeEmptyAssertion.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Assertion, AssertionError } from "@assertive-ts/core"; -import { ReactTestInstance } from "react-test-renderer"; - -import { instanceToString, isEmpty } from "./helpers/helpers"; - -/** - * Assertion for checking if a React element is empty. - */ -export class ToBeEmptyAssertion extends Assertion { - public constructor(actual: ReactTestInstance) { - super(actual); - } - - public override toString = (): string => { - return instanceToString(this.actual); - }; - - /** - * Check if the element is empty. - * - * @example - * ``` - * expect(element).toBeEmpty(); - * ``` - * - * @returns the assertion instance - */ - public toBeEmpty(): this { - const error = new AssertionError({ - actual: this.actual, - message: `Expected element ${this.toString()} to be empty.`, - }); - const invertedError = new AssertionError({ - actual: this.actual, - message: `Expected element ${this.toString()} NOT to be empty.`, - }); - - return this.execute({ - assertWhen: isEmpty(this.actual.children), - error, - invertedError, - }); - } -} diff --git a/packages/native/test/lib/ElementAssertion.test.tsx b/packages/native/test/lib/ElementAssertion.test.tsx index bdaabb40..ce3b4419 100644 --- a/packages/native/test/lib/ElementAssertion.test.tsx +++ b/packages/native/test/lib/ElementAssertion.test.tsx @@ -3,6 +3,7 @@ import { render } from "@testing-library/react-native"; import { View, TextInput, + Text, } from "react-native"; import { ElementAssertion } from "../../src/lib/ElementAssertion"; @@ -129,4 +130,34 @@ describe("[Unit] ElementAssertion.test.ts", () => { }); }); }); + + describe(".toBeEmpty", () => { + context("when the element is empty", () => { + it("returns the assertion instance", () => { + const element = render(); + const test = new ElementAssertion(element.getByTestId("id")); + + expect(test.toBeEmpty()).toBe(test); + expect(() => test.not.toBeEmpty()) + .toThrowError(AssertionError) + .toHaveMessage("Expected element NOT to be empty."); + }); + }); + + context("when the element is NOT empty", () => { + it("throws an error", () => { + const element = render( + + {"Not empty"} + , + ); + const test = new ElementAssertion(element.getByTestId("id")); + + expect(test.not.toBeEmpty()).toBeEqual(test); + expect(() => test.toBeEmpty()) + .toThrowError(AssertionError) + .toHaveMessage("Expected element to be empty."); + }); + }); + }); }); diff --git a/packages/native/test/lib/ToBeEmptyElementAssertion.test.tsx b/packages/native/test/lib/ToBeEmptyElementAssertion.test.tsx deleted file mode 100644 index 86fcb218..00000000 --- a/packages/native/test/lib/ToBeEmptyElementAssertion.test.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { AssertionError, expect } from "@assertive-ts/core"; -import { render } from "@testing-library/react-native"; -import { View, Text } from "react-native"; - -import { ToBeEmptyAssertion } from "../../src/lib/ToBeEmptyAssertion"; - -describe("[Unit] toBeEmptyAssertion.test.ts", () => { - describe(".toBeEmpty", () => { - context("when the element is empty", () => { - it("returns the assertion instance", () => { - const element = render(); - const test = new ToBeEmptyAssertion(element.getByTestId("id")); - - expect(test.toBeEmpty()).toBe(test); - expect(() => test.not.toBeEmpty()) - .toThrowError(AssertionError) - .toHaveMessage("Expected element NOT to be empty."); - }); - }); - - context("when the element is NOT empty", () => { - it("throws an error", () => { - const element = render( - - {"Not empty"} - , - ); - const test = new ToBeEmptyAssertion(element.getByTestId("id")); - - expect(test.not.toBeEmpty()).toBeEqual(test); - expect(() => test.toBeEmpty()) - .toThrowError(AssertionError) - .toHaveMessage("Expected element to be empty."); - }); - }); - }); -}); From 22e54c9f23033d912534aa53c4843848dc8d139b Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Fri, 21 Mar 2025 17:11:32 -0500 Subject: [PATCH 08/16] Add toBeVisible matcher --- packages/native/src/lib/ElementAssertion.ts | 47 +++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/packages/native/src/lib/ElementAssertion.ts b/packages/native/src/lib/ElementAssertion.ts index 283516c8..0872de16 100644 --- a/packages/native/src/lib/ElementAssertion.ts +++ b/packages/native/src/lib/ElementAssertion.ts @@ -93,6 +93,33 @@ export class ElementAssertion extends Assertion { }); } + /** + * Check if the element is visible. + * + * @example + * ``` + * expect(element).toBeVisible(); + * ``` + * + * @returns the assertion instance + */ + public toBeVisible(): this { + const error = new AssertionError({ + actual: this.actual, + message: `Expected element ${this.toString()} to be visible.`, + }); + const invertedError = new AssertionError({ + actual: this.actual, + message: `Expected element ${this.toString()} NOT to be visible.`, + }); + + return this.execute({ + assertWhen: this.isElementVisible(this.actual) && !this.isAncestorNotVisible(this.actual), + error, + invertedError, + }); + } + private isElementDisabled(element: ReactTestInstance): boolean { const { type } = element; const elementType = type.toString(); @@ -112,4 +139,24 @@ export class ElementAssertion extends Assertion { const { parent } = element; return parent !== null && (this.isElementDisabled(element) || this.isAncestorDisabled(parent)); } + + private isElementVisible(element: ReactTestInstance): boolean { + const { type } = element; + const elementType = type.toString(); + if (elementType === "Modal" && !element?.props?.visible === true) { + return false; + } + + return ( + get(element, "props.style.display") !== "none" + && get(element, "props.style.opacity") !== 0 + && get(element, "props.accessibilityElementsHidden") !== true + && get(element, "props.importantForAccessibility") !== "no-hide-descendants" + ); + } + + private isAncestorNotVisible(element: ReactTestInstance): boolean { + const { parent } = element; + return parent !== null && (!this.isElementVisible(element) || this.isAncestorNotVisible(parent)); + } } From 05a57e916a45852e622d330a5b126c72591fb4c1 Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Fri, 21 Mar 2025 17:11:42 -0500 Subject: [PATCH 09/16] Add tests for toBeVisible --- .../native/test/lib/ElementAssertion.test.tsx | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/packages/native/test/lib/ElementAssertion.test.tsx b/packages/native/test/lib/ElementAssertion.test.tsx index ce3b4419..0b42a3aa 100644 --- a/packages/native/test/lib/ElementAssertion.test.tsx +++ b/packages/native/test/lib/ElementAssertion.test.tsx @@ -4,6 +4,7 @@ import { View, TextInput, Text, + Modal, } from "react-native"; import { ElementAssertion } from "../../src/lib/ElementAssertion"; @@ -160,4 +161,114 @@ describe("[Unit] ElementAssertion.test.ts", () => { }); }); }); + + describe (".toBeVisible", () => { + context("when the modal is visible", () => { + it("returns the assertion instance", () => { + const element = render( + , + ); + const test = new ElementAssertion(element.getByTestId("id")); + + expect(test.toBeVisible()).toBe(test); + expect(() => test.not.toBeVisible()) + .toThrowError(AssertionError) + .toHaveMessage("Expected element NOT to be visible."); + }); + }); + + context("when the element contains 'display' property", () => { + it("returns the assertion instance", () => { + const element = render( + , + ); + const test = new ElementAssertion(element.getByTestId("id")); + + expect(test.toBeVisible()).toBe(test); + expect(() => test.not.toBeVisible()) + .toThrowError(AssertionError) + .toHaveMessage("Expected element NOT to be visible."); + }); + }); + + context("when the element contains 'accessibilityElementsHidden' property", () => { + it("returns the assertion instance", () => { + const element = render( + , + ); + const test = new ElementAssertion(element.getByTestId("id")); + + expect(test.toBeVisible()).toBe(test); + expect(() => test.not.toBeVisible()) + .toThrowError(AssertionError) + .toHaveMessage("Expected element NOT to be visible."); + }); + }); + + context("when the element contains 'importantForAccessibility' property", () => { + it("returns the assertion instance", () => { + const element = render( + , + ); + const test = new ElementAssertion(element.getByTestId("id")); + + expect(test.toBeVisible()).toBe(test); + expect(() => test.not.toBeVisible()) + .toThrowError(AssertionError) + .toHaveMessage("Expected element NOT to be visible."); + }); + }); + + context("when the parent element contains 'opacity' property", () => { + context("if parent opacity = 0", () => { + const element = render( + + + , + ); + + const parent = new ElementAssertion(element.getByTestId("parentId")); + const child = new ElementAssertion(element.getByTestId("childId")); + + it("returns assertion instance for NOT visible elements", () => { + expect(parent.not.toBeVisible()).toBeEqual(parent); + expect(child.not.toBeVisible()).toBeEqual(child); + }); + + it("throws an error for visible elements", () => { + expect(() => parent.toBeVisible()) + .toThrowError(AssertionError) + .toHaveMessage("Expected element to be visible."); + expect(() => child.toBeVisible()) + .toThrowError(AssertionError) + .toHaveMessage("Expected element to be visible."); + }); + }); + + context("if child opacity = 0", () => { + const element = render( + + + , + ); + + const parent = new ElementAssertion(element.getByTestId("parentId")); + const child = new ElementAssertion(element.getByTestId("childId")); + + it("returns assertion instance for NOT visible elements", () => { + expect(parent.toBeVisible()).toBeEqual(parent); + expect(child.not.toBeVisible()).toBeEqual(child); + }); + + it("throws an error for visible elements", () => { + expect(() => parent.not.toBeVisible()) + .toThrowError(AssertionError) + .toHaveMessage("Expected element NOT to be visible."); + expect(() => child.toBeVisible()) + .toThrowError(AssertionError) + .toHaveMessage("Expected element to be visible."); + }); + }); + }); + }); }); From abf480acce5901a7ff480c48ecdae625e09463e9 Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Fri, 21 Mar 2025 17:14:51 -0500 Subject: [PATCH 10/16] Fix: Update JSDocs --- packages/native/src/lib/ElementAssertion.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/native/src/lib/ElementAssertion.ts b/packages/native/src/lib/ElementAssertion.ts index 0872de16..4a0570ed 100644 --- a/packages/native/src/lib/ElementAssertion.ts +++ b/packages/native/src/lib/ElementAssertion.ts @@ -41,7 +41,7 @@ export class ElementAssertion extends Assertion { } /** - * Check if the component is enabled. + * Check if the component is enabled and has not been disabled by an ancestor. * * @example * ``` @@ -94,7 +94,7 @@ export class ElementAssertion extends Assertion { } /** - * Check if the element is visible. + * Check if the element is visible and has not been hidden by an ancestor. * * @example * ``` From 0c30feea875359bbce9cb6d917b2b01d3db291c1 Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Mon, 24 Mar 2025 15:30:55 -0500 Subject: [PATCH 11/16] toContainElement() assertion --- packages/native/src/lib/ElementAssertion.ts | 44 +++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/packages/native/src/lib/ElementAssertion.ts b/packages/native/src/lib/ElementAssertion.ts index 4a0570ed..4abdb73b 100644 --- a/packages/native/src/lib/ElementAssertion.ts +++ b/packages/native/src/lib/ElementAssertion.ts @@ -120,6 +120,50 @@ export class ElementAssertion extends Assertion { }); } + /** + * Check if an element is contained within another element. + * + * @example + * ``` + * expect(parent).toContainElement(child); + * ``` + * + * @param element - The element to check for. + * @returns the assertion instance + */ + public toContainElement(element: ReactTestInstance): this { + const error = new AssertionError({ + actual: this.actual, + message: `Expected element ${this.toString()} to contain element ${instanceToString(element)}.`, + }); + const invertedError = new AssertionError({ + actual: this.actual, + message: `Expected element ${this.toString()} NOT to contain element ${instanceToString(element)}.`, + }); + + const isElementContained = ( + parentElement: ReactTestInstance, + childElement: ReactTestInstance, + ): boolean => { + if (parentElement === null || childElement === null) { + return false; + } + + return ( + parentElement.findAll( + node => + node.type === childElement.type && node.props === childElement.props, + ).length > 0 + ); + }; + + return this.execute({ + assertWhen: isElementContained(this.actual, element), + error, + invertedError, + }); + } + private isElementDisabled(element: ReactTestInstance): boolean { const { type } = element; const elementType = type.toString(); From 05ef646a2501c84b63dcb5c533f3ef0d0b4fb4e2 Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Mon, 24 Mar 2025 15:36:10 -0500 Subject: [PATCH 12/16] Add tests for toContainElement() --- .../native/test/lib/ElementAssertion.test.tsx | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/packages/native/test/lib/ElementAssertion.test.tsx b/packages/native/test/lib/ElementAssertion.test.tsx index 0b42a3aa..5cadae1a 100644 --- a/packages/native/test/lib/ElementAssertion.test.tsx +++ b/packages/native/test/lib/ElementAssertion.test.tsx @@ -271,4 +271,50 @@ describe("[Unit] ElementAssertion.test.ts", () => { }); }); }); + + describe (".toContainElement", () => { + const element = render( + + + + + + , + ); + + const container = element.getByTestId("grandParentId"); + const containerElementAssertion = new ElementAssertion(container); + const parent = element.getByTestId("parentId"); + const parentElementAssertion = new ElementAssertion(parent); + const child = element.getByTestId("childId"); + const text = element.getByTestId("textId"); + + context("when the container element contains the target element", () => { + it("returns the assertion instance", () => { + expect(containerElementAssertion.toContainElement(parent)).toBe(containerElementAssertion); + expect(containerElementAssertion.toContainElement(child)).toBe(containerElementAssertion); + expect(containerElementAssertion.toContainElement(text)).toBe(containerElementAssertion); + expect(parentElementAssertion.toContainElement(child)).toBe(parentElementAssertion); + }); + + it("returns the assertion instance for negated assertions when the target element is not contained", () => { + expect(parentElementAssertion.not.toContainElement(text)).toBe(parentElementAssertion); + expect(parentElementAssertion.not.toContainElement(container)).toBe(parentElementAssertion); + }); + }); + + context("when the container element does NOT contain the target element", () => { + it("throws an error", () => { + expect(() => containerElementAssertion.not.toContainElement(parent)) + .toThrowError(AssertionError) + .toHaveMessage("Expected element NOT to contain element ."); + expect(() => containerElementAssertion.not.toContainElement(text)) + .toThrowError(AssertionError) + .toHaveMessage("Expected element NOT to contain element ."); + expect(() => parentElementAssertion.toContainElement(text)) + .toThrowError(AssertionError) + .toHaveMessage("Expected element to contain element ."); + }); + }); + }); }); From fda2999e3a85cfb67c34dc28593f7c9d5a74f8df Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Mon, 24 Mar 2025 15:49:32 -0500 Subject: [PATCH 13/16] fix: assertions on tests --- packages/native/test/lib/ElementAssertion.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/native/test/lib/ElementAssertion.test.tsx b/packages/native/test/lib/ElementAssertion.test.tsx index 5cadae1a..b657d36c 100644 --- a/packages/native/test/lib/ElementAssertion.test.tsx +++ b/packages/native/test/lib/ElementAssertion.test.tsx @@ -298,8 +298,8 @@ describe("[Unit] ElementAssertion.test.ts", () => { }); it("returns the assertion instance for negated assertions when the target element is not contained", () => { - expect(parentElementAssertion.not.toContainElement(text)).toBe(parentElementAssertion); - expect(parentElementAssertion.not.toContainElement(container)).toBe(parentElementAssertion); + expect(parentElementAssertion.not.toContainElement(text)).toBeEqual(parentElementAssertion); + expect(parentElementAssertion.not.toContainElement(container)).toBeEqual(parentElementAssertion); }); }); From ee0261b651eddad7be652d055fb11fc4225f42cc Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Wed, 2 Apr 2025 16:22:24 -0500 Subject: [PATCH 14/16] Add toHaveProp function --- packages/native/src/lib/ElementAssertion.ts | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/native/src/lib/ElementAssertion.ts b/packages/native/src/lib/ElementAssertion.ts index 4abdb73b..0c858c06 100644 --- a/packages/native/src/lib/ElementAssertion.ts +++ b/packages/native/src/lib/ElementAssertion.ts @@ -164,6 +164,42 @@ export class ElementAssertion extends Assertion { }); } + /** + * Check if the element has a specific property or a specific property value. + * + * @example + * ``` + * expect(element).toHaveProp("propName"); + * expect(element).toHaveProp("propName", "propValue"); + * ``` + * + * @param propName - The name of the prop to check for. + * @param value - The value of the prop to check for. + * @returns the assertion instance + */ + public toHaveProp(propName: string, value?: unknown): this { + const propValue: unknown = get(this.actual, `props.${propName}`, undefined); + const hasProp = propValue !== undefined; + const isPropEqual = value === undefined || propValue === value; + + const errorMessage = value === undefined + ? `Expected element ${this.toString()} to have prop '${propName}'.` + : `Expected element ${this.toString()} to have prop '${propName}' with value '${String(value)}'.`; + + const invertedErrorMessage = value === undefined + ? `Expected element ${this.toString()} NOT to have prop '${propName}'.` + : `Expected element ${this.toString()} NOT to have prop '${propName}' with value '${String(value)}'.`; + + const error = new AssertionError({ actual: this.actual, message: errorMessage }); + const invertedError = new AssertionError({ actual: this.actual, message: invertedErrorMessage }); + + return this.execute({ + assertWhen: hasProp && isPropEqual, + error, + invertedError, + }); + } + private isElementDisabled(element: ReactTestInstance): boolean { const { type } = element; const elementType = type.toString(); From 279a50ce9eca54c30d4bdbb2a48def6cb705bd0d Mon Sep 17 00:00:00 2001 From: Karla Quistanchala Date: Wed, 2 Apr 2025 16:23:18 -0500 Subject: [PATCH 15/16] Add tests for toHaveProp --- .../native/test/lib/ElementAssertion.test.tsx | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/packages/native/test/lib/ElementAssertion.test.tsx b/packages/native/test/lib/ElementAssertion.test.tsx index b657d36c..695db7dc 100644 --- a/packages/native/test/lib/ElementAssertion.test.tsx +++ b/packages/native/test/lib/ElementAssertion.test.tsx @@ -317,4 +317,62 @@ describe("[Unit] ElementAssertion.test.ts", () => { }); }); }); + + describe(".toHaveProp", () => { + context("when the element contains the target prop", () => { + it("returns the assertion instance", () => { + const element = render( + , + ); + const test = new ElementAssertion(element.getByTestId("id")); + + expect(test.toHaveProp("accessibilityLabel")).toBe(test); + expect(() => test.not.toHaveProp("accessibilityLabel")) + .toThrowError(AssertionError) + .toHaveMessage("Expected element NOT to have prop 'accessibilityLabel'."); + }); + }); + + context("when the element does NOT contain the target prop", () => { + it("throws an error", () => { + const element = render( + , + ); + const test = new ElementAssertion(element.getByTestId("id")); + + expect(test.not.toHaveProp("accessibilityLabel")).toBeEqual(test); + expect(() => test.toHaveProp("accessibilityLabel")) + .toThrowError(AssertionError) + .toHaveMessage("Expected element to have prop 'accessibilityLabel'."); + }); + }); + + context("when the element contains the target prop with a specific value", () => { + it("returns the assertion instance", () => { + const element = render( + , + ); + const test = new ElementAssertion(element.getByTestId("id")); + + expect(test.toHaveProp("accessibilityLabel", "label")).toBe(test); + expect(() => test.not.toHaveProp("accessibilityLabel", "label")) + .toThrowError(AssertionError) + .toHaveMessage("Expected element NOT to have prop 'accessibilityLabel' with value 'label'."); + }); + }); + + context("when the element does NOT contain the target prop with a specific value", () => { + it("throws an error", () => { + const element = render( + , + ); + const test = new ElementAssertion(element.getByTestId("id")); + + expect(test.not.toHaveProp("accessibilityLabel", "label")).toBeEqual(test); + expect(() => test.toHaveProp("accessibilityLabel", "label")) + .toThrowError(AssertionError) + .toHaveMessage("Expected element to have prop 'accessibilityLabel' with value 'label'."); + }); + }); + }); }); From 15a8bee3bf3d6bfb1348938bbbbf1beca0aa64c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Alejandro=20Coronel=20Rodrigues?= <78624635+ACR1209@users.noreply.github.com> Date: Tue, 24 Mar 2026 11:49:41 -0500 Subject: [PATCH 16/16] feat(native): add toHaveStyle (#152) --- packages/native/src/lib/ElementAssertion.ts | 140 +++++++- packages/native/src/lib/helpers/helpers.ts | 49 +++ packages/native/src/lib/helpers/types.ts | 34 ++ .../native/test/lib/ElementAssertion.test.tsx | 326 ++++++++++++++++++ 4 files changed, 544 insertions(+), 5 deletions(-) create mode 100644 packages/native/src/lib/helpers/types.ts diff --git a/packages/native/src/lib/ElementAssertion.ts b/packages/native/src/lib/ElementAssertion.ts index 0c858c06..7ffa2707 100644 --- a/packages/native/src/lib/ElementAssertion.ts +++ b/packages/native/src/lib/ElementAssertion.ts @@ -2,7 +2,14 @@ import { Assertion, AssertionError } from "@assertive-ts/core"; import { get } from "dot-prop-immutable"; import { ReactTestInstance } from "react-test-renderer"; -import { instanceToString, isEmpty } from "./helpers/helpers"; +import { + instanceToString, + isEmpty, + getFlattenedStyle, + styleToString, + textMatches, +} from "./helpers/helpers"; +import { AssertiveStyle, TestableTextMatcher, TextContent } from "./helpers/types"; export class ElementAssertion extends Assertion { public constructor(actual: ReactTestInstance) { @@ -200,6 +207,129 @@ export class ElementAssertion extends Assertion { }); } + /** + * Asserts that a component has the specified style(s) applied. + * + * This method supports both single style objects and arrays of style objects. + * It checks if all specified style properties match on the target element. + * + * @example + * ``` + * expect(element).toHaveStyle({ backgroundColor: "red" }); + * expect(element).toHaveStyle([{ backgroundColor: "red" }]); + * ``` + * + * @param style - A style object to check for. + * @returns the assertion instance + */ + public toHaveStyle(style: AssertiveStyle): this { + const stylesOnElement: AssertiveStyle = get(this.actual, "props.style", {}); + + const flattenedElementStyle = getFlattenedStyle(stylesOnElement); + const flattenedStyle = getFlattenedStyle(style); + + const hasStyle = Object.keys(flattenedStyle) + .every(key => flattenedElementStyle[key] === flattenedStyle[key]); + + const error = new AssertionError({ + actual: this.actual, + message: `Expected element ${this.toString()} to have style: \n${styleToString(flattenedStyle)}`, + }); + + const invertedError = new AssertionError({ + actual: this.actual, + message: `Expected element ${this.toString()} NOT to have style: \n${styleToString(flattenedStyle)}`, + }); + + return this.execute({ + assertWhen: hasStyle, + error, + invertedError, + }); + } + + /** + * Check if the element has text content matching the provided string, + * RegExp, or function. + * + * @example + * ``` + * expect(element).toHaveTextContent("Hello World"); + * expect(element).toHaveTextContent(/Hello/); + * expect(element).toHaveTextContent(text => text.startsWith("Hello")); + * ``` + * + * @param text - The text to check for. + * @returns the assertion instance + */ + public toHaveTextContent(text: TestableTextMatcher): this { + const actualTextContent = this.getTextContent(this.actual); + const matchesText = textMatches(actualTextContent, text); + + const error = new AssertionError({ + actual: this.actual, + message: `Expected element ${this.toString()} to have text content matching '` + + `${text.toString()}'.`, + }); + + const invertedError = new AssertionError({ + actual: this.actual, + message: + `Expected element ${this.toString()} NOT to have text content matching '` + + `${text.toString()}'.`, + }); + + return this.execute({ + assertWhen: matchesText, + error, + invertedError, + }); + } + + private getTextContent(element: ReactTestInstance): string { + if (!element) { + return ""; + } + + if (typeof element === "string") { + return element; + } + + if (typeof element.props?.value === "string") { + return element.props.value; + } + + return this.collectText(element).join(" "); + } + + private collectText = (element: TextContent): string[] => { + if (typeof element === "string") { + return [element]; + } + + if (Array.isArray(element)) { + return element.flatMap(child => this.collectText(child)); + } + + if (element && (typeof element === "object" && "props" in element)) { + const value = element.props?.value as TextContent; + if (typeof value === "string") { + return [value]; + } + + const children = (element.props?.children as ReactTestInstance[]) ?? element.children; + if (!children) { + return []; + } + + return Array.isArray(children) + ? children.flatMap(this.collectText) + : this.collectText(children); + } + + return []; + }; + private isElementDisabled(element: ReactTestInstance): boolean { const { type } = element; const elementType = type.toString(); @@ -208,10 +338,10 @@ export class ElementAssertion extends Assertion { } return ( - get(element, "props.aria-disabled") - || get(element, "props.disabled", false) - || get(element, "props.accessibilityState.disabled", false) - || get(element, "props.accessibilityStates", []).includes("disabled") + get(element, "props.aria-disabled") + || get(element, "props.disabled", false) + || get(element, "props.accessibilityState.disabled", false) + || get(element, "props.accessibilityStates", []).includes("disabled") ); } diff --git a/packages/native/src/lib/helpers/helpers.ts b/packages/native/src/lib/helpers/helpers.ts index 6ab4db1e..dc603a8b 100644 --- a/packages/native/src/lib/helpers/helpers.ts +++ b/packages/native/src/lib/helpers/helpers.ts @@ -1,5 +1,8 @@ +import { StyleSheet } from "react-native"; import { ReactTestInstance } from "react-test-renderer"; +import { AssertiveStyle, StyleObject, TestableTextMatcher } from "./types"; + /** * Checks if a value is empty. * @@ -31,3 +34,49 @@ export function instanceToString(instance: ReactTestInstance | null): string { return `<${instance.type.toString()} ... />`; } + +/** + * Checks if a text matches a given matcher. + * + * @param text - The text to check. + * @param matcher - The matcher to use for comparison. + * @returns `true` if the text matches the matcher, `false` otherwise. + * @throws Error if the matcher is not a string, RegExp, or function. + * @example + * ```ts + * textMatches("Hello World", "Hello World"); // true + * textMatches("Hello World", /Hello/); // true + * textMatches("Hello World", (text) => text.startsWith("Hello")); // true + * textMatches("Hello World", "Goodbye"); // false + * textMatches("Hello World", /Goodbye/); // false + * textMatches("Hello World", (text) => text.startsWith("Goodbye")); // false + * ``` + */ +export function textMatches( + text: string, + matcher: TestableTextMatcher, +): boolean { + if (typeof matcher === "string") { + return text.includes(matcher); + } + + if (matcher instanceof RegExp) { + return matcher.test(text); + } + + if (typeof matcher === "function") { + return matcher(text); + } + + throw new Error("Matcher must be a string, RegExp, or function."); +} + +export function getFlattenedStyle(style: AssertiveStyle): StyleObject { + const flattenedStyle = StyleSheet.flatten(style); + return flattenedStyle ? (flattenedStyle as StyleObject) : {}; +} + +export function styleToString(flattenedStyle: StyleObject): string { + const styleEntries = Object.entries(flattenedStyle); + return styleEntries.map(([key, value]) => `\t- ${key}: ${String(value)};`).join("\n"); +} diff --git a/packages/native/src/lib/helpers/types.ts b/packages/native/src/lib/helpers/types.ts new file mode 100644 index 00000000..93cc9f99 --- /dev/null +++ b/packages/native/src/lib/helpers/types.ts @@ -0,0 +1,34 @@ +import { ImageStyle, StyleProp, TextStyle, ViewStyle } from "react-native"; +import { ReactTestInstance } from "react-test-renderer"; + +/** + * Type representing a style that can be applied to a React Native component. + * It can be a style for text, view, or image components. + */ +export type Style = TextStyle | ViewStyle | ImageStyle; + +/** + * Type for a style prop that can be applied to a React Native component. + * It can be a single style or an array of styles. + */ +export type AssertiveStyle = StyleProp