From 52ede3ef6f6eec32eafd48695a8a9f54074581d9 Mon Sep 17 00:00:00 2001 From: Raphael Fakhri <153192858+RaphaelFakhri@users.noreply.github.com> Date: Tue, 27 Oct 2026 15:08:22 +0000 Subject: [PATCH] fix(fast-check): keep regex flags when generating matching strings --- ark/fast-check/__tests__/arktypeFastCheck.test.ts | 5 +++++ ark/fast-check/arbitraries/string.ts | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ark/fast-check/__tests__/arktypeFastCheck.test.ts b/ark/fast-check/__tests__/arktypeFastCheck.test.ts index da9423fd9d..071e7deb91 100644 --- a/ark/fast-check/__tests__/arktypeFastCheck.test.ts +++ b/ark/fast-check/__tests__/arktypeFastCheck.test.ts @@ -89,6 +89,11 @@ contextualize(() => { const arbitrary = arkToArbitrary(T) assertProperty(arbitrary, T) }) + it("regex with flags", () => { + const T = type(/^\u{1F600}[a-z]$/iu) + const arbitrary = arkToArbitrary(T) + assertProperty(arbitrary, T) + }) it("multiple regexes", () => { const T = type("string.email").and("string.alpha") attest(() => arkToArbitrary(T)).throws( diff --git a/ark/fast-check/arbitraries/string.ts b/ark/fast-check/arbitraries/string.ts index 2c9548eef1..f7796d5660 100644 --- a/ark/fast-check/arbitraries/string.ts +++ b/ark/fast-check/arbitraries/string.ts @@ -11,7 +11,9 @@ export const buildStringArbitrary = ( if ("pattern" in stringConstraints) { if (stringConstraints.minLength || stringConstraints.maxLength) throwInternalError("Bounded regex is not supported.") - return fc.stringMatching(new RegExp(stringConstraints.pattern)) + return fc.stringMatching( + new RegExp(stringConstraints.pattern, stringConstraints.flags) + ) } return fc.string(stringConstraints) @@ -22,6 +24,7 @@ const getFastCheckStringConstraints = ( ) => { const stringConstraints: fc.StringConstraints & { pattern?: string + flags?: string } = {} for (const refinement of refinements) { if (refinement.hasKind("pattern")) { @@ -31,6 +34,10 @@ const getFastCheckStringConstraints = ( ) } stringConstraints["pattern"] = refinement.rule + // fast-check doesn't support i, and dropping it only narrows what + // gets generated, so every generated string still matches + if (refinement.flags) + stringConstraints["flags"] = refinement.flags.replace("i", "") } else if (refinement.hasKind("exactLength")) { stringConstraints["minLength"] = refinement.rule stringConstraints["maxLength"] = refinement.rule