Skip to content

Commit

Permalink
Cache useHasPending Call
Browse files Browse the repository at this point in the history
  • Loading branch information
ealush committed Jul 20, 2024
1 parent 3bf3942 commit 002ee3e
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 37 deletions.
18 changes: 16 additions & 2 deletions packages/vest/src/core/Runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
seq,
tinyState,
} from 'vest-utils';
import { IRecociler, VestRuntime } from 'vestjs-runtime';
import { IRecociler, TIsolate, VestRuntime } from 'vestjs-runtime';

import { TIsolateSuite } from 'IsolateSuite';
import {
Expand All @@ -27,8 +27,10 @@ type StateExtra = {
suiteName: Maybe<string>;
suiteId: string;
suiteResultCache: CacheApi<SuiteResult<TFieldName, TGroupName>>;
pendingCache: CacheApi<TIsolate[]>;
};
const suiteResultCache = cache<SuiteResult<TFieldName, TGroupName>>();
const pendingCache = cache<TIsolate[]>();

export function useCreateVestState({
suiteName,
Expand All @@ -40,6 +42,7 @@ export function useCreateVestState({
const stateRef: StateExtra = {
doneCallbacks: tinyState.createTinyState<DoneCallbacks>(() => []),
fieldCallbacks: tinyState.createTinyState<FieldCallbacks>(() => ({})),
pendingCache,
suiteId: seq(),
suiteName,
suiteResultCache,
Expand Down Expand Up @@ -69,16 +72,27 @@ export function useSuiteId() {
}

export function useSuiteResultCache<F extends TFieldName, G extends TGroupName>(
action: CB<SuiteResult<F, G>>
action: CB<SuiteResult<F, G>>,
): SuiteResult<F, G> {
const suiteResultCache = useX().suiteResultCache;

return suiteResultCache([useSuiteId()], action) as SuiteResult<F, G>;
}

export function usePendingCache(action: CB<TIsolate[]>) {
const pendingCache = useX().pendingCache;

return pendingCache([useSuiteId()], action);
}

export function useExpireSuiteResultCache() {
const suiteResultCache = useX().suiteResultCache;
suiteResultCache.invalidate([useSuiteId()]);

// whenever we invalidate the entire result, we also want to invalidate the pending cache
// so that we do not get stale results there.
// there may be a better place to do this, but for now, this should work.
pendingCache.invalidate([useSuiteId()]);
}

export function useResetCallbacks() {
Expand Down
4 changes: 2 additions & 2 deletions packages/vest/src/core/VestBus/VestBus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export function useInitVestBus() {
}
}

if (!SuiteWalker.hasPending()) {
if (!SuiteWalker.useHasPending()) {
// When no more async tests are running, emit the done event
VestBus.emit(Events.ALL_RUNNING_TESTS_FINISHED);
}
Expand Down Expand Up @@ -84,7 +84,7 @@ export function useInitVestBus() {
});

on(Events.SUITE_CALLBACK_RUN_FINISHED, () => {
if (!SuiteWalker.hasPending()) {
if (!SuiteWalker.useHasPending()) {
// When no more async tests are running, emit the done event
VestBus.emit(Events.ALL_RUNNING_TESTS_FINISHED);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import wait from 'wait';
import { SuiteWalker } from 'SuiteWalker';
import * as vest from 'vest';

describe('SuiteWalker.hasRemainingWithTestNameMatching', () => {
describe('SuiteWalker.useHasRemainingWithTestNameMatching', () => {
let hasRemaining: boolean | null = null;
let count = 0;

Expand All @@ -15,7 +15,7 @@ describe('SuiteWalker.hasRemainingWithTestNameMatching', () => {
describe('When no remaining tests', () => {
it('should return false', () => {
vest.create(() => {
hasRemaining = SuiteWalker.hasRemainingWithTestNameMatching();
hasRemaining = SuiteWalker.useHasRemainingWithTestNameMatching();
})();
expect(hasRemaining).toBe(false);
});
Expand All @@ -27,7 +27,7 @@ describe('SuiteWalker.hasRemainingWithTestNameMatching', () => {
vest.test('f1', async () => {
await wait(100);
});
hasRemaining = SuiteWalker.hasRemainingWithTestNameMatching();
hasRemaining = SuiteWalker.useHasRemainingWithTestNameMatching();
})();

expect(hasRemaining).toBe(true);
Expand All @@ -40,7 +40,7 @@ describe('SuiteWalker.hasRemainingWithTestNameMatching', () => {
await wait(100);
});
count++;
hasRemaining = SuiteWalker.hasRemainingWithTestNameMatching();
hasRemaining = SuiteWalker.useHasRemainingWithTestNameMatching();
});
suite();
suite();
Expand All @@ -58,7 +58,7 @@ describe('SuiteWalker.hasRemainingWithTestNameMatching', () => {
await wait(100);
});
count++;
hasRemaining = SuiteWalker.hasRemainingWithTestNameMatching();
hasRemaining = SuiteWalker.useHasRemainingWithTestNameMatching();
});

suite();
Expand All @@ -73,7 +73,7 @@ describe('SuiteWalker.hasRemainingWithTestNameMatching', () => {
describe('When no remaining tests', () => {
it('Should return false', () => {
vest.create(() => {
hasRemaining = SuiteWalker.hasRemainingWithTestNameMatching('f1');
hasRemaining = SuiteWalker.useHasRemainingWithTestNameMatching('f1');
})();
expect(hasRemaining).toBe(false);
});
Expand All @@ -85,7 +85,7 @@ describe('SuiteWalker.hasRemainingWithTestNameMatching', () => {
vest.test('f1', async () => {
await wait(100);
});
hasRemaining = SuiteWalker.hasRemainingWithTestNameMatching('f1');
hasRemaining = SuiteWalker.useHasRemainingWithTestNameMatching('f1');
})();
expect(hasRemaining).toBe(true);
});
Expand All @@ -97,7 +97,7 @@ describe('SuiteWalker.hasRemainingWithTestNameMatching', () => {
await wait(100);
});
count++;
hasRemaining = SuiteWalker.hasRemainingWithTestNameMatching('f1');
hasRemaining = SuiteWalker.useHasRemainingWithTestNameMatching('f1');
});
suite();
suite();
Expand All @@ -116,8 +116,8 @@ describe('SuiteWalker.hasRemainingWithTestNameMatching', () => {
});
count++;
hasRemaining =
SuiteWalker.hasRemainingWithTestNameMatching('f1') &&
SuiteWalker.hasRemainingWithTestNameMatching('f2');
SuiteWalker.useHasRemainingWithTestNameMatching('f1') &&
SuiteWalker.useHasRemainingWithTestNameMatching('f2');
});

suite();
Expand Down
36 changes: 25 additions & 11 deletions packages/vest/src/suite/SuiteWalker.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Predicate, Predicates, isNullish } from 'vest-utils';
import { VestRuntime, Walker } from 'vestjs-runtime';
import { TIsolate, VestRuntime, Walker } from 'vestjs-runtime';

import { TIsolateTest } from 'IsolateTest';
import { usePendingCache } from 'Runtime';
import { TFieldName } from 'SuiteResultTypes';
import { VestIsolate } from 'VestIsolate';
import { VestTest } from 'VestTest';
Expand All @@ -10,32 +11,45 @@ import { matchesOrHasNoFieldName } from 'matchingFieldName';
export class SuiteWalker {
static defaultRoot = VestRuntime.useAvailableRoot;

static hasPending(predicate?: Predicate): boolean {
static useHasPending(predicate?: Predicate): boolean {
const root = SuiteWalker.defaultRoot();

if (!root) {
return false;
}

return Walker.some(
root,
Predicates.all(VestIsolate.isPending, predicate ?? true)
);
const allPending = usePendingCache(this.findAllPending);

if (!allPending.length) {
return false;
}

return allPending.some(Predicates.all(predicate ?? true));
}

static findAllPending(): TIsolate[] {
const root = SuiteWalker.defaultRoot();

if (!root) {
return [];
}

return Walker.findAll(root, VestIsolate.isPending);
}

// Checks whether there are pending isolates in the tree.
// If a fieldname is provided, will only check tests with a matching fieldname.
static hasRemainingWithTestNameMatching(fieldName?: TFieldName): boolean {
return SuiteWalker.hasPending(
static useHasRemainingWithTestNameMatching(fieldName?: TFieldName): boolean {
return SuiteWalker.useHasPending(
Predicates.any(
isNullish(fieldName),
Predicates.all(VestTest.is, (testObject: TIsolateTest) => {
return matchesOrHasNoFieldName(
VestTest.getData(testObject),
fieldName
fieldName,
);
})
)
}),
),
);
}
}
2 changes: 1 addition & 1 deletion packages/vest/src/suite/runCallbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function useRunFieldCallbacks(fieldName?: TFieldName): void {

if (
fieldName &&
!SuiteWalker.hasRemainingWithTestNameMatching(fieldName) &&
!SuiteWalker.useHasRemainingWithTestNameMatching(fieldName) &&
isArray(fieldCallbacks[fieldName])
) {
callEach(fieldCallbacks[fieldName]);
Expand Down
20 changes: 10 additions & 10 deletions packages/vest/src/suiteResult/selectors/shouldAddValidProperty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export function useShouldAddValidProperty(fieldName?: TFieldName): boolean {

export function useShouldAddValidPropertyInGroup(
groupName: TGroupName,
fieldName: TFieldName
fieldName: TFieldName,
): boolean {
if (useIsOptionalFieldApplied(fieldName)) {
return true;
Expand All @@ -64,30 +64,30 @@ export function useShouldAddValidPropertyInGroup(

// Does the given field have any pending tests that are not optional?
function useHasNonOptionalIncomplete(fieldName?: TFieldName) {
return SuiteWalker.hasPending(
return SuiteWalker.useHasPending(
Predicates.all(
VestTest.is,
(testObject: TIsolateTest) =>
!nonMatchingFieldName(VestTest.getData(testObject), fieldName),
() => !useIsOptionalFieldApplied(fieldName)
)
() => !useIsOptionalFieldApplied(fieldName),
),
);
}

// Do the given group/field have any pending tests that are not optional?
function useHasNonOptionalIncompleteByGroup(
groupName: TGroupName,
fieldName: TFieldName
fieldName: TFieldName,
): boolean {
return SuiteWalker.hasPending(
return SuiteWalker.useHasPending(
Predicates.all(
VestTest.is,
(testObject: TIsolateTest) =>
!nonMatchingGroupName(testObject, groupName),
(testObject: TIsolateTest) =>
!nonMatchingFieldName(VestTest.getData(testObject), fieldName),
() => !useIsOptionalFieldApplied(fieldName)
)
() => !useIsOptionalFieldApplied(fieldName),
),
);
}

Expand All @@ -102,7 +102,7 @@ function useNoMissingTests(fieldName?: string): boolean {
// Does the group have no missing tests?
function useNoMissingTestsByGroup(
groupName: TGroupName,
fieldName?: TFieldName
fieldName?: TFieldName,
): boolean {
return TestWalker.everyTest(testObject => {
if (nonMatchingGroupName(testObject, groupName)) {
Expand All @@ -115,7 +115,7 @@ function useNoMissingTestsByGroup(

function useNoMissingTestsLogic(
testObject: TIsolateTest,
fieldName?: TFieldName
fieldName?: TFieldName,
): boolean {
if (nonMatchingFieldName(VestTest.getData(testObject), fieldName)) {
return true;
Expand Down
2 changes: 1 addition & 1 deletion packages/vest/src/suiteResult/suiteRunResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ function done<F extends TFieldName, G extends TGroupName>(
return output;
}
const useDoneCallback = () => callback(useCreateSuiteResult());
if (!SuiteWalker.hasRemainingWithTestNameMatching(fieldName)) {
if (!SuiteWalker.useHasRemainingWithTestNameMatching(fieldName)) {
useDoneCallback();
return output;
}
Expand Down

0 comments on commit 002ee3e

Please sign in to comment.