Migrate woo.data export & import store to TS

This commit is contained in:
Chi-Hsuan Huang 2022-05-23 16:51:27 +08:00
parent 19a3e2c892
commit b8d79d86cf
21 changed files with 313 additions and 102 deletions

View File

@ -48,6 +48,7 @@
"@babel/runtime": "^7.17.2", "@babel/runtime": "^7.17.2",
"@testing-library/react": "^12.1.3", "@testing-library/react": "^12.1.3",
"@testing-library/react-hooks": "^7.0.2", "@testing-library/react-hooks": "^7.0.2",
"@types/md5": "^2.3.2",
"@types/wordpress__compose": "^4.0.1", "@types/wordpress__compose": "^4.0.1",
"@types/wordpress__core-data": "^2.4.5", "@types/wordpress__core-data": "^2.4.5",
"@types/wordpress__data": "^6.0.0", "@types/wordpress__data": "^6.0.0",

View File

@ -2,20 +2,26 @@
* External dependencies * External dependencies
*/ */
import { controls as dataControls } from '@wordpress/data-controls'; import { controls as dataControls } from '@wordpress/data-controls';
import { Action } from '@wordpress/data';
import apiFetch, { APIFetchOptions } from '@wordpress/api-fetch';
import apiFetch from '@wordpress/api-fetch'; export const fetchWithHeaders = ( options: APIFetchOptions ) => {
export const fetchWithHeaders = ( options ) => {
return { return {
type: 'FETCH_WITH_HEADERS', type: 'FETCH_WITH_HEADERS',
options, options,
}; };
}; };
export type FetchWithHeadersResponse< Data > = {
headers: Response[ 'headers' ];
status: Response[ 'status' ];
data: Data;
};
const controls = { const controls = {
...dataControls, ...dataControls,
FETCH_WITH_HEADERS( { options } ) { FETCH_WITH_HEADERS( action: Action ) {
return apiFetch( { ...options, parse: false } ) return apiFetch< Response >( { ...action.options, parse: false } )
.then( ( response ) => { .then( ( response ) => {
return Promise.all( [ return Promise.all( [
response.headers, response.headers,

View File

@ -1,8 +1,8 @@
const TYPES = { const TYPES = {
START_EXPORT: 'START_EXPORT', START_EXPORT: 'START_EXPORT' as const,
SET_EXPORT_ID: 'SET_EXPORT_ID', SET_EXPORT_ID: 'SET_EXPORT_ID' as const,
SET_ERROR: 'SET_ERROR', SET_ERROR: 'SET_ERROR' as const,
SET_IS_REQUESTING: 'SET_IS_REQUESTING', SET_IS_REQUESTING: 'SET_IS_REQUESTING' as const,
}; };
export default TYPES; export default TYPES;

View File

@ -1,11 +1,16 @@
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { fetchWithHeaders } from '../controls'; import { fetchWithHeaders, FetchWithHeadersResponse } from '../controls';
import TYPES from './action-types'; import TYPES from './action-types';
import { NAMESPACE } from '../constants'; import { NAMESPACE } from '../constants';
import { SelectorArgs, ExportArgs } from './types';
export function setExportId( exportType, exportArgs, exportId ) { export function setExportId(
exportType: string,
exportArgs: ExportArgs,
exportId: string
) {
return { return {
type: TYPES.SET_EXPORT_ID, type: TYPES.SET_EXPORT_ID,
exportType, exportType,
@ -14,7 +19,11 @@ export function setExportId( exportType, exportArgs, exportId ) {
}; };
} }
export function setIsRequesting( selector, selectorArgs, isRequesting ) { export function setIsRequesting(
selector: string,
selectorArgs: SelectorArgs,
isRequesting: boolean
) {
return { return {
type: TYPES.SET_IS_REQUESTING, type: TYPES.SET_IS_REQUESTING,
selector, selector,
@ -23,7 +32,11 @@ export function setIsRequesting( selector, selectorArgs, isRequesting ) {
}; };
} }
export function setError( selector, selectorArgs, error ) { export function setError(
selector: string,
selectorArgs: SelectorArgs,
error: unknown
) {
return { return {
type: TYPES.SET_ERROR, type: TYPES.SET_ERROR,
selector, selector,
@ -32,11 +45,14 @@ export function setError( selector, selectorArgs, error ) {
}; };
} }
export function* startExport( type, args ) { export function* startExport( type: string, args: ExportArgs ) {
yield setIsRequesting( 'startExport', { type, args }, true ); yield setIsRequesting( 'startExport', { type, args }, true );
try { try {
const response = yield fetchWithHeaders( { const response: FetchWithHeadersResponse< {
export_id: string;
message: string;
} > = yield fetchWithHeaders( {
path: `${ NAMESPACE }/reports/${ type }/export`, path: `${ NAMESPACE }/reports/${ type }/export`,
method: 'POST', method: 'POST',
data: { data: {
@ -46,7 +62,6 @@ export function* startExport( type, args ) {
} ); } );
yield setIsRequesting( 'startExport', { type, args }, false ); yield setIsRequesting( 'startExport', { type, args }, false );
const { export_id: exportId, message } = response.data; const { export_id: exportId, message } = response.data;
if ( exportId ) { if ( exportId ) {
@ -57,8 +72,18 @@ export function* startExport( type, args ) {
return response.data; return response.data;
} catch ( error ) { } catch ( error ) {
if ( error instanceof Error ) {
yield setError( 'startExport', { type, args }, error.message ); yield setError( 'startExport', { type, args }, error.message );
} else {
// eslint-disable-next-line no-console
console.error( `Unexpected Error: ${ JSON.stringify( error ) }` );
// eslint-enable-next-line no-console
}
yield setIsRequesting( 'startExport', { type, args }, false ); yield setIsRequesting( 'startExport', { type, args }, false );
throw error; throw error;
} }
} }
export type Action = ReturnType<
typeof setExportId | typeof setError | typeof setIsRequesting
>;

View File

@ -1,4 +1,4 @@
/** /**
* Internal dependencies * Internal dependencies
*/ */
export const STORE_NAME = 'wc/admin/export'; export const STORE_NAME = 'wc/admin/export' as const;

View File

@ -1,23 +1,36 @@
/** /**
* External dependencies * External dependencies
*/ */
import { registerStore } from '@wordpress/data'; import { registerStore } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
import { SelectFromMap, DispatchFromMap } from '@automattic/data-stores';
import { Reducer, AnyAction } from 'redux';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { STORE_NAME } from './constants'; import { STORE_NAME } from './constants';
import * as selectors from './selectors'; import * as selectors from './selectors';
import * as actions from './actions'; import * as actions from './actions';
import controls from '../controls'; import reducer, { State } from './reducer';
import reducer from './reducer'; import { WPDataSelectors } from '../types';
export * from './types';
export type { State };
registerStore( STORE_NAME, { registerStore< State >( STORE_NAME, {
reducer, reducer: reducer as Reducer< State, AnyAction >,
actions, actions,
controls, controls,
selectors, selectors,
} ); } );
export const EXPORT_STORE_NAME = STORE_NAME; export const EXPORT_STORE_NAME = STORE_NAME;
declare module '@wordpress/data' {
// TODO: convert action.js to TS
function dispatch(
key: typeof STORE_NAME
): DispatchFromMap< typeof actions >;
function select(
key: typeof STORE_NAME
): SelectFromMap< typeof selectors > & WPDataSelectors;
}

View File

@ -1,40 +1,42 @@
/**
* External dependencies
*/
import type { Reducer } from 'redux';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import TYPES from './action-types'; import TYPES from './action-types';
import { Action } from './actions';
import { hashExportArgs } from './utils'; import { hashExportArgs } from './utils';
import { ExportState } from './types';
const exportReducer = ( const reducer: Reducer< ExportState, Action > = (
state = { state = {
errors: {}, errors: {},
requesting: {}, requesting: {},
exportMeta: {}, exportMeta: {},
exportIds: {}, exportIds: {},
}, },
{ action
error,
exportArgs,
exportId,
exportType,
isRequesting,
selector,
selectorArgs,
type,
}
) => { ) => {
switch ( type ) { switch ( action.type ) {
case TYPES.SET_IS_REQUESTING: case TYPES.SET_IS_REQUESTING:
return { return {
...state, ...state,
requesting: { requesting: {
...state.requesting, ...state.requesting,
[ selector ]: { [ action.selector ]: {
...state.requesting[ selector ], ...state.requesting[ action.selector ],
[ hashExportArgs( selectorArgs ) ]: isRequesting, [ hashExportArgs(
action.selectorArgs
) ]: action.isRequesting,
}, },
}, },
}; };
case TYPES.SET_EXPORT_ID: case TYPES.SET_EXPORT_ID:
const { exportType, exportArgs, exportId } = action;
return { return {
...state, ...state,
exportMeta: { exportMeta: {
@ -60,9 +62,9 @@ const exportReducer = (
...state, ...state,
errors: { errors: {
...state.errors, ...state.errors,
[ selector ]: { [ action.selector ]: {
...state.errors[ selector ], ...state.errors[ action.selector ],
[ hashExportArgs( selectorArgs ) ]: error, [ hashExportArgs( action.selectorArgs ) ]: action.error,
}, },
}, },
}; };
@ -71,4 +73,5 @@ const exportReducer = (
} }
}; };
export default exportReducer; export type State = ReturnType< typeof reducer >;
export default reducer;

View File

@ -2,22 +2,35 @@
* Internal dependencies * Internal dependencies
*/ */
import { hashExportArgs } from './utils'; import { hashExportArgs } from './utils';
import { ExportState, SelectorArgs, ExportArgs } from './types';
export const isExportRequesting = ( state, selector, selectorArgs ) => { export const isExportRequesting = (
state: ExportState,
selector: string,
selectorArgs: SelectorArgs
) => {
return Boolean( return Boolean(
state.requesting[ selector ] && state.requesting[ selector ] &&
state.requesting[ selector ][ hashExportArgs( selectorArgs ) ] state.requesting[ selector ][ hashExportArgs( selectorArgs ) ]
); );
}; };
export const getExportId = ( state, exportType, exportArgs ) => { export const getExportId = (
state: ExportState,
exportType: string,
exportArgs: ExportArgs
) => {
return ( return (
state.exportIds[ exportType ] && state.exportIds[ exportType ] &&
state.exportIds[ exportType ][ hashExportArgs( exportArgs ) ] state.exportIds[ exportType ][ hashExportArgs( exportArgs ) ]
); );
}; };
export const getError = ( state, selector, selectorArgs ) => { export const getError = (
state: ExportState,
selector: string,
selectorArgs: SelectorArgs
) => {
return ( return (
state.errors[ selector ] && state.errors[ selector ] &&
state.errors[ selector ][ hashExportArgs( selectorArgs ) ] state.errors[ selector ][ hashExportArgs( selectorArgs ) ]

View File

@ -18,6 +18,7 @@ const defaultState = {
describe( 'export reducer', () => { describe( 'export reducer', () => {
it( 'should return a default state', () => { it( 'should return a default state', () => {
// @ts-expect-error reducer action should not be empty but it is
const state = reducer( undefined, {} ); const state = reducer( undefined, {} );
expect( state ).toEqual( defaultState ); expect( state ).toEqual( defaultState );
expect( state ).not.toBe( defaultState ); expect( state ).not.toBe( defaultState );

View File

@ -0,0 +1,32 @@
export type ExportArgs = {
[ key: string ]: unknown;
};
export type SelectorArgs = {
type: string;
args: ExportArgs;
};
export type ExportState = {
errors: {
[ selector: string ]: {
[ hashExportArgs: string ]: unknown;
};
};
requesting: {
[ selector: string ]: {
[ hashExportArgs: string ]: boolean;
};
};
exportMeta: {
[ exportId: string ]: {
exportType: string;
exportArgs: ExportArgs;
};
};
exportIds: {
[ exportType: string ]: {
[ hashExportArgs: string ]: string;
};
};
};

View File

@ -7,7 +7,8 @@ import md5 from 'md5';
* Internal dependencies * Internal dependencies
*/ */
import { getResourceName } from '../utils'; import { getResourceName } from '../utils';
import { ExportArgs } from './types';
export const hashExportArgs = ( args ) => { export const hashExportArgs = ( args: ExportArgs ) => {
return md5( getResourceName( 'export', args ) ); return md5( getResourceName( 'export', args ) );
}; };

View File

@ -1,11 +1,11 @@
const TYPES = { const TYPES = {
SET_IMPORT_DATE: 'SET_IMPORT_DATE', SET_IMPORT_DATE: 'SET_IMPORT_DATE' as const,
SET_IMPORT_ERROR: 'SET_IMPORT_ERROR', SET_IMPORT_ERROR: 'SET_IMPORT_ERROR' as const,
SET_IMPORT_PERIOD: 'SET_IMPORT_PERIOD', SET_IMPORT_PERIOD: 'SET_IMPORT_PERIOD' as const,
SET_IMPORT_STARTED: 'SET_IMPORT_STARTED', SET_IMPORT_STARTED: 'SET_IMPORT_STARTED' as const,
SET_IMPORT_STATUS: 'SET_IMPORT_STATUS', SET_IMPORT_STATUS: 'SET_IMPORT_STATUS' as const,
SET_IMPORT_TOTALS: 'SET_IMPORT_TOTALS', SET_IMPORT_TOTALS: 'SET_IMPORT_TOTALS' as const,
SET_SKIP_IMPORTED: 'SET_SKIP_IMPORTED', SET_SKIP_IMPORTED: 'SET_SKIP_IMPORTED' as const,
}; };
export default TYPES; export default TYPES;

View File

@ -7,15 +7,21 @@ import { apiFetch } from '@wordpress/data-controls';
* Internal dependencies * Internal dependencies
*/ */
import TYPES from './action-types'; import TYPES from './action-types';
import {
ImportStatusQuery,
ImportStatus,
ImportTotals,
ImportTotalsQuery,
} from './types';
export function setImportStarted( activeImport ) { export function setImportStarted( activeImport: boolean ) {
return { return {
type: TYPES.SET_IMPORT_STARTED, type: TYPES.SET_IMPORT_STARTED,
activeImport, activeImport,
}; };
} }
export function setImportPeriod( date, dateModified ) { export function setImportPeriod( date: string, dateModified: boolean ) {
if ( ! dateModified ) { if ( ! dateModified ) {
return { return {
type: TYPES.SET_IMPORT_PERIOD, type: TYPES.SET_IMPORT_PERIOD,
@ -28,14 +34,17 @@ export function setImportPeriod( date, dateModified ) {
}; };
} }
export function setSkipPrevious( skipPrevious ) { export function setSkipPrevious( skipPrevious: boolean ) {
return { return {
type: TYPES.SET_SKIP_IMPORTED, type: TYPES.SET_SKIP_IMPORTED,
skipPrevious, skipPrevious,
}; };
} }
export function setImportStatus( query, importStatus ) { export function setImportStatus(
query: ImportStatusQuery,
importStatus: ImportStatus
) {
return { return {
type: TYPES.SET_IMPORT_STATUS, type: TYPES.SET_IMPORT_STATUS,
importStatus, importStatus,
@ -43,7 +52,10 @@ export function setImportStatus( query, importStatus ) {
}; };
} }
export function setImportTotals( query, importTotals ) { export function setImportTotals(
query: ImportTotalsQuery,
importTotals: ImportTotals
) {
return { return {
type: TYPES.SET_IMPORT_TOTALS, type: TYPES.SET_IMPORT_TOTALS,
importTotals, importTotals,
@ -51,21 +63,33 @@ export function setImportTotals( query, importTotals ) {
}; };
} }
export function setImportError( query, error ) { export function setImportError(
queryOrPath: ImportStatusQuery | ImportTotalsQuery | string,
error: unknown
) {
return { return {
type: TYPES.SET_IMPORT_ERROR, type: TYPES.SET_IMPORT_ERROR,
error, error,
query, query: queryOrPath,
}; };
} }
export function* updateImportation( path, importStarted = false ) { export function* updateImportation( path: string, importStarted = false ) {
yield setImportStarted( importStarted ); yield setImportStarted( importStarted );
try { try {
const response = yield apiFetch( { path, method: 'POST' } ); const response: unknown = yield apiFetch( { path, method: 'POST' } );
return response; return response;
} catch ( error ) { } catch ( error ) {
yield setImportError( path, error ); yield setImportError( path, error );
throw error; throw error;
} }
} }
export type Action = ReturnType<
| typeof setImportStarted
| typeof setImportPeriod
| typeof setImportStatus
| typeof setImportTotals
| typeof setImportError
| typeof setSkipPrevious
>;

View File

@ -1,4 +1,4 @@
/** /**
* Internal dependencies * Internal dependencies
*/ */
export const STORE_NAME = 'wc/admin/import'; export const STORE_NAME = 'wc/admin/import' as const;

View File

@ -1,25 +1,36 @@
/** /**
* External dependencies * External dependencies
*/ */
import { registerStore } from '@wordpress/data'; import { registerStore } from '@wordpress/data';
import { controls } from '@wordpress/data-controls'; import { controls } from '@wordpress/data-controls';
import { SelectFromMap, DispatchFromMap } from '@automattic/data-stores';
import { Reducer, AnyAction } from 'redux';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { STORE_NAME } from './constants'; import { STORE_NAME } from './constants';
import * as selectors from './selectors'; import * as selectors from './selectors';
import * as actions from './actions'; import * as actions from './actions';
import * as resolvers from './resolvers'; import reducer, { State } from './reducer';
import reducer from './reducer'; import { WPDataSelectors } from '../types';
export * from './types';
export type { State };
registerStore( STORE_NAME, { registerStore< State >( STORE_NAME, {
reducer, reducer: reducer as Reducer< State, AnyAction >,
actions, actions,
controls, controls,
selectors, selectors,
resolvers,
} ); } );
export const IMPORT_STORE_NAME = STORE_NAME; export const IMPORT_STORE_NAME = STORE_NAME;
declare module '@wordpress/data' {
// TODO: convert action.js to TS
function dispatch(
key: typeof STORE_NAME
): DispatchFromMap< typeof actions >;
function select(
key: typeof STORE_NAME
): SelectFromMap< typeof selectors > & WPDataSelectors;
}

View File

@ -3,13 +3,16 @@
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import moment from 'moment'; import moment from 'moment';
import type { Reducer } from 'redux';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import TYPES from './action-types'; import TYPES from './action-types';
import { ImportState } from './types';
import { Action } from './actions';
const reducer = ( const reducer: Reducer< ImportState, Action > = (
state = { state = {
activeImport: false, activeImport: false,
importStatus: {}, importStatus: {},
@ -22,19 +25,11 @@ const reducer = (
}, },
skipPrevious: true, skipPrevious: true,
}, },
{ action
type,
query,
importStatus,
importTotals,
activeImport,
date,
error,
skipPrevious,
}
) => { ) => {
switch ( type ) { switch ( action.type ) {
case TYPES.SET_IMPORT_STARTED: case TYPES.SET_IMPORT_STARTED:
const { activeImport } = action;
state = { state = {
...state, ...state,
activeImport, activeImport,
@ -48,7 +43,7 @@ const reducer = (
...state, ...state,
period: { period: {
...state.period, ...state.period,
label: date, label: action.date,
}, },
activeImport: false, activeImport: false,
}; };
@ -57,7 +52,7 @@ const reducer = (
state = { state = {
...state, ...state,
period: { period: {
date, date: action.date,
label: 'custom', label: 'custom',
}, },
activeImport: false, activeImport: false,
@ -66,11 +61,12 @@ const reducer = (
case TYPES.SET_SKIP_IMPORTED: case TYPES.SET_SKIP_IMPORTED:
state = { state = {
...state, ...state,
skipPrevious, skipPrevious: action.skipPrevious,
activeImport: false, activeImport: false,
}; };
break; break;
case TYPES.SET_IMPORT_STATUS: case TYPES.SET_IMPORT_STATUS:
const { query, importStatus } = action;
state = { state = {
...state, ...state,
importStatus: { importStatus: {
@ -88,7 +84,7 @@ const reducer = (
...state, ...state,
importTotals: { importTotals: {
...state.importTotals, ...state.importTotals,
[ JSON.stringify( query ) ]: importTotals, [ JSON.stringify( action.query ) ]: action.importTotals,
}, },
}; };
break; break;
@ -97,7 +93,7 @@ const reducer = (
...state, ...state,
errors: { errors: {
...state.errors, ...state.errors,
[ JSON.stringify( query ) ]: error, [ JSON.stringify( action.query ) ]: action.error,
}, },
}; };
break; break;
@ -105,4 +101,5 @@ const reducer = (
return state; return state;
}; };
export type State = ReturnType< typeof reducer >;
export default reducer; export default reducer;

View File

@ -10,27 +10,33 @@ import { omit } from 'lodash';
*/ */
import { NAMESPACE } from '../constants'; import { NAMESPACE } from '../constants';
import { setImportError, setImportStatus, setImportTotals } from './actions'; import { setImportError, setImportStatus, setImportTotals } from './actions';
import {
ImportStatusQuery,
ImportTotalsQuery,
ImportStatus,
ImportTotals,
} from './types';
export function* getImportStatus( query ) { export function* getImportStatus( query: ImportStatusQuery ) {
try { try {
const url = addQueryArgs( const url = addQueryArgs(
`${ NAMESPACE }/reports/import/status`, `${ NAMESPACE }/reports/import/status`,
omit( query, [ 'timestamp' ] ) typeof query === 'object' ? omit( query, [ 'timestamp' ] ) : {}
); );
const response = yield apiFetch( { path: url } ); const response: ImportStatus = yield apiFetch( { path: url } );
yield setImportStatus( query, response ); yield setImportStatus( query, response );
} catch ( error ) { } catch ( error ) {
yield setImportError( query, error ); yield setImportError( query, error );
} }
} }
export function* getImportTotals( query ) { export function* getImportTotals( query: ImportTotalsQuery ) {
try { try {
const url = addQueryArgs( const url = addQueryArgs(
`${ NAMESPACE }/reports/import/totals`, `${ NAMESPACE }/reports/import/totals`,
query query
); );
const response = yield apiFetch( { path: url } ); const response: ImportTotals = yield apiFetch( { path: url } );
yield setImportTotals( query, response ); yield setImportTotals( query, response );
} catch ( error ) { } catch ( error ) {
yield setImportError( query, error ); yield setImportError( query, error );

View File

@ -1,19 +1,31 @@
export const getImportStarted = ( state ) => { /**
* Internal dependencies
*/
import { ImportState, ImportStatusQuery, ImportTotalsQuery } from './types';
export const getImportStarted = ( state: ImportState ) => {
const { activeImport, lastImportStartTimestamp } = state; const { activeImport, lastImportStartTimestamp } = state;
return { activeImport, lastImportStartTimestamp } || {}; return { activeImport, lastImportStartTimestamp } || {};
}; };
export const getFormSettings = ( state ) => { export const getFormSettings = ( state: ImportState ) => {
const { period, skipPrevious } = state; const { period, skipPrevious } = state;
return { period, skipPrevious } || {}; return { period, skipPrevious } || {};
}; };
export const getImportStatus = ( state, query ) => { export const getImportStatus = (
state: ImportState,
query: ImportStatusQuery
) => {
const stringifiedQuery = JSON.stringify( query ); const stringifiedQuery = JSON.stringify( query );
return state.importStatus[ stringifiedQuery ] || {}; return state.importStatus[ stringifiedQuery ] || {};
}; };
export const getImportTotals = ( state, query ) => { export const getImportTotals = (
state: ImportState,
query: ImportTotalsQuery
) => {
const { importTotals, lastImportStartTimestamp } = state; const { importTotals, lastImportStartTimestamp } = state;
const stringifiedQuery = JSON.stringify( query ); const stringifiedQuery = JSON.stringify( query );
return ( return (
@ -24,7 +36,10 @@ export const getImportTotals = ( state, query ) => {
); );
}; };
export const getImportError = ( state, query ) => { export const getImportError = (
state: ImportState,
query: ImportTotalsQuery | ImportStatusQuery | string
) => {
const stringifiedQuery = JSON.stringify( query ); const stringifiedQuery = JSON.stringify( query );
return state.errors[ stringifiedQuery ] || false; return state.errors[ stringifiedQuery ] || false;
}; };

View File

@ -24,6 +24,7 @@ const defaultState = {
describe( 'import reducer', () => { describe( 'import reducer', () => {
it( 'should return a default state', () => { it( 'should return a default state', () => {
// @ts-expect-error reducer action should not be empty but it is
const state = reducer( undefined, {} ); const state = reducer( undefined, {} );
expect( state ).toEqual( defaultState ); expect( state ).toEqual( defaultState );
expect( state ).not.toBe( defaultState ); expect( state ).not.toBe( defaultState );
@ -113,7 +114,10 @@ describe( 'import reducer', () => {
error: { code: 'error' }, error: { code: 'error' },
} ); } );
const stringifiedQuery = JSON.stringify( query ); const stringifiedQuery = JSON.stringify( query );
expect(
expect( state.errors[ stringifiedQuery ].code ).toBe( 'error' ); ( state.errors[ stringifiedQuery ] as {
code: string;
} ).code
).toBe( 'error' );
} ); } );
} ); } );

View File

@ -0,0 +1,52 @@
type SchedulerName = 'orders' | 'customers';
type isImporting = {
is_importing: boolean;
};
type SchedulerImportStatus = {
[ schedulerName in SchedulerName ]: {
imported: number;
totals: number;
};
} & {
imported_from?: string | number;
};
export type ImportStatus =
| isImporting
| ( isImporting & SchedulerImportStatus );
export type ImportStatusQuery = number;
export type ImportTotals = {
[ schedulerName in SchedulerName ]: number;
};
export type ImportTotalsQuery = {
skip_existing: boolean;
days: number;
};
export type ImportState = {
activeImport: boolean;
importStatus:
| Record< string, never >
| {
[ queryString: string ]: ImportStatus;
};
importTotals:
| Record< string, never >
| {
[ queryString: string ]: ImportTotals;
};
errors: {
[ queryString: string ]: unknown;
};
lastImportStartTimestamp: number;
period: {
date: string;
label: string;
};
skipPrevious: boolean;
};

View File

@ -485,6 +485,7 @@ importers:
'@babel/runtime': ^7.17.2 '@babel/runtime': ^7.17.2
'@testing-library/react': ^12.1.3 '@testing-library/react': ^12.1.3
'@testing-library/react-hooks': ^7.0.2 '@testing-library/react-hooks': ^7.0.2
'@types/md5': ^2.3.2
'@types/wordpress__compose': ^4.0.1 '@types/wordpress__compose': ^4.0.1
'@types/wordpress__core-data': ^2.4.5 '@types/wordpress__core-data': ^2.4.5
'@types/wordpress__data': ^6.0.0 '@types/wordpress__data': ^6.0.0
@ -536,6 +537,7 @@ importers:
'@babel/runtime': 7.17.7 '@babel/runtime': 7.17.7
'@testing-library/react': 12.1.4 '@testing-library/react': 12.1.4
'@testing-library/react-hooks': 7.0.2 '@testing-library/react-hooks': 7.0.2
'@types/md5': 2.3.2
'@types/wordpress__compose': 4.0.1 '@types/wordpress__compose': 4.0.1
'@types/wordpress__core-data': 2.4.5 '@types/wordpress__core-data': 2.4.5
'@types/wordpress__data': 6.0.0 '@types/wordpress__data': 6.0.0
@ -13418,6 +13420,10 @@ packages:
/@types/lodash/4.14.180: /@types/lodash/4.14.180:
resolution: {integrity: sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g==} resolution: {integrity: sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g==}
/@types/md5/2.3.2:
resolution: {integrity: sha512-v+JFDu96+UYJ3/UWzB0mEglIS//MZXgRaJ4ubUPwOM0gvLc/kcQ3TWNYwENEK7/EcXGQVrW8h/XqednSjBd/Og==}
dev: true
/@types/mdast/3.0.10: /@types/mdast/3.0.10:
resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==} resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==}
dependencies: dependencies:
@ -13711,6 +13717,7 @@ packages:
re-resizable: 4.11.0 re-resizable: 4.11.0
transitivePeerDependencies: transitivePeerDependencies:
- react - react
- react-dom
dev: true dev: true
/@types/wordpress__compose/4.0.1: /@types/wordpress__compose/4.0.1:
@ -18577,7 +18584,7 @@ packages:
dev: true dev: true
/buffer-crc32/0.2.13: /buffer-crc32/0.2.13:
resolution: {integrity: sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=} resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
/buffer-fill/1.0.0: /buffer-fill/1.0.0:
resolution: {integrity: sha1-+PeLdniYiO858gXNY39o5wISKyw=} resolution: {integrity: sha1-+PeLdniYiO858gXNY39o5wISKyw=}
@ -39221,7 +39228,7 @@ packages:
tapable: 1.1.3 tapable: 1.1.3
terser-webpack-plugin: 1.4.5_webpack@4.46.0 terser-webpack-plugin: 1.4.5_webpack@4.46.0
watchpack: 1.7.5 watchpack: 1.7.5
webpack-cli: 3.3.12_webpack@5.70.0 webpack-cli: 3.3.12_webpack@4.46.0
webpack-sources: 1.4.3 webpack-sources: 1.4.3
dev: true dev: true