Skip to content

feat(native): Add toHaveProp #148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: feat/native-to-contain-element
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions packages/native/src/lib/ElementAssertion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,42 @@ export class ElementAssertion extends Assertion<ReactTestInstance> {
});
}

/**
* 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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just as for my understanding, why are we using uknown instead of undefined or any in here?

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)}'.`;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about adding to the error message something like: Verify the element properties?

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();
Expand Down
58 changes: 58 additions & 0 deletions packages/native/test/lib/ElementAssertion.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(
<View testID="id" accessibilityLabel="label" />,
);
const test = new ElementAssertion(element.getByTestId("id"));

expect(test.toHaveProp("accessibilityLabel")).toBe(test);
expect(() => test.not.toHaveProp("accessibilityLabel"))
.toThrowError(AssertionError)
.toHaveMessage("Expected element <View ... /> NOT to have prop 'accessibilityLabel'.");
});
});

context("when the element does NOT contain the target prop", () => {
it("throws an error", () => {
const element = render(
<View testID="id" />,
);
const test = new ElementAssertion(element.getByTestId("id"));

expect(test.not.toHaveProp("accessibilityLabel")).toBeEqual(test);
expect(() => test.toHaveProp("accessibilityLabel"))
.toThrowError(AssertionError)
.toHaveMessage("Expected element <View ... /> to have prop 'accessibilityLabel'.");
});
});

context("when the element contains the target prop with a specific value", () => {
it("returns the assertion instance", () => {
const element = render(
<View testID="id" accessibilityLabel="label" />,
);
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 <View ... /> 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(
<View testID="id" accessibilityLabel="new-label" />,
);
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 <View ... /> to have prop 'accessibilityLabel' with value 'label'.");
});
});
});
});