gopeeker 0.1.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of gopeeker might be problematic. Click here for more details.

@@ -0,0 +1,111 @@
1
+ import { act } from '@testing-library/react-hooks'
2
+ import { createStore } from '../src/index'
3
+ import { counter } from './helper/model'
4
+ import { createHook } from './helper/createHook'
5
+
6
+ describe('getState test', () => {
7
+ it('call getState with no parameter should return all model state', () => {
8
+ const store = createStore({
9
+ counter,
10
+ })
11
+ const { Provider, useModel } = store
12
+
13
+ const { result } = createHook(Provider, useModel, 'counter')
14
+
15
+ const increase = result.current.reducers.increase
16
+ const decrease = result.current.reducers.decrease
17
+
18
+ expect(store.getState()).toEqual({
19
+ counter: {
20
+ count: 0,
21
+ data: {
22
+ a: 1,
23
+ b: '2',
24
+ },
25
+ },
26
+ })
27
+
28
+ act(() => {
29
+ increase()
30
+ })
31
+ expect(result.current.state.count).toBe(1)
32
+
33
+ expect(store.getState()).toEqual({
34
+ counter: {
35
+ count: 1,
36
+ data: {
37
+ a: 1,
38
+ b: '2',
39
+ },
40
+ },
41
+ })
42
+
43
+ act(() => {
44
+ decrease()
45
+ })
46
+ expect(store.getState()).toEqual({
47
+ counter: {
48
+ count: 0,
49
+ data: {
50
+ a: 1,
51
+ b: '2',
52
+ },
53
+ },
54
+ })
55
+ })
56
+
57
+ it('call getState with parameter should return specific model state', () => {
58
+ const store = createStore({
59
+ counter,
60
+ })
61
+ const { Provider, useModel } = store
62
+
63
+ const { result } = createHook(Provider, useModel, 'counter')
64
+
65
+ const increase = result.current.reducers.increase
66
+ const decrease = result.current.reducers.decrease
67
+
68
+ expect(store.getState('counter')).toEqual({
69
+ count: 0,
70
+ data: {
71
+ a: 1,
72
+ b: '2',
73
+ },
74
+ })
75
+
76
+ act(() => {
77
+ increase()
78
+ })
79
+ expect(result.current.state.count).toBe(1)
80
+
81
+ expect(store.getState('counter')).toEqual({
82
+ count: 1,
83
+ data: {
84
+ a: 1,
85
+ b: '2',
86
+ },
87
+ })
88
+
89
+ act(() => {
90
+ decrease()
91
+ })
92
+ expect(store.getState('counter')).toEqual({
93
+ count: 0,
94
+ data: {
95
+ a: 1,
96
+ b: '2',
97
+ },
98
+ })
99
+ })
100
+
101
+ it('call getState with not exist parameter should throw error', () => {
102
+ const store = createStore({
103
+ counter,
104
+ })
105
+
106
+ // @ts-ignore
107
+ expect(() => store.getState('counter1')).toThrow(
108
+ 'Invariant Failed: [store.getState] Expected the modelName to be one of counter, but got counter1'
109
+ )
110
+ })
111
+ })
@@ -0,0 +1,23 @@
1
+ import React from 'react'
2
+ import { RootModel } from './store'
3
+
4
+ interface CounterProps {
5
+ state: RootModel['counter']['state']
6
+ reducers: RootModel['counter']['reducers']
7
+ effects: RootModel['counter']['effects']
8
+ }
9
+
10
+ export class Counter extends React.Component<CounterProps> {
11
+ render() {
12
+ const { state, reducers, effects } = this.props
13
+
14
+ return (
15
+ <div>
16
+ <div data-testid="count">{state.count}</div>
17
+ <div data-testid="increase" onClick={reducers.increase} />
18
+ <div data-testid="decrease" onClick={reducers.decrease} />
19
+ <div data-testid="increaseAsync" onClick={effects.increaseAsync} />
20
+ </div>
21
+ )
22
+ }
23
+ }
@@ -0,0 +1,56 @@
1
+ import React, { useImperativeHandle } from 'react'
2
+ import { store } from './store'
3
+
4
+ export interface CounterProps {
5
+ onRender?: () => void
6
+ }
7
+
8
+ export const Counter: React.FC<CounterProps> = ({ onRender }) => {
9
+ const { state, reducers, effects } = store.useModel('counter')
10
+
11
+ if (onRender) {
12
+ onRender()
13
+ }
14
+
15
+ if (effects.increaseAsync.loading) {
16
+ return <div>Loading ...</div>
17
+ }
18
+
19
+ return (
20
+ <div>
21
+ <div data-testid="count">{state.count}</div>
22
+ <div data-testid="increase" onClick={reducers.increase} />
23
+ <div data-testid="decrease" onClick={reducers.decrease} />
24
+ <div data-testid="increaseAsync" onClick={effects.increaseAsync} />
25
+ </div>
26
+ )
27
+ }
28
+
29
+ export const Counter1: React.FC<CounterProps> = ({ onRender }) => {
30
+ const { state, reducers, effects } = store.useModel('counter')
31
+
32
+ if (onRender) {
33
+ onRender()
34
+ }
35
+
36
+ return (
37
+ <div>
38
+ <div data-testid="count1">{state.count}</div>
39
+ <div data-testid="increase1" onClick={reducers.increase} />
40
+ <div data-testid="decrease1" onClick={reducers.decrease} />
41
+ <div data-testid="increaseAsync1" onClick={effects.increaseAsync} />
42
+ </div>
43
+ )
44
+ }
45
+
46
+ export const CounterWithRef = store.withProviderForwardRef<any>(
47
+ React.forwardRef((props, ref) => {
48
+ useImperativeHandle(ref, () => {
49
+ return {
50
+ methodFromUseImperativeHandle: () => true,
51
+ }
52
+ })
53
+
54
+ return <></>
55
+ })
56
+ )
@@ -0,0 +1,77 @@
1
+ import React from 'react'
2
+ import { RootModel } from './store'
3
+
4
+ interface CounterProps {
5
+ [c: string]: RootModel
6
+ }
7
+
8
+ export class CounterWithContextName extends React.Component<CounterProps> {
9
+ render() {
10
+ const {
11
+ forDobux: {
12
+ counter,
13
+ counter2
14
+ }
15
+ } = this.props
16
+
17
+ return (
18
+ <div>
19
+ <div data-testid="count-1">{counter.state.count}</div>
20
+ <div data-testid="increase-1" onClick={counter.reducers.increase} />
21
+ <div data-testid="decrease-1" onClick={counter.reducers.decrease} />
22
+ <div data-testid="increaseAsync-1" onClick={counter.effects.increaseAsync} />
23
+
24
+ <div data-testid="count-2">{counter2.state.count}</div>
25
+ <div data-testid="increase-2" onClick={counter2.reducers.increase} />
26
+ <div data-testid="decrease-2" onClick={counter2.reducers.decrease} />
27
+ <div data-testid="increaseAsync-2" onClick={counter2.effects.increaseAsync} />
28
+ </div>
29
+ )
30
+ }
31
+ }
32
+
33
+ export class CounterWithDefault extends React.Component<CounterProps> {
34
+ render() {
35
+ const {
36
+ models: {
37
+ counter,
38
+ counter2
39
+ }
40
+ } = this.props
41
+
42
+ return (
43
+ <div>
44
+ <div data-testid="count-1">{counter.state.count}</div>
45
+ <div data-testid="increase-1" onClick={counter.reducers.increase} />
46
+ <div data-testid="decrease-1" onClick={counter.reducers.decrease} />
47
+ <div data-testid="increaseAsync-1" onClick={counter.effects.increaseAsync} />
48
+
49
+ <div data-testid="count-2">{counter2.state.count}</div>
50
+ <div data-testid="increase-2" onClick={counter2.reducers.increase} />
51
+ <div data-testid="decrease-2" onClick={counter2.reducers.decrease} />
52
+ <div data-testid="increaseAsync-2" onClick={counter2.effects.increaseAsync} />
53
+ </div>
54
+ )
55
+ }
56
+ }
57
+
58
+ export class CounterWithSameContextName extends React.Component<{
59
+ models: string,
60
+ myModel: any
61
+ }> {
62
+ render() {
63
+ return <div data-testid="show-models">{this.props.models}</div>
64
+ }
65
+ }
66
+
67
+ export class CounterWithOtherContextName extends React.Component<{
68
+ myProp: string,
69
+ myModel: any
70
+ }> {
71
+ render() {
72
+ return <div>
73
+ <div data-testid="show-myProp">{this.props.myProp}</div>
74
+ <div data-testid="show-myModel">{this.props.myModel.state.count}</div>
75
+ </div>
76
+ }
77
+ }
@@ -0,0 +1,15 @@
1
+ import React from 'react'
2
+ import { renderHook } from '@testing-library/react-hooks'
3
+ import { MapStateToModel } from '../../src/types'
4
+
5
+ export function createHook(
6
+ Provider: React.FC,
7
+ hook: any,
8
+ namespace?: string,
9
+ mapStateToModel?: MapStateToModel<any>
10
+ ) {
11
+ // https://react-hooks-testing-library.com/usage/advanced-hooks#context
12
+ return renderHook(() => hook(namespace, mapStateToModel), {
13
+ wrapper: props => <Provider {...props}>{props.children}</Provider>,
14
+ })
15
+ }
@@ -0,0 +1,7 @@
1
+ import { createModel } from '../../src'
2
+ import { RootModel } from './store'
3
+ import { config } from './shared'
4
+
5
+ export const counter = createModel<RootModel, 'counter'>()(config)
6
+
7
+ export const counter2 = createModel<RootModel, 'counter2'>()(config)
@@ -0,0 +1,15 @@
1
+ export const unsafeGetTestingRef = (tree, component) => {
2
+ // Unsafe way to get access to a ref property. Uses internal _fiber property of a ReactTestingInstance since AFAIK react-test-renderer does not expose refs in any other way
3
+ const node = tree.root.findByType(component)
4
+
5
+ expect(node).not.toBeNull()
6
+ expect(node._fiber).not.toBeNull()
7
+ expect(node._fiber).not.toBeUndefined()
8
+
9
+ const ref = node._fiber.ref
10
+
11
+ expect(ref).not.toBeNull()
12
+ expect(ref).not.toBeUndefined()
13
+
14
+ return ref
15
+ }
@@ -0,0 +1,58 @@
1
+ export function wait(ms: number) {
2
+ return new Promise(resolve => {
3
+ setTimeout(resolve, ms)
4
+ })
5
+ }
6
+
7
+ export const defaultStoreOptions = {
8
+ autoReset: false,
9
+ devtools: true,
10
+ name: 'dobuxStore',
11
+ }
12
+
13
+ export const config = {
14
+ state: {
15
+ count: 0,
16
+ data: {
17
+ a: 1,
18
+ b: '2',
19
+ },
20
+ },
21
+ reducers: {
22
+ increase(state: any) {
23
+ state.count++
24
+ },
25
+ decrease(state: any) {
26
+ state.count--
27
+ },
28
+ },
29
+ effects: (store: any, rootStore: any) => ({
30
+ async increaseAsync() {
31
+ await wait(10)
32
+ store.reducers.increase()
33
+ },
34
+
35
+ async decreaseAsync() {
36
+ await wait(10)
37
+ store.reducers.decrease()
38
+ },
39
+
40
+ async fetchError() {
41
+ return new Promise((_, reject) => {
42
+ reject('customer error')
43
+ })
44
+ },
45
+ }),
46
+ }
47
+
48
+ export const defaultModelOptions = {
49
+ storeName: 'dobuxStore',
50
+ name: 'counter',
51
+ config: {
52
+ ...config,
53
+ effects: {},
54
+ },
55
+ rootModel: Object.create(null),
56
+ autoReset: false,
57
+ devTools: true,
58
+ }
@@ -0,0 +1,6 @@
1
+ import { createStore, Models } from '../../src'
2
+ import * as models from './model'
3
+
4
+ export type RootModel = Models<typeof models>
5
+
6
+ export const store = createStore({ ...models })
@@ -0,0 +1,88 @@
1
+ import { createStore, createModel } from '../src'
2
+ import { Store } from '../src/core/Store'
3
+ import { config, defaultStoreOptions } from './helper/shared'
4
+
5
+ describe('entry test', () => {
6
+ it('createStore should be defined', () => {
7
+ expect(createStore).toBeDefined()
8
+ })
9
+
10
+ it('should return the instance of Store when call createStore', () => {
11
+ const store = createStore(
12
+ {
13
+ counter: config,
14
+ },
15
+ defaultStoreOptions
16
+ )
17
+
18
+ expect(store).toBeInstanceOf(Store)
19
+ })
20
+
21
+ it('should pass boolean to autoReset', () => {
22
+ const store = createStore(
23
+ {
24
+ counter: config,
25
+ },
26
+ {
27
+ autoReset: true,
28
+ }
29
+ )
30
+
31
+ expect(store).toBeInstanceOf(Store)
32
+ })
33
+
34
+ it('should pass array to autoReset', () => {
35
+ const store = createStore(
36
+ {
37
+ counter: config,
38
+ },
39
+ {
40
+ autoReset: ['counter'],
41
+ }
42
+ )
43
+
44
+ expect(store).toBeInstanceOf(Store)
45
+ })
46
+
47
+ it('should pass boolean to devtools', () => {
48
+ const store = createStore(
49
+ {
50
+ counter: config,
51
+ },
52
+ {
53
+ devtools: true,
54
+ }
55
+ )
56
+
57
+ expect(store).toBeInstanceOf(Store)
58
+ })
59
+
60
+ it('should pass array to devtools', () => {
61
+ const store = createStore(
62
+ {
63
+ counter: config,
64
+ },
65
+ {
66
+ devtools: ['counter'],
67
+ }
68
+ )
69
+
70
+ expect(store).toBeInstanceOf(Store)
71
+ })
72
+
73
+ it('createModel should be defined', () => {
74
+ expect(createModel).toBeDefined()
75
+ })
76
+
77
+ it('should return the default value when config is invalid', () => {
78
+ const store = createModel()({
79
+ state: {
80
+ count: 0,
81
+ },
82
+ })
83
+
84
+ expect(store.state).toEqual({ count: 0 })
85
+ expect(store.reducers).toEqual({})
86
+ expect(typeof store.effects).toBe('function')
87
+ })
88
+ })
@@ -0,0 +1,13 @@
1
+ import { Model } from '../src/core/Model'
2
+
3
+ describe('Model test', () => {
4
+ it('Model should be defined', () => {
5
+ expect(Model).toBeDefined()
6
+ expect(Model.prototype.constructor).toBe(Model)
7
+ })
8
+
9
+ it('should have valid api', () => {
10
+ expect(Object.keys(Model)).toEqual(['instances'])
11
+ expect(typeof Model.prototype.useModel).toBe('function')
12
+ })
13
+ })
@@ -0,0 +1,81 @@
1
+ import { act } from '@testing-library/react-hooks'
2
+ import { createStore } from '../src/index'
3
+ import { counter } from './helper/model'
4
+ import { createHook } from './helper/createHook'
5
+
6
+ describe('multiple stores test', () => {
7
+ it('should multiple stores to be isolated', () => {
8
+ const { Provider: Provider1, useModel: useModel1 } = createStore({
9
+ counter,
10
+ })
11
+ const { Provider: Provider2, useModel: useModel2 } = createStore({
12
+ counter,
13
+ })
14
+
15
+ const { result: result1 } = createHook(Provider1, useModel1, 'counter')
16
+ const { result: result2 } = createHook(Provider2, useModel2, 'counter')
17
+
18
+ expect(result1.current.state.count).toBe(0)
19
+ expect(result2.current.state.count).toBe(0)
20
+ })
21
+
22
+ it('should be able to exec specific stores', () => {
23
+ const { Provider: Provider1, useModel: useModel1 } = createStore({
24
+ counter,
25
+ })
26
+ const { Provider: Provider2, useModel: useModel2 } = createStore({
27
+ counter,
28
+ })
29
+
30
+ const { result: result1 } = createHook(Provider1, useModel1, 'counter')
31
+ const { result: result2 } = createHook(Provider2, useModel2, 'counter')
32
+
33
+ act(() => {
34
+ result1.current.reducers.increase()
35
+ result2.current.reducers.decrease()
36
+ })
37
+
38
+ expect(result1.current.state.count).toBe(1)
39
+ expect(result2.current.state.count).toBe(-1)
40
+ })
41
+
42
+ it('should share state when use same model', async () => {
43
+ const { Provider, useModel } = createStore({
44
+ counter,
45
+ })
46
+
47
+ const { result: result1, waitForNextUpdate } = createHook(Provider, useModel, 'counter')
48
+ const { result: result2 } = createHook(Provider, useModel, 'counter')
49
+
50
+ expect(result1.current.state.count).toBe(0)
51
+ expect(result2.current.state.count).toBe(0)
52
+
53
+ act(() => {
54
+ result1.current.reducers.increase()
55
+ })
56
+
57
+ expect(result1.current.state.count).toBe(1)
58
+ expect(result2.current.state.count).toBe(1)
59
+
60
+ act(() => {
61
+ result2.current.reducers.decrease()
62
+ })
63
+
64
+ expect(result1.current.state.count).toBe(0)
65
+ expect(result2.current.state.count).toBe(0)
66
+
67
+ expect(result1.current.effects.increaseAsync.loading).toBeFalsy()
68
+ expect(result2.current.effects.increaseAsync.loading).toBeFalsy()
69
+
70
+ act(() => {
71
+ result1.current.effects.increaseAsync()
72
+ })
73
+ expect(result1.current.effects.increaseAsync.loading).toBeTruthy()
74
+ expect(result2.current.effects.increaseAsync.loading).toBeTruthy()
75
+
76
+ await waitForNextUpdate()
77
+
78
+ expect(result1.current.effects.increaseAsync.loading).toBeFalsy()
79
+ expect(result2.current.effects.increaseAsync.loading).toBeFalsy()
80
+ })
81
+ })