add font-size tool, little fixes and refactor

This commit is contained in:
Sergey Krylov 2022-07-10 18:06:43 +05:00
parent cdd94a5d02
commit f7e04814a5
24 changed files with 163 additions and 127 deletions

View File

@ -1,9 +1,9 @@
import { $ } from 'core/dom'; import { $ } from 'core/dom';
import { Emitter } from 'core/Emitter'; import { Emitter } from 'core/Emitter';
import { ExcelComponent } from 'core/ExcelComponent'; import { ExcelComponent } from 'core/ExcelComponent';
import { Store } from 'core/store/createStore'; import { Store } from 'core/store/Store';
import { StoreSubscriber } from 'core/StoreSubscriber'; import { StoreSubscriber } from 'core/StoreSubscriber';
import { updateOpenDate } from 'redux/actions'; import { updateOpenDate } from 'redux/action-creators';
interface ExcelOptionsType { interface ExcelOptionsType {
components: any[], components: any[],
@ -48,7 +48,7 @@ export class Excel {
this.subscriber.subscribeComponents(this.components); this.subscriber.subscribeComponents(this.components);
this.components.forEach(component => component.init()); this.components.forEach(component => component.init());
this.store.dispatch(updateOpenDate(Date.now().toString())); this.store.dispatchToStore(updateOpenDate(Date.now().toString()));
} }
destroy() { destroy() {

View File

@ -1,15 +1,18 @@
import { Dom } from 'core/dom'; import { Dom } from 'core/dom';
import { ExcelComponent } from 'core/ExcelComponent'; import { ExcelComponent, ComponentOptionsType } from 'core/ExcelComponent';
export class Formula extends ExcelComponent { export class Formula extends ExcelComponent {
static className = 'excel__formula'; static className = 'excel__formula';
private formulaInput: Dom; private formulaInput: Dom;
constructor($root: Dom, options: any) { constructor($root: Dom, options: ComponentOptionsType) {
super($root, { super($root, {
listeners: ['input', 'keydown'], // @ts-ignore next-line
eventListeners: ['input', 'keydown'],
// @ts-ignore next-line
name: 'Formula', name: 'Formula',
// @ts-ignore next-line
subscribe: ['currentText'], subscribe: ['currentText'],
...options, ...options,
}); });
@ -27,8 +30,8 @@ export class Formula extends ExcelComponent {
this.formulaInput = this.$root.find('#formula-input'); this.formulaInput = this.$root.find('#formula-input');
this.$on('table:select-cell', text => { this.$on('table:select-cell', (cell: Dom) => {
this.formulaInput.text = text || ''; this.formulaInput.text = cell.data.value || '';
}); });
} }

View File

@ -1,16 +1,16 @@
import * as actions from 'redux/actions'; import * as actions from 'redux/action-creators';
import { $, Dom } from 'core/dom'; import { $, Dom } from 'core/dom';
import { ActiveRoute } from 'core/routes/ActiveRoute'; import { ActiveRoute } from 'core/routes/ActiveRoute';
import { ExcelStateComponent } from 'core/ExcelStateComponent'; import { ExcelComponentState } from 'core/ExcelComponentState';
import { deleteTable } from 'redux/actions'; import { deleteTable } from 'redux/action-creators';
export class Header extends ExcelStateComponent { export class Header extends ExcelComponentState {
static className = 'excel__header'; static className = 'excel__header';
constructor($root: Dom, options: any) { constructor($root: Dom, options: any) {
super($root, { super($root, {
name: 'Header', name: 'Header',
listeners: ['input', 'click'], eventListeners: ['input', 'click'],
subscribe: ['title'], subscribe: ['title'],
...options, ...options,
}); });
@ -35,7 +35,7 @@ export class Header extends ExcelStateComponent {
onInput(event: InputEvent) { onInput(event: InputEvent) {
const $target = $(event.target as HTMLInputElement); const $target = $(event.target as HTMLInputElement);
this.$dispatch(actions.changeTitle($target.text)); this.dispatchToStore(actions.changeTitle($target.text));
} }
onClick(event: MouseEvent) { onClick(event: MouseEvent) {
@ -54,7 +54,7 @@ export class Header extends ExcelStateComponent {
} }
case 'delete-table': { case 'delete-table': {
confirm('Действительно хочешь удалить ?') && this.$dispatch(deleteTable(this.store.getState().id)); confirm('Действительно хочешь удалить ?') && this.dispatchToStore(deleteTable(this.store.getState().id));
break; break;
} }

View File

@ -1,9 +1,9 @@
import { startCellId } from 'components/table/table.functions'; import { startCellId } from 'components/table/table.functions';
import * as actions from 'redux/actions'; import * as actions from 'redux/action-creators';
import { $, Dom } from 'core/dom'; import { $, Dom } from 'core/dom';
import { ExcelComponent } from 'core/ExcelComponent'; import { ExcelComponent } from 'core/ExcelComponent';
import { TableSelection } from 'components/table/TableSelection'; import { TableSelection } from 'components/table/TableSelection';
import { changeCurrentStyles } from 'redux/actions'; import { changeCurrentStyles } from 'redux/action-creators';
import { createTable } from 'components/table/table.template'; import { createTable } from 'components/table/table.template';
import { initialStyleState } from 'src/constants'; import { initialStyleState } from 'src/constants';
import { parse } from 'core/utils'; import { parse } from 'core/utils';
@ -18,7 +18,7 @@ export class Table extends ExcelComponent {
constructor($root: Dom, options: any) { constructor($root: Dom, options: any) {
super($root, { super($root, {
name: 'Table', name: 'Table',
listeners: ['mousedown', 'keydown', 'input'], eventListeners: ['mousedown', 'keydown', 'input'],
...options, ...options,
}); });
} }
@ -34,36 +34,17 @@ export class Table extends ExcelComponent {
init() { init() {
super.init(); super.init();
const $cell = this.$root.find(`[data-id="${startCellId}"]`);
this.selection.select($cell);
this.$emit('table:select-cell', $cell.data.value);
this.$on('formula:input', (data) => {
this.selection.current.attr('data-value', data);
this.selection.current.text = parse(data);
this.updateCurrentTextInStore(data);
});
this.$on('formula:enter-press', () => {
this.selection.current.focus();
});
this.$on('toolbar:applyStyle', (value) => {
this.selection.applyStyle(value);
this.$dispatch(actions.applyStyle({
value,
ids: this.selection.selectedIds,
}));
});
this.initTable(); this.initTable();
this.$on('formula:input', this.updateCurrentText);
this.$on('formula:enter-press', () => this.selection.current.focus());
this.$on('toolbar:applyStyle', this.updateCurrentStyles);
} }
initTable() { initTable() {
this.initTableSize(); this.initTableSize();
this.initTableContentAndStyles(); this.initTableContentAndStyles();
this.initStartCellFocus();
} }
initTableSize() { initTableSize() {
@ -87,6 +68,7 @@ export class Table extends ExcelComponent {
const tableState = this.store.getState(); const tableState = this.store.getState();
const tableContent = tableState?.dataState; const tableContent = tableState?.dataState;
const tableStyles = tableState?.stylesState; const tableStyles = tableState?.stylesState;
Object.keys(tableContent).forEach(cellId => { Object.keys(tableContent).forEach(cellId => {
const $cell = this.$root.find(`[data-id="${cellId}"]`); const $cell = this.$root.find(`[data-id="${cellId}"]`);
const styles = tableStyles[cellId]; const styles = tableStyles[cellId];
@ -97,28 +79,46 @@ export class Table extends ExcelComponent {
}); });
} }
initStartCellFocus() {
const $cell = this.$root.find(`[data-id="${startCellId}"]`);
this.selection.select($cell);
this.$emit('table:select-cell', $cell);
}
emitSelectCallback() { emitSelectCallback() {
this.$emit('table:select-cell', this.selection.current.data.value); this.$emit('table:select-cell', this.selection.current);
const styles = this.selection.current?.getStyles(Object.keys(initialStyleState)); const styles = this.selection.current?.getStyles(Object.keys(initialStyleState));
this.$dispatch(changeCurrentStyles(styles)); this.dispatchToStore(changeCurrentStyles(styles));
} }
async resizeTable(event: MouseEvent) { async resizeTable(event: MouseEvent) {
try { try {
const resizeData = await resizeHandler(this.$root, event); const resizeData = await resizeHandler(this.$root, event);
this.$dispatch(actions.tableResize({ resizeData })); this.dispatchToStore(actions.tableResize({ resizeData }));
} catch (e) { } catch (e) {
console.warn('Resize error', e.message); console.warn('Resize error', e.message);
} }
} }
updateCurrentTextInStore(text: string) { updateCurrentText = (text: string) => {
this.$dispatch(actions.changeText({ this.selection.current.attr('data-value', text);
this.selection.current.text = parse(text);
this.dispatchToStore(actions.changeText({
text, text,
id: this.selection.current.data.id || startCellId, id: this.selection.current.data.id || startCellId,
})); }));
} };
updateCurrentStyles = (style: CSSStyleRule) => {
this.selection.applyStyle(style);
this.dispatchToStore(actions.applyStyle({
value: style,
ids: this.selection.selectedIds,
}));
};
onMousedown(event: MouseEvent) { onMousedown(event: MouseEvent) {
selectHandler(event, this.selection, this.emitSelectCallback.bind(this)); selectHandler(event, this.selection, this.emitSelectCallback.bind(this));
@ -130,6 +130,6 @@ export class Table extends ExcelComponent {
} }
onInput(event: InputEvent) { onInput(event: InputEvent) {
this.updateCurrentTextInStore((event.target as HTMLElement).innerText.trim()); this.updateCurrentText((event.target as HTMLElement).innerText.trim());
} }
} }

View File

@ -1,17 +1,17 @@
import { startCellId } from 'components/table/table.functions'; import { startCellId } from 'components/table/table.functions';
import { $, Dom } from 'core/dom'; import { $, Dom } from 'core/dom';
import { ExcelStateComponent } from 'core/ExcelStateComponent'; import { ExcelComponentState } from 'core/ExcelComponentState';
import { OptionsType } from 'core/ExcelComponent'; import { ComponentOptionsType } from 'core/ExcelComponent';
import { createToolbar } from 'components/toolbar/toolbar.template'; import { createToolbar } from 'components/toolbar/toolbar.template';
import { initialStyleState } from 'src/constants'; import { initialStyleState } from 'src/constants';
export class Toolbar extends ExcelStateComponent { export class Toolbar extends ExcelComponentState {
static className = 'excel__toolbar'; static className = 'excel__toolbar';
constructor($root: Dom, options: OptionsType) { constructor($root: Dom, options: ComponentOptionsType) {
super($root, { super($root, {
...options, ...options,
listeners: ['click'], eventListeners: ['click', 'change'],
name: 'Toolbar', name: 'Toolbar',
subscribe: ['currentStyles'], subscribe: ['currentStyles'],
}); });
@ -20,7 +20,7 @@ export class Toolbar extends ExcelStateComponent {
prepare() { prepare() {
const currentToolbarState = this.toolbarState; const currentToolbarState = this.toolbarState;
this.initState(currentToolbarState); this.initComponentState(currentToolbarState);
} }
get toolbarState() { get toolbarState() {
@ -31,7 +31,7 @@ export class Toolbar extends ExcelStateComponent {
} }
get template(): string { get template(): string {
return createToolbar(this.state); return createToolbar(this.componentState);
} }
toHTML(): string { toHTML(): string {
@ -39,7 +39,7 @@ export class Toolbar extends ExcelStateComponent {
} }
storeChanged(args?: any) { storeChanged(args?: any) {
this.setState(args.currentStyles); this.setComponentState(args.currentStyles);
} }
onClick(event: MouseEvent) { onClick(event: MouseEvent) {
@ -51,7 +51,13 @@ export class Toolbar extends ExcelStateComponent {
const key = Object.keys(value)[0]; const key = Object.keys(value)[0];
this.$emit('toolbar:applyStyle', value); this.$emit('toolbar:applyStyle', value);
this.setComponentState({ [key]: value[key] });
}
this.setState({ [key]: value[key] }); onChange(e: any) {
const value = `${e.target.value.toString()}px`;
this.$emit('toolbar:applyStyle', { fontSize: value });
this.setComponentState({ fontSize: value });
} }
} }

View File

@ -4,4 +4,5 @@ export type ToolbarStateType = {
textDecoration?: 'none' | 'underline'; textDecoration?: 'none' | 'underline';
justifyContent?: 'start' | 'center' | 'end'; justifyContent?: 'start' | 'center' | 'end';
alignItems?: 'start' | 'center' | 'end'; alignItems?: 'start' | 'center' | 'end';
fontSize?: any;
}; };

View File

@ -80,7 +80,25 @@ export function createToolbar(state: ToolbarStateType): string {
], ],
]; ];
return btns.map(btn => (Array.isArray(btn) ? toButtonGroup(btn) : toButton(btn))).join(' '); const buttons = btns.map(btn => (Array.isArray(btn) ? toButtonGroup(btn) : toButton(btn)));
buttons.push(createFontSizeButton(state.fontSize));
return buttons.join(' ');
}
function createFontSizeButton(currentSize: string) {
const fontSizeInPixels = +currentSize.slice(0, -2);
const options = [];
for (let i = 8; i <= 24; i += 2) {
if (fontSizeInPixels === i) options.push(`<option value="${i}" selected>${i}</option>`);
else options.push(`<option value="${i}">${i}</option>`);
}
return `
<select class="button__size" id="button-size">
${options.join('')}
</select>
`;
} }
function toButtonGroup(buttons: ButtonConfigType[]) { function toButtonGroup(buttons: ButtonConfigType[]) {

View File

@ -8,6 +8,7 @@ export const initialStyleState: ToolbarStateType = {
fontWeight: 'normal', fontWeight: 'normal',
textDecoration: 'none', textDecoration: 'none',
fontStyle: 'normal', fontStyle: 'normal',
fontSize: '12px',
}; };
export function getNormalizeInitialState(params: string): StateType { export function getNormalizeInitialState(params: string): StateType {
@ -15,12 +16,12 @@ export function getNormalizeInitialState(params: string): StateType {
colState: {}, colState: {},
rowState: {}, rowState: {},
dataState: {}, dataState: {},
currentText: '',
stylesState: {}, stylesState: {},
title: 'New excel table', title: 'New excel table',
id: params, id: params,
openDate: Date.now(), openDate: Date.now(),
...storage(`excel:${params}`), ...storage(`excel:${params}`),
currentStyles: { ...storage(`excel:${params}`)?.stylesState?.[startCellId] }, currentStyles: { ...storage(`excel:${params}`)?.stylesState?.[startCellId] },
currentText: { ...storage(`excel:${params}`)?.dataState?.[startCellId] },
}; };
} }

View File

@ -1,3 +1,4 @@
import { startCellId } from 'components/table/table.functions';
import { storage } from 'core/utils'; import { storage } from 'core/utils';
import { storageName } from 'pages/ExcelPage'; import { storageName } from 'pages/ExcelPage';
import { StateType } from 'redux/types'; import { StateType } from 'redux/types';
@ -21,7 +22,7 @@ export class LocalStorageClient implements ClientDataType {
} }
get() { get() {
const data = storage(storageName(this.name)) || getNormalizeInitialState(this.name); const data = this.norm(storage(storageName(this.name))) || getNormalizeInitialState(this.name);
return new Promise(resolve => { return new Promise(resolve => {
setTimeout(() => { setTimeout(() => {
@ -29,4 +30,12 @@ export class LocalStorageClient implements ClientDataType {
}, 1500); }, 1500);
}); });
} }
norm(state) {
return {
...state,
currentStyles: { ...state.stylesState?.[startCellId] },
currentText: state.dataState?.[startCellId],
};
}
} }

View File

@ -3,19 +3,19 @@ import { capitalize } from 'core/utils';
export class DomListener { export class DomListener {
$root: Dom; $root: Dom;
listeners: string[]; eventListeners: string[];
constructor($root: Dom, listeners: string[]) { constructor($root: Dom, eventNames: string[]) {
if (!$root) throw new Error('Не передали корневой элемент'); if (!$root) throw new Error('Не передали корневой элемент');
this.$root = $root; this.$root = $root;
this.listeners = listeners; this.eventListeners = eventNames;
} }
initDOMListeners() { initDOMListeners() {
if (!this.listeners) return; if (!this.eventListeners) return;
this.listeners.forEach((listener: string) => { this.eventListeners.forEach((listener: string) => {
const method: any = getMethodName(listener); const method: any = getMethodName(listener);
// @ts-ignore FIXME: // @ts-ignore FIXME:
this[method] = this[method]?.bind(this); this[method] = this[method]?.bind(this);
@ -27,7 +27,7 @@ export class DomListener {
} }
removeDOMListeners() { removeDOMListeners() {
this.listeners.forEach(listener => { this.eventListeners.forEach(listener => {
// @ts-ignore FIXME: // @ts-ignore FIXME:
const method: any = getMethodName(listener); const method: any = getMethodName(listener);
// @ts-ignore FIXME: // @ts-ignore FIXME:

View File

@ -2,7 +2,7 @@ import { ActionType } from 'redux/types';
import { Dom } from 'core/dom'; import { Dom } from 'core/dom';
import { DomListener } from 'core/DomListener'; import { DomListener } from 'core/DomListener';
import { Emitter } from 'core/Emitter'; import { Emitter } from 'core/Emitter';
import { Store } from 'core/store/createStore'; import { Store } from 'core/store/Store';
interface ExcelComponentClass { interface ExcelComponentClass {
toHTML: () => string; toHTML: () => string;
@ -10,8 +10,8 @@ interface ExcelComponentClass {
storeChanged?: (args: any) => void; storeChanged?: (args: any) => void;
} }
export type OptionsType = { export type ComponentOptionsType = {
listeners: string[]; eventListeners: string[];
name: string; name: string;
emitter: Emitter; emitter: Emitter;
store: Store; store: Store;
@ -25,8 +25,8 @@ export abstract class ExcelComponent extends DomListener implements ExcelCompone
private subscribe: string[]; private subscribe: string[];
private unsubscribers: ((args?: any) => any)[]; private unsubscribers: ((args?: any) => any)[];
constructor($root: Dom, options: OptionsType) { constructor($root: Dom, options: ComponentOptionsType) {
super($root, options.listeners); super($root, options.eventListeners);
this.name = options.name; this.name = options.name;
this.emitter = options.emitter; this.emitter = options.emitter;
this.store = options.store; this.store = options.store;
@ -53,8 +53,8 @@ export abstract class ExcelComponent extends DomListener implements ExcelCompone
unsub && this.unsubscribers.push(unsub); unsub && this.unsubscribers.push(unsub);
} }
$dispatch(action: ActionType) { dispatchToStore(action: ActionType) {
this.store?.dispatch(action); this.store?.dispatchToStore(action);
} }
storeChanged(args?: any) { storeChanged(args?: any) {

View File

@ -0,0 +1,27 @@
import { Dom } from 'core/dom';
import { ExcelComponent, ComponentOptionsType } from 'core/ExcelComponent';
type ExcelComponentStateType = {
[k: string]: any;
};
export abstract class ExcelComponentState extends ExcelComponent {
componentState: ExcelComponentStateType;
protected constructor(root: Dom, options: ComponentOptionsType) {
super(root, options);
}
get template(): string {
return JSON.stringify(this.componentState, null, 2);
}
initComponentState(initialState = {}) {
this.componentState = { ...initialState };
}
setComponentState(newState: ExcelComponentStateType) {
this.componentState = { ...this.componentState, ...newState };
this.$root.html(this.template);
}
}

View File

@ -1,27 +0,0 @@
import { Dom } from 'core/dom';
import { ExcelComponent, OptionsType } from 'core/ExcelComponent';
type ExcelComponentStateType = {
[k: string]: any;
};
export abstract class ExcelStateComponent extends ExcelComponent {
state: ExcelComponentStateType;
protected constructor(root: Dom, options: OptionsType) {
super(root, options);
}
get template(): string {
return JSON.stringify(this.state, null, 2);
}
initState(initialState = {}) {
this.state = { ...initialState };
}
setState(newState: ExcelComponentStateType) {
this.state = { ...this.state, ...newState };
this.$root.html(this.template);
}
}

View File

@ -1,5 +1,5 @@
import { StateType } from 'redux/types'; import { StateType } from 'redux/types';
import { Store } from 'core/store/createStore'; import { Store } from 'core/store/Store';
import { isEqual } from 'core/utils'; import { isEqual } from 'core/utils';
export class StoreSubscriber { export class StoreSubscriber {
@ -14,7 +14,7 @@ export class StoreSubscriber {
subscribeComponents(components: any[]) { subscribeComponents(components: any[]) {
this.prevState = this.store.getState(); this.prevState = this.store.getState();
this.sub = this.store.subscribe((state: StateType) => { this.sub = this.store.subscribeFromStore((state: StateType) => {
if (!state) return; if (!state) return;
Object.keys(state).forEach(key => { Object.keys(state).forEach(key => {

View File

@ -9,7 +9,7 @@ export class Store {
this.listeners = []; this.listeners = [];
} }
subscribe(fn: (state: StateType) => void): SubscribeType { subscribeFromStore(fn: (state: StateType) => void): SubscribeType {
this.listeners.push(fn); this.listeners.push(fn);
return { return {
unsubscribe: () => { unsubscribe: () => {
@ -18,7 +18,7 @@ export class Store {
}; };
} }
dispatch(action: ActionType) { dispatchToStore(action: ActionType) {
this.state = this.reducer(this.state, action); this.state = this.reducer(this.state, action);
this.listeners.forEach(listener => listener(this.state)); this.listeners.forEach(listener => listener(this.state));
} }

View File

@ -4,7 +4,7 @@ import { Formula } from 'components/formula/Formula';
import { Header } from 'components/header/Header'; import { Header } from 'components/header/Header';
import { LocalStorageClient } from 'core/Clients'; import { LocalStorageClient } from 'core/Clients';
import { StateProcessor } from 'core/StateProcessor'; import { StateProcessor } from 'core/StateProcessor';
import { Store } from 'core/store/createStore'; import { Store } from 'core/store/Store';
import { SubscribeType } from 'redux/types'; import { SubscribeType } from 'redux/types';
import { Table } from 'components/table/Table'; import { Table } from 'components/table/Table';
import { Toolbar } from 'components/toolbar/Toolbar'; import { Toolbar } from 'components/toolbar/Toolbar';
@ -32,7 +32,7 @@ export class ExcelPage extends AbstractPage {
const state = await this.processor.get(); const state = await this.processor.get();
const store = new Store(rootReducer, state); const store = new Store(rootReducer, state);
this.storeSub = store.subscribe(this.processor.listen); this.storeSub = store.subscribeFromStore(this.processor.listen);
this.excel = new Excel({ this.excel = new Excel({
components: [Header, Toolbar, Formula, Table], components: [Header, Toolbar, Formula, Table],

View File

@ -7,7 +7,7 @@ import {
CHANGE_TITLE, CHANGE_TITLE,
DELETE_TABLE, DELETE_TABLE,
UPDATE_DATE, UPDATE_DATE,
} from 'redux/constants'; } from 'redux/action-constants';
export function tableResize(resizeData: any) { export function tableResize(resizeData: any) {
return { return {
@ -30,7 +30,7 @@ export function changeCurrentStyles(data: any) {
}; };
} }
export function applyStyle(data: any) { export function applyStyle(data: { ids: (string | undefined)[], value: CSSStyleRule }) {
return { return {
type: APPLY_STYLES, type: APPLY_STYLES,
data, data,

View File

@ -1,8 +0,0 @@
export type ResizePayloadType = {
colState: {
[k in number]: number
},
rowState: {
[k in number]: number
},
};

View File

@ -9,7 +9,7 @@ import {
CHANGE_TITLE, CHANGE_TITLE,
DELETE_TABLE, DELETE_TABLE,
UPDATE_DATE, UPDATE_DATE,
} from 'redux/constants'; } from 'redux/action-constants';
export function rootReducer(state: StateType, action: ActionType) { export function rootReducer(state: StateType, action: ActionType) {
switch (action.type) { switch (action.type) {

View File

@ -7,3 +7,4 @@ $info-cell-width: 40px;
$row-height: 25px; $row-height: 25px;
$toolbar-height: 40px; $toolbar-height: 40px;
$primary-color: #3c74ff; $primary-color: #3c74ff;
$default-cell-font-size: 12px;

View File

@ -7,6 +7,7 @@
right: 0; right: 0;
top: $header-height + $toolbar-height + $formula-height; top: $header-height + $toolbar-height + $formula-height;
overflow: auto; overflow: auto;
font-size: $default-cell-font-size;
.row{ .row{
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@ -22,4 +22,8 @@
border: none; border: none;
} }
} }
.button__size {
width: 50px;
}
} }

View File

@ -23,8 +23,8 @@ describe('Create store', () => {
test('should return store object', () => { test('should return store object', () => {
expect(store).toBeDefined(); expect(store).toBeDefined();
expect(store.dispatch).toBeDefined(); expect(store.dispatchToStore).toBeDefined();
expect(store.subscribe).toBeDefined(); expect(store.subscribeFromStore).toBeDefined();
expect(store.getState).not.toBeUndefined(); expect(store.getState).not.toBeUndefined();
}); });
@ -37,27 +37,27 @@ describe('Create store', () => {
}); });
test('should change state if actions exist', () => { test('should change state if actions exist', () => {
store.dispatch({ type: 'ADD' }); store.dispatchToStore({ type: 'ADD' });
expect(store.getState().count).toBe(1); expect(store.getState().count).toBe(1);
}); });
test("should NOT change state if actions don't exist", () => { test("should NOT change state if actions don't exist", () => {
store.dispatch({ type: 'NOT_EXISTING_TYPE' }); store.dispatchToStore({ type: 'NOT_EXISTING_TYPE' });
expect(store.getState().count).toBe(0); expect(store.getState().count).toBe(0);
}); });
test('should call subscriber', () => { test('should call subscriber', () => {
store.subscribe(handler); store.subscribeFromStore(handler);
store.dispatch({ type: 'ADD' }); store.dispatchToStore({ type: 'ADD' });
expect(handler).toHaveBeenCalled(); expect(handler).toHaveBeenCalled();
expect(handler).toHaveBeenCalledWith(store.getState()); expect(handler).toHaveBeenCalledWith(store.getState());
}); });
test('should NOT call sub if unsubscribe', () => { test('should NOT call sub if unsubscribe', () => {
const unsub = store.subscribe(handler); const unsub = store.subscribeFromStore(handler);
unsub.unsubscribe(); unsub.unsubscribe();
store.dispatch({ type: 'ADD' }); store.dispatchToStore({ type: 'ADD' });
expect(handler).not.toHaveBeenCalled(); expect(handler).not.toHaveBeenCalled();
}); });
@ -65,7 +65,7 @@ describe('Create store', () => {
test('should dispatch in async way', () => { test('should dispatch in async way', () => {
return new Promise(resolve => { return new Promise(resolve => {
setTimeout(() => { setTimeout(() => {
store.dispatch({ type: 'ADD' }); store.dispatchToStore({ type: 'ADD' });
}, 500); }, 500);
setTimeout(() => { setTimeout(() => {