Created
July 25, 2024 08:43
-
-
Save pachun/e9fda4b224d672b0fcc0b2e52cbbc3b1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react" | |
import * as ReactNative from "react-native" | |
import * as RNTL from "@testing-library/react-native" | |
const formatCompleteOrPartialPhoneNumber = ( | |
phoneNumberDigits: string, | |
): string => { | |
if (phoneNumberDigits.length < 4) { | |
return phoneNumberDigits | |
} else if (phoneNumberDigits.length < 7) { | |
return `(${phoneNumberDigits.slice(0, 3)}) ${phoneNumberDigits.slice(3)}` | |
} | |
return `(${phoneNumberDigits.slice(0, 3)}) ${phoneNumberDigits.slice(3, 6)}-${phoneNumberDigits.slice(6)}` | |
} | |
type PhoneNumberFieldType = ( | |
props: ReactNative.TextInputProps & { | |
phoneNumber: string | |
onChangePhoneNumber: (phoneNumber: string) => void | |
}, | |
) => React.ReactElement | |
const numberOfDigitsInFullPhoneNumber = 10 | |
const fullPhoneNumber = "0".repeat(numberOfDigitsInFullPhoneNumber) | |
const PhoneNumberField: PhoneNumberFieldType = props => { | |
const [displayedPhoneNumber, setDisplayedPhoneNumber] = | |
React.useState<string>( | |
formatCompleteOrPartialPhoneNumber(props.phoneNumber), | |
) | |
const setDigits = React.useMemo( | |
() => props.onChangePhoneNumber, | |
[props.onChangePhoneNumber], | |
) | |
return ( | |
<ReactNative.TextInput | |
keyboardType="number-pad" | |
{...props} | |
value={displayedPhoneNumber} | |
onChangeText={editedPhoneNumber => { | |
const digits = editedPhoneNumber.replace(/\D/g, "") | |
setDigits(digits) | |
setDisplayedPhoneNumber(formatCompleteOrPartialPhoneNumber(digits)) | |
}} | |
maxLength={formatCompleteOrPartialPhoneNumber(fullPhoneNumber).length} | |
/> | |
) | |
} | |
const typeIntoTestId = (testId: string, text: string): void => { | |
RNTL.userEvent.setup().type(RNTL.screen.getByTestId(testId), text) | |
} | |
const PhoneNumberFieldTestHelper = (): React.ReactElement => { | |
const [phoneNumber, setPhoneNumber] = React.useState("") | |
return ( | |
<> | |
<ReactNative.Text>{phoneNumber}</ReactNative.Text> | |
<PhoneNumberField | |
testID="Phone Number Field" | |
phoneNumber={phoneNumber} | |
onChangePhoneNumber={setPhoneNumber} | |
/> | |
</> | |
) | |
} | |
describe("The Phone Number Field Component", () => { | |
it("accepts and applies any ReactNative.TextField props", () => { | |
RNTL.render( | |
<PhoneNumberField | |
placeholder="Phone Number" | |
phoneNumber="" | |
onChangePhoneNumber={() => {}} | |
/>, | |
) | |
expect(RNTL.screen.getByPlaceholderText("Phone Number")) | |
}) | |
it("defaults its keyboardType to number-pad", () => { | |
RNTL.render( | |
<PhoneNumberField | |
testID="Phone Number Field" | |
phoneNumber="" | |
onChangePhoneNumber={() => {}} | |
/>, | |
) | |
const phoneNumberField = RNTL.screen.getByTestId("Phone Number Field") | |
expect(phoneNumberField.props.keyboardType).toEqual("number-pad") | |
}) | |
describe("given a digit-only initial phone number", () => { | |
it("formats the initially displayed phone number", () => { | |
RNTL.render( | |
<PhoneNumberField | |
testID="Phone Number Field" | |
phoneNumber="0123456789" | |
onChangePhoneNumber={() => {}} | |
/>, | |
) | |
const phoneNumberField = RNTL.screen.getByTestId("Phone Number Field") | |
expect(phoneNumberField.props.value).toEqual("(012) 345-6789") | |
}) | |
}) | |
describe("when digits are entered", () => { | |
it("does not permit entering more characters than are in a single full phone number", async () => { | |
RNTL.render(<PhoneNumberFieldTestHelper />) | |
const phoneNumberField = RNTL.screen.getByTestId("Phone Number Field") | |
await RNTL.waitFor(() => { | |
expect(phoneNumberField.props.maxLength).toEqual( | |
"(000) 000-0000".length, | |
) | |
}) | |
}) | |
it("formats the phone number in the text field and returns the unformatted phone number to the controlling component with onChangePhoneNumber", async () => { | |
RNTL.render(<PhoneNumberFieldTestHelper />) | |
const phoneNumberField = RNTL.screen.getByTestId("Phone Number Field") | |
typeIntoTestId("Phone Number Field", "0") | |
await RNTL.waitFor(() => { | |
expect(phoneNumberField.props.value).toEqual("0") | |
expect(RNTL.screen.getByText("0")) | |
}) | |
typeIntoTestId("Phone Number Field", "1") | |
await RNTL.waitFor(() => { | |
expect(phoneNumberField.props.value).toEqual("01") | |
expect(RNTL.screen.getByText("01")) | |
}) | |
typeIntoTestId("Phone Number Field", "2") | |
await RNTL.waitFor(() => { | |
expect(phoneNumberField.props.value).toEqual("012") | |
expect(RNTL.screen.getByText("012")) | |
}) | |
typeIntoTestId("Phone Number Field", "3") | |
await RNTL.waitFor(() => { | |
expect(phoneNumberField.props.value).toEqual("(012) 3") | |
expect(RNTL.screen.getByText("0123")) | |
}) | |
typeIntoTestId("Phone Number Field", "4") | |
await RNTL.waitFor(() => { | |
expect(phoneNumberField.props.value).toEqual("(012) 34") | |
expect(RNTL.screen.getByText("01234")) | |
}) | |
typeIntoTestId("Phone Number Field", "5") | |
await RNTL.waitFor(() => { | |
expect(phoneNumberField.props.value).toEqual("(012) 345") | |
expect(RNTL.screen.getByText("012345")) | |
}) | |
typeIntoTestId("Phone Number Field", "6") | |
await RNTL.waitFor(() => { | |
expect(phoneNumberField.props.value).toEqual("(012) 345-6") | |
expect(RNTL.screen.getByText("0123456")) | |
}) | |
typeIntoTestId("Phone Number Field", "7") | |
await RNTL.waitFor(() => { | |
expect(phoneNumberField.props.value).toEqual("(012) 345-67") | |
expect(RNTL.screen.getByText("01234567")) | |
}) | |
typeIntoTestId("Phone Number Field", "8") | |
await RNTL.waitFor(() => { | |
expect(phoneNumberField.props.value).toEqual("(012) 345-678") | |
expect(RNTL.screen.getByText("012345678")) | |
}) | |
typeIntoTestId("Phone Number Field", "9") | |
await RNTL.waitFor(() => { | |
expect(phoneNumberField.props.value).toEqual("(012) 345-6789") | |
expect(RNTL.screen.getByText("0123456789")) | |
}) | |
}) | |
}) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment