woocommerce/plugins/woocommerce-blocks/assets/js/data/validation/test/reducers.ts

249 lines
6.5 KiB
TypeScript
Raw Normal View History

Convert validation context to data store (https://github.com/woocommerce/woocommerce-blocks/pull/6402) * Add validation reducers, actions, and action types * Add selector for getValidationErrors * Export store key and register store * Export validation store key * Move TextInput files to checkout package * Export ValidatedTextInput from blocks-checkout package * Update imports of ValidatedTextInput to reflect new location * Use the validation wp-data store for showing error messages * Export getValidationError in checkout package * Move validation store to checkout package * Move ValidationInputError to blocks-checkout package * Only export "exposedSelectors" from validation * Convert validation context to data store * Fixed linting error * Fixed linting error * Change the validation selectors to return a function * Convert reducer and selectors to TS * Remove superfluous comments and improve test titles * Test to ensure visible errors remain visible * Make test for hasValidationErrors more robust * Augment the wp-data module to include our selectors and actions * Removed unused `exposedSelectors` variable * Remove TS error because of `instanceId` on props * Remove unnecessary as const * Use function returned by getValidationError * Use correct selector/action names now context has been decoupled * hide validation error when input value changes * Add correct aria-describedBy now we can get error id from store * Clear validation error from store when component unmounts * Clear validation error if input is valid * convert ValidationInputError to TS and get correct id/error from store * Ensure checkout block doesn't break when there are no errors * Get validation data from the store instead of context * Update country input to remove validation context * Move validation store out of checkout package * Move TextInput and ValidationInputError back out of the checkout package * Remove duplicate internal styles comment * Remove exports that no longer exist * Get validation store key from block-data * Make attribute-select-control use validation data store * Export FieldValidationStatus type * Make combobox use validation store not context * Make Address use validation store not context * Make Address use validation store not context * Use hasValidationErrors selector as a function in shipping calculator * Remove validation context from coupon story * Import VALIDATION_STORE_KEY from correct location * Stop coupon story from erroring * Update useStoreCartCoupons to use validation store not context * Make TotalsCoupon use validation store instead of context * Make AddToCartFormContext use validation store not context * Remove ValidationContext * Import FieldValidationStatus from correct location * Import ValidatedTextInput and ValidatedTextInput from correct location * Remove ValidationContextProvider * Update components to use validation store not context * Update useValidation to use the data store * Replace the validation context in checkout-events file * Use the re-mapped path for the store key import * Use "register" instead of the deprecated "registerStore" * Fix import error of the "FieldValidationStatus" type * Use TS instead of React's "PropTypes" * Fix the type of "ValidationInputError" in the "payment-method-interface" * Fix error not showing on the first place order click bug We were mutating the state in the reducer, which prevented re-rendering on state change * Fix state mutation issue in the Validation reducer Co-authored-by: Thomas Roberts <thomas.roberts@automattic.com> Co-authored-by: Saad Tarhi <saad.trh@gmail.com>
2022-07-01 23:06:25 +00:00
/**
* Internal dependencies
*/
import reducer from '../reducers';
import { FieldValidationStatus } from '../../types';
import { ACTION_TYPES as types } from '.././action-types';
import { ValidationAction } from '../actions';
describe( 'Validation reducer', () => {
it( 'Sets a single validation error', () => {
const singleValidationAction: ValidationAction = {
type: types.SET_VALIDATION_ERRORS,
errors: {
singleValidationError: {
message: 'This is a single validation error message',
hidden: false,
},
},
};
const nextState = reducer( {}, singleValidationAction );
expect( nextState ).toEqual( {
singleValidationError: {
message: 'This is a single validation error message',
hidden: false,
},
} );
} );
it( 'Does not add new errors if the same error already exists in state', () => {
const state: Record< string, FieldValidationStatus > = {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
};
const existingErrorValidation: ValidationAction = {
type: types.SET_VALIDATION_ERRORS,
errors: {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
},
};
const nextState = reducer( state, existingErrorValidation );
expect( nextState ).toEqual( {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
} );
} );
it( 'Does not add new errors if error message is not string, but keeps existing errors', () => {
const integerErrorAction: ValidationAction = {
type: types.SET_VALIDATION_ERRORS,
errors: {
integerError: {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore ignoring because we're testing runtime errors with integers.
message: 1234,
hidden: false,
},
},
};
const nextState = reducer( {}, integerErrorAction );
expect( nextState ).not.toHaveProperty( 'integerError' );
} );
it( 'Updates existing error if message or hidden property changes', () => {
const state: Record< string, FieldValidationStatus > = {
existingValidationError: {
message: 'This is an existing error message',
hidden: false,
},
};
const updateExistingErrorAction: ValidationAction = {
type: types.SET_VALIDATION_ERRORS,
errors: {
existingValidationError: {
message: 'This is an existing error message',
hidden: true,
},
},
};
const nextState = reducer( state, updateExistingErrorAction );
expect( nextState ).toEqual( {
existingValidationError: {
message: 'This is an existing error message',
hidden: true,
},
} );
} );
it( 'Appends new errors to list of existing errors', () => {
const state: Record< string, FieldValidationStatus > = {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
};
const addNewError: ValidationAction = {
type: types.SET_VALIDATION_ERRORS,
errors: {
newError: {
message: 'This is a new error',
hidden: false,
},
},
};
const nextState = reducer( state, addNewError );
expect( nextState ).toEqual( {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
newError: {
message: 'This is a new error',
hidden: false,
},
} );
} );
it( 'Clears all validation errors', () => {
const state: Record< string, FieldValidationStatus > = {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
};
const clearAllErrors: ValidationAction = {
type: types.CLEAR_ALL_VALIDATION_ERRORS,
};
const nextState = reducer( state, clearAllErrors );
expect( nextState ).toEqual( {} );
} );
it( 'Clears a single validation error', () => {
const state: Record< string, FieldValidationStatus > = {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
testError: {
message: 'This is error should not be removed',
hidden: false,
},
};
const clearError: ValidationAction = {
type: types.CLEAR_VALIDATION_ERROR,
error: 'existingError',
};
const nextState = reducer( state, clearError );
expect( nextState ).not.toHaveProperty( 'existingError' );
expect( nextState ).toHaveProperty( 'testError' );
} );
it( 'Hides a single validation error', () => {
const state: Record< string, FieldValidationStatus > = {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
testError: {
message: 'This is error should not be removed',
hidden: false,
},
};
const testAction: ValidationAction = {
type: types.HIDE_VALIDATION_ERROR,
error: 'existingError',
};
const nextState = reducer( state, testAction );
expect( nextState ).toEqual( {
existingError: {
message: 'This is an existing error message',
hidden: true,
},
testError: {
message: 'This is error should not be removed',
hidden: false,
},
} );
} );
it( 'Shows a single validation error', () => {
const state: Record< string, FieldValidationStatus > = {
existingError: {
message: 'This is an existing error message',
hidden: true,
},
testError: {
message: 'This is error should not be removed',
hidden: true,
},
visibleError: {
message: 'This is error should remain visible',
hidden: false,
},
};
const testAction: ValidationAction = {
type: types.SHOW_VALIDATION_ERROR,
error: 'existingError',
};
const nextState = reducer( state, testAction );
expect( nextState ).toEqual( {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
testError: {
message: 'This is error should not be removed',
hidden: true,
},
visibleError: {
message: 'This is error should remain visible',
hidden: false,
},
} );
} );
it( 'Shows all validation errors', () => {
const state: Record< string, FieldValidationStatus > = {
firstExistingError: {
message: 'This is first existing error message',
hidden: true,
},
secondExistingError: {
message: 'This is the second existing error message',
hidden: true,
},
};
const showAllErrors: ValidationAction = {
type: types.SHOW_ALL_VALIDATION_ERRORS,
};
const nextState = reducer( state, showAllErrors );
expect( nextState ).toEqual( {
firstExistingError: {
message: 'This is first existing error message',
hidden: false,
},
secondExistingError: {
message: 'This is the second existing error message',
hidden: false,
},
} );
} );
} );