initial commit
This commit is contained in:
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import TestRenderer, { act } from 'react-test-renderer';
|
||||
import { createRegistry, RegistryProvider } from '@wordpress/data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useCheckoutSubmit } from '../use-checkout-submit';
|
||||
|
||||
const mockUseCheckoutContext = {
|
||||
onSubmit: jest.fn(),
|
||||
};
|
||||
const mockUsePaymentMethodDataContext = {
|
||||
activePaymentMethod: '',
|
||||
currentStatus: {
|
||||
isDoingExpressPayment: false,
|
||||
},
|
||||
};
|
||||
|
||||
jest.mock( '../../providers/cart-checkout/checkout-state', () => ( {
|
||||
useCheckoutContext: () => mockUseCheckoutContext,
|
||||
} ) );
|
||||
|
||||
jest.mock( '../../providers/cart-checkout/payment-methods', () => ( {
|
||||
usePaymentMethodDataContext: () => mockUsePaymentMethodDataContext,
|
||||
} ) );
|
||||
|
||||
describe( 'useCheckoutSubmit', () => {
|
||||
let registry, renderer;
|
||||
|
||||
const getWrappedComponents = ( Component ) => (
|
||||
<RegistryProvider value={ registry }>
|
||||
<Component />
|
||||
</RegistryProvider>
|
||||
);
|
||||
|
||||
const getTestComponent = () => () => {
|
||||
const data = useCheckoutSubmit();
|
||||
return <div { ...data } />;
|
||||
};
|
||||
|
||||
beforeEach( () => {
|
||||
registry = createRegistry();
|
||||
renderer = null;
|
||||
} );
|
||||
|
||||
it( 'onSubmit calls the correct action in the checkout context', () => {
|
||||
const TestComponent = getTestComponent();
|
||||
|
||||
act( () => {
|
||||
renderer = TestRenderer.create(
|
||||
getWrappedComponents( TestComponent )
|
||||
);
|
||||
} );
|
||||
|
||||
const { onSubmit } = renderer.root.findByType( 'div' ).props;
|
||||
|
||||
onSubmit();
|
||||
|
||||
expect( mockUseCheckoutContext.onSubmit ).toHaveBeenCalledTimes( 1 );
|
||||
} );
|
||||
} );
|
@ -0,0 +1,259 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import TestRenderer, { act } from 'react-test-renderer';
|
||||
import { createRegistry, RegistryProvider } from '@wordpress/data';
|
||||
import { QUERY_STATE_STORE_KEY as storeKey } from '@woocommerce/block-data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
useQueryStateByContext,
|
||||
useQueryStateByKey,
|
||||
useSynchronizedQueryState,
|
||||
} from '../use-query-state';
|
||||
|
||||
jest.mock( '@woocommerce/block-data', () => ( {
|
||||
__esModule: true,
|
||||
QUERY_STATE_STORE_KEY: 'test/store',
|
||||
} ) );
|
||||
|
||||
describe( 'Testing Query State Hooks', () => {
|
||||
let registry, mocks;
|
||||
beforeAll( () => {
|
||||
registry = createRegistry();
|
||||
mocks = {};
|
||||
} );
|
||||
/**
|
||||
* Test helper to return a tuple containing the expected query value and the
|
||||
* expected query state action creator from the given rendered test instance.
|
||||
*
|
||||
* @param {Object} testRenderer An instance of the created test component.
|
||||
*
|
||||
* @return {Array} A tuple containing the expected query value as the first
|
||||
* element and the expected query action creator as the
|
||||
* second argument.
|
||||
*/
|
||||
const getProps = ( testRenderer ) => {
|
||||
const props = testRenderer.root.findByType( 'div' ).props;
|
||||
return [ props.queryState, props.setQueryState ];
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the given component wrapped in the registry provider for
|
||||
* instantiating using the TestRenderer using the current prepared registry
|
||||
* for the TestRenderer to instantiate with.
|
||||
*
|
||||
* @param {*} Component The test component to wrap.
|
||||
* @param {Object} props Props to feed the wrapped component.
|
||||
*
|
||||
* @return {*} Wrapped component.
|
||||
*/
|
||||
const getWrappedComponent = ( Component, props ) => (
|
||||
<RegistryProvider value={ registry }>
|
||||
<Component { ...props } />
|
||||
</RegistryProvider>
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns a TestComponent for the provided hook to test with, and the
|
||||
* expected PropKeys for obtaining the values to be fed to the hook as
|
||||
* arguments.
|
||||
*
|
||||
* @param {Function} hookTested The hook being tested to use in the
|
||||
* test comopnent.
|
||||
* @param {Array} propKeysForArgs An array of keys for the props that
|
||||
* will be used on the test component that
|
||||
* will have values fed to the tested
|
||||
* hook.
|
||||
*
|
||||
* @return {*} A component ready for testing with!
|
||||
*/
|
||||
const getTestComponent = ( hookTested, propKeysForArgs ) => ( props ) => {
|
||||
const args = propKeysForArgs.map( ( key ) => props[ key ] );
|
||||
const [ queryValue, setQueryValue ] = hookTested( ...args );
|
||||
return (
|
||||
<div queryState={ queryValue } setQueryState={ setQueryValue } />
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* A helper for setting up the `mocks` object and the `registry` mock before
|
||||
* each test.
|
||||
*
|
||||
* @param {string} actionMockName This should be the name of the action
|
||||
* that the hook returns. This will be
|
||||
* mocked using `mocks.action` when
|
||||
* registered in the mock registry.
|
||||
* @param {string} selectorMockName This should be the mame of the selector
|
||||
* that the hook uses. This will be mocked
|
||||
* using `mocks.selector` when registered
|
||||
* in the mock registry.
|
||||
*/
|
||||
const setupMocks = ( actionMockName, selectorMockName ) => {
|
||||
mocks.action = jest.fn().mockReturnValue( { type: 'testAction' } );
|
||||
mocks.selector = jest.fn().mockReturnValue( { foo: 'bar' } );
|
||||
registry.registerStore( storeKey, {
|
||||
reducer: () => ( {} ),
|
||||
actions: {
|
||||
[ actionMockName ]: mocks.action,
|
||||
},
|
||||
selectors: {
|
||||
[ selectorMockName ]: mocks.selector,
|
||||
},
|
||||
} );
|
||||
};
|
||||
describe( 'useQueryStateByContext', () => {
|
||||
const TestComponent = getTestComponent( useQueryStateByContext, [
|
||||
'context',
|
||||
] );
|
||||
let renderer;
|
||||
beforeEach( () => {
|
||||
renderer = null;
|
||||
setupMocks( 'setValueForQueryContext', 'getValueForQueryContext' );
|
||||
} );
|
||||
afterEach( () => {
|
||||
act( () => {
|
||||
renderer.unmount();
|
||||
} );
|
||||
} );
|
||||
it(
|
||||
'calls useSelect with the provided context and returns expected' +
|
||||
' values',
|
||||
() => {
|
||||
const { action, selector } = mocks;
|
||||
act( () => {
|
||||
renderer = TestRenderer.create(
|
||||
getWrappedComponent( TestComponent, {
|
||||
context: 'test-context',
|
||||
} )
|
||||
);
|
||||
} );
|
||||
const [ queryState, setQueryState ] = getProps( renderer );
|
||||
// the {} is because all selectors are called internally in the
|
||||
// registry with the first argument being the state which is empty.
|
||||
expect( selector ).toHaveBeenLastCalledWith(
|
||||
{},
|
||||
'test-context',
|
||||
undefined
|
||||
);
|
||||
expect( queryState ).toEqual( { foo: 'bar' } );
|
||||
expect( action ).not.toHaveBeenCalled();
|
||||
|
||||
//execute dispatcher and make sure it's called.
|
||||
act( () => {
|
||||
setQueryState( { foo: 'bar' } );
|
||||
} );
|
||||
expect( action ).toHaveBeenCalledWith( 'test-context', {
|
||||
foo: 'bar',
|
||||
} );
|
||||
}
|
||||
);
|
||||
} );
|
||||
describe( 'useQueryStateByKey', () => {
|
||||
const TestComponent = getTestComponent( useQueryStateByKey, [
|
||||
'queryKey',
|
||||
undefined,
|
||||
'context',
|
||||
] );
|
||||
let renderer;
|
||||
beforeEach( () => {
|
||||
renderer = null;
|
||||
setupMocks( 'setQueryValue', 'getValueForQueryKey' );
|
||||
} );
|
||||
afterEach( () => {
|
||||
act( () => {
|
||||
renderer.unmount();
|
||||
} );
|
||||
} );
|
||||
it(
|
||||
'calls useSelect with the provided context and returns expected' +
|
||||
' values',
|
||||
() => {
|
||||
const { selector, action } = mocks;
|
||||
act( () => {
|
||||
renderer = TestRenderer.create(
|
||||
getWrappedComponent( TestComponent, {
|
||||
context: 'test-context',
|
||||
queryKey: 'someValue',
|
||||
} )
|
||||
);
|
||||
} );
|
||||
const [ queryState, setQueryState ] = getProps( renderer );
|
||||
// the {} is because all selectors are called internally in the
|
||||
// registry with the first argument being the state which is empty.
|
||||
expect( selector ).toHaveBeenLastCalledWith(
|
||||
{},
|
||||
'test-context',
|
||||
'someValue',
|
||||
undefined
|
||||
);
|
||||
expect( queryState ).toEqual( { foo: 'bar' } );
|
||||
expect( action ).not.toHaveBeenCalled();
|
||||
|
||||
//execute dispatcher and make sure it's called.
|
||||
act( () => {
|
||||
setQueryState( { foo: 'bar' } );
|
||||
} );
|
||||
expect( action ).toHaveBeenCalledWith(
|
||||
'test-context',
|
||||
'someValue',
|
||||
{ foo: 'bar' }
|
||||
);
|
||||
}
|
||||
);
|
||||
} );
|
||||
// Note: these tests only add partial coverage because the state is not
|
||||
// actually updated by the action dispatch via our mocks.
|
||||
describe( 'useSynchronizedQueryState', () => {
|
||||
const TestComponent = getTestComponent( useSynchronizedQueryState, [
|
||||
'synchronizedQuery',
|
||||
'context',
|
||||
] );
|
||||
const initialQuery = { a: 'b' };
|
||||
let renderer;
|
||||
beforeEach( () => {
|
||||
setupMocks( 'setValueForQueryContext', 'getValueForQueryContext' );
|
||||
} );
|
||||
it( 'returns provided query state on initial render', () => {
|
||||
const { action, selector } = mocks;
|
||||
act( () => {
|
||||
renderer = TestRenderer.create(
|
||||
getWrappedComponent( TestComponent, {
|
||||
context: 'test-context',
|
||||
synchronizedQuery: initialQuery,
|
||||
} )
|
||||
);
|
||||
} );
|
||||
const [ queryState ] = getProps( renderer );
|
||||
expect( queryState ).toBe( initialQuery );
|
||||
expect( selector ).toHaveBeenLastCalledWith(
|
||||
{},
|
||||
'test-context',
|
||||
undefined
|
||||
);
|
||||
expect( action ).toHaveBeenCalledWith( 'test-context', {
|
||||
foo: 'bar',
|
||||
a: 'b',
|
||||
} );
|
||||
} );
|
||||
it( 'returns merged queryState on subsequent render', () => {
|
||||
act( () => {
|
||||
renderer.update(
|
||||
getWrappedComponent( TestComponent, {
|
||||
context: 'test-context',
|
||||
synchronizedQuery: initialQuery,
|
||||
} )
|
||||
);
|
||||
} );
|
||||
// note our test doesn't interact with an actual reducer so the
|
||||
// store state is not updated. Here we're just verifying that
|
||||
// what is is returned by the state selector mock is returned.
|
||||
// However we DO expect this to be a new object.
|
||||
const [ queryState ] = getProps( renderer );
|
||||
expect( queryState ).not.toBe( initialQuery );
|
||||
expect( queryState ).toEqual( { foo: 'bar' } );
|
||||
} );
|
||||
} );
|
||||
} );
|
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { render, act } from '@testing-library/react';
|
||||
import { StoreNoticesProvider } from '@woocommerce/base-context';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useStoreNotices } from '../use-store-notices';
|
||||
|
||||
describe( 'useStoreNotices', () => {
|
||||
function setup() {
|
||||
const returnVal = {};
|
||||
|
||||
function TestComponent() {
|
||||
Object.assign( returnVal, useStoreNotices() );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
render(
|
||||
<StoreNoticesProvider>
|
||||
<TestComponent />
|
||||
</StoreNoticesProvider>
|
||||
);
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
test( 'allows adding and removing notices and checking if there are notices of a specific type', () => {
|
||||
const storeNoticesData = setup();
|
||||
|
||||
// Assert initial state.
|
||||
expect( storeNoticesData.notices ).toEqual( [] );
|
||||
expect( storeNoticesData.hasNoticesOfType( 'default' ) ).toBe( false );
|
||||
|
||||
// Add error notice.
|
||||
act( () => {
|
||||
storeNoticesData.addErrorNotice( 'Error notice' );
|
||||
} );
|
||||
|
||||
expect( storeNoticesData.notices.length ).toBe( 1 );
|
||||
expect( storeNoticesData.hasNoticesOfType( 'default' ) ).toBe( true );
|
||||
|
||||
expect( storeNoticesData.notices.length ).toBe( 1 );
|
||||
expect( storeNoticesData.hasNoticesOfType( 'default' ) ).toBe( true );
|
||||
|
||||
// Remove error notice.
|
||||
act( () => {
|
||||
storeNoticesData.removeNotices( 'error' );
|
||||
} );
|
||||
|
||||
expect( storeNoticesData.notices.length ).toBe( 0 );
|
||||
expect( storeNoticesData.hasNoticesOfType( 'default' ) ).toBe( false );
|
||||
|
||||
// Remove all remaining notices.
|
||||
act( () => {
|
||||
storeNoticesData.removeNotices();
|
||||
} );
|
||||
|
||||
expect( storeNoticesData.notices.length ).toBe( 0 );
|
||||
expect( storeNoticesData.hasNoticesOfType( 'default' ) ).toBe( false );
|
||||
} );
|
||||
} );
|
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import TestRenderer, { act } from 'react-test-renderer';
|
||||
import { createRegistry, RegistryProvider } from '@wordpress/data';
|
||||
import { COLLECTIONS_STORE_KEY as storeKey } from '@woocommerce/block-data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useStoreProducts } from '../use-store-products';
|
||||
|
||||
jest.mock( '@woocommerce/block-data', () => ( {
|
||||
__esModule: true,
|
||||
COLLECTIONS_STORE_KEY: 'test/store',
|
||||
} ) );
|
||||
|
||||
describe( 'useStoreProducts', () => {
|
||||
let registry, mocks, renderer;
|
||||
const getProps = ( testRenderer ) => {
|
||||
const {
|
||||
products,
|
||||
totalProducts,
|
||||
productsLoading,
|
||||
} = testRenderer.root.findByType( 'div' ).props;
|
||||
return {
|
||||
products,
|
||||
totalProducts,
|
||||
productsLoading,
|
||||
};
|
||||
};
|
||||
|
||||
const getWrappedComponents = ( Component, props ) => (
|
||||
<RegistryProvider value={ registry }>
|
||||
<Component { ...props } />
|
||||
</RegistryProvider>
|
||||
);
|
||||
|
||||
const getTestComponent = () => ( { query } ) => {
|
||||
const items = useStoreProducts( query );
|
||||
return <div { ...items } />;
|
||||
};
|
||||
|
||||
const setUpMocks = () => {
|
||||
mocks = {
|
||||
selectors: {
|
||||
getCollectionError: jest.fn().mockReturnValue( false ),
|
||||
getCollection: jest
|
||||
.fn()
|
||||
.mockImplementation( () => ( { foo: 'bar' } ) ),
|
||||
getCollectionHeader: jest.fn().mockReturnValue( 22 ),
|
||||
hasFinishedResolution: jest.fn().mockReturnValue( true ),
|
||||
},
|
||||
};
|
||||
registry.registerStore( storeKey, {
|
||||
reducer: () => ( {} ),
|
||||
selectors: mocks.selectors,
|
||||
} );
|
||||
};
|
||||
|
||||
beforeEach( () => {
|
||||
registry = createRegistry();
|
||||
mocks = {};
|
||||
renderer = null;
|
||||
setUpMocks();
|
||||
} );
|
||||
it(
|
||||
'should return expected behaviour for equivalent query on props ' +
|
||||
'across renders',
|
||||
() => {
|
||||
const TestComponent = getTestComponent();
|
||||
act( () => {
|
||||
renderer = TestRenderer.create(
|
||||
getWrappedComponents( TestComponent, {
|
||||
query: { bar: 'foo' },
|
||||
} )
|
||||
);
|
||||
} );
|
||||
const { products } = getProps( renderer );
|
||||
// rerender
|
||||
act( () => {
|
||||
renderer.update(
|
||||
getWrappedComponents( TestComponent, {
|
||||
query: { bar: 'foo' },
|
||||
} )
|
||||
);
|
||||
} );
|
||||
// re-render should result in same products object because although
|
||||
// query-state is a different instance, it's still equivalent.
|
||||
const { products: newProducts } = getProps( renderer );
|
||||
expect( newProducts ).toBe( products );
|
||||
// now let's change the query passed through to verify new object
|
||||
// is created.
|
||||
// remember this won't actually change the results because the mock
|
||||
// selector is returning an equivalent object when it is called,
|
||||
// however it SHOULD be a new object instance.
|
||||
act( () => {
|
||||
renderer.update(
|
||||
getWrappedComponents( TestComponent, {
|
||||
query: { foo: 'bar' },
|
||||
} )
|
||||
);
|
||||
} );
|
||||
const { products: productsVerification } = getProps( renderer );
|
||||
expect( productsVerification ).not.toBe( products );
|
||||
expect( productsVerification ).toEqual( products );
|
||||
renderer.unmount();
|
||||
}
|
||||
);
|
||||
} );
|
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { render, act } from '@testing-library/react';
|
||||
import { StoreSnackbarNoticesProvider } from '@woocommerce/base-context/providers';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useStoreSnackbarNotices } from '../use-store-snackbar-notices';
|
||||
|
||||
describe( 'useStoreNoticesWithSnackbar', () => {
|
||||
function setup() {
|
||||
const returnVal = {};
|
||||
|
||||
function TestComponent() {
|
||||
Object.assign( returnVal, useStoreSnackbarNotices() );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
render(
|
||||
<StoreSnackbarNoticesProvider>
|
||||
<TestComponent />
|
||||
</StoreSnackbarNoticesProvider>
|
||||
);
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
test( 'allows adding and removing notices and checking if there are notices of a specific type', () => {
|
||||
const storeNoticesData = setup();
|
||||
|
||||
// Assert initial state.
|
||||
expect( storeNoticesData.notices ).toEqual( [] );
|
||||
|
||||
// Add snackbar notice.
|
||||
act( () => {
|
||||
storeNoticesData.addSnackbarNotice( 'Snackbar notice' );
|
||||
} );
|
||||
|
||||
expect( storeNoticesData.notices.length ).toBe( 1 );
|
||||
|
||||
// Remove all remaining notices.
|
||||
act( () => {
|
||||
storeNoticesData.removeNotices();
|
||||
} );
|
||||
|
||||
expect( storeNoticesData.notices.length ).toBe( 0 );
|
||||
} );
|
||||
} );
|
Reference in New Issue
Block a user