/* eslint-disable @typescript-eslint/no-empty-function */ import { AutoVerifier } from '../../webapp/auto-verifier'; function sleep(ms: number): Promise { if (ms === 0) return; return new Promise(resolve => { setTimeout(resolve, ms); }); } // disjoint the current async function to allow other promises to be handled before the next lines are run async function disjoint() { await sleep(0); } type QueryablePromise = Promise & { isPending: () => boolean; isRejected: () => boolean; isFulfilled: () => boolean }; /** * this function allow you to modify a JS Promise by adding some status properties. * Based on: http://stackoverflow.com/questions/21485545/is-there-a-way-to-tell-if-an-es6-promise-is-fulfilled-rejected-resolved * But modified according to the specs of promises : https://promisesaplus.com/ */ function makeQuerablePromise(promise: Promise) { // set initial state let isPending = true; let isRejected = false; let isFulfilled = false; // observe the promise, saving the fulfillment in a closure scope. const result = promise.then( v => { isFulfilled = true; isPending = false; return v; }, e => { isRejected = true; isPending = false; throw e; }, ); // eslint-disable-next-line @typescript-eslint/no-explicit-any (result as any).isFulfilled = function () { return isFulfilled; }; // eslint-disable-next-line @typescript-eslint/no-explicit-any (result as any).isPending = function () { return isPending; }; // eslint-disable-next-line @typescript-eslint/no-explicit-any (result as any).isRejected = function () { return isRejected; }; return result as QueryablePromise; } class AutoVerifierTest { static createSimple(primaryResult: T, trustedResult: T): AutoVerifier { return new AutoVerifier( async () => primaryResult, async () => trustedResult, async (_primaryResult: T | null, _trustedResult: T | null) => true, ); } static createPromises( primaryResult: T | null, trustedResult: T | null, primaryDelay: number, trustedDelay: number, verifyDelay: number, primaryFail = false, trustedFail = false, ): { primaryPromise: QueryablePromise; // resolves BEFORE the function returns trustedPromise: QueryablePromise; // resolves BEFORE the function returns verifyPromise: QueryablePromise<{ primaryResult: T | null; trustedResult: T | null }>; // resolves AFTER function returns verifier: AutoVerifier; } { let primaryResolve = (value: T | null) => { /* */ }; let trustedResolve = (value: T | null) => { /* */ }; let verifyResolve = (value: { primaryResult: T | null; trustedResult: T | null }) => { /* */ }; const primaryPromise = new Promise((resolve, reject) => { primaryResolve = resolve; }); const trustedPromise = new Promise((resolve, reject) => { trustedResolve = resolve; }); const verifyPromise = new Promise<{ primaryResult: T | null; trustedResult: T | null }>(resolve => { verifyResolve = resolve; }); const verifier = new AutoVerifier( async () => { await sleep(primaryDelay); if (primaryFail) { primaryResolve(null); throw new Error('primary reject'); } else { const result = primaryResult; primaryResolve(result); await disjoint(); // if you need to know what this does you will not be happy :) return result; } }, async () => { await sleep(trustedDelay); if (trustedFail) { trustedResolve(null); throw new Error('trusted reject'); } else { const result = trustedResult; trustedResolve(result); await disjoint(); return result; } }, async (primaryResult: T | null, trustedResult: T | null) => { await sleep(verifyDelay); if (primaryResult !== null && trustedResult !== null && primaryResult !== trustedResult) verifier.unverify(); // auto-unverify if not equal (async () => { await disjoint(); verifyResolve({ primaryResult, trustedResult }); })(); }, ); return { primaryPromise: makeQuerablePromise(primaryPromise), trustedPromise: makeQuerablePromise(trustedPromise), verifyPromise: makeQuerablePromise(verifyPromise), verifier, }; } } describe('basic functionality', () => { test('basic functionality', async () => { const verifier = AutoVerifierTest.createSimple(2, 2); expect(verifier.trustedPromise === null); expect(verifier.trustedStatus === 'none'); const result = await verifier.fetchAndVerifyIfNeeded(); expect(result).toBe(2); }); }); describe('promise order tests', () => { test('normal verification', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15); expect(primaryPromise.isFulfilled()).toBe(false); expect(trustedPromise.isFulfilled()).toBe(false); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded()); expect(verifier.trustedPromise !== null); expect(verifier.trustedStatus === 'fetching'); const primaryResult = await primaryPromise; expect(primaryResult).toBe(2); expect(fetchPromise.isFulfilled()).toBe(false); expect(primaryPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('fetching'); await fetchPromise; expect(fetchPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const trustedResult = await trustedPromise; expect(trustedResult).toBe(2); expect(trustedPromise.isFulfilled()).toBe(true); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const verification = await verifyPromise; expect(verification.primaryResult).toBe(2); expect(verification.trustedResult).toBe(2); expect(verifyPromise.isFulfilled()).toBe(true); expect(verifier.trustedStatus).toBe('verified'); }); test('odd-ordered verification', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 65, 35, 15); expect(primaryPromise.isFulfilled()).toBe(false); expect(trustedPromise.isFulfilled()).toBe(false); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded()); expect(verifier.trustedPromise !== null); expect(verifier.trustedStatus === 'fetching'); const primaryResult = await primaryPromise; expect(primaryResult).toBe(2); expect(primaryPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(true); // since 65ms > 35ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('fetching'); await fetchPromise; expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const trustedResult = await trustedPromise; // note: this is already fulfilled expect(trustedResult).toBe(2); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const verification = await verifyPromise; expect(verification.primaryResult).toBe(2); expect(verification.trustedResult).toBe(2); expect(verifyPromise.isFulfilled()).toBe(true); expect(verifier.trustedStatus).toBe('verified'); }); test('normal trusted override', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 3, 35, 65, 15); expect(primaryPromise.isFulfilled()).toBe(false); expect(trustedPromise.isFulfilled()).toBe(false); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded()); expect(verifier.trustedPromise !== null); expect(verifier.trustedStatus === 'fetching'); const primaryResult = await primaryPromise; expect(primaryResult).toBe(null); expect(fetchPromise.isFulfilled()).toBe(false); expect(primaryPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('fetching'); const trustedResult = await trustedPromise; expect(trustedResult).toBe(3); expect(fetchPromise.isFulfilled()).toBe(false); expect(trustedPromise.isFulfilled()).toBe(true); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const verification = await verifyPromise; expect(verification.primaryResult).toBe(null); expect(verification.trustedResult).toBe(3); expect(fetchPromise.isFulfilled()).toBe(true); // since verifyPromise is called AFTER expect(verifyPromise.isFulfilled()).toBe(true); expect(verifier.trustedStatus).toBe('verified'); // does not get auto unverified const result = await fetchPromise; expect(result).toBe(3); }); test('normal invalidation', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 3, 35, 65, 15); expect(primaryPromise.isFulfilled()).toBe(false); expect(trustedPromise.isFulfilled()).toBe(false); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded()); expect(verifier.trustedPromise !== null); expect(verifier.trustedStatus === 'fetching'); const primaryResult = await primaryPromise; expect(primaryResult).toBe(2); expect(fetchPromise.isFulfilled()).toBe(false); expect(primaryPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('fetching'); await fetchPromise; expect(fetchPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const trustedResult = await trustedPromise; expect(trustedResult).toBe(3); expect(trustedPromise.isFulfilled()).toBe(true); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const verification = await verifyPromise; expect(verification.primaryResult).toBe(2); expect(verification.trustedResult).toBe(3); expect(verifyPromise.isFulfilled()).toBe(true); expect(verifier.trustedStatus).toBe('none'); // gets auto unverified }); test('odd-ordered invalidation', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 3, 65, 35, 15); expect(primaryPromise.isFulfilled()).toBe(false); expect(trustedPromise.isFulfilled()).toBe(false); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded()); expect(verifier.trustedPromise !== null); expect(verifier.trustedStatus === 'fetching'); const primaryResult = await primaryPromise; expect(primaryResult).toBe(2); expect(fetchPromise.isFulfilled()).toBe(false); expect(primaryPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(true); // since 65ms > 35ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('fetching'); await fetchPromise; expect(fetchPromise.isFulfilled()).toBe(true); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const trustedResult = await trustedPromise; // note: this is already fulfilled expect(trustedResult).toBe(3); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const verification = await verifyPromise; expect(verification.primaryResult).toBe(2); expect(verification.trustedResult).toBe(3); expect(verifyPromise.isFulfilled()).toBe(true); expect(verifier.trustedStatus).toBe('none'); // gets auto unverified }); test('normal unverification during primary func', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15); expect(primaryPromise.isFulfilled()).toBe(false); expect(trustedPromise.isFulfilled()).toBe(false); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded()); expect(verifier.trustedPromise !== null); expect(verifier.trustedStatus === 'fetching'); const primaryResult = await primaryPromise; expect(primaryResult).toBe(2); expect(fetchPromise.isFulfilled()).toBe(false); expect(primaryPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('fetching'); verifier.unverify(); // keep in mind this is still during the primary func since this is before we await the fetchPromise expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); await fetchPromise; expect(fetchPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const trustedResult = await trustedPromise; expect(trustedResult).toBe(2); expect(trustedPromise.isFulfilled()).toBe(true); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const verification = await verifyPromise; expect(verification.primaryResult).toBe(2); expect(verification.trustedResult).toBe(2); expect(verifyPromise.isFulfilled()).toBe(true); expect(verifier.trustedStatus).toBe('verified'); }); test('odd-ordered unverification during primary func', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 65, 35, 15); expect(primaryPromise.isFulfilled()).toBe(false); expect(trustedPromise.isFulfilled()).toBe(false); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded()); expect(verifier.trustedPromise !== null); expect(verifier.trustedStatus === 'fetching'); const primaryResult = await primaryPromise; expect(primaryResult).toBe(2); expect(fetchPromise.isFulfilled()).toBe(false); expect(primaryPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(true); // since 65ms > 35ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('fetching'); verifier.unverify(); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); await fetchPromise; expect(fetchPromise.isFulfilled()).toBe(true); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const trustedResult = await trustedPromise; // note: this is already fulfilled expect(trustedResult).toBe(2); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const verification = await verifyPromise; expect(verification.primaryResult).toBe(2); expect(verification.trustedResult).toBe(2); expect(verifyPromise.isFulfilled()).toBe(true); expect(verifier.trustedStatus).toBe('verified'); }); test('normal unverification during trusted func', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15); expect(primaryPromise.isFulfilled()).toBe(false); expect(trustedPromise.isFulfilled()).toBe(false); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded()); expect(verifier.trustedPromise !== null); expect(verifier.trustedStatus === 'fetching'); const primaryResult = await primaryPromise; expect(primaryResult).toBe(2); expect(fetchPromise.isFulfilled()).toBe(false); expect(primaryPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('fetching'); await fetchPromise; expect(fetchPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); verifier.unverify(); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); const trustedResult = await trustedPromise; expect(trustedResult).toBe(2); expect(trustedPromise.isFulfilled()).toBe(true); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('none'); // verification will not happen since the verifier.trustedPromise is null and we already returned }); test('normal unverification during primary func with trusted override', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 2, 35, 65, 15); expect(primaryPromise.isFulfilled()).toBe(false); expect(trustedPromise.isFulfilled()).toBe(false); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded()); expect(verifier.trustedPromise !== null); expect(verifier.trustedStatus === 'fetching'); const primaryResult = await primaryPromise; expect(primaryResult).toBe(null); expect(fetchPromise.isFulfilled()).toBe(false); expect(primaryPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('fetching'); verifier.unverify(); // keep in mind this is still during the primary func since this is before we await the fetchPromise expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); const trustedResult = await trustedPromise; expect(trustedResult).toBe(2); expect(fetchPromise.isFulfilled()).toBe(false); expect(trustedPromise.isFulfilled()).toBe(true); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('verifying'); const verification = await verifyPromise; expect(verification.primaryResult).toBe(null); expect(verification.trustedResult).toBe(2); expect(fetchPromise.isFulfilled()).toBe(true); // since verifyPromise occurs AFTER it returns expect(verifyPromise.isFulfilled()).toBe(true); expect(verifier.trustedStatus).toBe('verified'); const fetchResult = await fetchPromise; expect(fetchResult).toBe(2); expect(fetchPromise.isFulfilled()).toBe(true); }); test('normal unverification during trusted func with trusted override', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 2, 35, 65, 15); expect(primaryPromise.isFulfilled()).toBe(false); expect(trustedPromise.isFulfilled()).toBe(false); expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); const fetchPromise = makeQuerablePromise(verifier.fetchAndVerifyIfNeeded()); expect(verifier.trustedPromise !== null); expect(verifier.trustedStatus === 'fetching'); const primaryResult = await primaryPromise; expect(primaryResult).toBe(null); expect(fetchPromise.isFulfilled()).toBe(false); expect(primaryPromise.isFulfilled()).toBe(true); expect(trustedPromise.isFulfilled()).toBe(false); // since 35ms < 65ms expect(verifyPromise.isFulfilled()).toBe(false); expect(verifier.trustedStatus).toBe('fetching'); const trustedResult = await trustedPromise; expect(trustedResult).toBe(2); verifier.unverify(); // keep in mind this is still during the trusted func since this is before we await the fetchPromise expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); expect(fetchPromise.isFulfilled()).toBe(false); expect(trustedPromise.isFulfilled()).toBe(true); expect(verifyPromise.isFulfilled()).toBe(false); // this will resolve with null since we got unverified during the fetch const fetchResult = await fetchPromise; expect(fetchResult).toBe(null); expect(fetchPromise.isFulfilled()).toBe(true); }); }); describe('error tests', () => { test('primary error', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15, true, false); expect.assertions(3); try { await verifier.fetchAndVerifyIfNeeded(); } catch (e) { expect(e).toBeDefined(); } await primaryPromise; await trustedPromise; await disjoint(); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); }); test('trusted error thrown out', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15, false, true); await verifier.fetchAndVerifyIfNeeded(); await primaryPromise; await trustedPromise; await disjoint(); await disjoint(); // :D since trustedPromise happens BEFORE expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); }); test('trusted error considered since null primary result', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 2, 35, 65, 15, false, true); expect.assertions(3); try { await verifier.fetchAndVerifyIfNeeded(); } catch (e) { expect(e).toBeDefined(); } await primaryPromise; await trustedPromise; await disjoint(); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); }); test('both error only one exception', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 2, 35, 65, 15, true, true); expect.assertions(3); try { await verifier.fetchAndVerifyIfNeeded(); } catch (e) { expect(e).toBeDefined(); } await primaryPromise; await trustedPromise; await disjoint(); expect(verifier.trustedPromise).toBe(null); expect(verifier.trustedStatus).toBe('none'); }); }); describe('deduplication', () => { test('primary deduplication', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(2, 3, 35, 65, 15); await Promise.all([ (async () => { const fetchResult = await verifier.fetchAndVerifyIfNeeded(); expect(fetchResult).toBe(2); })(), (async () => { const fetchResult = await verifier.fetchAndVerifyIfNeeded(); expect(fetchResult).toBe(2); })(), ]); }); test('trusted deduplication', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 3, 35, 65, 15); await Promise.all([ (async () => { const fetchResult = await verifier.fetchAndVerifyIfNeeded(); expect(fetchResult).toBe(3); })(), (async () => { const fetchResult = await verifier.fetchAndVerifyIfNeeded(); expect(fetchResult).toBe(3); })(), ]); // doesn't really test it but it gets the code coverage B) }); test('trusted deduplication with unverification', async () => { const { primaryPromise, trustedPromise, verifyPromise, verifier } = AutoVerifierTest.createPromises(null, 3, 35, 65, 15); await Promise.all([ (async () => { const fetchPromise = verifier.fetchAndVerifyIfNeeded(); const fetchResult = await fetchPromise; expect(fetchResult).toBe(null); })(), (async () => { const fetchPromise = verifier.fetchAndVerifyIfNeeded(); await trustedPromise; verifier.unverify(); const fetchResult = await fetchPromise; expect(fetchResult).toBe(null); })(), ]); }); }); // TODO: changesFunc // TODO: Standard autoverifiers?