Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scripts/build/deps/webkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* for local mode. Override via `--webkit-version=<hash>` to test a branch.
* From https://github.com/oven-sh/WebKit releases.
*/
export const WEBKIT_VERSION = "34c01d13391e00c06862a3d2c5b7fff350ac87e0";
export const WEBKIT_VERSION = "autobuild-preview-pr-374-9cfb1f57";

/**
* WebKit (JavaScriptCore) — the JS engine.
Expand Down
39 changes: 39 additions & 0 deletions test/js/web/intl/intl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,45 @@
}
expect(out).toMatchSnapshot();
});

// ICU-23110: with style:"percent", formatRange/formatRangeToParts collapsing to
// ~single-value applied scale/100 twice (0.5 → "~5,000%" instead of "~50%").
// Assert the numeric parts match format() exactly; the approximatelySign /
// literal decorations are locale-shaped and covered by the string check.
describe("style:'percent' formatRange identity (ICU-23110)", () => {
const numeric = (parts: Intl.NumberFormatPart[]) =>
parts
.filter(p => p.type !== "approximatelySign" && p.type !== "literal")
.map(p => `${p.type}:${p.value}`);

test.each(["en", "de", "ja", "ar"])("%s", loc => {
const nf = new Intl.NumberFormat(loc, { style: "percent" });
for (const [a, b] of [
[0.5, 0.5],
[0.5, 0.500001],
[0.145, 0.145],
] as const) {
const single = nf.format(a);
const range = nf.formatRange(a, b);
// The collapsed range is format(a) with a locale-specific "approximately" affix.
expect({ a, b, range }.range).toContain(single);
expect({ a, b, parts: numeric(nf.formatRangeToParts(a, b)) }.parts).toEqual(numeric(nf.formatToParts(a)));

Check warning on line 104 in test/js/web/intl/intl.test.ts

View check run for this annotation

Claude / Claude Code Review

No-op object wrapper in expect() — loop context (a, b) is discarded

`expect({ a, b, range }.range).toContain(single)` is exactly `expect(range).toContain(single)` — the `.range` access evaluates before `expect()` is called, so the wrapper object (and the `a`, `b` you presumably wanted in the failure output) is discarded before the matcher sees anything. Same for `.parts` on the next line. Either drop the wrapper, or if you want the loop context in the failure message, use `expect({ a, b, range }).toEqual({ a, b, range: expect.stringContaining(single) })`.
Comment thread
robobun marked this conversation as resolved.
Outdated
}
// Distinct endpoints must still render as a range.
expect(nf.formatRange(0.5, 0.6)).toContain(nf.format(0.6));
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});

test("BigInt and string inputs", () => {
const nf = new Intl.NumberFormat("en", { style: "percent" });
expect(numeric(nf.formatRangeToParts(5n, 5n))).toEqual(numeric(nf.formatToParts(5n)));
expect(numeric(nf.formatRangeToParts("0.5", "0.5"))).toEqual(numeric(nf.formatToParts("0.5")));
});

test("compact notation", () => {
const nf = new Intl.NumberFormat("en", { style: "percent", notation: "compact" });
expect(nf.formatRange(15, 15)).toContain(nf.format(15));
});
});
});

// ---------------------------------------------------------------------------
Expand Down
Loading