-
Notifications
You must be signed in to change notification settings - Fork 2
feat(native): Add toBeDisabled #140
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
Changes from 16 commits
5a8f357
3dbcce9
4146337
512f251
190ce45
39ff2b3
3f36d19
7e87056
543b776
72efbf8
7dd25a0
89ba184
e0cb309
5fbe42a
2aa8928
177eefe
3b3ebc1
898721a
102a4ed
9268ff8
109c6aa
b38d12b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,5 +17,8 @@ node_modules/ | |
# VSCode | ||
.vscode/ | ||
|
||
# idea | ||
.idea/ | ||
|
||
# Packages | ||
*.tgz |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { Assertion, AssertionError } from "@assertive-ts/core"; | ||
import { get } from "dot-prop-immutable"; | ||
import { ReactTestInstance } from "react-test-renderer"; | ||
|
||
export class ElementAssertion extends Assertion<ReactTestInstance> { | ||
public constructor(actual: ReactTestInstance) { | ||
super(actual); | ||
} | ||
|
||
public override toString = (): string => { | ||
if (this.actual === null) { | ||
return "null"; | ||
} | ||
|
||
return `<${this.actual.type.toString()} testID="${this.actual.props.testID}"... />`; | ||
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
/** | ||
* Check if the component is disabled. | ||
kdquistanchala marked this conversation as resolved.
Show resolved
Hide resolved
kdquistanchala marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* | ||
* @example | ||
* ``` | ||
* expect(component.toBeDisabled()).toBeTruthy(); | ||
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* ``` | ||
* | ||
* @returns the assertion instance | ||
*/ | ||
|
||
public toBeDisabled(): this { | ||
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const error = new AssertionError({ | ||
actual: this.actual, | ||
message: `Received element ${this.toString()} is enabled.`, | ||
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}); | ||
const invertedError = new AssertionError({ | ||
actual: this.actual, | ||
message: `Received element ${this.toString()} is disabled.`, | ||
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}); | ||
|
||
return this.execute({ | ||
assertWhen: this.isElementDisabled(this.actual) || this.isAncestorDisabled(this.actual), | ||
error, | ||
invertedError, | ||
}); | ||
} | ||
|
||
/** | ||
* Check if the component is enabled. | ||
* | ||
* @example | ||
* ``` | ||
* expect(component.toBeEnabled()).toBeTruthy(); | ||
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* ``` | ||
* @returns the assertion instance | ||
*/ | ||
public toBeEnabled(): this { | ||
return this.not.toBeDisabled(); | ||
} | ||
|
||
private isElementDisabled(element: ReactTestInstance): boolean { | ||
const { type } = element; | ||
const elementType = type.toString(); | ||
if (elementType === "TextInput" && element?.props?.editable === false) { | ||
return true; | ||
} | ||
|
||
return ( | ||
get(element, "props.aria-disabled") || | ||
get(element, "props.disabled", false) || | ||
get(element, "props.accessibilityState.disabled", false) || | ||
get<ReactTestInstance, [string]>(element, "props.accessibilityStates", []).includes("disabled") | ||
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
); | ||
} | ||
|
||
private isAncestorDisabled(element: ReactTestInstance): boolean { | ||
const { parent } = element; | ||
return parent !== null && (this.isElementDisabled(element) || this.isAncestorDisabled(parent)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { Plugin } from "@assertive-ts/core"; | ||
import { ReactTestInstance } from "react-test-renderer"; | ||
|
||
import { ElementAssertion } from "./lib/ElementAssertion"; | ||
|
||
declare module "@assertive-ts/core" { | ||
|
||
export interface Expect { | ||
// eslint-disable-next-line @typescript-eslint/prefer-function-type | ||
(actual: ReactTestInstance): ElementAssertion; | ||
} | ||
} | ||
|
||
const ElementPlugin: Plugin<ReactTestInstance, ElementAssertion> = { | ||
Assertion: ElementAssertion, | ||
insertAt: "top", | ||
predicate: (actual): actual is ReactTestInstance => | ||
typeof actual === "object" | ||
&& actual !== null | ||
&& "instance" in actual | ||
&& typeof actual.instance === "object" | ||
&& "type" in actual | ||
&& typeof actual.type === "object" | ||
&& "props" in actual | ||
&& typeof actual.props === "object" | ||
&& "parent" in actual | ||
&& typeof actual.parent === "object" | ||
&& "children" in actual | ||
&& typeof actual.children === "object", | ||
Comment on lines
+26
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these props still present if the element does not have a parent or children? 🤔 |
||
}; | ||
|
||
export const NativePlugin = [ElementPlugin]; |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're missing tests for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi José! I have reviewed the comment and had to modify the logic of |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { AssertionError, expect } from "@assertive-ts/core"; | ||
import { render } from "@testing-library/react-native"; | ||
import { | ||
View, | ||
TextInput, | ||
} from "react-native"; | ||
|
||
import { ElementAssertion } from "../../src/lib/ElementAssertion"; | ||
|
||
describe("[Unit] ElementAssertion.test.ts", () => { | ||
describe(".toBeDisabled", () => { | ||
context("when the element is TextInput", () => { | ||
it("returns the assertion instance when is not editable", () => { | ||
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const element = render( | ||
<TextInput testID="id" editable={false} />, | ||
); | ||
const test = new ElementAssertion(element.getByTestId("id")); | ||
expect(test.toBeDisabled()).toBe(test); | ||
}); | ||
it("throws an error when it is editable", () => { | ||
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const reactElement = render(<TextInput editable={true} testID="id" />); | ||
const test = new ElementAssertion(reactElement.getByTestId("id")); | ||
|
||
expect(() => test.toBeDisabled()) | ||
.toThrowError(AssertionError) | ||
.toHaveMessage('Received element <TextInput testID="id"... /> is enabled.'); | ||
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}); | ||
}); | ||
|
||
context("when the parent has property aria-disabled", () => { | ||
it("returns disable for parent and child element when aria-disabled=true", () => { | ||
const element = render( | ||
<View aria-disabled={true} testID="parentId"> | ||
<View testID="childId"> | ||
<TextInput /> | ||
</View> | ||
</View>, | ||
); | ||
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
const parent = new ElementAssertion(element.getByTestId("parentId")); | ||
const child = new ElementAssertion(element.getByTestId("childId")); | ||
expect(parent.toBeDisabled()).toBeTruthy(); | ||
expect(child.toBeDisabled()).toBeTruthy(); | ||
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}); | ||
it("throws an error when aria-disabled=false", () => { | ||
suany0805 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const element = render( | ||
<View aria-disabled={false} testID="parentId"> | ||
<View testID="childId"> | ||
<TextInput /> | ||
</View> | ||
</View>, | ||
); | ||
|
||
const parent = new ElementAssertion(element.getByTestId("parentId")); | ||
const child = new ElementAssertion(element.getByTestId("childId")); | ||
|
||
expect(parent.toBeEnabled()).toBeTruthy(); | ||
expect(() => parent.toBeDisabled()) | ||
.toThrowError(AssertionError) | ||
.toHaveMessage('Received element <View testID="parentId"... /> is enabled.'); | ||
expect(() => child.toBeDisabled()) | ||
.toThrowError(AssertionError) | ||
.toHaveMessage('Received element <View testID="childId"... /> is enabled.'); | ||
}); | ||
}); | ||
|
||
context("when the child has property aria-disabled", () => { | ||
const element = render( | ||
<View testID="parentId"> | ||
<View aria-disabled={true} testID="childId"> | ||
<TextInput /> | ||
</View> | ||
</View>, | ||
); | ||
|
||
const parent = new ElementAssertion(element.getByTestId("parentId")); | ||
const child = new ElementAssertion(element.getByTestId("childId")); | ||
|
||
it("returns disable for child element when aria-disabled=true", () => { | ||
expect(child.toBeDisabled()).toBeTruthy(); | ||
expect(() => child.toBeEnabled()) | ||
.toThrowError(AssertionError) | ||
.toHaveMessage("Received element <View testID=\"childId\"... /> is disabled."); | ||
}); | ||
it("returns enable for parent with disabled child", () => { | ||
expect(parent.toBeEnabled()).toBeTruthy(); | ||
expect(() => parent.toBeDisabled()) | ||
.toThrowError(AssertionError) | ||
.toHaveMessage("Received element <View testID=\"parentId\"... /> is enabled."); | ||
|
||
}); | ||
}); | ||
}); | ||
}); |
Uh oh!
There was an error while loading. Please reload this page.