add jest testing
This commit is contained in:
parent
c73008fe03
commit
21df4f3f78
3
.babelrc
Normal file
3
.babelrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"presets": ["@babel/preset-env", "@babel/preset-typescript"]
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
parser: '@typescript-eslint/parser',
|
parser: '@typescript-eslint/parser',
|
||||||
plugins: ['@typescript-eslint'],
|
plugins: ['@typescript-eslint', "jest"],
|
||||||
extends: [
|
extends: [
|
||||||
'eslint:recommended',
|
'eslint:recommended',
|
||||||
'plugin:@typescript-eslint/recommended',
|
'plugin:@typescript-eslint/recommended',
|
||||||
@ -27,6 +27,7 @@ module.exports = {
|
|||||||
"@typescript-eslint/restrict-template-expressions": "off",
|
"@typescript-eslint/restrict-template-expressions": "off",
|
||||||
"@typescript-eslint/unbound-method": "off",
|
"@typescript-eslint/unbound-method": "off",
|
||||||
"@typescript-eslint/quotes": "warn",
|
"@typescript-eslint/quotes": "warn",
|
||||||
|
"@typescript-eslint/no-unused-expressions": "off",
|
||||||
"arrow-parens": "off",
|
"arrow-parens": "off",
|
||||||
"class-methods-use-this": "off",
|
"class-methods-use-this": "off",
|
||||||
"func-names": "off",
|
"func-names": "off",
|
||||||
@ -38,11 +39,14 @@ module.exports = {
|
|||||||
"no-continue": "off",
|
"no-continue": "off",
|
||||||
"no-plusplus": "off",
|
"no-plusplus": "off",
|
||||||
"object-curly-newline": "off",
|
"object-curly-newline": "off",
|
||||||
|
"no-alert": "off",
|
||||||
|
"no-restricted-globals": "off",
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
node: true,
|
node: true,
|
||||||
es6: true,
|
es6: true,
|
||||||
|
jest: true,
|
||||||
},
|
},
|
||||||
ignorePatterns: ['.eslintrc.js', 'deploy-config.js']
|
ignorePatterns: ['.eslintrc.js', 'deploy-config.js'],
|
||||||
};
|
};
|
||||||
|
|||||||
8544
package-lock.json
generated
8544
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@ -3,21 +3,28 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/preset-env": "^7.18.6",
|
||||||
|
"@babel/preset-typescript": "^7.18.6",
|
||||||
"@types/happypack": "^5.0.2",
|
"@types/happypack": "^5.0.2",
|
||||||
"@types/html-webpack-plugin": "^3.2.6",
|
"@types/html-webpack-plugin": "^3.2.6",
|
||||||
|
"@types/jest": "^28.1.4",
|
||||||
"@types/node": "^17.0.40",
|
"@types/node": "^17.0.40",
|
||||||
"@types/sass-loader": "^8.0.3",
|
"@types/sass-loader": "^8.0.3",
|
||||||
"@types/webpack": "^5.28.0",
|
"@types/webpack": "^5.28.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.27.1",
|
"@typescript-eslint/eslint-plugin": "^5.27.1",
|
||||||
"@typescript-eslint/parser": "^5.27.1",
|
"@typescript-eslint/parser": "^5.27.1",
|
||||||
|
"babel-jest": "^28.1.2",
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
"css-loader": "^6.7.1",
|
"css-loader": "^6.7.1",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
"eslint": "^8.17.0",
|
"eslint": "^8.17.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-config-airbnb-typescript": "^17.0.0",
|
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||||
|
"eslint-plugin-jest": "^26.5.3",
|
||||||
"eslint-webpack-plugin": "^3.1.1",
|
"eslint-webpack-plugin": "^3.1.1",
|
||||||
"html-webpack-plugin": "^5.5.0",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
|
"jest": "^28.1.2",
|
||||||
|
"jest-environment-jsdom": "^28.1.2",
|
||||||
"mini-css-extract-plugin": "^2.6.0",
|
"mini-css-extract-plugin": "^2.6.0",
|
||||||
"sass": "^1.52.2",
|
"sass": "^1.52.2",
|
||||||
"sass-loader": "^13.0.0",
|
"sass-loader": "^13.0.0",
|
||||||
@ -38,7 +45,9 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "webpack serve --mode=development",
|
"start": "webpack serve --mode=development",
|
||||||
"build": "webpack --mode=production",
|
"build": "webpack --mode=production",
|
||||||
"deploy": "node deploy-config"
|
"deploy": "node deploy-config",
|
||||||
|
"test": "npx jest",
|
||||||
|
"test-watch": "npx jest --watch"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "ksv741",
|
"author": "ksv741",
|
||||||
@ -52,5 +61,10 @@
|
|||||||
"module": "true",
|
"module": "true",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"normalize.css": "^8.0.1"
|
"normalize.css": "^8.0.1"
|
||||||
|
},
|
||||||
|
"jest": {
|
||||||
|
"transform": {
|
||||||
|
"\\.[jt]sx?$": "babel-jest"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Store } from 'core/createStore';
|
import { Store } from 'core/store/createStore';
|
||||||
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';
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { ActionType } from 'redux/types';
|
import { ActionType } from 'redux/types';
|
||||||
import { Store } from './createStore';
|
import { Store } from 'core/store/createStore';
|
||||||
import { Dom } from './dom';
|
import { Dom } from 'core/dom';
|
||||||
import { DomListener } from './DomListener';
|
import { DomListener } from 'core/DomListener';
|
||||||
import { Emitter } from './Emitter';
|
import { Emitter } from 'core/Emitter';
|
||||||
|
|
||||||
interface ExcelComponentClass {
|
interface ExcelComponentClass {
|
||||||
toHTML: () => string;
|
toHTML: () => string;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { StateType } from 'redux/types';
|
import { StateType } from 'redux/types';
|
||||||
import { Store } from './createStore';
|
import { Store } from './store/createStore';
|
||||||
import { isEqual } from './utils';
|
import { isEqual } from './utils';
|
||||||
|
|
||||||
export class StoreSubscriber {
|
export class StoreSubscriber {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { initialStyleState } from '../constants';
|
import { initialStyleState } from '../constants';
|
||||||
|
|
||||||
type SelectorType = string | HTMLElement;
|
export type SelectorType = string | HTMLElement;
|
||||||
|
|
||||||
export interface DomClass {
|
export interface DomClass {
|
||||||
html(html?: string): string | DomClass;
|
html(html?: string): string | DomClass;
|
||||||
|
|||||||
38
src/core/routes/Router.spec.js
Normal file
38
src/core/routes/Router.spec.js
Normal 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>');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,17 +1,19 @@
|
|||||||
import { DashboardPage } from 'pages/DashboardPage';
|
import { DashboardPage } from 'pages/DashboardPage';
|
||||||
import { ExcelPage } from 'pages/ExcelPage';
|
import { ExcelPage } from 'pages/ExcelPage';
|
||||||
import { $, Dom } from 'core/dom';
|
import { $, Dom, SelectorType } from 'core/dom';
|
||||||
import { ActiveRoute } from './ActiveRoute';
|
import { ActiveRoute } from './ActiveRoute';
|
||||||
|
|
||||||
export class Router {
|
type RoutesType = {
|
||||||
private $placeholder: Dom;
|
|
||||||
private routes: {
|
|
||||||
dashboard: DashboardPage
|
dashboard: DashboardPage
|
||||||
excel: ExcelPage
|
excel: ExcelPage
|
||||||
};
|
};
|
||||||
private page: DashboardPage | ExcelPage;
|
|
||||||
|
|
||||||
constructor(selector: string, routes: any) {
|
export class Router {
|
||||||
|
private $placeholder: Dom;
|
||||||
|
private routes: RoutesType;
|
||||||
|
private page: DashboardPage | ExcelPage | null;
|
||||||
|
|
||||||
|
constructor(selector: SelectorType, routes: RoutesType) {
|
||||||
if (!selector) throw new Error('Selector not provided');
|
if (!selector) throw new Error('Selector not provided');
|
||||||
|
|
||||||
this.$placeholder = $(selector);
|
this.$placeholder = $(selector);
|
||||||
@ -47,8 +49,8 @@ export class Router {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.page = new Page(ActiveRoute.param);
|
this.page = new Page(ActiveRoute.param);
|
||||||
|
|
||||||
this.$placeholder.append(this.page.getRoot());
|
this.$placeholder.append(this.page?.getRoot());
|
||||||
this.page.afterRender();
|
this.page?.afterRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
|
|||||||
77
src/core/store/createStore.spec.js
Normal file
77
src/core/store/createStore.spec.js
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { ActionType, ReducerType, StateType, SubscribeType } from '../redux/types';
|
import { ActionType, ReducerType, StateType, SubscribeType } from 'redux/types';
|
||||||
|
|
||||||
export class Store {
|
export class Store {
|
||||||
state: StateType;
|
state: StateType;
|
||||||
@ -3,7 +3,7 @@ import { Formula } from 'components/formula/Formula';
|
|||||||
import { Header } from 'components/header/Header';
|
import { Header } from 'components/header/Header';
|
||||||
import { Table } from 'components/table/Table';
|
import { Table } from 'components/table/Table';
|
||||||
import { Toolbar } from 'components/toolbar/Toolbar';
|
import { Toolbar } from 'components/toolbar/Toolbar';
|
||||||
import { Store } from 'core/createStore';
|
import { Store } from 'core/store/createStore';
|
||||||
import { Page } from 'core/Page';
|
import { Page } from 'core/Page';
|
||||||
import { debounce, storage } from 'core/utils';
|
import { debounce, storage } from 'core/utils';
|
||||||
import { rootReducer } from 'redux/rootReducer';
|
import { rootReducer } from 'redux/rootReducer';
|
||||||
|
|||||||
@ -19,7 +19,8 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "CommonJS",
|
"module": "CommonJS",
|
||||||
"strictPropertyInitialization": true,
|
"strictPropertyInitialization": true,
|
||||||
"sourceMap": true
|
"sourceMap": true,
|
||||||
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules"],
|
"exclude": ["node_modules"],
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user