Fix toIncludeRepeated (#21366)

Fixes #12276: toIncludeRepeated should check for the exact repeat count
not >=

This is a breaking change because some people may be relying on the
existing behaviour. Should it be feature-flagged for 1.3?

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
pfg
2025-07-25 22:22:04 -07:00
committed by GitHub
parent bbdc3ae055
commit 0bd73b4363
3 changed files with 32 additions and 7 deletions

View File

@@ -3841,10 +3841,8 @@ pub const Expect = struct {
return globalThis.throw("toIncludeRepeated() requires the first argument to be a non-empty string", .{});
}
if (countAsNum == 0)
pass = !strings.contains(expectStringAsStr, subStringAsStr)
else
pass = std.mem.containsAtLeast(u8, expectStringAsStr, countAsNum, subStringAsStr);
const actual_count = std.mem.count(u8, expectStringAsStr, subStringAsStr);
pass = actual_count == countAsNum;
if (not) pass = !pass;
if (pass) return .js_undefined;

View File

@@ -601,13 +601,13 @@ describe("jest-extended", () => {
expect("abc").not.toIncludeRepeated("d", 1);
// Any other number
expect("abc abc abc").toIncludeRepeated("abc", 1);
expect("abc abc abc").toIncludeRepeated("abc", 2);
expect("abc abc abc").not.toIncludeRepeated("abc", 1);
expect("abc abc abc").not.toIncludeRepeated("abc", 2);
expect("abc abc abc").toIncludeRepeated("abc", 3);
expect("abc abc abc").not.toIncludeRepeated("abc", 4);
// Emojis/Unicode
expect("😘🥳😤😘🥳").toIncludeRepeated("😘", 1);
expect("😘🥳😤😘🥳").toIncludeRepeated("😘", 2);
expect("😘🥳😤😘🥳").toIncludeRepeated("🥳", 2);
expect("😘🥳😤😘🥳").not.toIncludeRepeated("😘", 3);
expect("😘🥳😤😘🥳").not.toIncludeRepeated("😶‍🌫️", 1);

View File

@@ -0,0 +1,27 @@
import { expect, test } from "bun:test";
// https://github.com/oven-sh/bun/issues/12276
test("toIncludeRepeated should check for exact count, not at least count", () => {
// The bug: toIncludeRepeated was checking if string contains AT LEAST n occurrences
// Instead of EXACTLY n occurrences
// These should pass - exact match
expect("hello hello world").toIncludeRepeated("hello", 2);
expect("hello world").toIncludeRepeated("hello", 1);
expect("world").toIncludeRepeated("hello", 0);
// These should pass - not exact match with .not
expect("hello hello world").not.toIncludeRepeated("hello", 1);
expect("hello hello world").not.toIncludeRepeated("hello", 3);
expect("hello hello hello").not.toIncludeRepeated("hello", 2);
// Additional test cases
expect("abc abc abc").toIncludeRepeated("abc", 3);
expect("abc abc abc").not.toIncludeRepeated("abc", 1);
expect("abc abc abc").not.toIncludeRepeated("abc", 2);
expect("abc abc abc").not.toIncludeRepeated("abc", 4);
// Edge cases - std.mem.count doesn't count overlapping occurrences
expect("aaa").toIncludeRepeated("aa", 1); // "aa" appears once (non-overlapping)
expect("aaaa").toIncludeRepeated("aa", 2); // "aa" appears twice (non-overlapping)
});