HEX
Server: LiteSpeed
System: Linux eko108.isimtescil.net 4.18.0-477.21.1.lve.1.el8.x86_64 #1 SMP Tue Sep 5 23:08:35 UTC 2023 x86_64
User: uyarreklamcomtr (11202)
PHP: 7.4.33
Disabled: opcache_get_status
Upload Files
File: /var/www/vhosts/uyarreklam.com.tr/httpdocs/test.tar
index.js000064400000006136151551725340006227 0ustar00/**
 * External dependencies
 */
import { renderHook } from '@testing-library/react-hooks';
/**
 * Internal dependencies
 */
import { registerCheckoutFilters, applyCheckoutFilter } from '../';

describe( 'Checkout registry', () => {
	const filterName = 'loremIpsum';

	test( 'should return default value if there are no filters', () => {
		const value = 'Hello World';
		const { result: newValue } = renderHook( () =>
			applyCheckoutFilter( {
				filterName,
				defaultValue: value,
			} )
		);
		expect( newValue.current ).toBe( value );
	} );

	test( 'should return filtered value when a filter is registered', () => {
		const value = 'Hello World';
		registerCheckoutFilters( filterName, {
			[ filterName ]: ( val, extensions, args ) =>
				val.toUpperCase() + args.punctuationSign,
		} );
		const { result: newValue } = renderHook( () =>
			applyCheckoutFilter( {
				filterName,
				defaultValue: value,
				arg: {
					punctuationSign: '!',
				},
			} )
		);

		expect( newValue.current ).toBe( 'HELLO WORLD!' );
	} );

	test( 'should not return filtered value if validation failed', () => {
		const value = 'Hello World';
		registerCheckoutFilters( filterName, {
			[ filterName ]: ( val ) => val.toUpperCase(),
		} );
		const { result: newValue } = renderHook( () =>
			applyCheckoutFilter( {
				filterName,
				defaultValue: value,
				validation: ( val ) => ! val.includes( 'HELLO' ),
			} )
		);

		expect( newValue.current ).toBe( value );
	} );

	test( 'should catch filter errors if user is not an admin', () => {
		const spy = {};
		spy.console = jest
			.spyOn( console, 'error' )
			.mockImplementation( () => {} );

		const error = new Error( 'test error' );
		// We use this new filter name here to avoid return the cached value for the filter
		const filterNameThatThrows = 'throw';
		const value = 'Hello World';
		registerCheckoutFilters( filterNameThatThrows, {
			[ filterNameThatThrows ]: () => {
				throw error;
			},
		} );
		const { result: newValue } = renderHook( () =>
			applyCheckoutFilter( {
				filterName: filterNameThatThrows,
				defaultValue: value,
			} )
		);

		expect( spy.console ).toHaveBeenCalledWith( error );
		expect( newValue.current ).toBe( value );
		spy.console.mockRestore();
	} );

	it( 'should allow filters to be registered multiple times and return the correct value each time', () => {
		const value = 'Hello World';
		registerCheckoutFilters( filterName, {
			[ filterName ]: ( val, extensions, args ) =>
				val.toUpperCase() + args?.punctuationSign,
		} );
		const { result: newValue } = renderHook( () =>
			applyCheckoutFilter( {
				filterName,
				defaultValue: value,
				arg: {
					punctuationSign: '!',
				},
			} )
		);
		expect( newValue.current ).toBe( 'HELLO WORLD!' );
		registerCheckoutFilters( filterName, {
			[ filterName ]: ( val, extensions, args ) =>
				args?.punctuationSign +
				val.toUpperCase() +
				args?.punctuationSign,
		} );
		const { result: newValue2 } = renderHook( () =>
			applyCheckoutFilter( {
				filterName,
				defaultValue: value,
				arg: {
					punctuationSign: '!',
				},
			} )
		);
		expect( newValue2.current ).toBe( '!HELLO WORLD!' );
	} );
} );
admin.js000064400000002640151552300330006171 0ustar00/**
 * External dependencies
 */
import { renderHook } from '@testing-library/react-hooks';
/**
 * Internal dependencies
 */
import { registerCheckoutFilters, applyCheckoutFilter } from '../';

jest.mock( '@woocommerce/settings', () => {
	const originalModule = jest.requireActual( '@woocommerce/settings' );
	return {
		// @ts-ignore We know @woocommerce/settings is an object.
		...originalModule,
		CURRENT_USER_IS_ADMIN: true,
	};
} );

describe( 'Checkout registry (as admin user)', () => {
	test( 'should throw if the filter throws and user is an admin', () => {
		const filterName = 'ErrorTestFilter';
		const value = 'Hello World';
		registerCheckoutFilters( filterName, {
			[ filterName ]: () => {
				throw new Error( 'test error' );
			},
		} );

		const { result } = renderHook( () =>
			applyCheckoutFilter( {
				filterName,
				defaultValue: value,
			} )
		);
		expect( result.error ).toEqual( Error( 'test error' ) );
	} );

	test( 'should throw if validation throws and user is an admin', () => {
		const filterName = 'ValidationTestFilter';
		const value = 'Hello World';
		registerCheckoutFilters( filterName, {
			[ filterName ]: ( val ) => val,
		} );
		const { result } = renderHook( () =>
			applyCheckoutFilter( {
				filterName,
				defaultValue: value,
				validation: () => {
					throw Error( 'validation error' );
				},
			} )
		);
		expect( result.error ).toEqual( Error( 'validation error' ) );
	} );
} );
price.js000064400000006177151553765760006243 0ustar00/**
 * Internal dependencies
 */
import { formatPrice, getCurrency } from '../price';

describe( 'The function formatPrice()', () => {
	test.each`
		value               | prefix    | suffix   | thousandSeparator | decimalSeparator | minorUnit | expected
		${ 1020 }           | ${ '€' }  | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 2 }    | ${ '€10.20' }
		${ 1000 }           | ${ '€' }  | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 2 }    | ${ '€10.00' }
		${ 1000 }           | ${ '' }   | ${ '€' } | ${ ',' }          | ${ '.' }         | ${ 2 }    | ${ '10.00€' }
		${ 1000 }           | ${ '' }   | ${ '$' } | ${ ',' }          | ${ '.' }         | ${ 2 }    | ${ '10.00$' }
		${ '1000' }         | ${ '€' }  | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 2 }    | ${ '€10.00' }
		${ 0 }              | ${ '€' }  | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 2 }    | ${ '€0.00' }
		${ '' }             | ${ '€' }  | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 2 }    | ${ '' }
		${ null }           | ${ '€' }  | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 2 }    | ${ '' }
		${ undefined }      | ${ '€' }  | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 2 }    | ${ '' }
		${ 100000 }         | ${ '€' }  | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 2 }    | ${ '€1,000.00' }
		${ 1000000 }        | ${ '€' }  | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 2 }    | ${ '€10,000.00' }
		${ 1000000000 }     | ${ '€' }  | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 2 }    | ${ '€10,000,000.00' }
		${ 10000000000 }    | ${ '€' }  | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 3 }    | ${ '€10,000,000.000' }
		${ 10000000000000 } | ${ '€ ' } | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 6 }    | ${ '€ 10,000,000.000000' }
		${ 10000000 }       | ${ '€ ' } | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 0 }    | ${ '€ 10,000,000' }
		${ 1000000099 }     | ${ '$' }  | ${ '' }  | ${ ',' }          | ${ '.' }         | ${ 2 }    | ${ '$10,000,000.99' }
		${ 1000000099 }     | ${ '$' }  | ${ '' }  | ${ '.' }          | ${ ',' }         | ${ 2 }    | ${ '$10.000.000,99' }
	`(
		'correctly formats price given "$value", "$prefix" prefix, "$suffix" suffix, "$thousandSeparator" thousandSeparator, "$decimalSeparator" decimalSeparator, and "$minorUnit" minorUnit as "$expected"',
		( {
			value,
			prefix,
			suffix,
			expected,
			thousandSeparator,
			decimalSeparator,
			minorUnit,
		} ) => {
			const formattedPrice = formatPrice(
				value,
				getCurrency( {
					prefix,
					suffix,
					thousandSeparator,
					decimalSeparator,
					minorUnit,
				} )
			);

			expect( formattedPrice ).toEqual( expected );
		}
	);

	test.each`
		value          | expected
		${ 1000 }      | ${ '$10.00' }
		${ 0 }         | ${ '$0.00' }
		${ '' }        | ${ '' }
		${ null }      | ${ '' }
		${ undefined } | ${ '' }
	`(
		'correctly formats price given "$value" only as "$expected"',
		( { value, expected } ) => {
			const formattedPrice = formatPrice( value );

			expect( formattedPrice ).toEqual( expected );
		}
	);
} );
index.tsx000064400000013340151556465040006427 0ustar00/**
 * External dependencies
 */
import { store as noticesStore } from '@wordpress/notices';
import { dispatch, select } from '@wordpress/data';
import { act, render, screen, waitFor } from '@testing-library/react';

/**
 * Internal dependencies
 */
import StoreNoticesContainer from '../index';

describe( 'StoreNoticesContainer', () => {
	it( 'Shows notices from the correct context', async () => {
		dispatch( noticesStore ).createErrorNotice( 'Custom test error', {
			id: 'custom-test-error',
			context: 'test-context',
		} );
		render( <StoreNoticesContainer context="test-context" /> );
		expect( screen.getAllByText( /Custom test error/i ) ).toHaveLength( 2 );
		// Clean up notices.
		await act( () =>
			dispatch( noticesStore ).removeNotice(
				'custom-test-error',
				'test-context'
			)
		);
		await waitFor( () => {
			return (
				select( noticesStore ).getNotices( 'test-context' ).length === 0
			);
		} );
	} );

	it( 'Does not show notices from other contexts', async () => {
		dispatch( noticesStore ).createErrorNotice( 'Custom test error 2', {
			id: 'custom-test-error-2',
			context: 'test-context',
		} );
		render( <StoreNoticesContainer context="other-context" /> );
		expect( screen.queryAllByText( /Custom test error 2/i ) ).toHaveLength(
			0
		);
		// Clean up notices.
		await act( () =>
			dispatch( noticesStore ).removeNotice(
				'custom-test-error-2',
				'test-context'
			)
		);
		await waitFor( () => {
			return (
				select( noticesStore ).getNotices( 'test-context' ).length === 0
			);
		} );
	} );

	it( 'Does not show snackbar notices', async () => {
		dispatch( noticesStore ).createErrorNotice( 'Custom test error 2', {
			id: 'custom-test-error-2',
			context: 'test-context',
			type: 'snackbar',
		} );
		render( <StoreNoticesContainer context="other-context" /> );
		expect( screen.queryAllByText( /Custom test error 2/i ) ).toHaveLength(
			0
		);
		// Clean up notices.
		await act( () =>
			dispatch( noticesStore ).removeNotice(
				'custom-test-error-2',
				'test-context'
			)
		);
		await waitFor( () => {
			return (
				select( noticesStore ).getNotices( 'test-context' ).length === 0
			);
		} );
	} );

	it( 'Shows additional notices', () => {
		render(
			<StoreNoticesContainer
				additionalNotices={ [
					{
						id: 'additional-test-error',
						status: 'error',
						spokenMessage: 'Additional test error',
						isDismissible: false,
						content: 'Additional test error',
						actions: [],
						speak: false,
						__unstableHTML: '',
						type: 'default',
					},
				] }
			/>
		);
		// Also counts the spokenMessage.
		expect( screen.getAllByText( /Additional test error/i ) ).toHaveLength(
			2
		);
	} );

	it( 'Shows notices from unregistered sub-contexts', async () => {
		dispatch( noticesStore ).createErrorNotice(
			'Custom first sub-context error',
			{
				id: 'custom-subcontext-test-error',
				context: 'wc/checkout/shipping-address',
			}
		);
		dispatch( noticesStore ).createErrorNotice(
			'Custom second sub-context error',
			{
				id: 'custom-subcontext-test-error',
				context: 'wc/checkout/billing-address',
			}
		);
		render( <StoreNoticesContainer context="wc/checkout" /> );
		// This should match against 2 messages, one for each sub-context.
		expect(
			screen.getAllByText( /Custom first sub-context error/i )
		).toHaveLength( 2 );
		expect(
			screen.getAllByText( /Custom second sub-context error/i )
		).toHaveLength( 2 );
		// Clean up notices.
		await act( () =>
			dispatch( noticesStore ).removeNotice(
				'custom-subcontext-test-error',
				'wc/checkout/shipping-address'
			)
		);
		await act( () =>
			dispatch( noticesStore ).removeNotice(
				'custom-subcontext-test-error',
				'wc/checkout/billing-address'
			)
		);
	} );

	it( 'Shows notices from several contexts', async () => {
		dispatch( noticesStore ).createErrorNotice( 'Custom shipping error', {
			id: 'custom-subcontext-test-error',
			context: 'wc/checkout/shipping-address',
		} );
		dispatch( noticesStore ).createErrorNotice( 'Custom billing error', {
			id: 'custom-subcontext-test-error',
			context: 'wc/checkout/billing-address',
		} );
		render(
			<StoreNoticesContainer
				context={ [
					'wc/checkout/billing-address',
					'wc/checkout/shipping-address',
				] }
			/>
		);
		// This should match against 4 elements; A written and spoken message for each error.
		expect( screen.getAllByText( /Custom shipping error/i ) ).toHaveLength(
			2
		);
		expect( screen.getAllByText( /Custom billing error/i ) ).toHaveLength(
			2
		);
		// Clean up notices.
		await act( () =>
			dispatch( noticesStore ).removeNotice(
				'custom-subcontext-test-error',
				'wc/checkout/shipping-address'
			)
		);
		await act( () =>
			dispatch( noticesStore ).removeNotice(
				'custom-subcontext-test-error',
				'wc/checkout/billing-address'
			)
		);
	} );

	it( 'Combine same notices from several contexts', async () => {
		dispatch( noticesStore ).createErrorNotice( 'Custom generic error', {
			id: 'custom-subcontext-test-error',
			context: 'wc/checkout/shipping-address',
		} );
		dispatch( noticesStore ).createErrorNotice( 'Custom generic error', {
			id: 'custom-subcontext-test-error',
			context: 'wc/checkout/billing-address',
		} );
		render(
			<StoreNoticesContainer
				context={ [
					'wc/checkout/billing-address',
					'wc/checkout/shipping-address',
				] }
			/>
		);
		// This should match against 2 elements; A written and spoken message.
		expect( screen.getAllByText( /Custom generic error/i ) ).toHaveLength(
			2
		);
		// Clean up notices.
		await act( () =>
			dispatch( noticesStore ).removeNotice(
				'custom-subcontext-test-error',
				'wc/checkout/shipping-address'
			)
		);
		await act( () =>
			dispatch( noticesStore ).removeNotice(
				'custom-subcontext-test-error',
				'wc/checkout/billing-address'
			)
		);
	} );
} );
is-postcode.ts000064400000010275151556465040007365 0ustar00/**
 * Internal dependencies
 */
import isPostcode from '../is-postcode';
import type { IsPostcodeProps } from '../is-postcode';

describe( 'isPostcode', () => {
	const cases = [
		// Austrian postcodes
		[ true, '1000', 'AT' ],
		[ true, '9999', 'AT' ],
		[ false, '0000', 'AT' ],
		[ false, '10000', 'AT' ],

		// Bosnian postcodes
		[ true, '71000', 'BA' ],
		[ true, '78256', 'BA' ],
		[ true, '89240', 'BA' ],
		[ false, '61000', 'BA' ],
		[ false, '7850', 'BA' ],

		// Belgian postcodes
		[ true, '1111', 'BE' ],
		[ false, '111', 'BE' ],
		[ false, '11111', 'BE' ],

		// Brazilian postcodes
		[ true, '99999-999', 'BR' ],
		[ true, '99999999', 'BR' ],
		[ false, '99999 999', 'BR' ],
		[ false, '99999-ABC', 'BR' ],

		// Canadian postcodes
		[ true, 'A9A 9A9', 'CA' ],
		[ true, 'A9A9A9', 'CA' ],
		[ true, 'a9a9a9', 'CA' ],
		[ false, 'D0A 9A9', 'CA' ],
		[ false, '99999', 'CA' ],
		[ false, 'ABC999', 'CA' ],
		[ false, '0A0A0A', 'CA' ],

		// Swiss postcodes
		[ true, '9999', 'CH' ],
		[ false, '99999', 'CH' ],
		[ false, 'ABCDE', 'CH' ],

		// Czech postcodes
		[ true, '160 00', 'CZ' ],
		[ true, '16000', 'CZ' ],
		[ false, '1600', 'CZ' ],

		// German postcodes
		[ true, '01234', 'DE' ],
		[ true, '12345', 'DE' ],
		[ false, '12 345', 'DE' ],
		[ false, '1234', 'DE' ],

		// Spanish postcodes
		[ true, '03000', 'ES' ],
		[ true, '08000', 'ES' ],
		[ false, '08 000', 'ES' ],
		[ false, '1234', 'ES' ],

		// French postcodes
		[ true, '01000', 'FR' ],
		[ true, '99999', 'FR' ],
		[ true, '01 000', 'FR' ],
		[ false, '1234', 'FR' ],

		// British postcodes
		[ true, 'AA9A 9AA', 'GB' ],
		[ true, 'A9A 9AA', 'GB' ],
		[ true, 'A9 9AA', 'GB' ],
		[ true, 'A99 9AA', 'GB' ],
		[ true, 'AA99 9AA', 'GB' ],
		[ true, 'BFPO 801', 'GB' ],
		[ false, '99999', 'GB' ],
		[ false, '9999 999', 'GB' ],
		[ false, '999 999', 'GB' ],
		[ false, '99 999', 'GB' ],
		[ false, '9A A9A', 'GB' ],

		// Hungarian postcodes
		[ true, '1234', 'HU' ],
		[ false, '123', 'HU' ],
		[ false, '12345', 'HU' ],

		// Irish postcodes
		[ true, 'A65F4E2', 'IE' ],
		[ true, 'A65 F4E2', 'IE' ],
		[ true, 'A65-F4E2', 'IE' ],
		[ false, 'B23F854', 'IE' ],

		// Indian postcodes
		[ true, '110001', 'IN' ],
		[ true, '110 001', 'IN' ],
		[ false, '11 0001', 'IN' ],
		[ false, '1100 01', 'IN' ],

		// Italian postcodes
		[ true, '99999', 'IT' ],
		[ false, '9999', 'IT' ],
		[ false, 'ABC 999', 'IT' ],
		[ false, 'ABC-999', 'IT' ],
		[ false, 'ABC_123', 'IT' ],

		// Japanese postcodes
		[ true, '1340088', 'JP' ],
		[ true, '134-0088', 'JP' ],
		[ false, '1340-088', 'JP' ],
		[ false, '12345', 'JP' ],
		[ false, '0123', 'JP' ],

		// Lichtenstein postcodes
		[ true, '9485', 'LI' ],
		[ true, '9486', 'LI' ],
		[ true, '9499', 'LI' ],
		[ false, '9585', 'LI' ],
		[ false, '9385', 'LI' ],
		[ false, '9475', 'LI' ],

		// Dutch postcodes
		[ true, '3852GC', 'NL' ],
		[ true, '3852 GC', 'NL' ],
		[ true, '3852 gc', 'NL' ],
		[ false, '3852SA', 'NL' ],
		[ false, '3852 SA', 'NL' ],
		[ false, '3852 sa', 'NL' ],

		// Polish postcodes
		[ true, '00-001', 'PL' ],
		[ true, '99-440', 'PL' ],
		[ false, '000-01', 'PL' ],
		[ false, '994-40', 'PL' ],
		[ false, '00001', 'PL' ],
		[ false, '99440', 'PL' ],

		// Puerto Rican postcodes
		[ true, '00901', 'PR' ],
		[ true, '00617', 'PR' ],
		[ true, '00602-1211', 'PR' ],
		[ false, '1234', 'PR' ],
		[ false, '0060-21211', 'PR' ],

		// Portuguese postcodes
		[ true, '1234-567', 'PT' ],
		[ true, '2345-678', 'PT' ],
		[ false, '123-4567', 'PT' ],
		[ false, '234-5678', 'PT' ],

		// Slovenian postcodes
		[ true, '1234', 'SI' ],
		[ true, '1000', 'SI' ],
		[ true, '9876', 'SI' ],
		[ false, '12345', 'SI' ],
		[ false, '0123', 'SI' ],

		// Slovak postcodes
		[ true, '010 01', 'SK' ],
		[ true, '01001', 'SK' ],
		[ false, '01 001', 'SK' ],
		[ false, '1234', 'SK' ],
		[ false, '123456', 'SK' ],

		// United States postcodes
		[ true, '90210', 'US' ],
		[ true, '99577-0727', 'US' ],
		[ false, 'ABCDE', 'US' ],
		[ false, 'ABCDE-9999', 'US' ],

		// Cambodian postcodes
		[ false, '12345', 'KH' ],
		[ false, '1234', 'KH' ],
		[ true, '123456', 'KH' ],
	];

	test.each( cases )( '%s: %s for %s', ( result, postcode, country ) =>
		expect( isPostcode( { postcode, country } as IsPostcodeProps ) ).toBe(
			result
		)
	);
} );
validated-text-input.tsx000064400000021571151560355250011375 0ustar00/**
 * External dependencies
 */
import { act, render, screen } from '@testing-library/react';
import { VALIDATION_STORE_KEY } from '@woocommerce/block-data';
import { dispatch, select } from '@wordpress/data';
import userEvent from '@testing-library/user-event';
import { useState } from '@wordpress/element';
import * as wpData from '@wordpress/data';

/**
 * Internal dependencies
 */
import ValidatedTextInput from '../validated-text-input';

jest.mock( '@wordpress/data', () => ( {
	__esModule: true,
	...jest.requireActual( '@wordpress/data' ),
	useDispatch: jest.fn().mockImplementation( ( args ) => {
		return jest.requireActual( '@wordpress/data' ).useDispatch( args );
	} ),
} ) );

describe( 'ValidatedTextInput', () => {
	it( 'Removes related validation error on change', async () => {
		render(
			<ValidatedTextInput
				instanceId={ '0' }
				accept={ 'image/*' }
				onChange={ () => void 0 }
				value={ 'Test' }
				id={ 'test-input' }
				label={ 'Test Input' }
			/>
		);

		await act( () =>
			dispatch( VALIDATION_STORE_KEY ).setValidationErrors( {
				'test-input': {
					message: 'Error message',
					hidden: false,
				},
			} )
		);

		await expect(
			select( VALIDATION_STORE_KEY ).getValidationError( 'test-input' )
		).not.toBe( undefined );
		const textInputElement = await screen.getByLabelText( 'Test Input' );
		await userEvent.type( textInputElement, 'New value' );
		await expect(
			select( VALIDATION_STORE_KEY ).getValidationError( 'test-input' )
		).toBe( undefined );
	} );
	it( 'Hides related validation error on change when id is not specified', async () => {
		render(
			<ValidatedTextInput
				instanceId={ '1' }
				accept={ 'image/*' }
				onChange={ () => void 0 }
				value={ 'Test' }
				label={ 'Test Input' }
			/>
		);

		await act( () =>
			dispatch( VALIDATION_STORE_KEY ).setValidationErrors( {
				'textinput-1': {
					message: 'Error message',
					hidden: false,
				},
			} )
		);
		await expect(
			select( VALIDATION_STORE_KEY ).getValidationError( 'textinput-1' )
		).not.toBe( undefined );
		const textInputElement = await screen.getByLabelText( 'Test Input' );
		await userEvent.type( textInputElement, 'New value' );
		await expect(
			select( VALIDATION_STORE_KEY ).getValidationError( 'textinput-1' )
		).toBe( undefined );
	} );
	it( 'Displays a passed error message', async () => {
		render(
			<ValidatedTextInput
				instanceId={ '2' }
				accept={ 'image/*' }
				onChange={ () => void 0 }
				value={ 'Test' }
				label={ 'Test Input' }
				errorMessage={ 'Custom error message' }
			/>
		);
		await act( () =>
			dispatch( VALIDATION_STORE_KEY ).setValidationErrors( {
				'textinput-2': {
					message: 'Error message in data store',
					hidden: false,
				},
			} )
		);
		const customErrorMessageElement = await screen.getByText(
			'Custom error message'
		);
		expect(
			screen.queryByText( 'Error message in data store' )
		).not.toBeInTheDocument();
		await expect( customErrorMessageElement ).toBeInTheDocument();
	} );
	it( 'Displays an error message from the data store', async () => {
		render(
			<ValidatedTextInput
				instanceId={ '3' }
				accept={ 'image/*' }
				onChange={ () => void 0 }
				value={ 'Test' }
				label={ 'Test Input' }
			/>
		);
		await act( () =>
			dispatch( VALIDATION_STORE_KEY ).setValidationErrors( {
				'textinput-3': {
					message: 'Error message 3',
					hidden: false,
				},
			} )
		);
		const errorMessageElement = await screen.getByText( 'Error message 3' );
		await expect( errorMessageElement ).toBeInTheDocument();
	} );
	it( 'Runs custom validation on the input', async () => {
		const TestComponent = () => {
			const [ inputValue, setInputValue ] = useState( 'Test' );
			return (
				<ValidatedTextInput
					instanceId={ '4' }
					id={ 'test-input' }
					onChange={ ( value ) => setInputValue( value ) }
					value={ inputValue }
					label={ 'Test Input' }
					customValidation={ ( inputObject ) => {
						return inputObject.value === 'Valid Value';
					} }
				/>
			);
		};
		render( <TestComponent /> );

		const textInputElement = await screen.getByLabelText( 'Test Input' );
		await userEvent.type( textInputElement, 'Invalid Value' );
		await expect(
			select( VALIDATION_STORE_KEY ).getValidationError( 'test-input' )
		).not.toBe( undefined );
		await userEvent.type( textInputElement, '{selectall}{del}Valid Value' );
		await expect( textInputElement.value ).toBe( 'Valid Value' );
		await expect(
			select( VALIDATION_STORE_KEY ).getValidationError( 'test-input' )
		).toBe( undefined );
	} );
	it( 'Shows a custom error message for an invalid required input', async () => {
		const TestComponent = () => {
			const [ inputValue, setInputValue ] = useState( '' );
			return (
				<ValidatedTextInput
					instanceId={ '5' }
					id={ 'test-input' }
					onChange={ ( value ) => setInputValue( value ) }
					value={ inputValue }
					label={ 'Test Input' }
					required={ true }
				/>
			);
		};
		render( <TestComponent /> );
		const textInputElement = await screen.getByLabelText( 'Test Input' );
		await userEvent.type( textInputElement, 'test' );
		await userEvent.type( textInputElement, '{selectall}{del}' );
		await textInputElement.blur();
		await expect(
			screen.queryByText( 'Please enter a valid test input' )
		).not.toBeNull();
	} );
	describe( 'correctly validates on mount', () => {
		it( 'validates when focusOnMount is true and validateOnMount is not set', async () => {
			const setValidationErrors = jest.fn();
			wpData.useDispatch.mockImplementation( ( storeName: string ) => {
				if ( storeName === VALIDATION_STORE_KEY ) {
					return {
						...jest
							.requireActual( '@wordpress/data' )
							.useDispatch( storeName ),
						setValidationErrors,
					};
				}
				return jest
					.requireActual( '@wordpress/data' )
					.useDispatch( storeName );
			} );

			const TestComponent = () => {
				const [ inputValue, setInputValue ] = useState( '' );
				return (
					<ValidatedTextInput
						instanceId={ '6' }
						id={ 'test-input' }
						onChange={ ( value ) => setInputValue( value ) }
						value={ inputValue }
						label={ 'Test Input' }
						required={ true }
						focusOnMount={ true }
					/>
				);
			};
			await render( <TestComponent /> );
			const textInputElement = await screen.getByLabelText(
				'Test Input'
			);
			await expect( textInputElement ).toHaveFocus();
			await expect( setValidationErrors ).toHaveBeenCalledWith( {
				'test-input': {
					message: 'Please enter a valid test input',
					hidden: true,
				},
			} );
		} );
		it( 'validates when focusOnMount is false, regardless of validateOnMount value', async () => {
			const setValidationErrors = jest.fn();
			wpData.useDispatch.mockImplementation( ( storeName: string ) => {
				if ( storeName === VALIDATION_STORE_KEY ) {
					return {
						...jest
							.requireActual( '@wordpress/data' )
							.useDispatch( storeName ),
						setValidationErrors,
					};
				}
				return jest
					.requireActual( '@wordpress/data' )
					.useDispatch( storeName );
			} );

			const TestComponent = ( { validateOnMount = false } ) => {
				const [ inputValue, setInputValue ] = useState( '' );
				return (
					<ValidatedTextInput
						instanceId={ '6' }
						id={ 'test-input' }
						onChange={ ( value ) => setInputValue( value ) }
						value={ inputValue }
						label={ 'Test Input' }
						required={ true }
						focusOnMount={ true }
						validateOnMount={ validateOnMount }
					/>
				);
			};
			const { rerender } = await render( <TestComponent /> );
			const textInputElement = await screen.getByLabelText(
				'Test Input'
			);
			await expect( textInputElement ).toHaveFocus();
			await expect( setValidationErrors ).not.toHaveBeenCalled();

			await rerender( <TestComponent validateOnMount={ true } /> );
			await expect( textInputElement ).toHaveFocus();
			await expect( setValidationErrors ).not.toHaveBeenCalled();
		} );
		it( 'does not validate when validateOnMount is false and focusOnMount is true', async () => {
			const setValidationErrors = jest.fn();
			wpData.useDispatch.mockImplementation( ( storeName: string ) => {
				if ( storeName === VALIDATION_STORE_KEY ) {
					return {
						...jest
							.requireActual( '@wordpress/data' )
							.useDispatch( storeName ),
						setValidationErrors,
					};
				}
				return jest
					.requireActual( '@wordpress/data' )
					.useDispatch( storeName );
			} );

			const TestComponent = () => {
				const [ inputValue, setInputValue ] = useState( '' );
				return (
					<ValidatedTextInput
						instanceId={ '6' }
						id={ 'test-input' }
						onChange={ ( value ) => setInputValue( value ) }
						value={ inputValue }
						label={ 'Test Input' }
						required={ true }
						focusOnMount={ true }
						validateOnMount={ false }
					/>
				);
			};
			await render( <TestComponent /> );
			const textInputElement = await screen.getByLabelText(
				'Test Input'
			);
			await expect( textInputElement ).toHaveFocus();
			await expect( setValidationErrors ).not.toHaveBeenCalled();
		} );
	} );
} );