Skip to content

Commit

Permalink
Many nested factories (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
igorkamyshev authored Oct 24, 2023
1 parent 0c506eb commit 2308868
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/breezy-icons-collect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@withease/factories': patch
---

Fix false-positive exception in case of many nexted factories
68 changes: 68 additions & 0 deletions packages/factories/src/factories.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,72 @@ describe('nested factories', () => {

expect(() => invoke(externalFactory)).not.toThrowError();
});

test('valid many nested factories', () => {
const internalFactory = createFactory(() => {
return 1;
});

const externalFactory = createFactory(() => {
const internal2 = invoke(internalFactory);
const internal1 = invoke(internalFactory);
return { internal1, internal2 };
});

expect(() => invoke(externalFactory)).not.toThrowError();
});

test('invalid many nested factories', () => {
const internalFactory = createFactory(() => {
return 1;
});

const externalFactory = createFactory(() => {
const internal2 = invoke(internalFactory);
const internal1 = internalFactory();
return { internal1, internal2 };
});

expect(() => invoke(externalFactory)).toThrowErrorMatchingInlineSnapshot(
'"Do not call factory directly, pass it to invoke function instead"'
);
});

test('valid very many nested factories', () => {
const veryInternalFactory = createFactory(() => {
return 1;
});

const internalFactory = createFactory(() => {
return invoke(veryInternalFactory);
});

const externalFactory = createFactory(() => {
const internal2 = invoke(internalFactory);
const internal1 = invoke(internalFactory);
return { internal1, internal2 };
});

expect(() => invoke(externalFactory)).not.toThrowError();
});

test('invalid very many nested factories', () => {
const veryInternalFactory = createFactory(() => {
return 1;
});

const internalFactory = createFactory(() => {
return veryInternalFactory();
});

const externalFactory = createFactory(() => {
const internal2 = invoke(internalFactory);
const internal1 = invoke(internalFactory);
return { internal1, internal2 };
});

expect(() => invoke(externalFactory)).toThrowErrorMatchingInlineSnapshot(
'"Do not call factory directly, pass it to invoke function instead"'
);
});
});
9 changes: 4 additions & 5 deletions packages/factories/src/invoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { factoryCalledDirectly, invokeAcceptsOnlyFactories } from './errors';
* The following variables are used for checking that factory is called inside invoke function on correct nesting level
*/
export let invokeLevel = 0;
let invokeCount = 0;
let factoryCalledCount = 0;
let maxInvokeLevel = 0;

/**
* Have to be called inside factory created by createFactory
Expand All @@ -29,11 +29,10 @@ export function invoke<
>(factory: C, params?: P): OverloadReturn<P, OverloadUnion<C>> {
/* Increase invoke level before factory calling */
invokeLevel += 1;
invokeCount += 1;

const result = factory(params);

/* Save max invoke level for later checks */
maxInvokeLevel = Math.max(maxInvokeLevel, invokeLevel);
/* And descrese in after */
invokeLevel -= 1;

Expand All @@ -42,11 +41,11 @@ export function invoke<

if (invokeLevel === 0 /* Ending of nexted invoke calls */) {
haveToThrowErrorBecauseInvokeLevel /* Amount of invokes and factoies does not match */ =
factoryCalledCount !== maxInvokeLevel;
factoryCalledCount !== invokeCount;

/* Reset related variables */
factoryCalledCount = 0;
maxInvokeLevel = 0;
invokeCount = 0;
}

if (haveToThrowBecauseOfCalledFactory) {
Expand Down

0 comments on commit 2308868

Please sign in to comment.