0

I am new to testing MobX stores in React with Jest. I have read this and this, but these posts are focused on testing components with the stores and not the stores themselves.

What would be the best approach for unit testing the stores in isolation with Jest?

My initial thought was instantiating the class (new EpochManager) and then calling the methods to change the state of the store, but a TypeError is thrown TypeError: _EpochManager.default is not a constructor. This probably shows my naivety with MobX.

For example, here is a store that I wish to unit test:

import { createContext } from 'react'
import UnirepContext from './Unirep'
import UserContext from './User'
import { makeAutoObservable } from 'mobx'

const unirepConfig = (UnirepContext as any)._currentValue
const userContext = (UserContext as any)._currentValue

class EpochManager {
    private timer: NodeJS.Timeout | null = null
    private currentEpoch = 0
    readonly nextTransition = 0
    readyToTransition = false

    constructor() {
        makeAutoObservable(this)
        if (typeof window !== 'undefined') {
            this.updateWatch()
        }
    }

    async updateWatch() {
        await unirepConfig.loadingPromise
        if (this.timer) {
            clearTimeout(this.timer)
            this.timer = null
        }
        this.readyToTransition = false
        this.currentEpoch = await unirepConfig.currentEpoch()
        // load the last transition time
        ;(this as any).nextTransition = await this._nextTransition()
        const waitTime = Math.max(this.nextTransition - +new Date(), 0)
        console.log(
            `Next epoch transition in ${waitTime / (60 * 60 * 1000)} hours`
        )
        this.timer = setTimeout(() => {
            this.timer = null
            this.tryTransition()
        }, waitTime) // if it's in the past make wait time 0
        return waitTime
    }

    private async _nextTransition() {
        await unirepConfig.loadingPromise
        const [lastTransition, epochLength] = await Promise.all([
            unirepConfig.unirep.latestEpochTransitionTime(),
            unirepConfig.epochLength,
        ])
        return (lastTransition.toNumber() + epochLength) * 1000
    }

    private async tryTransition() {
        // wait for someone to actually execute the epoch transition
        for (;;) {
            // wait for the epoch change to happen
            const newEpoch = await userContext.loadCurrentEpoch()
            if (newEpoch > this.currentEpoch) {
                // we're ready to transition,
                this.currentEpoch = newEpoch
                this.readyToTransition = true
                return
            }
            await new Promise((r) => setTimeout(r, 10000))
        }
    }
}

export default createContext(new EpochManager())
AAMCODE
  • 415
  • 1
  • 7
  • 20

1 Answers1

0

Have a named export for the EpochManager class:

export class EpochManager { ....

and when importing in test:

import { EpochManager } from '..context/EpochManager

Then, instantiate the class and do some testing.

AAMCODE
  • 415
  • 1
  • 7
  • 20