Skip to content

Commit 5b2b034

Browse files
longlhoLong Ho
authored and
Long Ho
committedMar 5, 2020
feat: Introduce ReactIntlErrorCode so we can distinguish and log things differently
1 parent 14aacfb commit 5b2b034

28 files changed

+344
-274
lines changed
 

‎package-lock.json

+6-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@
140140
"@types/invariant": "^2.2.31",
141141
"hoist-non-react-statics": "^3.3.2",
142142
"intl-format-cache": "^4.2.21",
143-
"intl-messageformat": "^8.1.0",
143+
"intl-messageformat": "^8.2.1",
144144
"intl-messageformat-parser": "^4.1.0",
145145
"shallow-equal": "^1.2.1"
146146
},
@@ -168,7 +168,7 @@
168168
"babel-jest": "^25.1.0",
169169
"benchmark": "^2.1.4",
170170
"core-js": "^3.6.4",
171-
"cross-env": "^7.0.1",
171+
"cross-env": "^7.0.2",
172172
"enzyme": "^3.11.0",
173173
"enzyme-adapter-react-16": "^1.15.2",
174174
"enzyme-to-json": "^3.4.4",

‎src/components/provider.tsx

+7-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import * as React from 'react';
88
import {Provider} from './injectIntl';
99
import {
10-
createError,
1110
DEFAULT_INTL_CONFIG,
1211
createFormatters,
1312
invariantIntlContext,
@@ -27,6 +26,7 @@ import {formatMessage} from '../formatters/message';
2726
import * as shallowEquals_ from 'shallow-equal/objects';
2827
import {formatList} from '../formatters/list';
2928
import {formatDisplayName} from '../formatters/displayName';
29+
import {ReactIntlError, ReactIntlErrorCode} from '../error';
3030
const shallowEquals: typeof shallowEquals_ =
3131
(shallowEquals_ as any).default || shallowEquals_;
3232

@@ -83,7 +83,8 @@ export function createIntl(
8383
if (!locale) {
8484
if (onError) {
8585
onError(
86-
createError(
86+
new ReactIntlError(
87+
ReactIntlErrorCode.INVALID_CONFIG,
8788
`"locale" was not configured, using "${defaultLocale}" as fallback. See https://github.com/formatjs/react-intl/blob/master/docs/API.md#intlshape for more details`
8889
)
8990
);
@@ -96,7 +97,8 @@ export function createIntl(
9697
resolvedConfig.locale = resolvedConfig.defaultLocale || 'en';
9798
} else if (!Intl.NumberFormat.supportedLocalesOf(locale).length && onError) {
9899
onError(
99-
createError(
100+
new ReactIntlError(
101+
ReactIntlErrorCode.MISSING_DATA,
100102
`Missing locale data for locale: "${locale}" in Intl.NumberFormat. Using default locale: "${defaultLocale}" as fallback. See https://github.com/formatjs/react-intl/blob/master/docs/Getting-Started.md#runtime-requirements for more details`
101103
)
102104
);
@@ -105,7 +107,8 @@ export function createIntl(
105107
onError
106108
) {
107109
onError(
108-
createError(
110+
new ReactIntlError(
111+
ReactIntlErrorCode.MISSING_DATA,
109112
`Missing locale data for locale: "${locale}" in Intl.DateTimeFormat. Using default locale: "${defaultLocale}" as fallback. See https://github.com/formatjs/react-intl/blob/master/docs/Getting-Started.md#runtime-requirements for more details`
110113
)
111114
);

‎src/error.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
export const enum ReactIntlErrorCode {
2+
FORMAT_ERROR = 'FORMAT_ERROR',
3+
UNSUPPORTED_FORMATTER = 'UNSUPPORTED_FORMATTER',
4+
INVALID_CONFIG = 'INVALID_CONFIG',
5+
MISSING_DATA = 'MISSING_DATA',
6+
MISSING_TRANSLATION = 'MISSING_TRANSLATION'
7+
}
8+
9+
export class ReactIntlError extends Error {
10+
public code: ReactIntlErrorCode
11+
constructor(code: ReactIntlErrorCode, message: string, exception?: Error) {
12+
super(`[React Intl Error ${code}] ${message} ${exception ? `\n${exception.stack}` : ''}`)
13+
this.code = code
14+
if (typeof Error.captureStackTrace === 'function') {
15+
Error.captureStackTrace(this, ReactIntlError)
16+
}
17+
}
18+
}

‎src/formatters/dateTime.ts

+30-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66

77
import {Formatters, IntlConfig, IntlFormatters} from '../types';
88

9-
import {createError, filterProps, getNamedFormat} from '../utils';
9+
import {filterProps, getNamedFormat} from '../utils';
10+
import {ReactIntlError, ReactIntlErrorCode} from '../error';
1011

1112
const DATE_TIME_FORMAT_OPTIONS: Array<keyof Intl.DateTimeFormatOptions> = [
1213
'localeMatcher',
@@ -74,7 +75,13 @@ export function formatDate(
7475
date
7576
);
7677
} catch (e) {
77-
config.onError(createError('Error formatting date.', e));
78+
config.onError(
79+
new ReactIntlError(
80+
ReactIntlErrorCode.FORMAT_ERROR,
81+
'Error formatting date.',
82+
e
83+
)
84+
);
7885
}
7986

8087
return String(date);
@@ -93,7 +100,13 @@ export function formatTime(
93100
date
94101
);
95102
} catch (e) {
96-
config.onError(createError('Error formatting time.', e));
103+
config.onError(
104+
new ReactIntlError(
105+
ReactIntlErrorCode.FORMAT_ERROR,
106+
'Error formatting time.',
107+
e
108+
)
109+
);
97110
}
98111

99112
return String(date);
@@ -114,7 +127,13 @@ export function formatDateToParts(
114127
options
115128
).formatToParts(date);
116129
} catch (e) {
117-
config.onError(createError('Error formatting date.', e));
130+
config.onError(
131+
new ReactIntlError(
132+
ReactIntlErrorCode.FORMAT_ERROR,
133+
'Error formatting date.',
134+
e
135+
)
136+
);
118137
}
119138

120139
return [];
@@ -136,7 +155,13 @@ export function formatTimeToParts(
136155
options
137156
).formatToParts(date);
138157
} catch (e) {
139-
config.onError(createError('Error formatting time.', e));
158+
config.onError(
159+
new ReactIntlError(
160+
ReactIntlErrorCode.FORMAT_ERROR,
161+
'Error formatting time.',
162+
e
163+
)
164+
);
140165
}
141166

142167
return [];

‎src/formatters/displayName.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import {IntlConfig, Formatters, IntlFormatters} from '../types';
2-
import {filterProps, createError} from '../utils';
2+
import {filterProps} from '../utils';
33
import {
44
DisplayNamesOptions,
55
DisplayNames as IntlDisplayNames,
66
} from '@formatjs/intl-displaynames';
7+
import {FormatError, ErrorCode} from 'intl-messageformat';
8+
import {ReactIntlErrorCode, ReactIntlError} from '../error';
79

810
const DISPLAY_NAMES_OPTONS: Array<keyof DisplayNamesOptions> = [
911
'localeMatcher',
@@ -21,15 +23,24 @@ export function formatDisplayName(
2123
const DisplayNames: typeof IntlDisplayNames = (Intl as any).DisplayNames;
2224
if (!DisplayNames) {
2325
onError(
24-
createError(`Intl.DisplayNames is not available in this environment.
26+
new FormatError(
27+
`Intl.DisplayNames is not available in this environment.
2528
Try polyfilling it using "@formatjs/intl-displaynames"
26-
`)
29+
`,
30+
ErrorCode.MISSING_INTL_API
31+
)
2732
);
2833
}
2934
const filteredOptions = filterProps(options, DISPLAY_NAMES_OPTONS);
3035
try {
3136
return getDisplayNames(locale, filteredOptions).of(value);
3237
} catch (e) {
33-
onError(createError('Error formatting display name.', e));
38+
onError(
39+
new ReactIntlError(
40+
ReactIntlErrorCode.FORMAT_ERROR,
41+
'Error formatting display name.',
42+
e
43+
)
44+
);
3445
}
3546
}

‎src/formatters/list.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import * as React from 'react';
22
import {IntlConfig, Formatters, IntlFormatters} from '../types';
3-
import {filterProps, createError} from '../utils';
3+
import {filterProps} from '../utils';
44
import IntlListFormat, {IntlListFormatOptions} from '@formatjs/intl-listformat';
5+
import {FormatError, ErrorCode} from 'intl-messageformat';
6+
import {ReactIntlError, ReactIntlErrorCode} from '../error';
57

68
const LIST_FORMAT_OPTIONS: Array<keyof IntlListFormatOptions> = [
79
'localeMatcher',
@@ -30,9 +32,12 @@ export function formatList(
3032
const ListFormat: typeof IntlListFormat = (Intl as any).ListFormat;
3133
if (!ListFormat) {
3234
onError(
33-
createError(`Intl.ListFormat is not available in this environment.
35+
new FormatError(
36+
`Intl.ListFormat is not available in this environment.
3437
Try polyfilling it using "@formatjs/intl-listformat"
35-
`)
38+
`,
39+
ErrorCode.MISSING_INTL_API
40+
)
3641
);
3742
}
3843
const filteredOptions = filterProps(options, LIST_FORMAT_OPTIONS);
@@ -65,7 +70,13 @@ Try polyfilling it using "@formatjs/intl-listformat"
6570
return all;
6671
}, []);
6772
} catch (e) {
68-
onError(createError('Error formatting list.', e));
73+
onError(
74+
new ReactIntlError(
75+
ReactIntlErrorCode.FORMAT_ERROR,
76+
'Error formatting list.',
77+
e
78+
)
79+
);
6980
}
7081

7182
return values;

‎src/formatters/message.ts

+17-15
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ import {
1414
CustomFormats,
1515
} from '../types';
1616

17-
import {createError} from '../utils';
1817
import IntlMessageFormat, {
1918
FormatXMLElementFn,
2019
PrimitiveType,
2120
} from 'intl-messageformat';
21+
import {ReactIntlError, ReactIntlErrorCode} from '../error';
2222

2323
function setTimeZoneInOptions(
2424
opts: Record<string, Intl.DateTimeFormatOptions>,
@@ -151,7 +151,8 @@ export function formatMessage<T>(
151151
formattedMessageParts = formatter.format(values);
152152
} catch (e) {
153153
onError(
154-
createError(
154+
new ReactIntlError(
155+
ReactIntlErrorCode.FORMAT_ERROR,
155156
`Error formatting message: "${id}" for locale: "${locale}"` +
156157
(defaultMessage ? ', using default message as fallback.' : ''),
157158
e
@@ -162,17 +163,13 @@ export function formatMessage<T>(
162163
// This prevents warnings from littering the console in development
163164
// when no `messages` are passed into the <IntlProvider> for the
164165
// default locale, and a default message is in the source.
165-
if (
166-
!defaultMessage ||
167-
(locale && locale.toLowerCase() !== defaultLocale.toLowerCase())
168-
) {
169-
onError(
170-
createError(
171-
`Missing message: "${id}" for locale: "${locale}"` +
172-
(defaultMessage ? ', using default message as fallback.' : '')
173-
)
174-
);
175-
}
166+
onError(
167+
new ReactIntlError(
168+
ReactIntlErrorCode.MISSING_TRANSLATION,
169+
`Missing message: "${id}" for locale: "${locale}"` +
170+
(defaultMessage ? ', using default message as fallback.' : '')
171+
)
172+
);
176173
}
177174

178175
if (!formattedMessageParts && defaultMessage) {
@@ -186,14 +183,19 @@ export function formatMessage<T>(
186183
formattedMessageParts = formatter.format(values);
187184
} catch (e) {
188185
onError(
189-
createError(`Error formatting the default message for: "${id}"`, e)
186+
new ReactIntlError(
187+
ReactIntlErrorCode.FORMAT_ERROR,
188+
`Error formatting the default message for: "${id}"`,
189+
e
190+
)
190191
);
191192
}
192193
}
193194

194195
if (!formattedMessageParts) {
195196
onError(
196-
createError(
197+
new ReactIntlError(
198+
ReactIntlErrorCode.FORMAT_ERROR,
197199
`Cannot format message: "${id}", ` +
198200
`using message ${
199201
message || defaultMessage ? 'source' : 'id'

‎src/formatters/number.ts

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {IntlConfig, Formatters, IntlFormatters} from '../types';
2-
import {getNamedFormat, filterProps, createError} from '../utils';
2+
import {getNamedFormat, filterProps} from '../utils';
33
import {UnifiedNumberFormatOptions} from '@formatjs/intl-unified-numberformat';
4+
import {ReactIntlError, ReactIntlErrorCode} from '../error';
45

56
const NUMBER_FORMAT_OPTIONS: Array<keyof UnifiedNumberFormatOptions> = [
67
'localeMatcher',
@@ -55,7 +56,13 @@ export function formatNumber(
5556
try {
5657
return getFormatter(config, getNumberFormat, options).format(value);
5758
} catch (e) {
58-
config.onError(createError('Error formatting number.', e));
59+
config.onError(
60+
new ReactIntlError(
61+
ReactIntlErrorCode.FORMAT_ERROR,
62+
'Error formatting number.',
63+
e
64+
)
65+
);
5966
}
6067

6168
return String(value);
@@ -70,7 +77,13 @@ export function formatNumberToParts(
7077
try {
7178
return getFormatter(config, getNumberFormat, options).formatToParts(value);
7279
} catch (e) {
73-
config.onError(createError('Error formatting number.', e));
80+
config.onError(
81+
new ReactIntlError(
82+
ReactIntlErrorCode.FORMAT_ERROR,
83+
'Error formatting number.',
84+
e
85+
)
86+
);
7487
}
7588

7689
return [];

‎src/formatters/plural.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import {IntlConfig, Formatters, IntlFormatters} from '../types';
2-
import {filterProps, createError} from '../utils';
2+
import {filterProps} from '../utils';
3+
import {ReactIntlErrorCode, ReactIntlError} from '../error';
4+
import {FormatError, ErrorCode} from 'intl-messageformat';
35

46
const PLURAL_FORMAT_OPTIONS: Array<keyof Intl.PluralRulesOptions> = [
57
'localeMatcher',
@@ -14,17 +16,26 @@ export function formatPlural(
1416
): string {
1517
if (!Intl.PluralRules) {
1618
onError(
17-
createError(`Intl.PluralRules is not available in this environment.
19+
new FormatError(
20+
`Intl.PluralRules is not available in this environment.
1821
Try polyfilling it using "@formatjs/intl-pluralrules"
19-
`)
22+
`,
23+
ErrorCode.MISSING_INTL_API
24+
)
2025
);
2126
}
2227
const filteredOptions = filterProps(options, PLURAL_FORMAT_OPTIONS);
2328

2429
try {
2530
return getPluralRules(locale, filteredOptions).select(value);
2631
} catch (e) {
27-
onError(createError('Error formatting plural.', e));
32+
onError(
33+
new ReactIntlError(
34+
ReactIntlErrorCode.FORMAT_ERROR,
35+
'Error formatting plural.',
36+
e
37+
)
38+
);
2839
}
2940

3041
return 'other';

‎src/formatters/relativeTime.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import {IntlConfig, IntlFormatters, Formatters} from '../types';
22

3-
import {getNamedFormat, filterProps, createError} from '../utils';
3+
import {getNamedFormat, filterProps} from '../utils';
44
import RelativeTimeFormat, {
55
IntlRelativeTimeFormatOptions,
66
} from '@formatjs/intl-relativetimeformat';
7+
import {FormatError, ErrorCode} from 'intl-messageformat';
8+
import {ReactIntlError, ReactIntlErrorCode} from '../error';
79

810
const RELATIVE_TIME_FORMAT_OPTIONS: Array<keyof IntlRelativeTimeFormatOptions> = [
911
'numeric',
@@ -45,9 +47,12 @@ export function formatRelativeTime(
4547
const RelativeTimeFormat = (Intl as any).RelativeTimeFormat;
4648
if (!RelativeTimeFormat) {
4749
config.onError(
48-
createError(`Intl.RelativeTimeFormat is not available in this environment.
50+
new FormatError(
51+
`Intl.RelativeTimeFormat is not available in this environment.
4952
Try polyfilling it using "@formatjs/intl-relativetimeformat"
50-
`)
53+
`,
54+
ErrorCode.MISSING_INTL_API
55+
)
5156
);
5257
}
5358
try {
@@ -56,7 +61,13 @@ Try polyfilling it using "@formatjs/intl-relativetimeformat"
5661
unit
5762
);
5863
} catch (e) {
59-
config.onError(createError('Error formatting relative time.', e));
64+
config.onError(
65+
new ReactIntlError(
66+
ReactIntlErrorCode.FORMAT_ERROR,
67+
'Error formatting relative time.',
68+
e
69+
)
70+
);
6071
}
6172

6273
return String(value);

‎src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,4 @@ export {default as FormattedRelativeTime} from './components/relative';
5555
export {default as FormattedPlural} from './components/plural';
5656
export {default as FormattedMessage} from './components/message';
5757
export {createIntlCache} from './utils';
58+
export {ReactIntlError, ReactIntlErrorCode} from './error'

‎src/types.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import IntlMessageFormat, {
88
Formats,
99
PrimitiveType,
1010
FormatXMLElementFn,
11+
FormatError,
1112
} from 'intl-messageformat';
1213
import IntlRelativeTimeFormat, {
1314
IntlRelativeTimeFormatOptions,
@@ -16,6 +17,7 @@ import {MessageFormatElement} from 'intl-messageformat-parser';
1617
import {UnifiedNumberFormatOptions} from '@formatjs/intl-unified-numberformat';
1718
import IntlListFormat, {IntlListFormatOptions} from '@formatjs/intl-listformat';
1819
import {DisplayNames, DisplayNamesOptions} from '@formatjs/intl-displaynames';
20+
import { ReactIntlError } from './error';
1921

2022
export interface IntlConfig {
2123
locale: string;
@@ -25,7 +27,7 @@ export interface IntlConfig {
2527
messages: Record<string, string> | Record<string, MessageFormatElement[]>;
2628
defaultLocale: string;
2729
defaultFormats: CustomFormats;
28-
onError(err: string): void;
30+
onError(err: ReactIntlError | FormatError): void;
2931
}
3032

3133
export interface CustomFormats extends Partial<Formats> {

‎src/utils.ts

+4-8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import IntlMessageFormat from 'intl-messageformat';
1515
import memoizeIntlConstructor from 'intl-format-cache';
1616
import {invariant} from '@formatjs/intl-utils';
1717
import {IntlRelativeTimeFormatOptions} from '@formatjs/intl-relativetimeformat';
18+
import { ReactIntlError, ReactIntlErrorCode } from './error';
1819

1920
export function filterProps<T extends Record<string, any>, K extends string>(
2021
props: T,
@@ -40,12 +41,7 @@ export function invariantIntlContext(intl?: any): asserts intl {
4041
);
4142
}
4243

43-
export function createError(message: string, exception?: Error): string {
44-
const eMsg = exception ? `\n${exception.stack}` : '';
45-
return `[React Intl] ${message}${eMsg}`;
46-
}
47-
48-
export function defaultErrorHandler(error: string): void {
44+
export function defaultErrorHandler(error: ReactIntlError): void {
4945
if (process.env.NODE_ENV !== 'production') {
5046
console.error(error);
5147
}
@@ -115,7 +111,7 @@ export function getNamedFormat<T extends keyof CustomFormats>(
115111
formats: CustomFormats,
116112
type: T,
117113
name: string,
118-
onError: (err: string) => void
114+
onError: (err: ReactIntlError) => void
119115
):
120116
| Intl.NumberFormatOptions
121117
| Intl.DateTimeFormatOptions
@@ -130,5 +126,5 @@ export function getNamedFormat<T extends keyof CustomFormats>(
130126
return format;
131127
}
132128

133-
onError(createError(`No ${type} format named: ${name}`));
129+
onError(new ReactIntlError(ReactIntlErrorCode.UNSUPPORTED_FORMATTER, `No ${type} format named: ${name}`));
134130
}
+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`format API formatDate() options falls back and warns on invalid Intl.DateTimeFormat options 1`] = `
4+
Array [
5+
"DATE_FORMAT_ERROR",
6+
]
7+
`;
8+
9+
exports[`format API formatDate() options handles missing named formats and warns 1`] = `
10+
Array [
11+
"UNSUPPORTED_FORMATTER",
12+
]
13+
`;
14+
15+
exports[`format API formatMessage() fallbacks formats \`defaultMessage\` when message has a syntax error 1`] = `
16+
Array [
17+
"DATE_FORMAT_ERROR",
18+
]
19+
`;
20+
21+
exports[`format API formatMessage() fallbacks formats \`defaultMessage\` when message has missing values 1`] = `
22+
Array [
23+
"DATE_FORMAT_ERROR",
24+
]
25+
`;
26+
27+
exports[`format API formatMessage() fallbacks returns \`defaultMessage\` source when formatting errors and missing message 1`] = `
28+
Array [
29+
"MISSING_TRANSLATION",
30+
"DATE_FORMAT_ERROR",
31+
"DATE_FORMAT_ERROR",
32+
]
33+
`;
34+
35+
exports[`format API formatMessage() fallbacks returns message \`id\` when message and \`defaultMessage\` are empty 1`] = `
36+
Array [
37+
"MISSING_TRANSLATION",
38+
"DATE_FORMAT_ERROR",
39+
]
40+
`;
41+
42+
exports[`format API formatMessage() fallbacks returns message \`id\` when message and \`defaultMessage\` are missing 1`] = `
43+
Array [
44+
"MISSING_TRANSLATION",
45+
"DATE_FORMAT_ERROR",
46+
]
47+
`;
48+
49+
exports[`format API formatMessage() fallbacks returns message source when formatting error and missing \`defaultMessage\` 1`] = `
50+
Array [
51+
"DATE_FORMAT_ERROR",
52+
"DATE_FORMAT_ERROR",
53+
]
54+
`;
55+
56+
exports[`format API formatMessage() fallbacks returns message source when message and \`defaultMessage\` have formatting errors 1`] = `
57+
Array [
58+
"DATE_FORMAT_ERROR",
59+
"DATE_FORMAT_ERROR",
60+
"DATE_FORMAT_ERROR",
61+
]
62+
`;
63+
64+
exports[`format API formatNumber() options falls back and warns on invalid Intl.NumberFormat options 1`] = `
65+
Array [
66+
"DATE_FORMAT_ERROR",
67+
]
68+
`;
69+
70+
exports[`format API formatNumber() options handles missing named formats and warns 1`] = `
71+
Array [
72+
"UNSUPPORTED_FORMATTER",
73+
]
74+
`;
75+
76+
exports[`format API formatRelativeTime() falls back and warns when no value is provided 1`] = `
77+
Array [
78+
"DATE_FORMAT_ERROR",
79+
]
80+
`;
81+
82+
exports[`format API formatRelativeTime() options falls back and warns on invalid IntlRelativeFormat options 1`] = `
83+
Array [
84+
"DATE_FORMAT_ERROR",
85+
]
86+
`;
87+
88+
exports[`format API formatRelativeTime() options handles missing named formats and warns 1`] = `
89+
Array [
90+
"UNSUPPORTED_FORMATTER",
91+
]
92+
`;
93+
94+
exports[`format API formatTime() options falls back and warns on invalid Intl.DateTimeFormat options 1`] = `
95+
Array [
96+
"DATE_FORMAT_ERROR",
97+
]
98+
`;
99+
100+
exports[`format API formatTime() options handles missing named formats and warns 1`] = `
101+
Array [
102+
"UNSUPPORTED_FORMATTER",
103+
]
104+
`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`<FormattedDate> falls back and warns on invalid Intl.DateTimeFormat options 1`] = `"DATE_FORMAT_ERROR"`;
4+
5+
exports[`<FormattedDate> requires a finite \`value\` prop 1`] = `"DATE_FORMAT_ERROR"`;
6+
7+
exports[`<FormattedDateParts> falls back and warns on invalid Intl.DateTimeFormat options 1`] = `"DATE_FORMAT_ERROR"`;
8+
9+
exports[`<FormattedDateParts> requires a finite \`value\` prop 1`] = `"DATE_FORMAT_ERROR"`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`<FormattedNumber> falls back and warns on invalid Intl.NumberFormat options 1`] = `"DATE_FORMAT_ERROR"`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`<IntlProvider> warns when \`locale\` prop provided has no locale data in Intl.DateTimeFormat 1`] = `"MISSING_DATA"`;
4+
5+
exports[`<IntlProvider> warns when \`locale\` prop provided has no locale data in Intl.NumberFormat 1`] = `"MISSING_DATA"`;
6+
7+
exports[`<IntlProvider> warns when no \`locale\` prop is provided 1`] = `"INVALID_CONFIG"`;

‎test/unit/components/__snapshots__/relative.tsx.snap

+2
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ exports[`<FormattedRelativeTime> supports function-as-child pattern 1`] = `
1010
</b>
1111
</FormattedRelativeTime>
1212
`;
13+
14+
exports[`<FormattedRelativeTime> throws an error for invalid unit 1`] = `"DATE_FORMAT_ERROR"`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`<FormattedTime> falls back and warns on invalid Intl.DateTimeFormat options 1`] = `"DATE_FORMAT_ERROR"`;
4+
5+
exports[`<FormattedTime> requires a finite \`value\` prop 1`] = `"DATE_FORMAT_ERROR"`;
6+
7+
exports[`<FormattedTimeParts> falls back and warns on invalid Intl.DateTimeFormat options 1`] = `"DATE_FORMAT_ERROR"`;
8+
9+
exports[`<FormattedTimeParts> requires a finite \`value\` prop 1`] = `"DATE_FORMAT_ERROR"`;

‎test/unit/components/date.tsx

+6-19
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {FormattedDate, FormattedDateParts} from '../../../src';
44
import {mountFormattedComponentWithProvider} from '../testUtils';
55
import {createIntl} from '../../../src/components/provider';
66
import {IntlShape} from '../../../src';
7+
import { FormatError } from 'intl-messageformat';
78

89
const mountWithProvider = mountFormattedComponentWithProvider(FormattedDate);
910
const mountPartsWithProvider = mountFormattedComponentWithProvider(
@@ -25,9 +26,7 @@ describe('<FormattedDate>', () => {
2526
});
2627

2728
it('throws when <IntlProvider> is missing from ancestry', () => {
28-
expect(() => mount(<FormattedDate value={Date.now()} />)).toThrow(
29-
'[React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.'
30-
);
29+
expect(() => mount(<FormattedDate value={Date.now()} />)).toThrow(Error)
3130
});
3231

3332
it('requires a finite `value` prop', () => {
@@ -39,9 +38,7 @@ describe('<FormattedDate>', () => {
3938

4039
mountWithProvider({value: NaN}, intl);
4140
expect(console.error).toHaveBeenCalledTimes(1);
42-
expect(console.error).toHaveBeenCalledWith(
43-
expect.stringContaining('[React Intl] Error formatting date.\nRangeError')
44-
);
41+
expect(console.error.mock.calls[0][0].code).toMatchSnapshot()
4542
});
4643

4744
it('renders a formatted date in a <>', () => {
@@ -77,11 +74,7 @@ describe('<FormattedDate>', () => {
7774

7875
expect(rendered.text()).toBe(String(date));
7976
expect(console.error).toHaveBeenCalledTimes(1);
80-
expect(console.error).toHaveBeenCalledWith(
81-
expect.stringMatching(
82-
/Error formatting date.\nRangeError: Value invalid out of range for (.*) options property year/
83-
)
84-
);
77+
expect(console.error.mock.calls[0][0].code).toMatchSnapshot()
8578
});
8679

8780
it('accepts `format` prop', () => {
@@ -151,9 +144,7 @@ describe('<FormattedDateParts>', () => {
151144

152145
mountPartsWithProvider({value: NaN, children}, intl);
153146
expect(console.error).toHaveBeenCalledTimes(1);
154-
expect(console.error).toHaveBeenCalledWith(
155-
expect.stringContaining('[React Intl] Error formatting date.\nRangeError')
156-
);
147+
expect(console.error.mock.calls[0][0].code).toMatchSnapshot()
157148
});
158149

159150
it('accepts valid Intl.DateTimeFormat options as props', () => {
@@ -175,11 +166,7 @@ describe('<FormattedDateParts>', () => {
175166
intl.formatDateToParts(date, {year: 'invalid'})
176167
);
177168
expect(console.error).toHaveBeenCalledTimes(2);
178-
expect(console.error).toHaveBeenCalledWith(
179-
expect.stringMatching(
180-
/Error formatting date.\nRangeError: Value invalid out of range for (.*) options property year/
181-
)
182-
);
169+
expect(console.error.mock.calls[0][0].code).toMatchSnapshot()
183170
});
184171

185172
it('renders a string date', () => {

‎test/unit/components/message.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ describe('<FormattedMessage>', () => {
7373
);
7474

7575
expect(rendered.text()).toBe('Hello');
76-
expect(console.error).toHaveBeenCalledTimes(1);
76+
expect(console.error).toHaveBeenCalledTimes(2);
7777
});
7878

7979
it('should work w/ multiple context', function() {

‎test/unit/components/number.tsx

+1-5
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,7 @@ describe('<FormattedNumber>', () => {
6666
const rendered = mountWithProvider({value: 0, style: 'invalid'}, intl);
6767

6868
expect(rendered.text()).toBe('0');
69-
expect(console.error).toHaveBeenCalledWith(
70-
expect.stringMatching(
71-
/\[React Intl\] Error formatting number.\nRangeError: Value invalid out of range for (.*) options property style/
72-
)
73-
);
69+
expect(console.error.mock.calls[0][0].code).toMatchSnapshot()
7470
expect(console.error).toHaveBeenCalledTimes(1);
7571
});
7672

‎test/unit/components/provider.tsx

+3-9
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,7 @@ describe('<IntlProvider>', () => {
5757
</IntlProvider>
5858
);
5959

60-
expect(console.error).toHaveBeenCalledWith(
61-
'[React Intl] "locale" was not configured, using "en" as fallback. See https://github.com/formatjs/react-intl/blob/master/docs/API.md#intlshape for more details'
62-
);
60+
expect(console.error.mock.calls[0][0].code).toMatchSnapshot()
6361
expect(console.error).toHaveBeenCalledTimes(1);
6462
});
6563

@@ -71,9 +69,7 @@ describe('<IntlProvider>', () => {
7169
</IntlProvider>
7270
);
7371

74-
expect(console.error).toHaveBeenCalledWith(
75-
`[React Intl] Missing locale data for locale: "missing" in Intl.NumberFormat. Using default locale: "en" as fallback. See https://github.com/formatjs/react-intl/blob/master/docs/Getting-Started.md#runtime-requirements for more details`
76-
);
72+
expect(console.error.mock.calls[0][0].code).toMatchSnapshot()
7773
expect(console.error).toHaveBeenCalledTimes(1);
7874
});
7975

@@ -87,9 +83,7 @@ describe('<IntlProvider>', () => {
8783
</IntlProvider>
8884
);
8985

90-
expect(console.error).toHaveBeenCalledWith(
91-
`[React Intl] Missing locale data for locale: "xx-HA" in Intl.DateTimeFormat. Using default locale: "en" as fallback. See https://github.com/formatjs/react-intl/blob/master/docs/Getting-Started.md#runtime-requirements for more details`
92-
);
86+
expect(console.error.mock.calls[0][0].code).toMatchSnapshot()
9387
expect(console.error).toHaveBeenCalledTimes(1);
9488
Intl.NumberFormat.supportedLocalesOf = supportedLocalesOf
9589
});

‎test/unit/components/relative.tsx

+1-5
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,8 @@ describe('<FormattedRelativeTime>', () => {
7676
it('throws an error for invalid unit', () => {
7777
const rendered = mountWithProvider({value: 0, unit: 'invalid' as any});
7878
expect(rendered.text()).toBe('0');
79-
expect(console.error).toHaveBeenCalledWith(
80-
expect.stringMatching(
81-
/Error formatting relative time.\nRangeError: Invalid unit(.*)invalid/
82-
)
83-
);
8479
expect(console.error).toHaveBeenCalledTimes(1);
80+
expect(console.error.mock.calls[0][0].code).toMatchSnapshot()
8581
});
8682

8783
it('accepts `format` prop', () => {

‎test/unit/components/time.tsx

+6-18
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,14 @@ describe('<FormattedTime>', () => {
3131

3232
it('requires a finite `value` prop', () => {
3333
const injectIntlContext = mountWithProvider({value: 0}, intl);
34-
expect(console.error).toHaveBeenCalledTimes(0);
34+
expect(console.error).not.toHaveBeenCalled()
3535

3636
injectIntlContext.setProps({
3737
...injectIntlContext.props(),
3838
value: NaN,
3939
});
40-
expect(console.error).toHaveBeenCalledWith(
41-
expect.stringContaining('[React Intl] Error formatting time.\nRangeError')
42-
);
4340
expect(console.error).toHaveBeenCalledTimes(1);
41+
expect(console.error.mock.calls[0][0].code).toMatchSnapshot()
4442
});
4543

4644
it('renders a formatted time in a <>', () => {
@@ -77,11 +75,7 @@ describe('<FormattedTime>', () => {
7775
const rendered = mountWithProvider({value: date, hour: 'invalid'}, intl);
7876

7977
expect(rendered.text()).toBe(String(date));
80-
expect(console.error).toHaveBeenCalledWith(
81-
expect.stringMatching(
82-
/\[React Intl\] Error formatting time.\nRangeError: Value invalid out of range for (.*) options property hour/
83-
)
84-
);
78+
expect(console.error.mock.calls[0][0].code).toMatchSnapshot()
8579
expect(console.error).toHaveBeenCalledTimes(1);
8680
});
8781

@@ -150,15 +144,13 @@ describe('<FormattedTimeParts>', () => {
150144
{value: 0, children},
151145
intl
152146
);
153-
expect(console.error).toHaveBeenCalledTimes(0);
147+
expect(console.error).not.toHaveBeenCalled()
154148

155149
injectIntlContext.setProps({
156150
...injectIntlContext.props(),
157151
value: NaN,
158152
});
159-
expect(console.error).toHaveBeenCalledWith(
160-
expect.stringContaining('[React Intl] Error formatting time.\nRangeError')
161-
);
153+
expect(console.error.mock.calls[0][0].code).toMatchSnapshot()
162154
expect(console.error).toHaveBeenCalledTimes(1);
163155
});
164156

@@ -197,11 +189,7 @@ describe('<FormattedTimeParts>', () => {
197189
expect(children.mock.calls[0][0]).toEqual(
198190
intl.formatTimeToParts(date, {hour: 'invalid'})
199191
);
200-
expect(console.error).toHaveBeenCalledWith(
201-
expect.stringMatching(
202-
/\[React Intl\] Error formatting time.\nRangeError: Value invalid out of range for (.*) options property hour/
203-
)
204-
);
192+
expect(console.error.mock.calls[0][0].code).toMatchSnapshot()
205193
expect(console.error).toHaveBeenCalledTimes(2);
206194
});
207195

‎test/unit/format.tsx

+28-141
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {formatPlural as formatPluralFn} from '../../src/formatters/plural';
1212
import {formatList as formatListFn} from '../../src/formatters/list';
1313
import {formatDisplayName as formatDisplayNameFn} from '../../src/formatters/displayName';
1414
import {formatMessage as baseFormatMessage} from '../../src/formatters/message';
15-
import {IntlFormatters, defineMessages} from '../../src';
15+
import {IntlFormatters, defineMessages, IntlConfig} from '../../src';
1616

1717
describe('format API', () => {
1818
const {NODE_ENV} = process.env;
@@ -30,14 +30,14 @@ describe('format API', () => {
3030
with_named_format: 'It is {now, date, year_only}',
3131
with_html: 'Hello, <b>{name}</b>!',
3232

33-
missing: undefined,
33+
missing: undefined as any,
3434
empty: '',
3535
invalid: 'invalid {}',
3636
missing_value: 'missing {arg_missing}',
3737
missing_named_format: 'missing {now, date, format_missing}',
3838
ast_simple: parse('hello world'),
3939
ast_var: parse('hello there, {name}'),
40-
},
40+
} as Record<string, any>,
4141

4242
formats: {
4343
date: {
@@ -69,7 +69,7 @@ describe('format API', () => {
6969
},
7070
missing: undefined,
7171
},
72-
},
72+
} as any,
7373

7474
defaultLocale: 'en',
7575
defaultFormats: {},
@@ -178,12 +178,7 @@ describe('format API', () => {
178178

179179
it('falls back and warns on invalid Intl.DateTimeFormat options', () => {
180180
expect(formatDate(0, {year: 'invalid'})).toBe('0');
181-
expect(config.onError).toHaveBeenCalledTimes(1);
182-
expect(config.onError).toHaveBeenCalledWith(
183-
expect.stringMatching(
184-
/\[React Intl\] Error formatting date.\nRangeError: Value invalid out of range for (.*) options property year/
185-
)
186-
);
181+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
187182
});
188183

189184
it('uses configured named formats', () => {
@@ -217,10 +212,7 @@ describe('format API', () => {
217212
df = new Intl.DateTimeFormat(config.locale);
218213

219214
expect(formatDate(date, {format})).toBe(df.format(date));
220-
expect(config.onError).toHaveBeenCalledTimes(1);
221-
expect(config.onError).toHaveBeenCalledWith(
222-
`[React Intl] No date format named: ${format}`
223-
);
215+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
224216
});
225217

226218
it('uses time zone specified in options over the one passed through by the provider', () => {
@@ -310,12 +302,7 @@ describe('format API', () => {
310302

311303
it('falls back and warns on invalid Intl.DateTimeFormat options', () => {
312304
expect(formatTime(0, {hour: 'invalid'})).toBe('0');
313-
expect(config.onError).toHaveBeenCalledTimes(1);
314-
expect(config.onError).toHaveBeenCalledWith(
315-
expect.stringMatching(
316-
/\[React Intl\] Error formatting time.\nRangeError: Value invalid out of range for (.*) options property hour/
317-
)
318-
);
305+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
319306
});
320307

321308
it('uses configured named formats', () => {
@@ -347,10 +334,7 @@ describe('format API', () => {
347334
const format = 'missing';
348335

349336
expect(formatTime(date, {format})).toBe(df.format(date));
350-
expect(config.onError).toHaveBeenCalledTimes(1);
351-
expect(config.onError).toHaveBeenCalledWith(
352-
`[React Intl] No time format named: ${format}`
353-
);
337+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
354338
});
355339

356340
it('should set default values', () => {
@@ -420,12 +404,7 @@ describe('format API', () => {
420404

421405
it('falls back and warns when no value is provided', () => {
422406
expect(formatRelativeTime()).toBe('undefined');
423-
expect(config.onError).toHaveBeenCalledTimes(1);
424-
expect(config.onError).toHaveBeenCalledWith(
425-
expect.stringContaining(
426-
'[React Intl] Error formatting relative time.\nRangeError:'
427-
)
428-
);
407+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
429408
});
430409

431410
it('falls back and warns when a non-finite value is provided', () => {
@@ -463,12 +442,7 @@ describe('format API', () => {
463442

464443
it('falls back and warns on invalid IntlRelativeFormat options', () => {
465444
expect(formatRelativeTime(0, 'invalid')).toBe('0');
466-
expect(config.onError).toHaveBeenCalledTimes(1);
467-
expect(config.onError).toHaveBeenCalledWith(
468-
expect.stringMatching(
469-
/\[React Intl\] Error formatting relative time.\nRangeError: Invalid unit(.*)invalid/
470-
)
471-
);
445+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
472446
});
473447

474448
it('uses configured named formats', () => {
@@ -505,10 +479,7 @@ describe('format API', () => {
505479
expect(formatRelativeTime(-1, 'second', {format})).toBe(
506480
rf.format(-1, 'second')
507481
);
508-
expect(config.onError).toHaveBeenCalledTimes(1);
509-
expect(config.onError).toHaveBeenCalledWith(
510-
`[React Intl] No relative format named: ${format}`
511-
);
482+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
512483
});
513484
});
514485
});
@@ -562,12 +533,7 @@ describe('format API', () => {
562533

563534
it('falls back and warns on invalid Intl.NumberFormat options', () => {
564535
expect(formatNumber(0, {style: 'invalid'})).toBe(String(0));
565-
expect(config.onError).toHaveBeenCalledTimes(1);
566-
expect(config.onError).toHaveBeenCalledWith(
567-
expect.stringMatching(
568-
/\[React Intl\] Error formatting number.\nRangeError: Value invalid out of range for (.*) options property style/
569-
)
570-
);
536+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
571537
});
572538

573539
it('uses configured named formats', () => {
@@ -601,10 +567,7 @@ describe('format API', () => {
601567
nf = new Intl.NumberFormat(config.locale);
602568

603569
expect(formatNumber(num, {format})).toBe(nf.format(num));
604-
expect(config.onError).toHaveBeenCalledTimes(1);
605-
expect(config.onError).toHaveBeenCalledWith(
606-
`[React Intl] No number format named: ${format}`
607-
);
570+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
608571
});
609572
});
610573
});
@@ -815,11 +778,10 @@ describe('format API', () => {
815778
)
816779
).toBe(mf.format(values));
817780

818-
expect(config.onError.mock.calls).toMatchInlineSnapshot(`
781+
expect(config.onError.mock.calls.map(c => c[0].code))
782+
.toMatchInlineSnapshot(`
819783
Array [
820-
Array [
821-
"[React Intl] Missing message: \\"missing\\" for locale: \\"fr\\", using default message as fallback.",
822-
],
784+
"MISSING_TRANSLATION",
823785
]
824786
`);
825787
});
@@ -839,14 +801,11 @@ describe('format API', () => {
839801
)
840802
).toBe(id);
841803

842-
expect(config.onError.mock.calls).toMatchInlineSnapshot(`
804+
expect(config.onError.mock.calls.map(c => c[0].code))
805+
.toMatchInlineSnapshot(`
843806
Array [
844-
Array [
845-
"[React Intl] Missing message: \\"missing\\" for locale: \\"en\\"",
846-
],
847-
Array [
848-
"[React Intl] Cannot format message: \\"missing\\", using message id as fallback.",
849-
],
807+
"MISSING_TRANSLATION",
808+
"DATE_FORMAT_ERROR",
850809
]
851810
`);
852811
});
@@ -867,12 +826,7 @@ describe('format API', () => {
867826
)
868827
).toBe(mf.format(values));
869828

870-
expect(config.onError).toHaveBeenCalledTimes(1);
871-
expect(config.onError).toHaveBeenCalledWith(
872-
expect.stringContaining(
873-
`[React Intl] Error formatting message: "${id}" for locale: "${locale}", using default message as fallback.`
874-
)
875-
);
829+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
876830
});
877831

878832
it('formats `defaultMessage` when message has missing values', () => {
@@ -891,12 +845,7 @@ describe('format API', () => {
891845
)
892846
).toBe(mf.format(values));
893847

894-
expect(config.onError).toHaveBeenCalledTimes(1);
895-
expect(config.onError).toHaveBeenCalledWith(
896-
expect.stringContaining(
897-
`[React Intl] Error formatting message: "${id}" for locale: "${locale}", using default message as fallback.`
898-
)
899-
);
848+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
900849
});
901850

902851
it('returns message source when message and `defaultMessage` have formatting errors', () => {
@@ -909,23 +858,7 @@ describe('format API', () => {
909858
defaultMessage: messages.invalid,
910859
})
911860
).toBe(messages[id]);
912-
913-
expect(config.onError).toHaveBeenCalledTimes(3);
914-
expect(config.onError).toHaveBeenCalledWith(
915-
expect.stringContaining(
916-
`[React Intl] Error formatting message: "${id}" for locale: "${locale}"`
917-
)
918-
);
919-
expect(config.onError).toHaveBeenCalledWith(
920-
expect.stringContaining(
921-
`[React Intl] Error formatting the default message for: "${id}"`
922-
)
923-
);
924-
expect(config.onError).toHaveBeenCalledWith(
925-
expect.stringContaining(
926-
`[React Intl] Cannot format message: "${id}", using message source as fallback.`
927-
)
928-
);
861+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
929862
});
930863

931864
it('returns message source when formatting error and missing `defaultMessage`', () => {
@@ -938,18 +871,7 @@ describe('format API', () => {
938871
defaultMessage: messages.missing,
939872
})
940873
).toBe(messages[id]);
941-
942-
expect(config.onError).toHaveBeenCalledTimes(2);
943-
expect(config.onError).toHaveBeenCalledWith(
944-
expect.stringContaining(
945-
`[React Intl] Error formatting message: "${id}" for locale: "${locale}"`
946-
)
947-
);
948-
expect(config.onError).toHaveBeenCalledWith(
949-
expect.stringContaining(
950-
`[React Intl] Cannot format message: "${id}", using message source as fallback.`
951-
)
952-
);
874+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
953875
});
954876

955877
it('returns `defaultMessage` source when formatting errors and missing message', () => {
@@ -965,44 +887,19 @@ describe('format API', () => {
965887
})
966888
).toBe(messages.invalid);
967889

968-
expect(config.onError).toHaveBeenCalledTimes(3);
969-
expect(config.onError).toHaveBeenCalledWith(
970-
expect.stringContaining(
971-
`[React Intl] Missing message: "${id}" for locale: "${locale}", using default message as fallback.`
972-
)
973-
);
974-
expect(config.onError).toHaveBeenCalledWith(
975-
expect.stringContaining(
976-
`[React Intl] Error formatting the default message for: "${id}"`
977-
)
978-
);
979-
expect(config.onError).toHaveBeenCalledWith(
980-
expect.stringContaining(
981-
`[React Intl] Cannot format message: "${id}", using message source as fallback.`
982-
)
983-
);
890+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
984891
});
985892

986893
it('returns message `id` when message and `defaultMessage` are missing', () => {
987894
const id = 'missing';
988895

989896
expect(formatMessage({id: id})).toBe(id);
990897

991-
expect(config.onError).toHaveBeenCalledTimes(2);
992-
expect(config.onError).toHaveBeenCalledWith(
993-
expect.stringContaining(
994-
`[React Intl] Missing message: "${id}" for locale: "${config.locale}"`
995-
)
996-
);
997-
expect(config.onError).toHaveBeenCalledWith(
998-
expect.stringContaining(
999-
`[React Intl] Cannot format message: "${id}", using message id as fallback.`
1000-
)
1001-
);
898+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
1002899
});
1003900

1004901
it('returns message `id` when message and `defaultMessage` are empty', () => {
1005-
const {locale, messages} = config;
902+
const {messages} = config;
1006903
const id = 'empty';
1007904

1008905
expect(
@@ -1012,17 +909,7 @@ describe('format API', () => {
1012909
})
1013910
).toBe(id);
1014911

1015-
expect(config.onError).toHaveBeenCalledTimes(2);
1016-
expect(config.onError).toHaveBeenCalledWith(
1017-
expect.stringContaining(
1018-
`[React Intl] Missing message: "${id}" for locale: "${locale}"`
1019-
)
1020-
);
1021-
expect(config.onError).toHaveBeenCalledWith(
1022-
expect.stringContaining(
1023-
`[React Intl] Cannot format message: "${id}", using message id as fallback.`
1024-
)
1025-
);
912+
expect(config.onError.mock.calls.map(c => c[0].code)).toMatchSnapshot();
1026913
});
1027914
});
1028915
});

‎test/unit/utils.ts

-16
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.