Skip to content

Commit b86638d

Browse files
authored
feat(helpers): add length range support in arrayElements (#1772)
1 parent c7ce35a commit b86638d

File tree

3 files changed

+96
-13
lines changed

3 files changed

+96
-13
lines changed

src/modules/helpers/index.ts

+27-12
Original file line numberDiff line numberDiff line change
@@ -561,36 +561,51 @@ export class HelpersModule {
561561
*
562562
* @template T The type of the entries to pick from.
563563
* @param array Array to pick the value from.
564-
* @param count Number of elements to pick.
564+
* @param count Number or range of elements to pick.
565565
* When not provided, random number of elements will be picked.
566566
* When value exceeds array boundaries, it will be limited to stay inside.
567567
*
568568
* @example
569569
* faker.helpers.arrayElements(['cat', 'dog', 'mouse']) // ['mouse', 'cat']
570570
* faker.helpers.arrayElements([1, 2, 3, 4, 5], 2) // [4, 2]
571+
* faker.helpers.arrayElements([1, 2, 3, 4, 5], { min: 2, max: 4 }) // [3, 5, 1]
571572
*
572573
* @since 6.3.0
573574
*/
574575
arrayElements<T>(
575576
// TODO @Shinigami92 2022-04-30: We want to remove this default value, but currently it's not possible because some definitions could be empty
576577
// See https://github.com/faker-js/faker/issues/893
577578
array: ReadonlyArray<T> = ['a', 'b', 'c'] as unknown as ReadonlyArray<T>,
578-
count?: number
579+
count?:
580+
| number
581+
| {
582+
/**
583+
* The minimum number of elements to pick.
584+
*/
585+
min: number;
586+
/**
587+
* The maximum number of elements to pick.
588+
*/
589+
max: number;
590+
}
579591
): T[] {
580-
if (typeof count !== 'number') {
581-
count =
582-
array.length === 0
583-
? 0
584-
: this.faker.number.int({ min: 1, max: array.length });
585-
} else if (count > array.length) {
586-
count = array.length;
587-
} else if (count < 0) {
588-
count = 0;
592+
if (array.length === 0) {
593+
return [];
594+
}
595+
596+
const numElements = this.rangeToNumber(
597+
count ?? { min: 1, max: array.length }
598+
);
599+
600+
if (numElements >= array.length) {
601+
return this.shuffle(array);
602+
} else if (numElements <= 0) {
603+
return [];
589604
}
590605

591606
const arrayCopy = array.slice(0);
592607
let i = array.length;
593-
const min = i - count;
608+
const min = i - numElements;
594609
let temp: T;
595610
let index: number;
596611

test/__snapshots__/helpers.spec.ts.snap

+24
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ exports[`helpers > 42 > arrayElements > with array and count 1`] = `
2929
]
3030
`;
3131

32+
exports[`helpers > 42 > arrayElements > with array and count range 1`] = `
33+
[
34+
"d",
35+
"l",
36+
]
37+
`;
38+
3239
exports[`helpers > 42 > fake > with a dynamic template 1`] = `"my string: Cky2eiXX/J"`;
3340

3441
exports[`helpers > 42 > fake > with a static template 1`] = `"my test string"`;
@@ -218,6 +225,16 @@ exports[`helpers > 1211 > arrayElements > with array and count 1`] = `
218225
]
219226
`;
220227

228+
exports[`helpers > 1211 > arrayElements > with array and count range 1`] = `
229+
[
230+
"e",
231+
"l",
232+
"o",
233+
"l",
234+
" ",
235+
]
236+
`;
237+
221238
exports[`helpers > 1211 > fake > with a dynamic template 1`] = `"my string: wKti5-}$_/"`;
222239

223240
exports[`helpers > 1211 > fake > with a static template 1`] = `"my test string"`;
@@ -403,6 +420,13 @@ exports[`helpers > 1337 > arrayElements > with array and count 1`] = `
403420
]
404421
`;
405422

423+
exports[`helpers > 1337 > arrayElements > with array and count range 1`] = `
424+
[
425+
"e",
426+
"W",
427+
]
428+
`;
429+
406430
exports[`helpers > 1337 > fake > with a dynamic template 1`] = `"my string: 9U/4:SK$>6"`;
407431

408432
exports[`helpers > 1337 > fake > with a static template 1`] = `"my test string"`;

test/helpers.spec.ts

+45-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,11 @@ describe('helpers', () => {
7676
t.describe('arrayElements', (t) => {
7777
t.it('noArgs')
7878
.it('with array', 'Hello World!'.split(''))
79-
.it('with array and count', 'Hello World!'.split(''), 3);
79+
.it('with array and count', 'Hello World!'.split(''), 3)
80+
.it('with array and count range', 'Hello World!'.split(''), {
81+
min: 1,
82+
max: 5,
83+
});
8084
});
8185

8286
t.describe('shuffle', (t) => {
@@ -281,6 +285,46 @@ describe('helpers', () => {
281285
expect(subset).toHaveLength(new Set(subset).size);
282286
});
283287

288+
it('should return a subset with random elements in the array for a length range', () => {
289+
const testArray = ['hello', 'to', 'you', 'my', 'friend'];
290+
const subset = faker.helpers.arrayElements(testArray, {
291+
min: 2,
292+
max: 4,
293+
});
294+
295+
// Check length
296+
expect(subset.length).toBeGreaterThanOrEqual(2);
297+
expect(subset.length).toBeLessThanOrEqual(4);
298+
299+
// Check elements
300+
subset.forEach((element) => {
301+
expect(testArray).toContain(element);
302+
});
303+
304+
// Check uniqueness
305+
expect(subset).not.toContainDuplicates();
306+
});
307+
308+
it('should return an array with all elements when count > array length', () => {
309+
const testArray = ['hello', 'to', 'you', 'my', 'friend'];
310+
const subset = faker.helpers.arrayElements(testArray, 6);
311+
312+
// Check length
313+
expect(subset.length).toEqual(5);
314+
315+
// Check elements
316+
subset.forEach((element) => {
317+
expect(testArray).toContain(element);
318+
});
319+
});
320+
321+
it('should return an empty array when array length > 0 and count = 0', () => {
322+
const testArray = ['hello', 'to', 'you', 'my', 'friend'];
323+
const result = faker.helpers.arrayElements(testArray, 0);
324+
325+
expect(result).toHaveLength(0);
326+
});
327+
284328
it('should return an empty array when receiving an empty array', () => {
285329
const result = faker.helpers.arrayElements([]);
286330

0 commit comments

Comments
 (0)