diff --git a/src/CONST.ts b/src/CONST.ts index eda1dd34cc50..1a30b4d7058f 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1366,10 +1366,6 @@ const CONST = { ILLEGAL_FILENAME_CHARACTERS: /\/|<|>|\*|"|:|\?|\\|\|/g, ENCODE_PERCENT_CHARACTER: /%(25)+/g, - - INVISIBLE_CHARACTERS_GROUPS: /[\p{C}\p{Z}]/gu, - - OTHER_INVISIBLE_CHARACTERS: /[\u3164]/g, }, PRONOUNS: { diff --git a/src/components/Form.js b/src/components/Form.js index 372c7a0c5d9b..4d3acf754715 100644 --- a/src/components/Form.js +++ b/src/components/Form.js @@ -6,7 +6,6 @@ import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import compose from '@libs/compose'; import * as ErrorUtils from '@libs/ErrorUtils'; -import * as ValidationUtils from '@libs/ValidationUtils'; import Visibility from '@libs/Visibility'; import stylePropTypes from '@styles/stylePropTypes'; import styles from '@styles/styles'; @@ -127,8 +126,14 @@ function Form(props) { */ const onValidate = useCallback( (values, shouldClearServerError = true) => { - // Trim all string values - const trimmedStringValues = ValidationUtils.prepareValues(values); + const trimmedStringValues = {}; + _.each(values, (inputValue, inputID) => { + if (_.isString(inputValue)) { + trimmedStringValues[inputID] = inputValue.trim(); + } else { + trimmedStringValues[inputID] = inputValue; + } + }); if (shouldClearServerError) { FormActions.setErrors(props.formID, null); @@ -186,7 +191,7 @@ function Form(props) { return touchedInputErrors; }, - [props.formID, validate, errors], + [errors, touchedInputs, props.formID, validate], ); useEffect(() => { @@ -223,14 +228,11 @@ function Form(props) { return; } - // Trim all string values - const trimmedStringValues = ValidationUtils.prepareValues(inputValues); - // Touches all form inputs so we can validate the entire form _.each(inputRefs.current, (inputRef, inputID) => (touchedInputs.current[inputID] = true)); // Validate form and return early if any errors are found - if (!_.isEmpty(onValidate(trimmedStringValues))) { + if (!_.isEmpty(onValidate(inputValues))) { return; } @@ -240,8 +242,8 @@ function Form(props) { } // Call submit handler - onSubmit(trimmedStringValues); - }, [props.formState.isLoading, props.network.isOffline, props.enabledWhenOffline, inputValues, onValidate, onSubmit]); + onSubmit(inputValues); + }, [props.formState, onSubmit, inputRefs, inputValues, onValidate, touchedInputs, props.network.isOffline, props.enabledWhenOffline]); /** * Loops over Form's children and automatically supplies Form props to them diff --git a/src/components/Form/FormProvider.js b/src/components/Form/FormProvider.js index fa0cc3ebd723..92baa9727832 100644 --- a/src/components/Form/FormProvider.js +++ b/src/components/Form/FormProvider.js @@ -6,7 +6,6 @@ import _ from 'underscore'; import networkPropTypes from '@components/networkPropTypes'; import {withNetwork} from '@components/OnyxProvider'; import compose from '@libs/compose'; -import * as ValidationUtils from '@libs/ValidationUtils'; import Visibility from '@libs/Visibility'; import stylePropTypes from '@styles/stylePropTypes'; import * as FormActions from '@userActions/FormActions'; @@ -109,7 +108,14 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC const onValidate = useCallback( (values, shouldClearServerError = true) => { - const trimmedStringValues = ValidationUtils.prepareValues(values); + const trimmedStringValues = {}; + _.each(values, (inputValue, inputID) => { + if (_.isString(inputValue)) { + trimmedStringValues[inputID] = inputValue.trim(); + } else { + trimmedStringValues[inputID] = inputValue; + } + }); if (shouldClearServerError) { FormActions.setErrors(formID, null); @@ -180,14 +186,11 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC return; } - // Prepare values before submitting - const trimmedStringValues = ValidationUtils.prepareValues(inputValues); - // Touches all form inputs so we can validate the entire form _.each(inputRefs.current, (inputRef, inputID) => (touchedInputs.current[inputID] = true)); // Validate form and return early if any errors are found - if (!_.isEmpty(onValidate(trimmedStringValues))) { + if (!_.isEmpty(onValidate(inputValues))) { return; } @@ -196,7 +199,7 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC return; } - onSubmit(trimmedStringValues); + onSubmit(inputValues); }, [enabledWhenOffline, formState.isLoading, inputValues, network.isOffline, onSubmit, onValidate]); const registerInput = useCallback( diff --git a/src/libs/StringUtils.ts b/src/libs/StringUtils.ts index 3c721302e5c0..290380ce2cff 100644 --- a/src/libs/StringUtils.ts +++ b/src/libs/StringUtils.ts @@ -10,50 +10,4 @@ function sanitizeString(str: string): string { return _.deburr(str).toLowerCase().replaceAll(CONST.REGEX.NON_ALPHABETIC_AND_NON_LATIN_CHARS, ''); } -/** - * Check if the string would be empty if all invisible characters were removed. - */ -function isEmptyString(value: string): boolean { - // \p{C} matches all 'Other' characters - // \p{Z} matches all separators (spaces etc.) - // Source: http://www.unicode.org/reports/tr18/#General_Category_Property - let transformed = value.replace(CONST.REGEX.INVISIBLE_CHARACTERS_GROUPS, ''); - - // Remove other invisible characters that are not in the above unicode categories - transformed = transformed.replace(CONST.REGEX.OTHER_INVISIBLE_CHARACTERS, ''); - - // Check if after removing invisible characters the string is empty - return transformed === ''; -} - -/** - * Remove invisible characters from a string except for spaces and format characters for emoji, and trim it. - */ -function removeInvisibleCharacters(value: string): string { - let result = value; - - // Remove spaces: - // - \u200B: zero-width space - // - \u00A0: non-breaking space - // - \u2060: word joiner - result = result.replace(/[\u200B\u00A0\u2060]/g, ''); - - // Remove all characters from the 'Other' (C) category except for format characters (Cf) - // because some of them are used for emojis - result = result.replace(/[\p{Cc}\p{Cs}\p{Co}\p{Cn}]/gu, ''); - - // Remove characters from the (Cf) category that are not used for emojis - result = result.replace(/[\u200E-\u200F]/g, ''); - - // Remove all characters from the 'Separator' (Z) category except for Space Separator (Zs) - result = result.replace(/[\p{Zl}\p{Zp}]/gu, ''); - - // If the result consist of only invisible characters, return an empty string - if (isEmptyString(result)) { - return ''; - } - - return result.trim(); -} - -export default {sanitizeString, isEmptyString, removeInvisibleCharacters}; +export default {sanitizeString}; diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts index 7c49006c10a5..5947d45a6f76 100644 --- a/src/libs/ValidationUtils.ts +++ b/src/libs/ValidationUtils.ts @@ -9,7 +9,6 @@ import {Report} from '@src/types/onyx'; import * as OnyxCommon from '@src/types/onyx/OnyxCommon'; import * as CardUtils from './CardUtils'; import * as LoginUtils from './LoginUtils'; -import StringUtils from './StringUtils'; /** * Implements the Luhn Algorithm, a checksum formula used to validate credit card @@ -74,7 +73,7 @@ function isValidPastDate(date: string | Date): boolean { */ function isRequiredFulfilled(value: string | Date | unknown[] | Record): boolean { if (typeof value === 'string') { - return !StringUtils.isEmptyString(value); + return value.trim().length > 0; } if (isDate(value)) { @@ -353,25 +352,6 @@ function isValidAccountRoute(accountID: number): boolean { return CONST.REGEX.NUMBER.test(String(accountID)) && accountID > 0; } -type ValuesType = Record; - -/** - * This function is used to remove invisible characters from strings before validation and submission. - */ -function prepareValues(values: ValuesType): ValuesType { - const trimmedStringValues: ValuesType = {}; - - for (const [inputID, inputValue] of Object.entries(values)) { - if (typeof inputValue === 'string') { - trimmedStringValues[inputID] = StringUtils.removeInvisibleCharacters(inputValue); - } else { - trimmedStringValues[inputID] = inputValue; - } - } - - return trimmedStringValues; -} - export { meetsMinimumAgeRequirement, meetsMaximumAgeRequirement, @@ -405,5 +385,4 @@ export { isNumeric, isValidAccountRoute, isValidRecoveryCode, - prepareValues, }; diff --git a/src/pages/workspace/WorkspaceSettingsPage.js b/src/pages/workspace/WorkspaceSettingsPage.js index 789726a915a8..b78e593e8c8a 100644 --- a/src/pages/workspace/WorkspaceSettingsPage.js +++ b/src/pages/workspace/WorkspaceSettingsPage.js @@ -20,7 +20,6 @@ import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import * as UserUtils from '@libs/UserUtils'; -import * as ValidationUtils from '@libs/ValidationUtils'; import styles from '@styles/styles'; import * as Policy from '@userActions/Policy'; import CONST from '@src/CONST'; @@ -78,7 +77,7 @@ function WorkspaceSettingsPage({policy, currencyList, windowWidth, route}) { const errors = {}; const name = values.name.trim(); - if (!ValidationUtils.isRequiredFulfilled(name)) { + if (!name || !name.length) { errors.name = 'workspace.editor.nameIsRequiredError'; } else if ([...name].length > CONST.WORKSPACE_NAME_CHARACTER_LIMIT) { // Uses the spread syntax to count the number of Unicode code points instead of the number of UTF-16 diff --git a/src/stories/Form.stories.js b/src/stories/Form.stories.js index e09ec755b68d..d385cf0613e6 100644 --- a/src/stories/Form.stories.js +++ b/src/stories/Form.stories.js @@ -10,7 +10,6 @@ import StatePicker from '@components/StatePicker'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; import NetworkConnection from '@libs/NetworkConnection'; -import * as ValidationUtils from '@libs/ValidationUtils'; import styles from '@styles/styles'; import * as FormActions from '@userActions/FormActions'; import CONST from '@src/CONST'; @@ -178,28 +177,28 @@ const defaultArgs = { submitButtonText: 'Submit', validate: (values) => { const errors = {}; - if (!ValidationUtils.isRequiredFulfilled(values.routingNumber)) { + if (!values.routingNumber) { errors.routingNumber = 'Please enter a routing number'; } - if (!ValidationUtils.isRequiredFulfilled(values.accountNumber)) { + if (!values.accountNumber) { errors.accountNumber = 'Please enter an account number'; } - if (!ValidationUtils.isRequiredFulfilled(values.street)) { + if (!values.street) { errors.street = 'Please enter an address'; } - if (!ValidationUtils.isRequiredFulfilled(values.dob)) { + if (!values.dob) { errors.dob = 'Please enter your date of birth'; } - if (!ValidationUtils.isRequiredFulfilled(values.pickFruit)) { + if (!values.pickFruit) { errors.pickFruit = 'Please select a fruit'; } - if (!ValidationUtils.isRequiredFulfilled(values.pickAnotherFruit)) { + if (!values.pickAnotherFruit) { errors.pickAnotherFruit = 'Please select a fruit'; } - if (!ValidationUtils.isRequiredFulfilled(values.state)) { + if (!values.state) { errors.state = 'Please select a state'; } - if (!ValidationUtils.isRequiredFulfilled(values.checkbox)) { + if (!values.checkbox) { errors.checkbox = 'You must accept the Terms of Service to continue'; } return errors; diff --git a/tests/unit/isEmptyString.js b/tests/unit/isEmptyString.js deleted file mode 100644 index 0de9b791fa97..000000000000 --- a/tests/unit/isEmptyString.js +++ /dev/null @@ -1,92 +0,0 @@ -import _ from 'underscore'; -import enEmojis from '../../assets/emojis/en'; -import StringUtils from '../../src/libs/StringUtils'; - -describe('libs/StringUtils.isEmptyString', () => { - it('basic tests', () => { - expect(StringUtils.isEmptyString('test')).toBe(false); - expect(StringUtils.isEmptyString('test test')).toBe(false); - expect(StringUtils.isEmptyString('test test test')).toBe(false); - expect(StringUtils.isEmptyString(' ')).toBe(true); - }); - it('trim spaces', () => { - expect(StringUtils.isEmptyString(' test')).toBe(false); - expect(StringUtils.isEmptyString('test ')).toBe(false); - expect(StringUtils.isEmptyString(' test ')).toBe(false); - }); - it('remove invisible characters', () => { - expect(StringUtils.isEmptyString('\u200B')).toBe(true); - expect(StringUtils.isEmptyString('\u200B')).toBe(true); - expect(StringUtils.isEmptyString('\u200B ')).toBe(true); - expect(StringUtils.isEmptyString('\u200B \u200B')).toBe(true); - expect(StringUtils.isEmptyString('\u200B \u200B ')).toBe(true); - }); - it('remove invisible characters (Cc)', () => { - expect(StringUtils.isEmptyString('\u0000')).toBe(true); - expect(StringUtils.isEmptyString('\u0001')).toBe(true); - expect(StringUtils.isEmptyString('\u0009')).toBe(true); - }); - it('remove invisible characters (Cf)', () => { - expect(StringUtils.isEmptyString('\u200E')).toBe(true); - expect(StringUtils.isEmptyString('\u200F')).toBe(true); - expect(StringUtils.isEmptyString('\u2060')).toBe(true); - }); - it('remove invisible characters (Cs)', () => { - expect(StringUtils.isEmptyString('\uD800')).toBe(true); - expect(StringUtils.isEmptyString('\uD801')).toBe(true); - expect(StringUtils.isEmptyString('\uD802')).toBe(true); - }); - it('remove invisible characters (Co)', () => { - expect(StringUtils.isEmptyString('\uE000')).toBe(true); - expect(StringUtils.isEmptyString('\uE001')).toBe(true); - expect(StringUtils.isEmptyString('\uE002')).toBe(true); - }); - it('remove invisible characters (Zl)', () => { - expect(StringUtils.isEmptyString('\u2028')).toBe(true); - expect(StringUtils.isEmptyString('\u2029')).toBe(true); - expect(StringUtils.isEmptyString('\u202A')).toBe(true); - }); - it('basic check emojis not removed', () => { - expect(StringUtils.isEmptyString('😀')).toBe(false); - }); - it('all emojis not removed', () => { - _.keys(enEmojis).forEach((key) => { - expect(StringUtils.isEmptyString(key)).toBe(false); - }); - }); - it('remove invisible characters (editpad)', () => { - expect(StringUtils.isEmptyString('\u0020')).toBe(true); - expect(StringUtils.isEmptyString('\u00A0')).toBe(true); - expect(StringUtils.isEmptyString('\u2000')).toBe(true); - expect(StringUtils.isEmptyString('\u2001')).toBe(true); - expect(StringUtils.isEmptyString('\u2002')).toBe(true); - expect(StringUtils.isEmptyString('\u2003')).toBe(true); - expect(StringUtils.isEmptyString('\u2004')).toBe(true); - expect(StringUtils.isEmptyString('\u2005')).toBe(true); - expect(StringUtils.isEmptyString('\u2006')).toBe(true); - expect(StringUtils.isEmptyString('\u2007')).toBe(true); - expect(StringUtils.isEmptyString('\u2008')).toBe(true); - expect(StringUtils.isEmptyString('\u2009')).toBe(true); - expect(StringUtils.isEmptyString('\u200A')).toBe(true); - expect(StringUtils.isEmptyString('\u2028')).toBe(true); - expect(StringUtils.isEmptyString('\u205F')).toBe(true); - expect(StringUtils.isEmptyString('\u3000')).toBe(true); - expect(StringUtils.isEmptyString(' ')).toBe(true); - }); - it('other tests', () => { - expect(StringUtils.isEmptyString('\u200D')).toBe(true); - expect(StringUtils.isEmptyString('\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67\uDB40\uDC7F')).toBe(false); - expect(StringUtils.isEmptyString('\uD83C')).toBe(true); - expect(StringUtils.isEmptyString('\uDFF4')).toBe(true); - expect(StringUtils.isEmptyString('\uDB40')).toBe(true); - expect(StringUtils.isEmptyString('\uDC67')).toBe(true); - expect(StringUtils.isEmptyString('\uDC62')).toBe(true); - expect(StringUtils.isEmptyString('\uDC65')).toBe(true); - expect(StringUtils.isEmptyString('\uDC6E')).toBe(true); - expect(StringUtils.isEmptyString('\uDC67')).toBe(true); - expect(StringUtils.isEmptyString('\uDC7F')).toBe(true); - - // A special test, an invisible character from other Unicode categories than format and control - expect(StringUtils.isEmptyString('\u3164')).toBe(true); - }); -}); diff --git a/tests/unit/removeInvisibleCharacters.js b/tests/unit/removeInvisibleCharacters.js deleted file mode 100644 index f0495b004583..000000000000 --- a/tests/unit/removeInvisibleCharacters.js +++ /dev/null @@ -1,120 +0,0 @@ -import _ from 'underscore'; -import enEmojis from '../../assets/emojis/en'; -import StringUtils from '../../src/libs/StringUtils'; - -describe('libs/StringUtils.removeInvisibleCharacters', () => { - it('basic tests', () => { - expect(StringUtils.removeInvisibleCharacters('test')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test test')).toBe('test test'); - expect(StringUtils.removeInvisibleCharacters('abcdefghijklmnopqrstuvwxyz')).toBe('abcdefghijklmnopqrstuvwxyz'); - expect(StringUtils.removeInvisibleCharacters('ABCDEFGHIJKLMNOPQRSTUVWXYZ')).toBe('ABCDEFGHIJKLMNOPQRSTUVWXYZ'); - expect(StringUtils.removeInvisibleCharacters('0123456789')).toBe('0123456789'); - expect(StringUtils.removeInvisibleCharacters('!@#$%^&*()_+-=[]{}|;:\'",.<>/?`~')).toBe('!@#$%^&*()_+-=[]{}|;:\'",.<>/?`~'); - expect(StringUtils.removeInvisibleCharacters('')).toBe(''); - expect(StringUtils.removeInvisibleCharacters(' ')).toBe(''); - }); - it('other alphabets, list of all characters', () => { - // arabic - expect(StringUtils.removeInvisibleCharacters('أبجدية عربية')).toBe('أبجدية عربية'); - // chinese - expect(StringUtils.removeInvisibleCharacters('的一是了我不人在他们')).toBe('的一是了我不人在他们'); - // cyrillic - expect(StringUtils.removeInvisibleCharacters('абвгдезиклмнопр')).toBe('абвгдезиклмнопр'); - // greek - expect(StringUtils.removeInvisibleCharacters('αβγδεζηθικλμνξοπρ')).toBe('αβγδεζηθικλμνξοπρ'); - // hebrew - expect(StringUtils.removeInvisibleCharacters('אבגדהוזחטיכלמנ')).toBe('אבגדהוזחטיכלמנ'); - // hindi - expect(StringUtils.removeInvisibleCharacters('अआइईउऊऋऍऎ')).toBe('अआइईउऊऋऍऎ'); - // japanese - expect(StringUtils.removeInvisibleCharacters('あいうえおかきくけこ')).toBe('あいうえおかきくけこ'); - // korean - expect(StringUtils.removeInvisibleCharacters('가나다라마바사아자')).toBe('가나다라마바사아자'); - // thai - expect(StringUtils.removeInvisibleCharacters('กขคงจฉชซ')).toBe('กขคงจฉชซ'); - }); - it('trim spaces', () => { - expect(StringUtils.removeInvisibleCharacters(' test')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test ')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters(' test ')).toBe('test'); - }); - it('remove invisible characters', () => { - expect(StringUtils.removeInvisibleCharacters('test\u200B')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u200Btest')).toBe('testtest'); - expect(StringUtils.removeInvisibleCharacters('test\u200B test')).toBe('test test'); - expect(StringUtils.removeInvisibleCharacters('test\u200B test\u200B')).toBe('test test'); - expect(StringUtils.removeInvisibleCharacters('test\u200B test\u200B test')).toBe('test test test'); - }); - it('remove invisible characters (Cc)', () => { - expect(StringUtils.removeInvisibleCharacters('test\u0000')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u0001')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u0009')).toBe('test'); - }); - it('remove invisible characters (Cf)', () => { - expect(StringUtils.removeInvisibleCharacters('test\u200E')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u200F')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u2060')).toBe('test'); - }); - it('check other visible characters (Cs)', () => { - expect(StringUtils.removeInvisibleCharacters('test\uD800')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\uD801')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\uD802')).toBe('test'); - }); - it('check other visible characters (Co)', () => { - expect(StringUtils.removeInvisibleCharacters('test\uE000')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\uE001')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\uE002')).toBe('test'); - }); - it('remove invisible characters (Cn)', () => { - expect(StringUtils.removeInvisibleCharacters('test\uFFF0')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\uFFF1')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\uFFF2')).toBe('test'); - }); - it('remove invisible characters (Zl)', () => { - expect(StringUtils.removeInvisibleCharacters('test\u2028')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u2029')).toBe('test'); - }); - it('basic check emojis not removed', () => { - expect(StringUtils.removeInvisibleCharacters('test😀')).toBe('test😀'); - expect(StringUtils.removeInvisibleCharacters('test😀😀')).toBe('test😀😀'); - expect(StringUtils.removeInvisibleCharacters('test😀😀😀')).toBe('test😀😀😀'); - }); - it('all emojis not removed', () => { - _.keys(enEmojis).forEach((key) => { - expect(StringUtils.removeInvisibleCharacters(key)).toBe(key); - }); - }); - it('remove invisible characters (editpad)', () => { - expect(StringUtils.removeInvisibleCharacters('test\u0020')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u00A0')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u2000')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u2001')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u2002')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u2003')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u2004')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u2005')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u2006')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u2007')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u2008')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u2009')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u200A')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u2028')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u205F')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test\u3000')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test ')).toBe('test'); - }); - it('other tests', () => { - expect(StringUtils.removeInvisibleCharacters('\uD83D\uDE36\u200D\uD83C\uDF2B\uFE0F')).toBe('😶‍🌫️'); - expect(StringUtils.removeInvisibleCharacters('⁠test')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('test⁠test')).toBe('testtest'); - expect(StringUtils.removeInvisibleCharacters('  ‎ ‏ ⁠   ')).toBe(''); - expect(StringUtils.removeInvisibleCharacters('te ‎‏⁠st')).toBe('test'); - expect(StringUtils.removeInvisibleCharacters('\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67\uDB40\uDC7F')).toBe('🏴󠁧󠁢󠁥󠁮󠁧󠁿'); - }); - it('special scenarios', () => { - // Normally we do not remove this character, because it is used in Emojis. - // But if the String consist of only invisible characters, we can safely remove it. - expect(StringUtils.removeInvisibleCharacters('\u200D')).toBe(''); - expect(StringUtils.removeInvisibleCharacters('⁠')).toBe(''); - }); -});