Skip to content

Commit 5073395

Browse files
committed
fix(react-intl): fix type inference and overload for formatMessage, fix #4538
1 parent 50e6d57 commit 5073395

38 files changed

+421
-283
lines changed

.bazelignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ packages/ecma402-abstract/node_modules
1212
packages/editor/node_modules
1313
packages/eslint-plugin-formatjs/node_modules
1414
packages/fast-memoize/node_modules
15-
packages/utils/node_modules
1615
packages/icu-messageformat-parser/integration-tests/node_modules
1716
packages/icu-messageformat-parser/node_modules
1817
packages/icu-skeleton-parser/node_modules
@@ -29,13 +28,15 @@ packages/intl-numberformat/node_modules
2928
packages/intl-pluralrules/node_modules
3029
packages/intl-relativetimeformat/node_modules
3130
packages/intl-segmenter/node_modules
32-
packages/intl/node_modules
3331
packages/intl/integration-tests/node_modules
32+
packages/intl/node_modules
3433
packages/react-intl/examples/node_modules
34+
packages/react-intl/integration-tests/node_modules
3535
packages/react-intl/node_modules
3636
packages/swc-plugin-experimental/node_modules
3737
packages/swc-plugin/node_modules
3838
packages/ts-transformer/integration-tests/node_modules
3939
packages/ts-transformer/node_modules
40+
packages/utils/node_modules
4041
packages/vue-intl/node_modules
4142
website/node_modules

BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ TSCONFIG_FILES = [
235235
"tsconfig.node.json",
236236
"tsconfig.esm.json",
237237
"tsconfig.esm.esnext.json",
238+
"tsconfig.jest.json",
238239
]
239240

240241
[

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@
3131
"@bazel/ibazel": "~0.25.0",
3232
"@bazel/runfiles": "^6.3.1",
3333
"@commitlint/cli": "^19.5.0",
34-
"@commitlint/config-angular": "^19.5.0",
3534
"@commitlint/config-angular-type-enum": "^19.5.0",
35+
"@commitlint/config-angular": "^19.5.0",
3636
"@glimmer/env": "^0.1.7",
3737
"@glimmer/reference": "^0.92.3",
3838
"@glimmer/syntax": "0.92.3",
3939
"@glimmer/validator": "^0.92.3",
40+
"@jest/globals": "^29.7.0",
4041
"@jest/transform": "^29.7.0",
4142
"@jest/types": "^29.6.3",
4243
"@napi-rs/cli": "^2.18.4",
@@ -47,6 +48,7 @@
4748
"@taplo/cli": "^0.7.0",
4849
"@testing-library/jest-dom": "^6.6.2",
4950
"@testing-library/react": "^16.0.1",
51+
"@types/aria-query": "5.0.4",
5052
"@types/babel__core": "^7.20.5",
5153
"@types/babel__helper-plugin-utils": "^7.10.3",
5254
"@types/babel__traverse": "^7.20.6",
@@ -61,8 +63,8 @@
6163
"@types/minimist": "^1.2.5",
6264
"@types/node": "^22.0.0",
6365
"@types/picomatch": "^3.0.1",
64-
"@types/react": "^18.3.12",
6566
"@types/react-dom": "^18.3.1",
67+
"@types/react": "^18.3.12",
6668
"@types/regenerate": "^1.4.3",
6769
"@types/serialize-javascript": "^5.0.4",
6870
"@types/webpack": "^5.28.5",
@@ -78,7 +80,6 @@
7880
"benchmark": "^2.1.4",
7981
"chalk": "^4.1.2",
8082
"chokidar": "^4.0.1",
81-
"cjs-module-lexer": "^1.4.1",
8283
"cldr-bcp47": "^46.0.0",
8384
"cldr-core": "^46.0.0",
8485
"cldr-dates-full": "^46.0.0",

packages/intl-messageformat/src/formatters.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {NumberFormatOptions} from '@formatjs/ecma402-abstract'
22
import {
3+
ExtendedNumberFormatOptions,
34
isArgumentElement,
45
isDateElement,
56
isDateTimeSkeleton,
@@ -9,17 +10,16 @@ import {
910
isPluralElement,
1011
isPoundElement,
1112
isSelectElement,
13+
isTagElement,
1214
isTimeElement,
1315
MessageFormatElement,
14-
isTagElement,
15-
ExtendedNumberFormatOptions,
1616
} from '@formatjs/icu-messageformat-parser'
1717
import {
18-
MissingValueError,
19-
InvalidValueError,
2018
ErrorCode,
2119
FormatError,
20+
InvalidValueError,
2221
InvalidValueTypeError,
22+
MissingValueError,
2323
} from './error'
2424

2525
declare global {

packages/react-intl/BUILD

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ load("@aspect_rules_esbuild//esbuild:defs.bzl", "esbuild")
44
load("@aspect_rules_js//npm:defs.bzl", "npm_package")
55
load("@npm//:defs.bzl", "npm_link_all_packages")
66
load("//tools:index.bzl", "package_json_test", "ts_compile")
7-
load("//tools:jest.bzl", "jest_test")
7+
load("//tools:jest.bzl", "jest_test_v2")
88

99
npm_link_all_packages()
1010

@@ -51,8 +51,8 @@ TEST_DEPS = SRC_DEPS + [
5151
":node_modules/@formatjs/intl-relativetimeformat",
5252
"//:node_modules/@testing-library/jest-dom",
5353
"//:node_modules/@testing-library/react",
54+
"//:node_modules/@types/aria-query",
5455
"//:node_modules/@types/node",
55-
"//:node_modules/cjs-module-lexer",
5656
"//:node_modules/jest-environment-jsdom",
5757
"//:node_modules/react-dom",
5858
"//:node_modules/typescript",
@@ -84,20 +84,15 @@ genrule(
8484
cmd = "cat $< | sed -E 's/__require\\(\"react\"\\)/window.React/g' > $@",
8585
)
8686

87-
jest_test(
87+
jest_test_v2(
8888
name = "unit_test",
89-
data = [":srcs"] + TESTS + TEST_DEPS + ["tests/setup.js"],
90-
jest_config = "jest.config.js",
91-
snapshots = glob(["tests/unit/components/__snapshots__/*"]),
92-
)
93-
94-
jest_test(
95-
name = "functional_test",
96-
data = TEST_DEPS + glob(["tests/functional/**/*.ts*"]) + [
97-
"tests/setup.js",
89+
srcs = [
9890
":dist",
99-
],
91+
":tests_setup",
92+
] + TESTS,
10093
jest_config = "jest.config.js",
94+
snapshots = glob(["tests/unit/components/__snapshots__/*"]),
95+
deps = TEST_DEPS,
10196
)
10297

10398
write_source_files(
@@ -114,3 +109,8 @@ copy_to_bin(
114109
name = "srcs",
115110
srcs = SRCS,
116111
)
112+
113+
copy_to_bin(
114+
name = "tests_setup",
115+
srcs = ["tests/setup.js"],
116+
)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
load("@npm//:defs.bzl", "npm_link_all_packages")
2+
load("//tools:jest.bzl", "jest_test_v2")
3+
4+
npm_link_all_packages()
5+
6+
TEST_DEPS = [
7+
":node_modules/react-intl",
8+
"//:node_modules/@jest/globals",
9+
"//:node_modules/@testing-library/jest-dom",
10+
"//:node_modules/@testing-library/react",
11+
"//:node_modules/@types/aria-query",
12+
"//:node_modules/@types/node",
13+
"//:node_modules/@types/react-dom",
14+
"//:node_modules/@types/react",
15+
"//:node_modules/jest-environment-jsdom",
16+
"//:node_modules/react-dom",
17+
"//:node_modules/react",
18+
"//:node_modules/tslib",
19+
]
20+
21+
jest_test_v2(
22+
name = "test",
23+
srcs = glob(["*.ts*"]),
24+
jest_config = "jest.config.js",
25+
deps = TEST_DEPS,
26+
)
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import {
2+
FormattedDate,
3+
FormattedMessage,
4+
FormattedNumber,
5+
FormattedRelativeTime,
6+
FormattedTime,
7+
IntlProvider,
8+
} from 'react-intl'
9+
10+
import {render, screen} from '@testing-library/react'
11+
import React from 'react'
12+
13+
describe('format', () => {
14+
const renderWithIntlProvider = (
15+
Element: React.JSX.Element,
16+
providerProps = {}
17+
) =>
18+
render(
19+
<IntlProvider locale="en" {...providerProps}>
20+
{Element}
21+
</IntlProvider>
22+
)
23+
24+
it('formats dates', () => {
25+
const date = new Date()
26+
const el = (
27+
<span data-testid="test">
28+
<FormattedDate value={date} month="numeric" />
29+
</span>
30+
)
31+
32+
renderWithIntlProvider(el)
33+
expect(screen.getByTestId('test')).toHaveTextContent(
34+
String(date.getMonth() + 1)
35+
)
36+
})
37+
38+
it('formats times', () => {
39+
const date = new Date()
40+
const el = (
41+
<span data-testid="test">
42+
<FormattedTime value={date} />
43+
</span>
44+
)
45+
46+
const hours = date.getHours()
47+
const minutes = date.getMinutes()
48+
49+
renderWithIntlProvider(el)
50+
expect(screen.getByTestId('test')).toHaveTextContent(
51+
`${hours > 12 ? hours % 12 : hours || '12'}:` +
52+
`${minutes < 10 ? `0${minutes}` : minutes} ` +
53+
`${hours < 12 ? 'AM' : 'PM'}`
54+
)
55+
})
56+
57+
it('formats relative time', () => {
58+
const el = (
59+
<span data-testid="test">
60+
<FormattedRelativeTime value={-1} />
61+
</span>
62+
)
63+
64+
renderWithIntlProvider(el)
65+
expect(screen.getByTestId('test')).toHaveTextContent('1 second ago')
66+
})
67+
68+
it('formats numbers with thousands separators', () => {
69+
const el = (
70+
<span data-testid="test">
71+
<FormattedNumber value={1000} />
72+
</span>
73+
)
74+
75+
renderWithIntlProvider(el)
76+
expect(screen.getByTestId('test')).toHaveTextContent('1,000')
77+
})
78+
79+
it('formats numbers with decimal separators', () => {
80+
const el = (
81+
<span data-testid="test">
82+
<FormattedNumber value={0.1} minimumFractionDigits={2} />
83+
</span>
84+
)
85+
86+
renderWithIntlProvider(el)
87+
expect(screen.getByTestId('test')).toHaveTextContent('0.10')
88+
})
89+
90+
it('pluralizes labels in strings', () => {
91+
const message = 'You have {emails, plural, one {# email} other {# emails}}.'
92+
const el = (
93+
<span data-testid="test">
94+
<FormattedMessage
95+
id="foo"
96+
defaultMessage={message}
97+
values={{
98+
emails: 1000,
99+
}}
100+
/>
101+
</span>
102+
)
103+
104+
renderWithIntlProvider(el)
105+
expect(screen.getByTestId('test')).toHaveTextContent(
106+
'You have 1,000 emails.'
107+
)
108+
})
109+
})
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module.exports = {
2+
testEnvironment: 'jsdom',
3+
setupFilesAfterEnv: ['<rootDir>/setup.js'],
4+
coverageThreshold: {
5+
global: {
6+
branches: 85,
7+
functions: 100,
8+
lines: 95,
9+
statements: 95,
10+
},
11+
},
12+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "integration-tests",
3+
"private": true,
4+
"dependencies": {
5+
"react-intl": "workspace:*"
6+
}
7+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// add custom jest matchers from jest-dom
2+
import '@testing-library/jest-dom/jest-globals'

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy