How to use maxGeneratedLength method in fast-check-monorepo

Best JavaScript code snippet using fast-check-monorepo

ArrayArbitrary.spec.ts

Source:ArrayArbitrary.spec.ts Github

copy

Full Screen

1import fc from 'fast-check';2import prand from 'pure-rand';3import { ArrayArbitrary } from '../../../../src/arbitrary/_internals/ArrayArbitrary';4import { Value } from '../../../../src/check/arbitrary/definition/Value';5import { MaxLengthUpperBound } from '../../../../src/arbitrary/_internals/helpers/MaxLengthFromMinLength';6import { CustomSet } from '../../../../src/arbitrary/_internals/interfaces/CustomSet';7import { Stream } from '../../../../src/stream/Stream';8import { cloneMethod, hasCloneMethod } from '../../../../src/check/symbols';9import { Arbitrary } from '../../../../src/check/arbitrary/definition/Arbitrary';10import { Random } from '../../../../src/random/generator/Random';11import * as IntegerMock from '../../../../src/arbitrary/integer';12import { fakeArbitrary } from '../__test-helpers__/ArbitraryHelpers';13import { fakeRandom } from '../__test-helpers__/RandomHelpers';14import { buildShrinkTree, walkTree } from '../__test-helpers__/ShrinkTree';15import * as DepthContextMock from '../../../../src/arbitrary/_internals/helpers/DepthContext';16function beforeEachHook() {17 jest.resetModules();18 jest.restoreAllMocks();19 fc.configureGlobal({ beforeEach: beforeEachHook });20}21beforeEach(beforeEachHook);22describe('ArrayArbitrary', () => {23 describe('generate', () => {24 it('should concat all the generated values together when no set constraints ', () => {25 fc.assert(26 fc.property(27 fc.array(fc.tuple(fc.anything(), fc.anything())),28 fc.nat(),29 fc.nat(MaxLengthUpperBound),30 fc.nat(MaxLengthUpperBound),31 fc.anything(),32 (generatedValues, seed, aLength, bLength, integerContext) => {33 // Arrange34 const { acceptedValues, instance, generate } = prepareSetBuilderData(generatedValues, false);35 const { minLength, maxGeneratedLength, maxLength } = extractLengths(seed, aLength, bLength, acceptedValues);36 const { instance: integerInstance, generate: generateInteger } = fakeArbitrary();37 generateInteger.mockReturnValue(new Value(acceptedValues.size, integerContext));38 const integer = jest.spyOn(IntegerMock, 'integer');39 integer.mockReturnValue(integerInstance);40 const { instance: mrng } = fakeRandom();41 // Act42 const arb = new ArrayArbitrary(43 instance,44 minLength,45 maxGeneratedLength,46 maxLength,47 undefined,48 undefined,49 []50 );51 const g = arb.generate(mrng, undefined);52 // Assert53 expect(g.hasToBeCloned).toBe(false);54 expect(g.value).toEqual([...acceptedValues].map((v) => v.value));55 expect(integer).toHaveBeenCalledTimes(1);56 expect(integer).toHaveBeenCalledWith({ min: minLength, max: maxGeneratedLength });57 expect(generateInteger).toHaveBeenCalledTimes(1);58 expect(generateInteger).toHaveBeenCalledWith(mrng, undefined);59 expect(generate).toHaveBeenCalledTimes(acceptedValues.size);60 for (const call of generate.mock.calls) {61 expect(call).toEqual([mrng, undefined]);62 }63 }64 )65 );66 });67 it("should not concat all the values together in case they don't follow set contraints", () => {68 fc.assert(69 fc.property(70 fc.array(fc.tuple(fc.anything(), fc.anything(), fc.boolean())),71 fc.nat(),72 fc.nat(MaxLengthUpperBound),73 fc.nat(MaxLengthUpperBound),74 fc.anything(),75 (generatedValues, seed, aLength, bLength, integerContext) => {76 // Arrange77 const { acceptedValues, instance, generate, setBuilder } = prepareSetBuilderData(generatedValues, false);78 const { minLength, maxGeneratedLength, maxLength } = extractLengths(seed, aLength, bLength, acceptedValues);79 const { instance: integerInstance, generate: generateInteger } = fakeArbitrary();80 generateInteger.mockReturnValue(new Value(acceptedValues.size, integerContext));81 const integer = jest.spyOn(IntegerMock, 'integer');82 integer.mockReturnValue(integerInstance);83 const { instance: mrng } = fakeRandom();84 // Act85 const arb = new ArrayArbitrary(86 instance,87 minLength,88 maxGeneratedLength,89 maxLength,90 undefined,91 setBuilder,92 []93 );94 const g = arb.generate(mrng, undefined);95 // Assert96 expect(g.hasToBeCloned).toBe(false);97 // In the case of set the generated value might be smaller98 // The generator is allowed to stop whenever it considers at already tried to many times (maxGeneratedLength times)99 expect(g.value).toEqual([...acceptedValues].map((v) => v.value).slice(0, g.value.length));100 expect(integer).toHaveBeenCalledTimes(1);101 expect(integer).toHaveBeenCalledWith({ min: minLength, max: maxGeneratedLength });102 expect(generateInteger).toHaveBeenCalledTimes(1);103 expect(generateInteger).toHaveBeenCalledWith(mrng, undefined);104 expect(setBuilder).toHaveBeenCalledTimes(1);105 for (const call of generate.mock.calls) {106 expect(call).toEqual([mrng, undefined]);107 }108 }109 )110 );111 });112 it("should always pass bias to values' arbitrary when minLength equals maxGeneratedLength", () => {113 fc.assert(114 fc.property(115 fc.array(fc.tuple(fc.anything(), fc.anything(), fc.boolean())),116 fc.nat(),117 fc.nat(MaxLengthUpperBound),118 fc.anything(),119 fc.integer({ min: 2 }),120 fc.boolean(),121 (generatedValues, seed, aLength, integerContext, biasFactor, withSetBuilder) => {122 // Arrange123 const { acceptedValues, instance, setBuilder, generate } = prepareSetBuilderData(124 generatedValues,125 !withSetBuilder126 );127 const { minLength, maxLength } = extractLengths(seed, aLength, aLength, acceptedValues);128 const { instance: integerInstance, generate: generateInteger } = fakeArbitrary();129 generateInteger.mockReturnValue(new Value(minLength, integerContext));130 const integer = jest.spyOn(IntegerMock, 'integer');131 integer.mockReturnValue(integerInstance);132 const { instance: mrng } = fakeRandom();133 // Act134 const arb = new ArrayArbitrary(135 instance,136 minLength,137 minLength,138 maxLength,139 undefined,140 withSetBuilder ? setBuilder : undefined,141 []142 );143 const g = arb.generate(mrng, biasFactor);144 // Assert145 expect(g.hasToBeCloned).toBe(false);146 if (!withSetBuilder) {147 // In the case of set the generated value might be smaller148 // The generator is allowed to stop whenever it considers at already tried to many times (maxGeneratedLength times)149 expect(g.value).toEqual([...acceptedValues].map((v) => v.value).slice(0, minLength));150 } else {151 expect(g.value).toEqual(152 [...acceptedValues].map((v) => v.value).slice(0, Math.min(g.value.length, minLength))153 );154 }155 expect(integer).toHaveBeenCalledTimes(1);156 expect(integer).toHaveBeenCalledWith({ min: minLength, max: minLength });157 expect(generateInteger).toHaveBeenCalledTimes(1);158 expect(generateInteger).toHaveBeenCalledWith(mrng, undefined); // no need to bias it159 expect(setBuilder).toHaveBeenCalledTimes(withSetBuilder ? 1 : 0);160 expect(generate.mock.calls.length).toBeGreaterThanOrEqual(minLength);161 for (const call of generate.mock.calls) {162 expect(call).toEqual([mrng, biasFactor]); // but bias all sub-values163 }164 }165 )166 );167 });168 it('should bias depth the same way for any child and reset it at the end', () => {169 fc.assert(170 fc.property(171 fc.array(fc.tuple(fc.anything(), fc.anything(), fc.boolean())),172 fc.nat(),173 fc.nat(MaxLengthUpperBound),174 fc.nat(MaxLengthUpperBound),175 fc.anything(),176 fc.integer({ min: 2 }),177 fc.boolean(),178 (generatedValues, seed, aLength, bLength, integerContext, biasFactor, withSetBuilder) => {179 // Arrange180 const getDepthContextFor = jest.spyOn(DepthContextMock, 'getDepthContextFor');181 const depthContext = { depth: 0 };182 getDepthContextFor.mockReturnValue(depthContext);183 const seenDepths = new Set<number>();184 const { acceptedValues, instance, generate, setBuilder } = prepareSetBuilderData(185 generatedValues,186 !withSetBuilder,187 () => {188 seenDepths.add(depthContext.depth);189 }190 );191 const { minLength, maxGeneratedLength, maxLength } = extractLengths(seed, aLength, bLength, acceptedValues);192 const { instance: integerInstance, generate: generateInteger } = fakeArbitrary();193 generateInteger.mockReturnValue(new Value(minLength, integerContext));194 const integer = jest.spyOn(IntegerMock, 'integer');195 integer.mockReturnValue(integerInstance);196 const { instance: mrng } = fakeRandom();197 // Act198 const arb = new ArrayArbitrary(199 instance,200 minLength,201 maxGeneratedLength,202 maxLength,203 undefined,204 withSetBuilder ? setBuilder : undefined,205 []206 );207 arb.generate(mrng, biasFactor);208 // Assert209 expect(getDepthContextFor).toHaveBeenCalledTimes(1); // only array calls it in the test210 expect(depthContext.depth).toBe(0); // properly reset211 if (generate.mock.calls.length !== 0) {212 expect([...seenDepths]).toHaveLength(1); // always called with same depth213 } else {214 expect([...seenDepths]).toHaveLength(0); // never called on items215 }216 }217 )218 );219 });220 it('should produce a cloneable instance if provided one cloneable underlying', () => {221 // Arrange222 const { instance, generate } = fakeArbitrary<string[]>();223 generate224 .mockReturnValueOnce(new Value(['a'], undefined))225 .mockReturnValueOnce(new Value(Object.defineProperty(['b'], cloneMethod, { value: jest.fn() }), undefined))226 .mockReturnValueOnce(new Value(['c'], undefined))227 .mockReturnValueOnce(new Value(['d'], undefined));228 const { instance: integerInstance, generate: generateInteger } = fakeArbitrary();229 generateInteger.mockReturnValue(new Value(4, undefined));230 const integer = jest.spyOn(IntegerMock, 'integer');231 integer.mockReturnValue(integerInstance);232 const { instance: mrng } = fakeRandom();233 // Act234 const arb = new ArrayArbitrary(instance, 0, 10, 100, undefined, undefined, []);235 const g = arb.generate(mrng, undefined);236 // Assert237 expect(g.hasToBeCloned).toBe(true);238 expect(hasCloneMethod(g.value)).toBe(true);239 expect(g.value_).not.toEqual([['a'], ['b'], ['c'], ['d']]); // 2nd item is not just ['b']240 expect(g.value_.map((v) => [...v])).toEqual([['a'], ['b'], ['c'], ['d']]);241 });242 it('should not clone cloneable on generate', () => {243 // Arrange244 const cloneMethodImpl = jest.fn();245 const { instance, generate } = fakeArbitrary<string[]>();246 generate247 .mockReturnValueOnce(new Value(['a'], undefined))248 .mockReturnValueOnce(249 new Value(Object.defineProperty(['b'], cloneMethod, { value: cloneMethodImpl }), undefined)250 )251 .mockReturnValueOnce(new Value(['c'], undefined))252 .mockReturnValueOnce(new Value(['d'], undefined));253 const { instance: integerInstance, generate: generateInteger } = fakeArbitrary();254 generateInteger.mockReturnValue(new Value(4, undefined));255 const integer = jest.spyOn(IntegerMock, 'integer');256 integer.mockReturnValue(integerInstance);257 const { instance: mrng } = fakeRandom();258 // Act259 const arb = new ArrayArbitrary(instance, 0, 10, 100, undefined, undefined, []);260 const g = arb.generate(mrng, undefined);261 // Assert262 expect(cloneMethodImpl).not.toHaveBeenCalled();263 g.value; // not calling clone as this is the first access264 expect(cloneMethodImpl).not.toHaveBeenCalled();265 g.value; // calling clone as this is the second access266 expect(cloneMethodImpl).toHaveBeenCalledTimes(1);267 g.value; // calling clone (again) as this is the third access268 expect(cloneMethodImpl).toHaveBeenCalledTimes(2);269 g.value_; // not calling clone as we access value_ not value270 expect(cloneMethodImpl).toHaveBeenCalledTimes(2);271 });272 });273 describe('canShrinkWithoutContext', () => {274 it('should reject any array not matching the requirements on length', () => {275 fc.assert(276 fc.property(277 fc.array(fc.anything()),278 fc.boolean(),279 fc.nat(MaxLengthUpperBound),280 fc.nat(MaxLengthUpperBound),281 fc.nat(MaxLengthUpperBound),282 (value, withSetBuilder, aLength, bLength, cLength) => {283 // Arrange284 const [minLength, maxGeneratedLength, maxLength] = [aLength, bLength, cLength].sort((a, b) => a - b);285 fc.pre(value.length < minLength || value.length > maxLength);286 const { instance, canShrinkWithoutContext } = fakeArbitrary();287 const data: any[] = [];288 const customSet: CustomSet<Value<any>> = {289 size: () => data.length,290 getData: () => data,291 tryAdd: (vTest) => {292 data.push(vTest.value_);293 return true;294 },295 };296 const setBuilder = jest.fn();297 setBuilder.mockReturnValue(customSet);298 // Act299 const arb = new ArrayArbitrary(300 instance,301 minLength,302 maxGeneratedLength,303 maxLength,304 undefined,305 withSetBuilder ? setBuilder : undefined,306 []307 );308 const out = arb.canShrinkWithoutContext(value);309 // Assert310 expect(out).toBe(false);311 expect(canShrinkWithoutContext).not.toHaveBeenCalled();312 expect(setBuilder).not.toHaveBeenCalled();313 }314 )315 );316 });317 it('should reject any array with at least one entry rejected by the sub-arbitrary', () => {318 fc.assert(319 fc.property(320 fc.uniqueArray(fc.tuple(fc.anything(), fc.boolean()), {321 minLength: 1,322 selector: (v) => v[0],323 comparator: 'SameValue',324 }),325 fc.boolean(),326 fc.nat(MaxLengthUpperBound),327 fc.nat(MaxLengthUpperBound),328 fc.nat(MaxLengthUpperBound),329 (value, withSetBuilder, offsetMin, offsetMax, maxGeneratedLength) => {330 // Arrange331 fc.pre(value.some((v) => !v[1]));332 const minLength = Math.min(Math.max(0, value.length - offsetMin), maxGeneratedLength);333 const maxLength = Math.max(Math.min(MaxLengthUpperBound, value.length + offsetMax), maxGeneratedLength);334 const { instance, canShrinkWithoutContext } = fakeArbitrary();335 canShrinkWithoutContext.mockImplementation((vTest) => value.find((v) => Object.is(v[0], vTest))![1]);336 const data: any[] = [];337 const customSet: CustomSet<Value<any>> = {338 size: () => data.length,339 getData: () => data,340 tryAdd: (vTest) => {341 data.push(vTest.value_);342 return true;343 },344 };345 const setBuilder = jest.fn();346 setBuilder.mockReturnValue(customSet);347 // Act348 const arb = new ArrayArbitrary(349 instance,350 minLength,351 maxGeneratedLength,352 maxLength,353 undefined,354 withSetBuilder ? setBuilder : undefined,355 []356 );357 const out = arb.canShrinkWithoutContext(value.map((v) => v[0]));358 // Assert359 expect(out).toBe(false);360 expect(canShrinkWithoutContext).toHaveBeenCalled();361 }362 )363 );364 });365 it('should reject any array not matching requirements for set constraints', () => {366 fc.assert(367 fc.property(368 fc.uniqueArray(fc.tuple(fc.anything(), fc.boolean()), {369 minLength: 1,370 selector: (v) => v[0],371 comparator: 'SameValue',372 }),373 fc.nat(MaxLengthUpperBound),374 fc.nat(MaxLengthUpperBound),375 fc.nat(MaxLengthUpperBound),376 (value, offsetMin, offsetMax, maxGeneratedLength) => {377 // Arrange378 fc.pre(value.some((v) => !v[1]));379 const minLength = Math.min(Math.max(0, value.length - offsetMin), maxGeneratedLength);380 const maxLength = Math.max(Math.min(MaxLengthUpperBound, value.length + offsetMax), maxGeneratedLength);381 const { instance, canShrinkWithoutContext } = fakeArbitrary();382 canShrinkWithoutContext.mockReturnValue(true);383 const data: any[] = [];384 const customSet: CustomSet<Value<any>> = {385 size: () => data.length,386 getData: () => data,387 tryAdd: (vTest) => {388 if (value.find((v) => Object.is(v[0], vTest.value_))![1]) {389 data.push(vTest.value_);390 return true;391 }392 return false;393 },394 };395 const setBuilder = jest.fn();396 setBuilder.mockReturnValue(customSet);397 // Act398 const arb = new ArrayArbitrary(399 instance,400 minLength,401 maxGeneratedLength,402 maxLength,403 undefined,404 setBuilder,405 []406 );407 const out = arb.canShrinkWithoutContext(value.map((v) => v[0]));408 // Assert409 expect(out).toBe(false);410 expect(canShrinkWithoutContext).toHaveBeenCalled();411 expect(setBuilder).toHaveBeenCalled();412 }413 )414 );415 });416 it('should reject any sparse array', () => {417 fc.assert(418 fc.property(419 fc.sparseArray(fc.anything()),420 fc.boolean(),421 fc.nat(MaxLengthUpperBound),422 fc.nat(MaxLengthUpperBound),423 fc.nat(MaxLengthUpperBound),424 (value, withSetBuilder, offsetMin, offsetMax, maxGeneratedLength) => {425 // Arrange426 fc.pre(value.length !== Object.keys(value).length);427 const minLength = Math.min(Math.max(0, value.length - offsetMin), maxGeneratedLength);428 const maxLength = Math.max(Math.min(MaxLengthUpperBound, value.length + offsetMax), maxGeneratedLength);429 const { instance, canShrinkWithoutContext } = fakeArbitrary();430 canShrinkWithoutContext.mockReturnValue(true);431 const data: any[] = [];432 const customSet: CustomSet<Value<any>> = {433 size: () => data.length,434 getData: () => data,435 tryAdd: (vTest) => {436 data.push(vTest.value_);437 return true;438 },439 };440 const setBuilder = jest.fn();441 setBuilder.mockReturnValue(customSet);442 // Act443 const arb = new ArrayArbitrary(444 instance,445 minLength,446 maxGeneratedLength,447 maxLength,448 undefined,449 withSetBuilder ? setBuilder : undefined,450 []451 );452 const out = arb.canShrinkWithoutContext(value);453 // Assert454 expect(out).toBe(false);455 }456 )457 );458 });459 it('should accept all other arrays', () => {460 fc.assert(461 fc.property(462 fc.array(fc.anything()),463 fc.boolean(),464 fc.nat(MaxLengthUpperBound),465 fc.nat(MaxLengthUpperBound),466 fc.nat(MaxLengthUpperBound),467 (value, withSetBuilder, offsetMin, offsetMax, maxGeneratedLength) => {468 // Arrange469 const minLength = Math.min(Math.max(0, value.length - offsetMin), maxGeneratedLength);470 const maxLength = Math.max(Math.min(MaxLengthUpperBound, value.length + offsetMax), maxGeneratedLength);471 const { instance, canShrinkWithoutContext } = fakeArbitrary();472 canShrinkWithoutContext.mockReturnValue(true);473 const data: any[] = [];474 const customSet: CustomSet<Value<any>> = {475 size: () => data.length,476 getData: () => data,477 tryAdd: (vTest) => {478 data.push(vTest.value_);479 return true;480 },481 };482 const setBuilder = jest.fn();483 setBuilder.mockReturnValue(customSet);484 // Act485 const arb = new ArrayArbitrary(486 instance,487 minLength,488 maxGeneratedLength,489 maxLength,490 undefined,491 withSetBuilder ? setBuilder : undefined,492 []493 );494 const out = arb.canShrinkWithoutContext(value);495 // Assert496 expect(out).toBe(true);497 }498 )499 );500 });501 });502});503describe('ArrayArbitrary (integration)', () => {504 it('should not re-use twice the same instance of cloneable', () => {505 // Arrange506 const alreadySeenCloneable = new Set<unknown>();507 const mrng = new Random(prand.mersenne(0));508 const arb = new ArrayArbitrary(new CloneableArbitrary(), 0, 5, 100, undefined, undefined, []); // 0 to 5 generated items509 // Act510 let g = arb.generate(mrng, undefined);511 while (g.value.length !== 3) {512 // 3 allows to shrink something large enough but not too large513 // walking through the tree when >3 takes much longer514 g = arb.generate(mrng, undefined);515 }516 const treeA = buildShrinkTree(arb, g);517 const treeB = buildShrinkTree(arb, g);518 // Assert519 walkTree(treeA, (cloneable) => {520 expect(alreadySeenCloneable.has(cloneable)).toBe(false);521 alreadySeenCloneable.add(cloneable);522 for (const subCloneable of cloneable) {523 expect(alreadySeenCloneable.has(subCloneable)).toBe(false);524 alreadySeenCloneable.add(subCloneable);525 }526 });527 walkTree(treeB, (cloneable) => {528 expect(alreadySeenCloneable.has(cloneable)).toBe(false);529 alreadySeenCloneable.add(cloneable);530 for (const subCloneable of cloneable) {531 expect(alreadySeenCloneable.has(subCloneable)).toBe(false);532 alreadySeenCloneable.add(subCloneable);533 }534 });535 });536});537// Helpers538function prepareSetBuilderData(539 generatedValues: [value: any, context: any, rejected?: boolean][],540 acceptAll: boolean,541 onGenerateHook?: () => void542) {543 const acceptedValues = new Set<Value<any>>();544 const { instance, generate } = fakeArbitrary();545 for (const v of generatedValues) {546 const value = new Value(v[0], v[1]);547 const rejected = v[2];548 if (!rejected || acceptAll) {549 acceptedValues.add(value);550 }551 generate.mockImplementationOnce(() => {552 if (onGenerateHook !== undefined) {553 onGenerateHook();554 }555 return value;556 });557 }558 const data: any[] = [];559 const customSet: CustomSet<Value<any>> = {560 size: () => data.length,561 getData: () => data,562 tryAdd: (value) => {563 if (acceptedValues.has(value)) {564 data.push(value);565 return true;566 }567 return false;568 },569 };570 const setBuilder = jest.fn();571 setBuilder.mockReturnValue(customSet);572 return { acceptedValues, instance, generate, setBuilder };573}574function extractLengths(minLengthSeed: number, aLength: number, bLength: number, acceptedValues: Set<unknown>) {575 const minLength = minLengthSeed % (acceptedValues.size || 1);576 const [maxGeneratedLength, maxLength] = aLength < bLength ? [aLength, bLength] : [bLength, aLength];577 fc.pre(maxGeneratedLength >= acceptedValues.size);578 return { minLength, maxGeneratedLength, maxLength };579}580class CloneableArbitrary extends Arbitrary<number[]> {581 private instance() {582 return Object.defineProperty([], cloneMethod, { value: () => this.instance() });583 }584 generate(_mrng: Random): Value<number[]> {585 return new Value(this.instance(), { shrunkOnce: false });586 }587 canShrinkWithoutContext(_value: unknown): _value is number[] {588 throw new Error('No call expected in that scenario');589 }590 shrink(value: number[], context?: unknown): Stream<Value<number[]>> {591 if (typeof context !== 'object' || context === null || !('shrunkOnce' in context)) {592 throw new Error('Invalid context for CloneableArbitrary');593 }594 const safeContext = context as { shrunkOnce: boolean };595 if (safeContext.shrunkOnce) {596 return Stream.nil();597 }598 return Stream.of(new Value(this.instance(), { shrunkOnce: true }));599 }...

Full Screen

Full Screen

ArrayArbitrary.ts

Source:ArrayArbitrary.ts Github

copy

Full Screen

1import { Random } from '../../random/generator/Random';2import { Stream } from '../../stream/Stream';3import { cloneIfNeeded, cloneMethod } from '../../check/symbols';4import { integer } from '../integer';5import { makeLazy } from '../../stream/LazyIterableIterator';6import { Arbitrary } from '../../check/arbitrary/definition/Arbitrary';7import { Value } from '../../check/arbitrary/definition/Value';8import { CustomSetBuilder } from './interfaces/CustomSet';9import { DepthContext, DepthIdentifier, getDepthContextFor } from './helpers/DepthContext';10import { buildSlicedGenerator } from './helpers/BuildSlicedGenerator';11import { safeMap, safePush, safeSlice } from '../../utils/globals';12const safeMathFloor = Math.floor;13const safeMathLog = Math.log;14const safeMathMax = Math.max;15const safeArrayIsArray = Array.isArray;16/** @internal */17type ArrayArbitraryContext = {18 shrunkOnce: boolean;19 lengthContext: unknown;20 itemsContexts: unknown[];21 startIndex: number;22};23/** @internal */24function biasedMaxLength(minLength: number, maxLength: number): number {25 if (minLength === maxLength) {26 return minLength;27 }28 return minLength + safeMathFloor(safeMathLog(maxLength - minLength) / safeMathLog(2));29}30/** @internal */31export class ArrayArbitrary<T> extends Arbitrary<T[]> {32 readonly lengthArb: Arbitrary<number>;33 readonly depthContext: DepthContext;34 constructor(35 readonly arb: Arbitrary<T>,36 readonly minLength: number,37 readonly maxGeneratedLength: number,38 readonly maxLength: number,39 depthIdentifier: DepthIdentifier | string | undefined,40 // Whenever passing a isEqual to ArrayArbitrary, you also have to filter41 // it's output just in case produced values are too small (below minLength)42 readonly setBuilder: CustomSetBuilder<Value<T>> | undefined,43 readonly customSlices: T[][]44 ) {45 super();46 this.lengthArb = integer({ min: minLength, max: maxGeneratedLength });47 this.depthContext = getDepthContextFor(depthIdentifier);48 }49 private preFilter(tab: Value<T>[]): Value<T>[] {50 if (this.setBuilder === undefined) {51 return tab;52 }53 const s = this.setBuilder();54 for (let index = 0; index !== tab.length; ++index) {55 s.tryAdd(tab[index]);56 }57 return s.getData();58 }59 private static makeItCloneable<T>(vs: T[], shrinkables: Value<T>[]) {60 (vs as any)[cloneMethod] = () => {61 const cloned: T[] = [];62 for (let idx = 0; idx !== shrinkables.length; ++idx) {63 safePush(cloned, shrinkables[idx].value); // push potentially cloned values64 }65 this.makeItCloneable(cloned, shrinkables);66 return cloned;67 };68 return vs;69 }70 private generateNItemsNoDuplicates(71 setBuilder: CustomSetBuilder<Value<T>>,72 N: number,73 mrng: Random,74 biasFactorItems: number | undefined75 ): Value<T>[] {76 let numSkippedInRow = 0;77 const s = setBuilder();78 const slicedGenerator = buildSlicedGenerator(this.arb, mrng, this.customSlices, biasFactorItems);79 // Try to append into items up to the target size80 // We may reject some items as they are already part of the set81 // so we need to retry and generate other ones. In order to prevent infinite loop,82 // we accept a max of maxGeneratedLength consecutive failures. This circuit breaker may cause83 // generated to be smaller than the minimal accepted one.84 while (s.size() < N && numSkippedInRow < this.maxGeneratedLength) {85 const current = slicedGenerator.next();86 if (s.tryAdd(current)) {87 numSkippedInRow = 0;88 } else {89 numSkippedInRow += 1;90 }91 }92 return s.getData();93 }94 private safeGenerateNItemsNoDuplicates(95 setBuilder: CustomSetBuilder<Value<T>>,96 N: number,97 mrng: Random,98 biasFactorItems: number | undefined99 ): Value<T>[] {100 const depthImpact = safeMathMax(0, N - biasedMaxLength(this.minLength, this.maxGeneratedLength)); // no depth impact for biased lengths101 this.depthContext.depth += depthImpact; // increase depth102 try {103 return this.generateNItemsNoDuplicates(setBuilder, N, mrng, biasFactorItems);104 } finally {105 this.depthContext.depth -= depthImpact; // decrease depth (reset depth)106 }107 }108 private generateNItems(N: number, mrng: Random, biasFactorItems: number | undefined): Value<T>[] {109 const items: Value<T>[] = [];110 const slicedGenerator = buildSlicedGenerator(this.arb, mrng, this.customSlices, biasFactorItems);111 slicedGenerator.attemptExact(N);112 for (let index = 0; index !== N; ++index) {113 const current = slicedGenerator.next();114 safePush(items, current);115 }116 return items;117 }118 private safeGenerateNItems(N: number, mrng: Random, biasFactorItems: number | undefined): Value<T>[] {119 const depthImpact = safeMathMax(0, N - biasedMaxLength(this.minLength, this.maxGeneratedLength)); // no depth impact for biased lengths120 this.depthContext.depth += depthImpact; // increase depth121 try {122 return this.generateNItems(N, mrng, biasFactorItems);123 } finally {124 this.depthContext.depth -= depthImpact; // decrease depth (reset depth)125 }126 }127 private wrapper(128 itemsRaw: Value<T>[],129 shrunkOnce: boolean,130 itemsRawLengthContext: unknown,131 startIndex: number132 ): Value<T[]> {133 // We need to explicitly apply filtering on shrink items134 // has they might have duplicates (on non shrunk it is not the case by construct)135 const items = shrunkOnce ? this.preFilter(itemsRaw) : itemsRaw;136 let cloneable = false;137 const vs: T[] = [];138 const itemsContexts: unknown[] = [];139 for (let idx = 0; idx !== items.length; ++idx) {140 const s = items[idx];141 cloneable = cloneable || s.hasToBeCloned;142 safePush(vs, s.value);143 safePush(itemsContexts, s.context);144 }145 if (cloneable) {146 ArrayArbitrary.makeItCloneable(vs, items);147 }148 const context: ArrayArbitraryContext = {149 shrunkOnce,150 lengthContext:151 itemsRaw.length === items.length && itemsRawLengthContext !== undefined152 ? itemsRawLengthContext // items and itemsRaw have the same length context is applicable153 : undefined,154 itemsContexts,155 startIndex,156 };157 return new Value(vs, context);158 }159 generate(mrng: Random, biasFactor: number | undefined): Value<T[]> {160 const biasMeta = this.applyBias(mrng, biasFactor);161 const targetSize = biasMeta.size;162 const items =163 this.setBuilder !== undefined164 ? this.safeGenerateNItemsNoDuplicates(this.setBuilder, targetSize, mrng, biasMeta.biasFactorItems)165 : this.safeGenerateNItems(targetSize, mrng, biasMeta.biasFactorItems);166 return this.wrapper(items, false, undefined, 0);167 }168 private applyBias(mrng: Random, biasFactor: number | undefined): { size: number; biasFactorItems?: number } {169 if (biasFactor === undefined) {170 // We don't bias anything171 return { size: this.lengthArb.generate(mrng, undefined).value };172 }173 // We directly forward bias to items whenever no bias applicable onto length174 if (this.minLength === this.maxGeneratedLength) {175 // We only apply bias on items176 return { size: this.lengthArb.generate(mrng, undefined).value, biasFactorItems: biasFactor };177 }178 if (mrng.nextInt(1, biasFactor) !== 1) {179 // We don't bias anything180 return { size: this.lengthArb.generate(mrng, undefined).value };181 }182 // We apply bias (1 chance over biasFactor)183 if (mrng.nextInt(1, biasFactor) !== 1 || this.minLength === this.maxGeneratedLength) {184 // We only apply bias on items ((biasFactor-1) chances over biasFactor²)185 return { size: this.lengthArb.generate(mrng, undefined).value, biasFactorItems: biasFactor };186 }187 // We apply bias for both items and length (1 chance over biasFactor²)188 const maxBiasedLength = biasedMaxLength(this.minLength, this.maxGeneratedLength);189 const targetSizeValue = integer({ min: this.minLength, max: maxBiasedLength }).generate(mrng, undefined);190 return { size: targetSizeValue.value, biasFactorItems: biasFactor };191 }192 canShrinkWithoutContext(value: unknown): value is T[] {193 if (!safeArrayIsArray(value) || this.minLength > value.length || value.length > this.maxLength) {194 return false;195 }196 for (let index = 0; index !== value.length; ++index) {197 if (!(index in value)) {198 // sparse array cannot be produced by this instance199 return false;200 }201 if (!this.arb.canShrinkWithoutContext(value[index])) {202 // item at index cannot be produced by our arbitrary203 return false;204 }205 }206 // `preFilter` only drops items, it does not reorder them or add some more207 // if calling it with `value` results into a smaller array it means that the value was not generated by this instance208 const filtered = this.preFilter(safeMap(value, (item) => new Value(item, undefined)));209 return filtered.length === value.length;210 }211 private shrinkItemByItem(212 value: T[],213 safeContext: ArrayArbitraryContext,214 endIndex: number215 ): IterableIterator<[Value<T>[], unknown, number]> {216 let shrinks = Stream.nil<[Value<T>[], unknown, number]>();217 for (let index = safeContext.startIndex; index < endIndex; ++index) {218 shrinks = shrinks.join(219 makeLazy(() =>220 this.arb.shrink(value[index], safeContext.itemsContexts[index]).map((v): [Value<T>[], unknown, number] => {221 const beforeCurrent = safeMap(222 safeSlice(value, 0, index),223 (v, i) => new Value(cloneIfNeeded(v), safeContext.itemsContexts[i])224 );225 const afterCurrent = safeMap(226 safeSlice(value, index + 1),227 (v, i) => new Value(cloneIfNeeded(v), safeContext.itemsContexts[i + index + 1])228 );229 return [230 [...beforeCurrent, v, ...afterCurrent],231 undefined, // no length context232 index, // avoid shrinking entries before index in sub-shrinks233 ];234 })235 )236 );237 }238 return shrinks;239 }240 private shrinkImpl(value: T[], context?: unknown): Stream<[Value<T>[], unknown, number]> {241 if (value.length === 0) {242 return Stream.nil();243 }244 const safeContext: ArrayArbitraryContext =245 context !== undefined246 ? (context as ArrayArbitraryContext)247 : { shrunkOnce: false, lengthContext: undefined, itemsContexts: [], startIndex: 0 };248 return (249 this.lengthArb250 .shrink(251 value.length,252 // lengthContext is a context returned by a previous call to the integer253 // arbitrary and the integer value items.length.254 safeContext.lengthContext255 )256 // in case we already shrunk once but don't have any dedicated context to help the shrinker, we drop the first item257 // except if reached we have the minimal size +1, in that case we apply a last chance try policy258 .drop(259 safeContext.shrunkOnce && safeContext.lengthContext === undefined && value.length > this.minLength + 1 ? 1 : 0260 )261 .map((lengthValue): [Value<T>[], unknown, number] => {262 const sliceStart = value.length - lengthValue.value;263 return [264 safeMap(265 safeSlice(value, sliceStart),266 (v, index) => new Value(cloneIfNeeded(v), safeContext.itemsContexts[index + sliceStart])267 ), // array of length lengthValue.value268 lengthValue.context, // integer context for value lengthValue.value (the length)269 0,270 ];271 })272 // Length context value will be set to undefined for remaining shrinking values273 // as they are outside of our shrinking process focused on items.length.274 // None of our computed contexts will apply for them.275 .join(276 makeLazy(() =>277 value.length > this.minLength278 ? this.shrinkItemByItem(value, safeContext, 1)279 : this.shrinkItemByItem(value, safeContext, value.length)280 )281 )282 .join(283 value.length > this.minLength284 ? makeLazy(() => {285 // We pass itemsLengthContext=undefined to next shrinker to start shrinking286 // without any assumptions on the current state (we never explored that one)287 const subContext: ArrayArbitraryContext = {288 shrunkOnce: false,289 lengthContext: undefined,290 itemsContexts: safeSlice(safeContext.itemsContexts, 1),291 startIndex: 0,292 };293 return this.shrinkImpl(safeSlice(value, 1), subContext)294 .filter((v) => this.minLength <= v[0].length + 1)295 .map((v): [Value<T>[], unknown, number] => {296 return [[new Value(cloneIfNeeded(value[0]), safeContext.itemsContexts[0]), ...v[0]], undefined, 0];297 });298 })299 : Stream.nil()300 )301 );302 }303 shrink(value: T[], context?: unknown): Stream<Value<T[]>> {304 return this.shrinkImpl(value, context).map((contextualValue) =>305 this.wrapper(contextualValue[0], true, contextualValue[1], contextualValue[2])306 );307 }...

Full Screen

Full Screen

sparseArray.ts

Source:sparseArray.ts Github

copy

Full Screen

1import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';2import { Array, safeMap, safeSlice } from '../utils/globals';3import { tuple } from './tuple';4import { uniqueArray } from './uniqueArray';5import { restrictedIntegerArbitraryBuilder } from './_internals/builders/RestrictedIntegerArbitraryBuilder';6import { DepthIdentifier } from './_internals/helpers/DepthContext';7import {8 maxGeneratedLengthFromSizeForArbitrary,9 MaxLengthUpperBound,10 SizeForArbitrary,11} from './_internals/helpers/MaxLengthFromMinLength';12const safeMathMin = Math.min;13const safeMathMax = Math.max;14const safeArrayIsArray = Array.isArray;15const safeObjectEntries = Object.entries;16/**17 * Constraints to be applied on {@link sparseArray}18 * @remarks Since 2.13.019 * @public20 */21export interface SparseArrayConstraints {22 /**23 * Upper bound of the generated array size (maximal size: 4294967295)24 * @remarks Since 2.13.025 */26 maxLength?: number;27 /**28 * Lower bound of the number of non-hole elements29 * @remarks Since 2.13.030 */31 minNumElements?: number;32 /**33 * Upper bound of the number of non-hole elements34 * @remarks Since 2.13.035 */36 maxNumElements?: number;37 /**38 * When enabled, all generated arrays will either be the empty array or end by a non-hole39 * @remarks Since 2.13.040 */41 noTrailingHole?: boolean;42 /**43 * Define how large the generated values should be (at max)44 * @remarks Since 2.22.045 */46 size?: SizeForArbitrary;47 /**48 * When receiving a depth identifier, the arbitrary will impact the depth49 * attached to it to avoid going too deep if it already generated lots of items.50 *51 * In other words, if the number of generated values within the collection is large52 * then the generated items will tend to be less deep to avoid creating structures a lot53 * larger than expected.54 *55 * For the moment, the depth is not taken into account to compute the number of items to56 * define for a precise generate call of the array. Just applied onto eligible items.57 *58 * @remarks Since 2.25.059 */60 depthIdentifier?: DepthIdentifier | string;61}62/** @internal */63function extractMaxIndex(indexesAndValues: [number, unknown][]) {64 let maxIndex = -1;65 for (let index = 0; index !== indexesAndValues.length; ++index) {66 maxIndex = safeMathMax(maxIndex, indexesAndValues[index][0]);67 }68 return maxIndex;69}70/** @internal */71function arrayFromItems<T>(length: number, indexesAndValues: [number, T][]) {72 const array = Array<T>(length);73 for (let index = 0; index !== indexesAndValues.length; ++index) {74 const it = indexesAndValues[index];75 if (it[0] < length) array[it[0]] = it[1];76 }77 return array;78}79/**80 * For sparse arrays of values coming from `arb`81 * @param arb - Arbitrary used to generate the values inside the sparse array82 * @param constraints - Constraints to apply when building instances83 * @remarks Since 2.13.084 * @public85 */86export function sparseArray<T>(arb: Arbitrary<T>, constraints: SparseArrayConstraints = {}): Arbitrary<T[]> {87 const {88 size,89 minNumElements = 0,90 maxLength = MaxLengthUpperBound,91 maxNumElements = maxLength, // cap maxNumElements to maxLength92 noTrailingHole,93 depthIdentifier,94 } = constraints;95 const maxGeneratedNumElements = maxGeneratedLengthFromSizeForArbitrary(96 size,97 minNumElements,98 maxNumElements,99 constraints.maxNumElements !== undefined100 );101 const maxGeneratedLength = maxGeneratedLengthFromSizeForArbitrary(102 size,103 maxGeneratedNumElements,104 maxLength,105 constraints.maxLength !== undefined106 );107 if (minNumElements > maxLength) {108 throw new Error(`The minimal number of non-hole elements cannot be higher than the maximal length of the array`);109 }110 if (minNumElements > maxNumElements) {111 throw new Error(`The minimal number of non-hole elements cannot be higher than the maximal number of non-holes`);112 }113 const resultedMaxNumElements = safeMathMin(maxNumElements, maxLength);114 const resultedSizeMaxNumElements = constraints.maxNumElements !== undefined || size !== undefined ? size : '=';115 const maxGeneratedIndexAuthorized = safeMathMax(maxGeneratedLength - 1, 0); // just preventing special case for maxGeneratedLength=0116 const maxIndexAuthorized = safeMathMax(maxLength - 1, 0); // just preventing special case for maxLength=0117 const sparseArrayNoTrailingHole = uniqueArray(118 tuple(restrictedIntegerArbitraryBuilder(0, maxGeneratedIndexAuthorized, maxIndexAuthorized), arb),119 {120 size: resultedSizeMaxNumElements,121 minLength: minNumElements,122 maxLength: resultedMaxNumElements,123 selector: (item) => item[0],124 depthIdentifier,125 }126 ).map(127 (items) => {128 // When maxLength=0 (implies resultedMaxNumElements=0) we will have items=[] leading to lastIndex=-1129 // resulting in an empty array130 const lastIndex = extractMaxIndex(items);131 return arrayFromItems(lastIndex + 1, items);132 },133 (value: unknown): [number, T][] => {134 if (!safeArrayIsArray(value)) {135 throw new Error('Not supported entry type');136 }137 if (noTrailingHole && value.length !== 0 && !(value.length - 1 in value)) {138 throw new Error('No trailing hole');139 }140 return safeMap(safeObjectEntries(value as T[]), (entry): [number, T] => [Number(entry[0]), entry[1]]);141 }142 );143 if (noTrailingHole || maxLength === minNumElements) {144 return sparseArrayNoTrailingHole;145 }146 return tuple(147 sparseArrayNoTrailingHole,148 restrictedIntegerArbitraryBuilder(minNumElements, maxGeneratedLength, maxLength)149 ).map(150 (data) => {151 const sparse = data[0];152 const targetLength = data[1];153 if (sparse.length >= targetLength) {154 return sparse;155 }156 const longerSparse = safeSlice(sparse);157 longerSparse.length = targetLength;158 return longerSparse;159 },160 (value: unknown): [T[], number] => {161 if (!safeArrayIsArray(value)) {162 throw new Error('Not supported entry type');163 }164 return [value, value.length];165 }166 );...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1const fc = require('fast-check');2const { maxGeneratedLength } = require('fast-check/lib/check/arbitrary/definition/MaxGeneratedLengthArbitrary');3const { stringOf } = require('fast-check/lib/arbitrary/stringOf');4const { string16bits } = require('fast-check/lib/arbitrary/string16bits');5const str = stringOf(string16bits(), { minLength: 1, maxLength: 1 });6console.log(maxGeneratedLength(str));7const fc = require('fast-check');8const { maxGeneratedLength } = require('fast-check/lib/check/arbitrary/definition/MaxGeneratedLengthArbitrary');9const { stringOf } = require('fast-check/lib/arbitrary/stringOf');10const { string16bits } = require('fast-check/lib/arbitrary/string16bits');11const str = stringOf(string16bits(), { minLength: 1, maxLength: 2 });12console.log(maxGeneratedLength(str));

Full Screen

Using AI Code Generation

copy

Full Screen

1const fc = require('fast-check');2const {maxGeneratedLength} = require('fast-check/lib/runner/configuration/GlobalParameters');3console.log('maxGeneratedLength: ' + maxGeneratedLength);4const fc = require('fast-check');5const {maxGeneratedLength} = require('fast-check/lib/runner/configuration/GlobalParameters');6console.log('maxGeneratedLength: ' + maxGeneratedLength);

Full Screen

Using AI Code Generation

copy

Full Screen

1const maxGeneratedLength = require('fast-check-monorepo');2const fc = require('fast-check');3const assert = require('assert');4const max = maxGeneratedLength(fc.integer());5assert(max > 0);6console.log(max);

Full Screen

Using AI Code Generation

copy

Full Screen

1const fc = require('fast-check');2const { maxGeneratedLength } = require('fast-check-monorepo');3const max = maxGeneratedLength(4 fc.string(),5 (s) => s.length > 20,6);7console.log(max);8const fc = require('fast-check');9const { maxGeneratedLength } = require('fast-check-monorepo');10const max = maxGeneratedLength(11 fc.string(),12 (s) => s.length > 20,13);14console.log(max);15const fc = require('fast-check');16const { maxGeneratedLength } = require('fast-check-monorepo');17const max = maxGeneratedLength(18 fc.string(),19 (s) => s.length > 20,20);21console.log(max);22const fc = require('fast-check');23const { maxGeneratedLength } = require('fast-check-monorepo');24const max = maxGeneratedLength(25 fc.string(),26 (s) => s.length > 20,27);28console.log(max);29const fc = require('fast-check');30const { maxGeneratedLength } = require('fast-check-monorepo');31const max = maxGeneratedLength(32 fc.string(),33 (s) => s.length > 20,34);35console.log(max);

Full Screen

Using AI Code Generation

copy

Full Screen

1const fc = require('fast-check');2 .stringOf(fc.ascii())3 .filter(s => s.length >= 10)4 .noShrink();5const maxGeneratedLength = myStringArb.maxGeneratedLength();6console.log(maxGeneratedLength);7const fc = require('fast-check');8 .stringOf(fc.ascii())9 .filter(s => s.length >= 10)10 .noShrink();11const maxDepth = myStringArb.maxDepth();12console.log(maxDepth);13const fc = require('fast-check');14 .stringOf(fc.ascii())15 .filter(s => s.length >= 10)16 .noShrink();17const maxSkipsPerRun = myStringArb.maxSkipsPerRun();18console.log(maxSkipsPerRun);

Full Screen

Using AI Code Generation

copy

Full Screen

1const fc = require('fast-check');2console.log(fc.maxGeneratedLength(fc.nat(), 5));3console.log(fc.maxGeneratedLength(fc.nat(), 10));4console.log(fc.maxGeneratedLength(fc.nat(), 15));5Recommended Posts: JavaScript | maxGeneratedLength() method of fast-check-monorepo6JavaScript | maxSkippedPerRun() method of fast-check-monorepo7JavaScript | maxRuns() method of fast-check-monorepo8JavaScript | maxShrinks() method of fast-check-monorepo9JavaScript | maxTime() method of fast-check-monorepo10JavaScript | maxDepth() method of fast-check-monorepo11JavaScript | maxLength() method of fast-check-monorepo12JavaScript | maxItems() me

Full Screen

Using AI Code Generation

copy

Full Screen

1const { maxGeneratedLength } = require("fast-check");2const { array } = require("fast-check");3const maxGeneratedLengthArray = maxGeneratedLength(array);4console.log(maxGeneratedLengthArray);5const maxGeneratedLengthArray2 = maxGeneratedLength(array, 2);6console.log(maxGeneratedLengthArray2);7const maxGeneratedLengthArray3 = maxGeneratedLength(array, 3);8console.log(maxGeneratedLengthArray3);9const maxGeneratedLengthArray4 = maxGeneratedLength(array, 4);10console.log(maxGeneratedLengthArray4);11const maxGeneratedLengthArray5 = maxGeneratedLength(array, 5);12console.log(maxGeneratedLengthArray5);13const maxGeneratedLengthArray6 = maxGeneratedLength(array, 6);14console.log(maxGeneratedLengthArray6);15const maxGeneratedLengthArray7 = maxGeneratedLength(array, 7);16console.log(maxGeneratedLengthArray7);17const maxGeneratedLengthArray8 = maxGeneratedLength(array, 8);18console.log(maxGeneratedLengthArray8);19const maxGeneratedLengthArray9 = maxGeneratedLength(array, 9);20console.log(maxGeneratedLengthArray9);21const maxGeneratedLengthArray10 = maxGeneratedLength(array, 10);22console.log(maxGeneratedLengthArray10);23const maxGeneratedLengthArray11 = maxGeneratedLength(array, 11);24console.log(maxGeneratedLengthArray11);25const maxGeneratedLengthArray12 = maxGeneratedLength(array, 12);26console.log(maxGeneratedLengthArray12);27const maxGeneratedLengthArray13 = maxGeneratedLength(array, 13);28console.log(maxGeneratedLengthArray13);29const maxGeneratedLengthArray14 = maxGeneratedLength(array, 14);30console.log(maxGeneratedLengthArray14);31const maxGeneratedLengthArray15 = maxGeneratedLength(array, 15);32console.log(maxGeneratedLengthArray15);

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run fast-check-monorepo automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful