add jest testing

This commit is contained in:
Sergey Krylov 2022-07-08 08:43:52 +05:00
parent c73008fe03
commit 21df4f3f78
14 changed files with 8347 additions and 380 deletions

3
.babelrc Normal file
View File

@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env", "@babel/preset-typescript"]
}

View File

@ -1,7 +1,7 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
plugins: ['@typescript-eslint', "jest"],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
@ -27,6 +27,7 @@ module.exports = {
"@typescript-eslint/restrict-template-expressions": "off",
"@typescript-eslint/unbound-method": "off",
"@typescript-eslint/quotes": "warn",
"@typescript-eslint/no-unused-expressions": "off",
"arrow-parens": "off",
"class-methods-use-this": "off",
"func-names": "off",
@ -38,11 +39,14 @@ module.exports = {
"no-continue": "off",
"no-plusplus": "off",
"object-curly-newline": "off",
"no-alert": "off",
"no-restricted-globals": "off",
},
env: {
browser: true,
node: true,
es6: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js', 'deploy-config.js']
ignorePatterns: ['.eslintrc.js', 'deploy-config.js'],
};

8544
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,21 +3,28 @@
"version": "1.0.0",
"main": "index.js",
"devDependencies": {
"@babel/preset-env": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@types/happypack": "^5.0.2",
"@types/html-webpack-plugin": "^3.2.6",
"@types/jest": "^28.1.4",
"@types/node": "^17.0.40",
"@types/sass-loader": "^8.0.3",
"@types/webpack": "^5.28.0",
"@typescript-eslint/eslint-plugin": "^5.27.1",
"@typescript-eslint/parser": "^5.27.1",
"babel-jest": "^28.1.2",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.1",
"dotenv": "^16.0.1",
"eslint": "^8.17.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-plugin-jest": "^26.5.3",
"eslint-webpack-plugin": "^3.1.1",
"html-webpack-plugin": "^5.5.0",
"jest": "^28.1.2",
"jest-environment-jsdom": "^28.1.2",
"mini-css-extract-plugin": "^2.6.0",
"sass": "^1.52.2",
"sass-loader": "^13.0.0",
@ -38,7 +45,9 @@
"scripts": {
"start": "webpack serve --mode=development",
"build": "webpack --mode=production",
"deploy": "node deploy-config"
"deploy": "node deploy-config",
"test": "npx jest",
"test-watch": "npx jest --watch"
},
"keywords": [],
"author": "ksv741",
@ -52,5 +61,10 @@
"module": "true",
"dependencies": {
"normalize.css": "^8.0.1"
},
"jest": {
"transform": {
"\\.[jt]sx?$": "babel-jest"
}
}
}

View File

@ -1,4 +1,4 @@
import { Store } from 'core/createStore';
import { Store } from 'core/store/createStore';
import { $ } from 'core/dom';
import { Emitter } from 'core/Emitter';
import { ExcelComponent } from 'core/ExcelComponent';

View File

@ -1,8 +1,8 @@
import { ActionType } from 'redux/types';
import { Store } from './createStore';
import { Dom } from './dom';
import { DomListener } from './DomListener';
import { Emitter } from './Emitter';
import { Store } from 'core/store/createStore';
import { Dom } from 'core/dom';
import { DomListener } from 'core/DomListener';
import { Emitter } from 'core/Emitter';
interface ExcelComponentClass {
toHTML: () => string;

View File

@ -1,5 +1,5 @@
import { StateType } from 'redux/types';
import { Store } from './createStore';
import { Store } from './store/createStore';
import { isEqual } from './utils';
export class StoreSubscriber {

View File

@ -1,6 +1,6 @@
import { initialStyleState } from '../constants';
type SelectorType = string | HTMLElement;
export type SelectorType = string | HTMLElement;
export interface DomClass {
html(html?: string): string | DomClass;

View File

@ -0,0 +1,38 @@
/**
* @jest-environment jsdom
*/
import { Router } from './router';
import { Page } from '../Page';
class DashboardPage extends Page {
getRoot() {
const root = document.createElement('div');
root.innerHTML = 'dashboard';
return root;
}
}
class ExcelPage extends Page {}
describe('Router:', () => {
let router;
let $root;
beforeEach(() => {
$root = document.createElement('div');
router = new Router($root, {
excel: ExcelPage,
dashboard: DashboardPage,
});
});
test('should be defined', () => {
expect(router).toBeDefined();
});
test('should render Dasboard Page', () => {
router.changePageHandler();
expect($root.innerHTML).toBe('<div>dashboard</div>');
});
});

View File

@ -1,17 +1,19 @@
import { DashboardPage } from 'pages/DashboardPage';
import { ExcelPage } from 'pages/ExcelPage';
import { $, Dom } from 'core/dom';
import { $, Dom, SelectorType } from 'core/dom';
import { ActiveRoute } from './ActiveRoute';
type RoutesType = {
dashboard: DashboardPage
excel: ExcelPage
};
export class Router {
private $placeholder: Dom;
private routes: {
dashboard: DashboardPage
excel: ExcelPage
};
private page: DashboardPage | ExcelPage;
private routes: RoutesType;
private page: DashboardPage | ExcelPage | null;
constructor(selector: string, routes: any) {
constructor(selector: SelectorType, routes: RoutesType) {
if (!selector) throw new Error('Selector not provided');
this.$placeholder = $(selector);
@ -47,8 +49,8 @@ export class Router {
// @ts-ignore
this.page = new Page(ActiveRoute.param);
this.$placeholder.append(this.page.getRoot());
this.page.afterRender();
this.$placeholder.append(this.page?.getRoot());
this.page?.afterRender();
}
destroy() {

View File

@ -0,0 +1,77 @@
import { Store } from './createStore';
const initialState = {
count: 0,
};
const reducer = (state, action) => {
if (action.type === 'ADD') {
return { ...state, count: state.count + 1 };
}
return state;
};
describe('Create store', () => {
let store;
let handler;
beforeEach(() => {
store = new Store(reducer, initialState);
handler = jest.fn();
});
test('should return store object', () => {
expect(store).toBeDefined();
expect(store.dispatch).toBeDefined();
expect(store.subscribe).toBeDefined();
expect(store.getState).not.toBeUndefined();
});
test('should return object as a state', () => {
expect(store.getState()).toBeInstanceOf(Object);
});
test('should return default state', () => {
expect(store.getState()).toEqual(initialState);
});
test('should change state if actions exist', () => {
store.dispatch({ type: 'ADD' });
expect(store.getState().count).toBe(1);
});
test("should NOT change state if actions don't exist", () => {
store.dispatch({ type: 'NOT_EXISTING_TYPE' });
expect(store.getState().count).toBe(0);
});
test('should call subscriber', () => {
store.subscribe(handler);
store.dispatch({ type: 'ADD' });
expect(handler).toHaveBeenCalled();
expect(handler).toHaveBeenCalledWith(store.getState());
});
test('should NOT call sub if unsubscribe', () => {
const unsub = store.subscribe(handler);
unsub.unsubscribe();
store.dispatch({ type: 'ADD' });
expect(handler).not.toHaveBeenCalled();
});
test('should dispatch in async way', () => {
return new Promise(resolve => {
setTimeout(() => {
store.dispatch({ type: 'ADD' });
}, 500);
setTimeout(() => {
expect(store.getState().count).toBe(1);
resolve();
}, 1000);
});
});
});

View File

@ -1,4 +1,4 @@
import { ActionType, ReducerType, StateType, SubscribeType } from '../redux/types';
import { ActionType, ReducerType, StateType, SubscribeType } from 'redux/types';
export class Store {
state: StateType;

View File

@ -3,7 +3,7 @@ import { Formula } from 'components/formula/Formula';
import { Header } from 'components/header/Header';
import { Table } from 'components/table/Table';
import { Toolbar } from 'components/toolbar/Toolbar';
import { Store } from 'core/createStore';
import { Store } from 'core/store/createStore';
import { Page } from 'core/Page';
import { debounce, storage } from 'core/utils';
import { rootReducer } from 'redux/rootReducer';

View File

@ -19,7 +19,8 @@
"compilerOptions": {
"module": "CommonJS",
"strictPropertyInitialization": true,
"sourceMap": true
"sourceMap": true,
"exclude": ["node_modules"]
}
},
"exclude": ["node_modules"],