From 2ff6948d197bd3e646432882c4e9c7a617af56c3 Mon Sep 17 00:00:00 2001 From: ealush Date: Mon, 6 Jul 2020 02:12:03 +0300 Subject: [PATCH] fix: outdated cache in done results --- packages/vest/src/core/produce/index.js | 6 +- packages/vest/src/core/produce/spec.js | 109 +++++++++++++----- .../vest/src/core/test/lib/VestTest/index.js | 1 - .../vest/src/core/test/runAsyncTest/index.js | 1 + 4 files changed, 85 insertions(+), 32 deletions(-) diff --git a/packages/vest/src/core/produce/index.js b/packages/vest/src/core/produce/index.js index b67be1fd9..3b9ad28e7 100644 --- a/packages/vest/src/core/produce/index.js +++ b/packages/vest/src/core/produce/index.js @@ -33,7 +33,11 @@ const done = (state, ...args) => { return output; } - const cb = () => callback(produce(state, { draft: true })); + // This won't be cached. Because we do not know where in the + // Lifecycle of our validations this produce will run, the test may be + // outdated and we might even not have a reference for it, so we're spreading + // to skip the cache. + const cb = () => callback(produce({ ...state }, { draft: true })); const isFinishedTest = fieldName && !hasRemainingTests(state, fieldName); const isSuiteFinished = !hasRemainingTests(state); const shouldRunCallback = isFinishedTest || isSuiteFinished; diff --git a/packages/vest/src/core/produce/spec.js b/packages/vest/src/core/produce/spec.js index 645055905..12740c7b5 100644 --- a/packages/vest/src/core/produce/spec.js +++ b/packages/vest/src/core/produce/spec.js @@ -727,36 +727,85 @@ runSpec(vest => { }); describe('produce cache (integragion)', () => { - const control = jest.fn(); - let draft, state; - const validate = vest.create('cache', () => { - draft = vest.draft(); - state = vest.get('cache'); - expect(draft).toBe(vest.draft()); - expect(state).toBe(vest.get('cache')); - testDummy(vest).failing(); - expect(state).not.toBe(vest.get('cache')); - expect(draft).not.toBe(vest.draft()); - testDummy(vest).failing(); - state = vest.get('cache'); - control(); - }); - - it('Should return same result as as long as the state did not change', () => { - let res = validate().done(result => { - expect(result).toBe(vest.get('cache')); - }); - expect(control).toHaveBeenCalledTimes(1); - expect(state).toBe(vest.get('cache')); - expect(res).not.toBe(draft); - expect(res).not.toBe(state); - expect(draft).not.toBe(vest.get('cache')); - res = validate().done(result => { - expect(result).toBe(vest.get('cache')); - }); - expect(res).not.toBe(draft); - expect(res).not.toBe(state); - expect(control).toHaveBeenCalledTimes(2); + describe('sync', () => { + const control = jest.fn(); + let draft, state; + const validate = vest.create('cache', () => { + draft = vest.draft(); + state = vest.get('cache'); + expect(draft).toBe(vest.draft()); + expect(state).toBe(vest.get('cache')); + testDummy(vest).failing(); + expect(state).not.toBe(vest.get('cache')); + expect(draft).not.toBe(vest.draft()); + testDummy(vest).failing(); + state = vest.get('cache'); + control(); + }); + + it('Should return same result as as long as the state did not change', () => { + let res = validate().done(result => { + // Done results are not cached. + // See produce / index for more info + expect(result).isDeepCopyOf(vest.get('cache')); + }); + expect(control).toHaveBeenCalledTimes(1); + expect(state).toBe(vest.get('cache')); + expect(res).not.toBe(draft); + expect(res).not.toBe(state); + expect(draft).not.toBe(vest.get('cache')); + res = validate().done(result => { + expect(result).isDeepCopyOf(vest.get('cache')); + }); + expect(res).not.toBe(draft); + expect(res).not.toBe(state); + expect(control).toHaveBeenCalledTimes(2); + }); + }); + + describe('Async', () => { + let result; + const validate = vest.create('cache-async', () => { + testDummy(vest).passing('field_1'); + testDummy(vest).failing('field_2'); + testDummy(vest).failingAsync('field_3'); + testDummy(vest).failingAsync('field_4', { time: 250 }); + }); + + it('Should produce correct validation result', () => { + result = validate(); + const control = jest.fn(); + return new Promise(done => { + expect(result.hasErrors('field_1')).toBe(false); + expect(result.hasErrors('field_2')).toBe(true); + expect(result.hasErrors('field_3')).toBe(false); + expect(result.hasErrors('field_4')).toBe(false); + + result.done('field_3', res => { + expect(res).isDeepCopyOf(vest.get('cache-async')); + expect(res).not.toBe(result); + expect(res).not.isDeepCopyOf(result); + expect(res.hasErrors('field_1')).toBe(false); + expect(res.hasErrors('field_2')).toBe(true); + expect(res.hasErrors('field_3')).toBe(true); + expect(res.hasErrors('field_4')).toBe(false); + control(); + }); + + result.done(res => { + expect(res.tests.field_4.errorCount).toBe(1); + expect(res).isDeepCopyOf(vest.get('cache-async')); + expect(res).not.toBe(result); + expect(res).not.isDeepCopyOf(result); + expect(res.hasErrors('field_1')).toBe(false); + expect(res.hasErrors('field_2')).toBe(true); + expect(res.hasErrors('field_3')).toBe(true); + expect(res.hasErrors('field_4')).toBe(true); + + done(); + }); + }); + }); }); }); }); diff --git a/packages/vest/src/core/test/lib/VestTest/index.js b/packages/vest/src/core/test/lib/VestTest/index.js index 014579f01..4c2ad784c 100644 --- a/packages/vest/src/core/test/lib/VestTest/index.js +++ b/packages/vest/src/core/test/lib/VestTest/index.js @@ -23,7 +23,6 @@ function VestTest({ suiteId, fieldName, statement, testFn, group }) { this.groupName = group; } } - /** * @returns {Boolean} Current validity status of a test. */ diff --git a/packages/vest/src/core/test/runAsyncTest/index.js b/packages/vest/src/core/test/runAsyncTest/index.js index b6ede4544..b48db6e9c 100644 --- a/packages/vest/src/core/test/runAsyncTest/index.js +++ b/packages/vest/src/core/test/runAsyncTest/index.js @@ -72,6 +72,7 @@ const runAsyncTest = testObject => { }; const fail = rejectionMessage => { done(() => { + const state = getSuiteState(suiteId); testObject.statement = typeof rejectionMessage === 'string' ? rejectionMessage : statement; testObject.fail();