diff --git a/packages/native/src/lib/ElementAssertion.ts b/packages/native/src/lib/ElementAssertion.ts index 0c858c0..ed7a11d 100644 --- a/packages/native/src/lib/ElementAssertion.ts +++ b/packages/native/src/lib/ElementAssertion.ts @@ -3,6 +3,8 @@ import { get } from "dot-prop-immutable"; import { ReactTestInstance } from "react-test-renderer"; import { instanceToString, isEmpty } from "./helpers/helpers"; +import { getFlattenedStyle } from "./helpers/styles"; +import { AssertiveStyle } from "./helpers/types"; export class ElementAssertion extends Assertion { public constructor(actual: ReactTestInstance) { @@ -200,6 +202,47 @@ 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 ${JSON.stringify(flattenedStyle)}.`, + }); + + const invertedError = new AssertionError({ + actual: this.actual, + message: `Expected element ${this.toString()} NOT to have style ${JSON.stringify(flattenedStyle)}.`, + }); + + return this.execute({ + assertWhen: hasStyle, + error, + invertedError, + }); + } + private isElementDisabled(element: ReactTestInstance): boolean { const { type } = element; const elementType = type.toString(); diff --git a/packages/native/src/lib/helpers/styles.ts b/packages/native/src/lib/helpers/styles.ts new file mode 100644 index 0000000..091983d --- /dev/null +++ b/packages/native/src/lib/helpers/styles.ts @@ -0,0 +1,8 @@ +import { StyleSheet } from "react-native"; + +import { AssertiveStyle, StyleObject } from "./types"; + +export function getFlattenedStyle(style: AssertiveStyle): StyleObject { + const flattenedStyle = StyleSheet.flatten(style); + return flattenedStyle ? (flattenedStyle as StyleObject) : {}; +} diff --git a/packages/native/src/lib/helpers/types.ts b/packages/native/src/lib/helpers/types.ts new file mode 100644 index 0000000..f2263f9 --- /dev/null +++ b/packages/native/src/lib/helpers/types.ts @@ -0,0 +1,19 @@ +import { ImageStyle, StyleProp, TextStyle, ViewStyle } from "react-native"; + +/** + * 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