Browse Source

FEATURE | Create task tests (in progress)

tests
Oksana Stepanenko 11 months ago
parent
commit
a7e3f8a836
  1. 13
      e2e/changeWorkPhoneNumber.test.js
  2. 10
      e2e/createReason.test.js
  3. 85
      e2e/createTask.test.js
  4. 23
      e2e/editProfile.test.js
  5. 5
      e2e/logout.test.js
  6. 8
      e2e/signIn.test.js
  7. 3
      src/modules/root/smart-components/date-picker.smart-component.tsx
  8. 14
      src/modules/tasks/atoms/add-task-row.atom.tsx
  9. 1
      src/modules/tasks/atoms/create-task-description.atom.tsx
  10. 1
      src/modules/tasks/atoms/create-task-title-field.atom.tsx
  11. 8
      src/modules/tasks/components/set-task-interval.component.tsx
  12. 2
      src/modules/tasks/screens/add-update-task.screen.tsx
  13. 1
      src/modules/tasks/smart-components/select-task-executor-list.smart-component.tsx
  14. 3
      src/shared/components/forms/form-fake-date-input.component.tsx
  15. 7
      src/shared/components/forms/form-textarea.component.tsx

13
e2e/changeWorkPhoneNumber.test.js

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
/* eslint-disable no-undef */
const { config } = require('@/config')
const { insertPhoneAndEnter, goToProfileScreen } = require('./snippets')
const { newPhoneNumber } = require('./config')
@ -15,11 +16,13 @@ describe('Change work phone number', () => { @@ -15,11 +16,13 @@ describe('Change work phone number', () => {
it('Should success sign in the app with default phone number (need no confirmation)', async () => {
await insertPhoneAndEnter(config.defaultPhoneNumber)
await expect(element(by.id('homeScreen'))).toExist()
})
it('Should navigate to profile screen', async () => {
await goToProfileScreen()
await expect(element(by.text('Налаштування профілю'))).toBeVisible()
})
@ -30,11 +33,13 @@ describe('Change work phone number', () => { @@ -30,11 +33,13 @@ describe('Change work phone number', () => {
.scroll(250, 'down')
await element(by.id(`workPhone`)).tap()
await expect(element(by.id('workPhoneInput'))).toBeVisible()
})
it('Should not go further and show error message when trying to go ahead with empty phone number field', async () => {
await element(by.id('changeWorkPhoneBtn')).tap()
await expect(element(by.id('workPhoneInputError'))).toBeVisible()
})
@ -43,6 +48,7 @@ describe('Change work phone number', () => { @@ -43,6 +48,7 @@ describe('Change work phone number', () => {
config.defaultPhoneNumber,
)
await element(by.id('changeWorkPhoneBtn')).tap()
await expect(element(by.id('workPhoneInputError'))).toBeVisible()
await expect(element(by.id('workPhoneInputError'))).toHaveText(
'Номер зайнятий',
@ -53,11 +59,13 @@ describe('Change work phone number', () => { @@ -53,11 +59,13 @@ describe('Change work phone number', () => {
await element(by.id('workPhoneInput')).clearText()
await element(by.id('workPhoneInput')).typeText(newPhoneNumber)
await element(by.id('changeWorkPhoneBtn')).tap()
await expect(element(by.id('confirmCodeInput'))).toBeVisible()
})
it('Should not go further and show error message when trying to confirm change work phone number with empty OTP', async () => {
await element(by.id('confirmCodeBtn')).tap()
await expect(
element(
by.id('confirmCodeInputError').and(by.text("Обов'язкове поле")),
@ -68,6 +76,7 @@ describe('Change work phone number', () => { @@ -68,6 +76,7 @@ describe('Change work phone number', () => {
it('Should not go further and show error message when trying to confirm change work phone number with invalid OTP', async () => {
await element(by.id('confirmCodeInput')).typeText('0000')
await element(by.id('confirmCodeBtn')).tap()
await expect(element(by.text('Не дійсний код'))).toBeVisible()
})
@ -76,18 +85,21 @@ describe('Change work phone number', () => { @@ -76,18 +85,21 @@ describe('Change work phone number', () => {
.toBeVisible()
.withTimeout(config.initialTimerCount * 1000)
await element(by.text('Надіслати код повторно')).tap()
await expect(element(by.id('timer'))).toBeVisible()
})
it('Should success change work phone number with correct OTP', async () => {
await element(by.id('confirmCodeInput')).clearText()
await element(by.id('confirmCodeInput')).typeText('1234')
await expect(element(by.id('signInScreen'))).toBeVisible()
})
it('Should success sign in with new work phone number', async () => {
await insertPhoneAndEnter(newPhoneNumber)
await element(by.id('signInCodeInput')).typeText('1234')
await expect(element(by.id('homeScreen'))).toExist()
})
@ -104,6 +116,7 @@ describe('Change work phone number', () => { @@ -104,6 +116,7 @@ describe('Change work phone number', () => {
)
await element(by.id('changeWorkPhoneBtn')).tap()
await element(by.id('confirmCodeInput')).typeText('1234')
await expect(element(by.id('signInScreen'))).toBeVisible()
})
})

10
e2e/createReason.test.js

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
/* eslint-disable no-undef */
const { config } = require('@/config')
const { insertPhoneAndEnter, goToCreateTaskScreen } = require('./snippets')
const { personalReason, commonReason } = require('./config')
@ -24,35 +25,42 @@ describe('Create task reason', () => { @@ -24,35 +25,42 @@ describe('Create task reason', () => {
it('Should success sign in the app with default phone number (need no confirmation)', async () => {
await insertPhoneAndEnter(config.defaultPhoneNumber)
await expect(element(by.id('homeScreen'))).toExist()
})
it('Should navigate to create task screen', async () => {
await goToCreateTaskScreen()
await expect(element(by.text('Нова задача'))).toBeVisible()
})
it('Should open add new reason modal', async () => {
await openAddReasonModal()
await expect(element(by.id('reasonInput'))).toBeVisible()
})
it('Should close add reason modal and show error when trying to save personal reason with empty reason name field', async () => {
await element(by.id('savePersonalReasonBtn')).tap()
await expect(element(by.id('reasonInput'))).not.toBeVisible()
await expect(
element(by.id('infoModalTxt').and(by.text('Виникла помилка'))),
).toBeVisible()
await element(by.id('infoModalBtn')).tap()
})
it('Should close add reason modal and show error when trying to save common reason with empty reason name field', async () => {
await openAddReasonModal()
await element(by.id('saveCommonReasonBtn')).tap()
await expect(element(by.id('reasonInput'))).not.toBeVisible()
await expect(
element(by.id('infoModalTxt').and(by.text('Виникла помилка'))),
).toBeVisible()
await element(by.id('infoModalBtn')).tap()
})
@ -63,6 +71,7 @@ describe('Create task reason', () => { @@ -63,6 +71,7 @@ describe('Create task reason', () => {
else await element(by.id('reasonInput')).typeText(personalReason)
await element(by.id('savePersonalReasonBtn')).tap()
await expect(element(by.id('reasonInput'))).not.toBeVisible()
await expect(element(by.id('reasonSelectValue'))).toHaveText(
personalReason,
@ -75,6 +84,7 @@ describe('Create task reason', () => { @@ -75,6 +84,7 @@ describe('Create task reason', () => {
await element(by.id('reasonInput')).replaceText(commonReason)
else await element(by.id('reasonInput')).typeText(commonReason)
await element(by.id('saveCommonReasonBtn')).tap()
await expect(element(by.id('reasonInput'))).not.toBeVisible()
await expect(element(by.id('reasonSelectValue'))).toHaveText(
commonReason,

85
e2e/createTask.test.js

@ -0,0 +1,85 @@ @@ -0,0 +1,85 @@
const { config } = require('@/config')
const { insertPhoneAndEnter, goToCreateTaskScreen } = require('./snippets')
const requiredFields = ['executor', 'initiator', 'description', 'title']
const currentDate = new Date()
const checkFieldHasError = async fieldName => {
const field = `task${fieldName.charAt(0).toUpperCase()}${fieldName.slice(
1,
)}`
await waitFor(
element(
by
.id(`${field}Error`)
.and(by.text("Поле обов'язкове до заповнення")),
),
)
.toBeVisible()
.whileElement(by.id('editTaskScreenScroll'))
.scroll(250, 'up')
}
describe('Create task reason', () => {
beforeAll(async () => {
await device.launchApp({
permissions: {
notifications: 'YES',
},
newInstance: true,
delete: true,
})
})
it('Should success sign in the app with default phone number (need no confirmation)', async () => {
await insertPhoneAndEnter(config.defaultPhoneNumber)
await expect(element(by.id('homeScreen'))).toExist()
})
it('Should navigate to create task screen', async () => {
await goToCreateTaskScreen()
await expect(element(by.text('Нова задача'))).toBeVisible()
})
// ***** TEST SAVE EMPTY FIELDS *****
it('Should show errors under required fields when trying to create task without filling in those fields', async () => {
await element(by.id('editTaskScreenScroll')).scrollTo('bottom')
await element(by.id('saveTaskBtn')).tap()
for await (const field of requiredFields) {
await checkFieldHasError(field)
}
})
it("Should show error when trying to create task with end date that doesn't meet requirements", async () => {
await element(by.id('editTaskScreenScroll')).scrollTo('top')
await element(by.id('taskStartDate')).tap()
if (device.getPlatform() === 'android') {
const date = currentDate.getDate()
await element(by.text(date.toString())).swipe('up', 'slow')
await element(by.id('datePickerView')).tap({ x: 30, y: -200 })
} else {
const datePicker = element(by.id('datePicker'))
await datePicker.setDatePickerDate(
new Date(
currentDate.setDate(currentDate.getDate() + 2),
).toISOString(),
'ISO8601',
)
await element(by.type('RCTRootContentView')).tap({ x: 0, y: 0 })
}
await element(by.id('editTaskScreenScroll')).scrollTo('bottom')
await element(by.id('saveTaskBtn')).tap()
await waitFor(element(by.id('taskDateError')))
.toBeVisible()
.whileElement(by.id('editTaskScreenScroll'))
.scroll(250, 'up')
await expect(element(by.id('taskDateError'))).toBeVisible()
await expect(element(by.id('taskDateError'))).toHaveText(
'Кінцева дата не може бути меншою, ніж початкова',
)
})
})

23
e2e/editProfile.test.js

@ -1,8 +1,9 @@ @@ -1,8 +1,9 @@
/* eslint-disable no-undef */
const { config } = require('@/config')
const { insertPhoneAndEnter, goToProfileScreen } = require('./snippets')
const { fieldErrors, validProfileData } = require('./config')
const testSaveClearedField = async (fieldName: string) => {
const testSaveClearedField = async fieldName => {
await element(by.id(`profile${fieldName}Input`)).clearText()
await element(by.id('profileScreenScroll')).scrollTo('bottom')
await element(by.id('profileSaveBtn')).tap()
@ -18,10 +19,7 @@ const testSaveClearedField = async (fieldName: string) => { @@ -18,10 +19,7 @@ const testSaveClearedField = async (fieldName: string) => {
.scroll(250, 'up')
}
const testSaveInvalidData = async (
fieldName: string,
newValue: string | number,
) => {
const testSaveInvalidData = async (fieldName, newValue) => {
const field = `profile${fieldName}Input`
await element(by.id(field)).replaceText(newValue)
@ -46,7 +44,7 @@ const doBeforeActions = async () => { @@ -46,7 +44,7 @@ const doBeforeActions = async () => {
await goToProfileScreen()
}
const insertNewValue = async (fieldName: string, newValue: string | number) => {
const insertNewValue = async (fieldName, newValue) => {
const field = `profile${fieldName}Input`
if (fieldName === 'DOB') {
@ -60,7 +58,7 @@ const insertNewValue = async (fieldName: string, newValue: string | number) => { @@ -60,7 +58,7 @@ const insertNewValue = async (fieldName: string, newValue: string | number) => {
}
}
const fillFields = async (fieldName: string, newValue: string | number) => {
const fillFields = async (fieldName, newValue) => {
if (device.getPlatform() === 'android' && fieldName === 'DOB') return
const field = `profile${fieldName}Input`
@ -93,11 +91,13 @@ describe('Edit profile', () => { @@ -93,11 +91,13 @@ describe('Edit profile', () => {
it('Should success sign in the app with default phone number (need no confirmation)', async () => {
await insertPhoneAndEnter(config.defaultPhoneNumber)
await expect(element(by.id('homeScreen'))).toExist()
})
it('Should navigate to profile screen', async () => {
await goToProfileScreen()
await expect(element(by.text('Налаштування профілю'))).toBeVisible()
})
@ -190,6 +190,7 @@ describe('Edit profile', () => { @@ -190,6 +190,7 @@ describe('Edit profile', () => {
await element(by.id('profileSaveBtn')).tap()
await element(by.id('confirmModalOkBtn')).tap()
await expect(
element(by.id('infoModalTxt').and(by.text('Дані оновлені.'))),
).toBeVisible()
@ -207,6 +208,7 @@ describe('Edit profile', () => { @@ -207,6 +208,7 @@ describe('Edit profile', () => {
await element(by.id('profileScreenScroll')).scrollTo('bottom')
await element(by.id('profileSaveBtn')).tap()
await element(by.id('confirmModalOkBtn')).tap()
await expect(
element(by.id('infoModalTxt').and(by.text('Дані оновлені.'))),
).toBeVisible()
@ -222,6 +224,7 @@ describe('Edit profile', () => { @@ -222,6 +224,7 @@ describe('Edit profile', () => {
await element(by.id('profileScreenScroll')).scrollTo('bottom')
await element(by.id('profileSaveBtn')).tap()
await element(by.id('confirmModalOkBtn')).tap()
await expect(
element(
by
@ -237,10 +240,13 @@ describe('Edit profile', () => { @@ -237,10 +240,13 @@ describe('Edit profile', () => {
await doBeforeActions()
await element(by.id('profileAvatar')).tap()
await element(by.text('Фото з галереї')).tap()
await expect(element(by.id('clearAvatarBtn'))).toBeVisible()
await element(by.id('profileScreenScroll')).scrollTo('bottom')
await element(by.id('profileSaveBtn')).tap()
await element(by.id('confirmModalOkBtn')).tap()
await expect(
element(by.id('infoModalTxt').and(by.text('Дані оновлені.'))),
).toBeVisible()
@ -251,10 +257,13 @@ describe('Edit profile', () => { @@ -251,10 +257,13 @@ describe('Edit profile', () => {
it('Should clear profile avatar and show success message', async () => {
await doBeforeActions()
await element(by.id('clearAvatarBtn')).tap()
await expect(element(by.id('clearAvatarBtn'))).not.toBeVisible()
await element(by.id('profileScreenScroll')).scrollTo('bottom')
await element(by.id('profileSaveBtn')).tap()
await element(by.id('confirmModalOkBtn')).tap()
await expect(
element(by.id('infoModalTxt').and(by.text('Дані оновлені.'))),
).toBeVisible()

5
e2e/logout.test.js

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
/* eslint-disable no-undef */
const { config } = require('@/config')
const { insertPhoneAndEnter, goToProfileScreen } = require('./snippets')
@ -12,11 +13,13 @@ describe('Logout', () => { @@ -12,11 +13,13 @@ describe('Logout', () => {
it('Should success sign in the app with default phone number (need no confirmation)', async () => {
await insertPhoneAndEnter(config.defaultPhoneNumber)
await expect(element(by.id('homeScreen'))).toExist()
})
it('Should navigate to profile screen', async () => {
await goToProfileScreen()
await expect(element(by.text('Налаштування профілю'))).toBeVisible()
})
@ -24,6 +27,7 @@ describe('Logout', () => { @@ -24,6 +27,7 @@ describe('Logout', () => {
await element(by.id('profileScreenScroll')).scrollTo('bottom')
await element(by.id('profileLogoutBtn')).tap()
await element(by.id('confirmModalCancelBtn')).tap()
await expect(element(by.text('Налаштування профілю'))).toBeVisible()
})
@ -31,6 +35,7 @@ describe('Logout', () => { @@ -31,6 +35,7 @@ describe('Logout', () => {
await element(by.id('profileScreenScroll')).scrollTo('bottom')
await element(by.id('profileLogoutBtn')).tap()
await element(by.id('confirmModalOkBtn')).tap()
await expect(element(by.id('signInScreen'))).toBeVisible()
})
})

8
e2e/signIn.test.js

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
/* eslint-disable no-undef */
const { config } = require('@/config')
const { insertPhoneAndEnter } = require('./snippets')
@ -18,12 +19,14 @@ describe('Sign in', () => { @@ -18,12 +19,14 @@ describe('Sign in', () => {
it('Should not go further and show error message when trying to sign with empty phone number', async () => {
await element(by.id('signInBtn')).tap()
await expect(element(by.text("Обов'язкове поле"))).toExist()
})
it('Should not go further and show error message when trying to sign in with empty OTP', async () => {
await insertPhoneAndEnter(config.phoneNumber)
await element(by.id('sendCodeBtn')).tap()
await expect(element(by.text("Обов'язкове поле"))).toBeVisible()
})
@ -32,6 +35,7 @@ describe('Sign in', () => { @@ -32,6 +35,7 @@ describe('Sign in', () => {
await element(by.id('signInCodeInput')).typeText('0000')
await element(by.text('Вхід')).tap()
await element(by.id('sendCodeBtn')).tap()
await expect(element(by.text('Не дійсний код'))).toBeVisible()
})
@ -41,16 +45,19 @@ describe('Sign in', () => { @@ -41,16 +45,19 @@ describe('Sign in', () => {
.toBeVisible()
.withTimeout(config.initialTimerCount * 1000)
await element(by.text('Надіслати код повторно')).tap()
await expect(element(by.id('timer'))).toBeVisible()
})
it('Should not go further and show error message when trying to sign in with invalid phone number (not exists in DB))', async () => {
await insertPhoneAndEnter('123456789012')
await expect(element(by.text('Невірно введені дані'))).toBeVisible()
})
it('Should success sign in the app with default phone number (need no confirmation)', async () => {
await insertPhoneAndEnter(config.defaultPhoneNumber)
await expect(element(by.id('homeScreen'))).toExist()
})
@ -64,6 +71,7 @@ describe('Sign in', () => { @@ -64,6 +71,7 @@ describe('Sign in', () => {
await insertPhoneAndEnter(config.phoneNumber)
await element(by.id('signInCodeInput')).typeText('1234')
await expect(element(by.id('homeScreen'))).toExist()
})
})

3
src/modules/root/smart-components/date-picker.smart-component.tsx

@ -79,8 +79,9 @@ export const DatePickerSmartComponent: FC = () => { @@ -79,8 +79,9 @@ export const DatePickerSmartComponent: FC = () => {
keyboardBlurBehavior="restore"
onDismiss={onClose}
handleIndicatorStyle={[styles.indicator]}>
<View style={styles.wrapper}>
<View style={styles.wrapper} testID="datePickerView">
<DatePicker
testID="datePicker"
date={date}
mode={settingsRef.current.mode}
textColor={theme?.$textPrimary}

14
src/modules/tasks/atoms/add-task-row.atom.tsx

@ -11,6 +11,7 @@ interface IProps { @@ -11,6 +11,7 @@ interface IProps {
onPressDelIcon?: () => void
border?: boolean
error?: string
testID?: string
}
export const AddTaskRow: FC<IProps> = ({
@ -20,6 +21,7 @@ export const AddTaskRow: FC<IProps> = ({ @@ -20,6 +21,7 @@ export const AddTaskRow: FC<IProps> = ({
onPress,
onPressDelIcon,
border = true,
testID,
}) => {
const { styles, theme } = useTheme(createStyles)
@ -32,7 +34,9 @@ export const AddTaskRow: FC<IProps> = ({ @@ -32,7 +34,9 @@ export const AddTaskRow: FC<IProps> = ({
{rightComponent?.text ? (
<View style={styles.rigthBlock}>
<TouchableOpacity onPress={onPress}>
<Txt style={styles.text}>{rightComponent.text}</Txt>
<Txt style={styles.text} testID={testID}>
{rightComponent.text}
</Txt>
</TouchableOpacity>
{onPressDelIcon ? (
<RoundButton
@ -59,7 +63,13 @@ export const AddTaskRow: FC<IProps> = ({ @@ -59,7 +63,13 @@ export const AddTaskRow: FC<IProps> = ({
)}
</Pressable>
{error ? <Txt style={styles.error}>{error}</Txt> : null}
{error ? (
<Txt
style={styles.error}
testID={testID ? `${testID}Error` : null}>
{error}
</Txt>
) : null}
</>
)
}

1
src/modules/tasks/atoms/create-task-description.atom.tsx

@ -20,6 +20,7 @@ export const CreateTaskDescription: FC<IProps> = ({ @@ -20,6 +20,7 @@ export const CreateTaskDescription: FC<IProps> = ({
return (
<FormTextarea
testID="taskDescription"
name="description"
label="Опис"
inputStyle={styles.input}

1
src/modules/tasks/atoms/create-task-title-field.atom.tsx

@ -18,6 +18,7 @@ export const CreateTaskTitleField: FC<IProps> = ({ @@ -18,6 +18,7 @@ export const CreateTaskTitleField: FC<IProps> = ({
return (
<FormTextarea
testID="taskTitle"
name="title"
label="Назва"
inputStyle={styles.input}

8
src/modules/tasks/components/set-task-interval.component.tsx

@ -35,6 +35,7 @@ export const SetTaskInterval: FC<IProps> = ({ @@ -35,6 +35,7 @@ export const SetTaskInterval: FC<IProps> = ({
<>
<View style={styles.container}>
<FakeDateInputForm
testID="taskStartDate"
value={startDate.date}
onPress={() => openDateModal('startDate', startDate)}
title={'Початок'}
@ -42,6 +43,7 @@ export const SetTaskInterval: FC<IProps> = ({ @@ -42,6 +43,7 @@ export const SetTaskInterval: FC<IProps> = ({
/>
<FakeDateInputForm
testID="taskEndDate"
value={endDate.date}
onPress={() => openDateModal('endDate', endDate)}
title={'Кінець'}
@ -49,7 +51,11 @@ export const SetTaskInterval: FC<IProps> = ({ @@ -49,7 +51,11 @@ export const SetTaskInterval: FC<IProps> = ({
/>
</View>
{error && <Text style={styles.error}>{error}</Text>}
{error && (
<Text style={styles.error} testID="taskDateError">
{error}
</Text>
)}
</>
)
}

2
src/modules/tasks/screens/add-update-task.screen.tsx

@ -249,6 +249,7 @@ export const AddUpdateTaskScreen: FC<IProps> = ({ route, navigation }) => { @@ -249,6 +249,7 @@ export const AddUpdateTaskScreen: FC<IProps> = ({ route, navigation }) => {
)}
<AddTaskRow
testID="taskInitiator"
onPress={openSelectInitiatorModal}
onPressDelIcon={clearInitiatorField}
title={'Ініціатор'}
@ -307,6 +308,7 @@ export const AddUpdateTaskScreen: FC<IProps> = ({ route, navigation }) => { @@ -307,6 +308,7 @@ export const AddUpdateTaskScreen: FC<IProps> = ({ route, navigation }) => {
/>
<Button
testID="saveTaskBtn"
title={buttonTitle}
type={'primary'}
style={styles.submitBtn}

1
src/modules/tasks/smart-components/select-task-executor-list.smart-component.tsx

@ -47,6 +47,7 @@ export const SelectTaskExecutorListSmart: FC<IProps> = ({ @@ -47,6 +47,7 @@ export const SelectTaskExecutorListSmart: FC<IProps> = ({
return (
<>
<AddTaskRow
testID="taskExecutor"
title={'Виконавець'}
rightComponent={{ icon: 'plus-1' }}
onPress={() =>

3
src/shared/components/forms/form-fake-date-input.component.tsx

@ -19,6 +19,7 @@ interface IProps { @@ -19,6 +19,7 @@ interface IProps {
needIcon?: boolean
iconName?: string
disabled?: boolean
testID?: string
}
export const FakeDateInputForm = ({
@ -45,7 +46,7 @@ export const FakeDateInputForm = ({ @@ -45,7 +46,7 @@ export const FakeDateInputForm = ({
disabled={props.disabled}
/>
)}
<Text style={styles.date}>
<Text style={styles.date} testID={props.testID}>
{props.value &&
moment(new Date(props.value)).format('DD-MM-YYYY')}
{props.timeValue &&

7
src/shared/components/forms/form-textarea.component.tsx

@ -37,6 +37,7 @@ interface IProps { @@ -37,6 +37,7 @@ interface IProps {
disabled?: boolean
onSizeChange?: (reactNode: any) => void
inputProps?: TextInputProps
testID?: string
}
export const FormTextarea = ({ inputProps, ...props }: IProps) => {
@ -78,7 +79,11 @@ export const FormTextarea = ({ inputProps, ...props }: IProps) => { @@ -78,7 +79,11 @@ export const FormTextarea = ({ inputProps, ...props }: IProps) => {
/>
</View>
{props.error ? (
<Text style={styles.error}>{props.error}</Text>
<Text
style={styles.error}
testID={props.testID ? `${props.testID}Error` : null}>
{props.error}
</Text>
) : null}
{!props.disabled && Platform.OS === 'ios' ? (

Loading…
Cancel
Save