Skip to content

Commit

Permalink
chore: 🤖 release 0.8.1 (#93)
Browse files Browse the repository at this point in the history
* fix: set loading state as false before return data in @effect
* feat: keep the bean alive witch provided in StatedBeanProvider
* test: add some unit test
  • Loading branch information
foreleven authored Oct 15, 2019
1 parent bbc7c9c commit bb8a138
Show file tree
Hide file tree
Showing 18 changed files with 220 additions and 95 deletions.
3 changes: 2 additions & 1 deletion example/src/components/Todo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ function TodoList(props: { items: Todo[] }) {

export const TodoApp = () => {
const todo = useInject(TodoModel);
const { loading } = useObserveEffect(todo, 'fetchTodo');
const { loading, error } = useObserveEffect(todo, 'fetchTodo');

console.log(loading, error, todo.todoList);
return (
<div>
<h3>TODO</h3>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "stated-bean",
"version": "0.8.0",
"version": "0.8.1",
"description": "A light but scalable state management library with react hooks",
"repository": "git@github.com:mjolnirjs/stated-bean.git",
"license": "MIT",
Expand Down
10 changes: 0 additions & 10 deletions src/core/StatedBeanApplication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import { DefaultBeanFactory, IBeanFactory } from './StatedBeanFactory';
export class StatedBeanApplication {
private _beanFactory: IBeanFactory = new DefaultBeanFactory();

private _debug = false;

getBeanFactory(): IBeanFactory {
return this._beanFactory;
}
Expand All @@ -18,12 +16,4 @@ export class StatedBeanApplication {
this._beanFactory = beanFactory;
return this;
}

setDebug(_debug: boolean) {
this._debug = _debug;
}

isDebug() {
return this._debug;
}
}
17 changes: 10 additions & 7 deletions src/decorator/Effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,35 @@ export function Effect(name?: string | symbol): MethodDecorator {
descriptor.value = function<T>(this: T, ...args: unknown[]) {
const beanWrapper = getBeanWrapper(this);
if (beanWrapper !== undefined) {
const emitEffectAction = (action: Partial<EffectAction>) => {
const emitEffectAction = (action: Partial<EffectAction<T>>) => {
const observer = beanWrapper.beanObserver;

if (observer !== undefined) {
observer.effect$.next({
effect: effectName,
...action,
} as EffectAction);
} as EffectAction<T>);
}
};
emitEffectAction({ loading: true, data: null, error: null });
emitEffectAction({ loading: true, error: null });

const result = originalMethod.apply(this, args);

if (isPromise(result)) {
return result
.then((data: unknown) => {
emitEffectAction({ loading: false, data, error: null });
.then(data => {
emitEffectAction({ data: data as T });
return data;
})
.catch((e: unknown) => {
emitEffectAction({ loading: false, data: null, error: e });
emitEffectAction({ loading: false, error: e });
throw e;
})
.finally(() => {
emitEffectAction({ loading: false });
});
} else {
emitEffectAction({ loading: false, data: result, error: null });
emitEffectAction({ loading: false, data: result });
}
return result;
}
Expand Down
1 change: 0 additions & 1 deletion src/decorator/ObservableProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export function ObservableProps(name?: string): PropertyDecorator {

if (prop === undefined) {
prop = String(propertyKey);

if (prop.endsWith('$')) {
prop = prop.substring(0, prop.length - 1);
}
Expand Down
2 changes: 0 additions & 2 deletions src/hooks/useBean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ export function useBean<T, TProps = Record<string, unknown>>(
props = option.props;
} else if (typeof option === 'string' || typeof option === 'symbol') {
name = option;
} else {
throw new Error('invalid UseBeanOptions');
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/hooks/useContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ export function useContainer({ providers, application }: UseContainerOption) {
} else {
beanProvider = provider;
}
return container.register(new BeanDefinition(beanProvider));
// Subscribing to the bean makes it not destroyed
container.register(new BeanDefinition(beanProvider)).state$.subscribe();
});
return container;
});
Expand Down
3 changes: 1 addition & 2 deletions src/hooks/useInject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@ export function useInject<T>(option: ClassType<T> | BeanInjectOption<T>): T {

const beanChangeListener = useCallback(
(action: StateAction<T>) => {
const field = action.fieldMeta.name as keyof T;
if (
observedFields == null ||
observedFields.length === 0 ||
observedFields.includes(field)
observedFields.includes(action.fieldMeta.name as keyof T)
) {
setVersion(prev => prev + 1);
}
Expand Down
2 changes: 1 addition & 1 deletion src/types/Actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export interface StateAction<T = unknown> {

export interface EffectAction<T = unknown> {
loading: boolean;
error: unknown;
data: T;
error: unknown;
effect: string | symbol;
}

Expand Down
23 changes: 0 additions & 23 deletions test/application.test.ts

This file was deleted.

57 changes: 57 additions & 0 deletions test/application.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {
BeanDefinition,
IBeanFactory,
StatedBeanApplication,
StatedBeanProvider,
StatedBeanConsumer,
StatedBeanContextValue,
} from '../src';

import React from 'react';
import ReactDOM from 'react-dom';

describe('StatedBeanApplication', () => {
it('application bean factory test', () => {
const application = new StatedBeanApplication();

class CustomBeanFactory implements IBeanFactory {
createBean<T>(beanDefinition: BeanDefinition<T>): T {
// eslint-disable-next-line new-cap
return new beanDefinition.beanType();
}

destroyBean() {
//
}
}

const beanFactory = new CustomBeanFactory();
application.setBeanFactory(beanFactory);

expect(application.getBeanFactory() === beanFactory).toEqual(true);
});

it('StatedBeanConsumer test', () => {
const application = new StatedBeanApplication();
const Sample = () => (
<StatedBeanConsumer>
{(context: StatedBeanContextValue) => {
expect(context).not.toBeNull();
expect(context.container).not.toBeNull();
expect(context.container!.application).toBe(application);
return null;
}}
</StatedBeanConsumer>
);

const App = () => (
<StatedBeanProvider application={application}>
<Sample />
</StatedBeanProvider>
);

const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});
});
27 changes: 25 additions & 2 deletions test/effect-action.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ class PostProvidedSample {
}
}

describe('effect action', () => {
it('effect action change', async () => {
describe('effect action test', () => {
it('promise effect action test', async () => {
const wrapper = ({ children }: { children: React.ReactNode }) => (
<StatedBeanProvider providers={[PostProvidedSample]}>
{children}
Expand All @@ -59,11 +59,34 @@ describe('effect action', () => {
expect(result.current.action.loading).toBe(false);

await act(() => result.current.bean.add3().catch(() => {}));

expect(result.current.action3.error).not.toBeNull();

unmount();
});

it('no-promise effect action test', () => {
const wrapper = ({ children }: { children: React.ReactNode }) => (
<StatedBeanProvider providers={[PostProvidedSample]}>
{children}
</StatedBeanProvider>
);

const { result, unmount } = renderHook(
() => {
const bean = useInject(PostProvidedSample);
const action = useObserveEffect(bean, 'add2');
return { bean, action };
},
{ wrapper },
);
expect(result.current.action.loading).toBe(false);
act(() => result.current.bean.add2());
expect(result.current.action.loading).toBe(false);

unmount();
});

it('useObserveEffect without provider container', () => {
renderHook(() => {
expect(() => {
Expand Down
32 changes: 32 additions & 0 deletions test/plain-object.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { renderHook, act } from '@testing-library/react-hooks';

import { StatedBeanProvider, useBean } from '../src';

import React from 'react';

const PlanObjectBean = {
count: 0,
add() {
this.count++;
},
};

describe('props observer test', () => {
it('Props init value test', () => {
const wrapper = ({ children }: { children: React.ReactNode }) => (
<StatedBeanProvider>{children}</StatedBeanProvider>
);

const { result } = renderHook(
() => {
return useBean(() => PlanObjectBean);
},
{ wrapper },
);
expect(result.current.count).toBe(0);
act(() => {
result.current.add();
});
expect(result.current.count).toBe(1);
});
});
19 changes: 12 additions & 7 deletions test/props.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@ import React from 'react';
@StatedBean()
class StatedBeanSample {
@Stated()
@Props()
value = 0;
@Props('value')
value3 = 0;

@ObservableProps()
value$!: BehaviorSubject<number>;

@ObservableProps('value')
value2!: BehaviorSubject<number>;
value2$!: BehaviorSubject<number>;

@ObservableProps()
value!: BehaviorSubject<number>;
}

describe('props observer test', () => {
Expand All @@ -37,14 +40,16 @@ describe('props observer test', () => {
},
{ wrapper, initialProps: { value: 10 } },
);
expect(result.current.value).toBe(10);
expect(result.current.value3).toBe(10);
expect(result.current.value.getValue()).toBe(10);
expect(result.current.value$.getValue()).toBe(10);
expect(result.current.value2.getValue()).toBe(10);
expect(result.current.value2$.getValue()).toBe(10);

rerender({ value: 20 });

expect(result.current.value).toBe(20);
expect(result.current.value3).toBe(20);
expect(result.current.value.getValue()).toBe(20);
expect(result.current.value$.getValue()).toBe(20);
expect(result.current.value2.getValue()).toBe(20);
expect(result.current.value2$.getValue()).toBe(20);
});
});
32 changes: 1 addition & 31 deletions test/stated-change.test.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import { act, renderHook } from '@testing-library/react-hooks';

import {
Stated,
StatedBean,
StatedBeanConsumer,
StatedBeanContextValue,
StatedBeanProvider,
useInject,
} from '../src';
import { Stated, StatedBean, StatedBeanProvider, useInject } from '../src';

import React from 'react';
import ReactDOM from 'react-dom';
import renderer from 'react-test-renderer';

@StatedBean()
Expand Down Expand Up @@ -73,26 +65,4 @@ describe('stated value changed test', () => {
act(() => result.current.addStatedField());
expect(result.current.statedField).toEqual(1);
});

it('StatedBeanConsumer', () => {
const Sample = () => (
<StatedBeanConsumer>
{(context: StatedBeanContextValue) => {
expect(context).not.toBeNull();
expect(context.container).not.toBeNull();
return null;
}}
</StatedBeanConsumer>
);

const App = () => (
<StatedBeanProvider providers={[SampleStatedBean]}>
<Sample />
</StatedBeanProvider>
);

const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});
});
Loading

0 comments on commit bb8a138

Please sign in to comment.