@sigi/react
Version:
React bindings for sigi framework
193 lines • 7.18 kB
JavaScript
import { __decorate, __metadata } from "tslib";
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
import '@abraham/reflection';
import { Module, EffectModule, Effect, ImmerReducer } from '@sigi/core';
import { useEffect } from 'react';
import { render, act } from '@testing-library/react';
import { Observable, timer } from 'rxjs';
import { mergeMap, map, endWith, switchMap } from 'rxjs/operators';
import { useModuleState, useModule } from '../index.browser';
let CountModel = class CountModel extends EffectModule {
constructor() {
super(...arguments);
this.defaultState = { count: 0, name: 'John Doe' };
}
setCount(state, count) {
state.count = count;
}
setName(state, name) {
state.name = name;
}
getCount(payload$) {
return payload$.pipe(mergeMap(() => timer(20).pipe(map(() => this.getActions().setCount(1)), endWith(this.terminate()))));
}
skippedEffect(payload$) {
return payload$.pipe(switchMap((name) => timer(20).pipe(map(() => this.getActions().setName(name)), endWith(this.terminate()))));
}
};
__decorate([
ImmerReducer(),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Number]),
__metadata("design:returntype", void 0)
], CountModel.prototype, "setCount", null);
__decorate([
ImmerReducer(),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, String]),
__metadata("design:returntype", void 0)
], CountModel.prototype, "setName", null);
__decorate([
Effect({
ssr: true,
}),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Observable]),
__metadata("design:returntype", Observable)
], CountModel.prototype, "getCount", null);
__decorate([
Effect({
payloadGetter: (ctx, skip) => ctx.url || skip,
skipFirstClientDispatch: false,
}),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Observable]),
__metadata("design:returntype", Observable)
], CountModel.prototype, "skippedEffect", null);
CountModel = __decorate([
Module('CountModel')
], CountModel);
describe('React components test', () => {
const mockRender = jest.fn();
const TestComponent = () => {
const state = useModuleState(CountModel);
mockRender();
return (_jsxs("div", { children: [state.name, ": ", state.count] }));
};
afterEach(() => {
mockRender.mockReset();
});
it('should render once while initial rendering', () => {
const node = render(_jsx(TestComponent, {}));
expect(mockRender).toHaveBeenCalledTimes(1);
expect(node.baseElement.innerHTML).toMatchSnapshot();
});
});
describe('Hooks', () => {
const resetStore = jest.fn();
const setCount = jest.fn();
const mockRender = jest.fn();
const TestComponent = () => {
const [state, dispatcher] = useModule(CountModel, {
selector: (state) => {
return state.count;
},
});
mockRender();
useEffect(() => {
setCount.mockImplementation(() => {
dispatcher.setCount(10);
});
resetStore.mockImplementation(() => {
dispatcher.reset();
});
}, []);
return _jsx("div", { children: state });
};
let testWrapper;
beforeEach(() => {
act(() => {
testWrapper = render(_jsx(TestComponent, {}));
});
});
afterEach(() => {
act(() => {
resetStore();
testWrapper.unmount();
});
mockRender.mockReset();
setCount.mockReset();
resetStore.mockReset();
});
it('could reset state from dispatcher', () => {
var _a, _b, _c;
expect((_a = testWrapper.container.querySelector('div')) === null || _a === void 0 ? void 0 : _a.textContent).toBe('0');
expect(mockRender).toHaveBeenCalledTimes(1);
act(() => {
setCount();
});
expect((_b = testWrapper.container.querySelector('div')) === null || _b === void 0 ? void 0 : _b.textContent).toBe('10');
expect(mockRender).toHaveBeenCalledTimes(2);
act(() => {
resetStore();
});
expect((_c = testWrapper.container.querySelector('div')) === null || _c === void 0 ? void 0 : _c.textContent).toBe('0');
expect(mockRender).toHaveBeenCalledTimes(3);
});
it('should not re-render if return state shallow equaled', () => {
var _a;
const fooRenderSpy = jest.fn();
const FooComponent = () => {
const state = useModuleState(CountModel, {
selector: (state) => ({ name: state.name }),
});
fooRenderSpy();
return _jsx("div", { children: state.name });
};
let fooWrapper;
act(() => {
fooWrapper = render(_jsx(FooComponent, {}));
});
expect((_a = fooWrapper.container.querySelector('div')) === null || _a === void 0 ? void 0 : _a.textContent).toBe('John Doe');
act(() => {
setCount();
});
expect(fooRenderSpy).toHaveBeenCalledTimes(1);
expect(mockRender).toHaveBeenCalledTimes(2);
fooRenderSpy.mockReset();
});
it('should re-render if return state not pass custom equality function', () => {
var _a;
const fooRenderSpy = jest.fn();
const FooComponent = () => {
const state = useModuleState(CountModel, {
selector: (state) => ({ name: state.name }),
equalFn: (a, b) => a === b,
});
fooRenderSpy();
return _jsx("div", { children: state.name });
};
let fooWrapper;
act(() => {
fooWrapper = render(_jsx(FooComponent, {}));
});
expect((_a = fooWrapper.container.querySelector('div')) === null || _a === void 0 ? void 0 : _a.textContent).toBe('John Doe');
act(() => {
setCount();
});
expect(fooRenderSpy).toHaveBeenCalledTimes(2);
fooRenderSpy.mockReset();
});
it('Child <-> Parent scenario', () => {
var _a, _b;
const name = 'tj';
const ChildComponent = () => {
const [state, dispatcher] = useModule(CountModel);
useEffect(() => {
dispatcher.setName(name);
}, [dispatcher]);
return _jsx("span", { children: state.name });
};
const FooComponent = () => {
const state = useModuleState(CountModel);
return (_jsxs("div", { children: [state.name, _jsx(ChildComponent, {})] }));
};
let fooWrapper;
act(() => {
fooWrapper = render(_jsx(FooComponent, {}));
});
expect((_a = fooWrapper.container.querySelector('span')) === null || _a === void 0 ? void 0 : _a.textContent).toBe(name);
expect((_b = fooWrapper.container.querySelector('div')) === null || _b === void 0 ? void 0 : _b.childNodes.item(0).textContent).toBe(name);
});
});
//# sourceMappingURL=react.spec.js.map