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()
, thenconst i = comp.instance()
but this returnsnull
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.