Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Randomly length for toCollection generator #304

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions docs-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const functionModifiers = {
randRecentDate: 'randRecentDate().toString()',
randSoonDate: 'randSoonDate().toString()',
randTextRange: 'randTextRange({ min: 10, max: 100 })',
toCollection: 'toCollection(() => { return { data: randNumber() }}, {length: 10})',
}

const skipLivePreview = ['seed'];
Expand Down
60 changes: 50 additions & 10 deletions packages/falso/src/lib/collection.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,72 @@
import { FakeOptions, fake } from './core/core';
import { FakeOptions, fake, Return, getRandomInRange } from './core/core';

export interface ToCollectionOptions extends FakeOptions {
minLength?: number; // default 0
maxLength?: number; // default minLength + 10 = 10
}

/**
* Generate a collection from a custom generators functions
*
* @category util
* The generator function, could receive two parameters :
* - options : the options object. You can pass to the generator some other options, if needed
* - index : The index of item currently generated. if you would like to use it in your generator function.
*
* ### Randomly length generator.
*
* You can specify minLength or maxLength (or both), to generate a random length collection.
* If one of minLength or maxLength is specified, a random length will be calculated before,
* and will return this random number of items.
* By default, minLength was equal to 0 and maxLength equal to min + 10.
*
* If minLength was equals to 0 and random return to 0, this function will return an empty array.
*
* @category general
*
* @example
*
* toCollection(() => { return { data: randNumber() }}) // {data: 2}
*
* @example
*
*
* toCollection(() => {
* return { data: randNumber(); }
* })
* }, { length: 10 }) // default is no length.
* // [{data: 2}, {data: 5}, ..., {data: 3}]
*
* @example
*
* toCollection(() => {
* return { data: randNumber(); }
* }, { length: 10 }) // default is no length.
* }, { minLength: 1, maxLength: 10 }) // default is minLength = 0 and maxLength = min + 10.
* // [{data: 2}, {data: 5}, ..., {data: 3}]
*
*/
* */
export function toCollection<
Collection = never,
Options extends FakeOptions = never
Options extends ToCollectionOptions = never
>(
generateCollection: (options?: Options) => Collection,
generateCollection: (options?: Options, index?: number) => Collection,
options?: Options
): Collection | Collection[] {
): Return<Collection, Options> | Collection[] {
if (
options &&
!options?.length &&
(options?.minLength !== null || options?.maxLength !== null)
) {
const min = options.minLength || 0;
options.length = getRandomInRange({
min,
max: options.maxLength || min + 10,
fraction: 0,
});
if (options.length === 0) {
return [];
}
}
return fake<Collection, Options>(
() => generateCollection(options),
(index: number) => generateCollection(options, index),
options
) as Collection | Collection[];
);
}
170 changes: 169 additions & 1 deletion packages/falso/src/tests/collection.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { toCollection } from '../lib/collection';
import { randNumber, random, seed } from '@ngneat/falso';
import * as numberFunctions from '../lib/number';
import * as coreFunctions from '../lib/core/core';
import Mock = jest.Mock;

interface fakeData {
Expand Down Expand Up @@ -56,7 +57,8 @@ describe('randCollection', () => {
})
).toEqual([{ data: 1 }, { data: 1 }]);
expect(generatorFunction).toHaveBeenCalledTimes(2);
expect(generatorFunction).toHaveBeenCalledWith({ length: 2 });
expect(generatorFunction).toHaveBeenNthCalledWith(1, { length: 2 }, 0);
expect(generatorFunction).toHaveBeenNthCalledWith(2, { length: 2 }, 1);
});
});
describe('with call external random function', () => {
Expand All @@ -83,4 +85,170 @@ describe('randCollection', () => {
).toEqual([{ data: 1 }, { data: 2 }]);
});
});

describe('Generate a random lenth of collection', () => {
let randNumberSpy: jest.SpyInstance;

beforeAll(() => {
randNumberSpy = jest.spyOn(coreFunctions, 'getRandomInRange');
});

afterEach(() => {
jest.clearAllMocks();
});

it('should return an empty array if getRandomInRange equal to zero', () => {
randNumberSpy.mockReturnValueOnce(0);

expect(
toCollection(
(__option, index) => {
return { data: index };
},
{ minLength: 0 }
)
).toEqual([]);
});

it('should return an array with one element if getRandomInRange equal to 1', () => {
randNumberSpy.mockReturnValueOnce(1);

expect(
toCollection(
(__option, index) => {
return { data: index };
},
{ minLength: 0 }
)
).toEqual([{ data: 0 }]);
});

it('should return an array with one element if minLength and maxLength equal to 1', () => {
expect(
toCollection(
(__option, index) => {
return { data: index };
},
{ minLength: 1, maxLength: 1 }
)
).toEqual([{ data: 0 }]);
});

it('should return an array with 8 element if getRandomInRange return a 8 value', () => {
randNumberSpy.mockReturnValueOnce(8);

expect(
toCollection(
(__option, index) => {
return { data: index };
},
{ maxLength: 10 }
)
).toEqual([
{ data: 0 },
{ data: 1 },
{ data: 2 },
{ data: 3 },
{ data: 4 },
{ data: 5 },
{ data: 6 },
{ data: 7 },
]);
});

it('should getRandomInRange with correct value', () => {
randNumberSpy.mockReturnValue(5);

toCollection(
(__option, index) => {
return { data: index };
},
{ maxLength: 8 }
);
expect(randNumberSpy).toHaveBeenNthCalledWith(1, {
min: 0,
max: 8,
fraction: 0,
});

toCollection(
(__option, index) => {
return { data: index };
},
{ minLength: 1, maxLength: 7 }
);
expect(randNumberSpy).toHaveBeenNthCalledWith(2, {
min: 1,
max: 7,
fraction: 0,
});

toCollection(
(__option, index) => {
return { data: index };
},
{ minLength: 8 }
);
expect(randNumberSpy).toHaveBeenNthCalledWith(3, {
min: 8,
max: 18,
fraction: 0,
});
});

it('should getRandomInRange with default value if default value is given', () => {
randNumberSpy.mockReturnValue(5);

toCollection(
(__option, index) => {
return { data: index };
},
{ maxLength: 10 }
);
expect(randNumberSpy).toHaveBeenNthCalledWith(1, {
min: 0,
max: 10,
fraction: 0,
});

toCollection(
(__option, index) => {
return { data: index };
},
{ minLength: 0, maxLength: 10 }
);
expect(randNumberSpy).toHaveBeenNthCalledWith(2, {
min: 0,
max: 10,
fraction: 0,
});

toCollection(
(__option, index) => {
return { data: index };
},
{ minLength: 0 }
);
expect(randNumberSpy).toHaveBeenNthCalledWith(3, {
min: 0,
max: 10,
fraction: 0,
});
});

it('should not call getRandomInRange if minLength or maxLength was not called', () => {
toCollection(
(__option, index) => {
return { data: index };
},
{ length: 10 }
);
expect(randNumberSpy).not.toBeCalled();

toCollection((__option, index) => {
return { data: index };
});
expect(randNumberSpy).not.toBeCalled();
});
});
});