mobxjs / mobx-react

React bindings for MobX

Home Page:https://mobx.js.org/react-integration.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to test a simple action in Jest and Enzyme

g-wozniak opened this issue · comments

Having a simple Locale store:
(works in real component)

import { observable, action } from 'mobx'
import { BaseMobxStore } from '../../../common/_base'
import { IKeyAny } from '../../../common/intf/IKeyAny'

class LocaleMobxStore extends BaseMobxStore {
  @observable translations: IKeyAny = {}
  @observable language: string

  // Add a translation
  @action public setTranslation(language: string, translation: IKeyAny): void {
    this.translations[language] = translation
  }

  // Set a default language to be used
  @action public setLanguage(language: string): void {
    if (this.translations.hasOwnProperty(language)) {
      this.language = language
    }
  }

  // Get a translation text if exists from nested JS object
  public text(key: string, subkey?: string): any {
    if (!this.language) {
      throw new Error('Unable to retrieve translation. Are you sure you filled the plugin with data?')
    }
    const char = '?'
    const sheet = this.translations[this.language]
    const hasKey = sheet.hasOwnProperty(key)
    if (hasKey && !subkey) {
      return sheet[key]
    }
    if (subkey && hasKey && sheet[key].hasOwnProperty(subkey)) {
      return sheet[key][subkey]
    } else if (subkey && hasKey && !sheet[key].hasOwnProperty(subkey)) {
      return char
    }
    return char
  }

}

and trying to test it in Enzyme / TS / React:

import * as React from 'react'
import { Provider, inject, observer } from 'mobx-react'
import LocaleMobx from '../modules/mobx'
import { mount } from 'enzyme'
import Languages from '../props/Languages'
import { IKeyAny } from '../../../common/intf/IKeyAny'

const lang1: IKeyAny = {
  foo: 'text',
  bar: 'sample',
  nested: {
    example: 'great'
  }
}

const lang2: IKeyAny = {
  foo: 'other',
  bar: 'test'
}

const locale = new LocaleMobx()
locale.setTranslation(Languages.english, lang1)
locale.setTranslation(Languages.polish, lang2)
locale.setLanguage(Languages.english)

const Container = (props: any): JSX.Element => {
  const store = { locale }
  return <Provider {...store}>{props.children}</Provider>
}

@observer
@inject('locale')
class SwitchTranslation extends React.Component<any, {}> {
  public componentDidMount(): void {
    this.props.locale.setLanguage(Languages.polish)
  }
  public render(): JSX.Element {
    const l = this.props.locale as LocaleMobx
    return <div>{l.text('bar')}</div>
  }
}

describe('React component', () => {
  it('returns a correctly translated text based on a language set', () => {
    const comp = mount(<Container><SwitchTranslation /></Container>)
    console.log(comp.debug())
    // instance.componentDidMount()
    // expect(comp.find('div').text()).toEqual(lang2.bar)
  })
})

It works properly if I want just to render component but my goal here is to use setLanguage method to change the default language to a different value.

Ideally, I'd like to test if div.test is lang1.bar before mount and lang2.bar after mount.

I tried the approach with:

  • shallow(), then const i = comp.instance() but this returns null
  • shallow().dive() - didn't help
  • inject store directly as per #176 but I didn't manage to get this work due to TS error, also I think it makes code looks complicated and I'd like to try something more clear

What would be best approach to test this scenario? How would you approach to it?

Note: I've replaced @observable (ofc!) with @observer. I am seeing Mobx observer: You are trying to use 'observer' on a component that already has 'inject'. Please apply 'observer' before applying 'inject' warning regardless the fact @observer is added before inject.

Ok, I resolved it. The problem was in placement of the @observer which is fairly pointed out by warning. I missed the obvious, that decorator "closer" to element (class/component) is the one applied earlier. Once I switched their places it started to show the right value.