From ed6866547890ebf57c44a5dfdbbdc2cfcf8c217f Mon Sep 17 00:00:00 2001 From: Raine Revere Date: Sat, 1 Aug 2020 18:04:24 -0600 Subject: [PATCH] Fix db.test. - Fake timers cause an infinite loop on _.debounce. - Jest v26 contains a 'modern' option for useFakeTimers, but create-react-app uses an older version of jest https://github.com/facebook/jest/issues/3465#issuecomment-504908570 - Mock debounce - Test fails without a dummy call to the database. Why? --- src/action-creators/loadLocalState.js | 5 +-- src/db.test.js | 61 ++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/action-creators/loadLocalState.js b/src/action-creators/loadLocalState.js index f43e9b30079..87b9b4e977e 100644 --- a/src/action-creators/loadLocalState.js +++ b/src/action-creators/loadLocalState.js @@ -7,15 +7,12 @@ import { never } from '../util' /** Loads the local state from the IndexedDB database. */ const loadLocalState = () => async (dispatch, getState) => { - // TODO: Fix IndexedDB during tests - const test = process.env.NODE_ENV === 'test' - // load helpers and settings from local database const [{ cursor: localUrl, lastUpdated, recentlyEdited, - }, settings] = test ? [{}] : await Promise.all([ + }, settings] = await Promise.all([ db.getHelpers(), db.getContext([EM_TOKEN, 'Settings']) ]) diff --git a/src/db.test.js b/src/db.test.js index af87f0c8e3f..cd7cfbdcce2 100644 --- a/src/db.test.js +++ b/src/db.test.js @@ -1,23 +1,72 @@ import { store } from './store' import * as db from './data-providers/dexie' import { initialize } from './initialize' -import { hashThought } from './util' import { getThought } from './selectors' +// mock debounce to use 0 delay +jest.mock('lodash', () => ({ + ...jest.requireActual('lodash'), + + // jest.mock must be inline + // possible workarounds: https://stackoverflow.com/questions/40465047/how-can-i-mock-an-es6-module-import-using-jest + debounce: jest.fn().mockImplementation((callback, delay) => { + let timer = null + let pendingArgs = null + + const cancel = jest.fn(() => { + if (timer) { + clearTimeout(timer) + } + timer = null + pendingArgs = null + }) + + const flush = jest.fn(() => { + if (timer) { + callback(...pendingArgs) + cancel() + } + }) + + const wrapped = (...args) => { + cancel() + + pendingArgs = args + + // TODO: why doesn't jest.runAllTimers work here? + // use 0 instead of given delay as a workaround + timer = setTimeout(flush, 0) + } + + wrapped.cancel = cancel + wrapped.flush = flush + wrapped.delay = delay + + return wrapped + }), +})) + + beforeAll(async () => { await initialize() -}) -// TODO: Make pass with iterative loading -it.skip('load settings into indexedDB on initialization', async () => { - const hash = hashThought('Settings') + // fake timers cause an infinite loop on _.debounce + // Jest v26 contains a 'modern' option for useFakeTimers, but create-react-app uses an older version of jest + // https://github.com/facebook/jest/issues/3465#issuecomment-504908570 + jest.useFakeTimers() + jest.runAllTimers() +}) +it('load settings into indexedDB on initialization', async () => { const thoughtState = getThought(store.getState(), 'Settings') expect(thoughtState).not.toBeUndefined() expect(thoughtState.contexts).toHaveLength(1) - const thoughtDB = await db.getThought(hash) + // TODO: Tests fail without a dummy call to the database. Why? + await db.getHelpers() + + const thoughtDB = await db.getThought('Settings') expect(thoughtDB).not.toBeUndefined() expect(thoughtDB.contexts).toHaveLength(1)