Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lab-nathan/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"presets": ["es2015", "react"],
"plugins": ["transform-object-rest-spread"]
}
1 change: 1 addition & 0 deletions lab-nathan/.dev.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NODE_ENV='dev'
10 changes: 10 additions & 0 deletions lab-nathan/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": ["eslint:recommended", "plugin:react/recommended", "plugin:jest/recommended"],
"parser": "babel-eslint",
"env": {
"browser": true,
"node": true,
"jest": true
},
"plugins": ["jest"]
}
4 changes: 4 additions & 0 deletions lab-nathan/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
build
.vscode
coverage
58 changes: 58 additions & 0 deletions lab-nathan/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "lab-nathan",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
"watch": "webpack-dev-server --inline --hot",
"test": "jest --coverage",
"test-watch": "jest --watchAll"
},
"jest": {
"globals": {
"__DEBUG__": false,
"process.env": {
"NODE_ENV": "testing"
}
}
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"clean-webpack-plugin": "^0.1.16",
"css-loader": "^0.28.5",
"dotenv": "^4.0.0",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.30.1",
"jest": "^20.0.4",
"node-sass": "^4.5.3",
"prop-types": "^15.5.10",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-redux": "^5.0.6",
"react-router-dom": "^4.2.2",
"react-test-renderer": "^15.6.1",
"redux": "^3.7.2",
"sass-loader": "^6.0.6",
"superagent": "^3.6.0",
"uglifyjs-webpack-plugin": "^0.4.6",
"url-loader": "^0.5.9",
"uuid": "^3.1.0",
"webpack": "^3.5.5",
"webpack-dev-server": "^2.7.1"
},
"devDependencies": {
"babel-eslint": "^7.2.3",
"eslint": "^4.5.0",
"eslint-plugin-jest": "^20.0.3",
"eslint-plugin-react": "^7.3.0"
}
}
29 changes: 29 additions & 0 deletions lab-nathan/src/__test__/category-actions.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { categoryCreate, categoryUpdate, categoryDelete } from '../actions/category-actions.js';

describe('Category Actions', () => {
test('categoryCreate returns a CATEGORY_CREATE action', () => {
let action = categoryCreate({ name: 'test title' });
expect(action.type).toEqual('CATEGORY_CREATE');
expect(action.payload.id).toBeTruthy();
expect(action.payload.timestamp).toBeTruthy();
expect(action.payload.name).toBe('test title');
});

test('categoryDelete returns a CATEGORY_DELETE action', () => {
let category = { id: '01234', timestamp: new Date(), title: 'test title' };
let action = categoryDelete(category);
expect(action).toEqual({
type: 'CATEGORY_DELETE',
payload: category
});
});

test('categoryUpdate returns a CATEGORY_UPDATE action', () => {
let category = { id: '01234', timestamp: new Date(), title: 'test title' };
let action = categoryUpdate(category);
expect(action).toEqual({
type: 'CATEGORY_UPDATE',
payload: category
});
});
});
71 changes: 71 additions & 0 deletions lab-nathan/src/__test__/category-reducer.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import categoryReducer from '../reducers/category-reducer.js';

describe('Category Reducer', () => {
test('initialState should be an empty array', () => {
let result = categoryReducer(undefined, { type: null });
expect(result).toEqual([]);
});

test('if no action type is presented, the state should be returned', () => {
let state = [
{ id: 'someid', title: 'some title', budget: 234, timestamp: Date.now() },
{ id: 'anotherid', title: 'another title', budget: 234, timestamp: Date.now() }
];
let result = categoryReducer(state, { type: null });
expect(result).toEqual(state);
});

test('CATEGORY_CREATE should append a category to the categories array', () => {
let action = {
type: 'CATEGORY_CREATE',
payload: { name: 'sample payload', id: "1", budget: 30, timestamp: Date.now() }
};

let result = categoryReducer([], action);
expect(result.length).toBe(1);
expect(result[0]).toBe(action.payload);
});

test('CATEGORY_UPDATE should update a category', () => {
let createAction = {
type: 'CATEGORY_CREATE',
payload: { name: 'sample payload', id: "1", budget: 30, timestamp: Date.now() }
};

let createResult = categoryReducer([], createAction);

let createAction2 = {
type: 'CATEGORY_CREATE',
payload: { name: 'sample payload 2', id: "2", budget: 30, timestamp: Date.now() }
};

let createResult2 = categoryReducer(createResult, createAction2);

let updateAction = {
type: 'CATEGORY_UPDATE',
payload: { name: 'updated payload', id: "1", budget: 30, timestamp: Date.now() }
};

let updateResult = categoryReducer(createResult2, updateAction);

expect(updateResult[0]).toBe(updateAction.payload);
});

test('CATEGORY_DELETE should delete a category', () => {
let createAction = {
type: 'CATEGORY_CREATE',
payload: { name: 'sample payload', id: "1", budget: 30, timestamp: Date.now() }
};

let createResult = categoryReducer([], createAction);

let deleteAction = {
type: 'CATEGORY_DELETE',
payload: { name: 'sample payload', id: "1", budget: 234, timestamp: Date.now() }
};

let deleteResult = categoryReducer(createResult, deleteAction);

expect(deleteResult.length).toBe(0);
});
});
30 changes: 30 additions & 0 deletions lab-nathan/src/__test__/expense-actions.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { expenseCreate, expenseUpdate, expenseDelete } from '../actions/expense-actions.js';

describe('Expense Actions', () => {
test('expenseCreate returns a EXPENSE_CREATE action', () => {
let {payload, type} = expenseCreate({ name: 'test name', budget: 1342 });
expect(type).toEqual('EXPENSE_CREATE');
expect(payload.id).toBeTruthy();
expect(payload.timestamp).toBeTruthy();
expect(payload.name).toBe('test name');
expect(payload.budget).toBe(1342);
});

test('expenseDelete returns a EXPENSE_DELETE action', () => {
let expense = { id: '01234', timestamp: new Date(), name: 'test name', budget: 1 };
let action = expenseDelete(expense);
expect(action).toEqual({
type: 'EXPENSE_DELETE',
payload: expense
});
});

test('expenseUpdate returns a EXPENSE_UPDATE action', () => {
let expense = { id: '01234', timestamp: new Date(), name: 'test name', budget: 1 };
let action = expenseUpdate(expense);
expect(action).toEqual({
type: 'EXPENSE_UPDATE',
payload: expense
});
});
});
72 changes: 72 additions & 0 deletions lab-nathan/src/__test__/expense-reducer.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import expenseReducer from '../reducers/expense-reducer.js';

describe('Expense Reducer', () => {
test('initialState should be an empty object', () => {
let result = expenseReducer(undefined, { type: null });
expect(result).toEqual({});
});

test('if no action type is presented, the state should be returned', () => {
let state = {
0: [{ id: 'someid', title: 'some title', price: 2, categoryId: "2" }],
1: [{ id: 'anotherid', title: 'another title', price: 2, categoryId: "2" }]
};
let result = expenseReducer(state, { type: null });
expect(result).toEqual(state);
});

test('CATEGORY_CREATE should create an empty array at the supplied category id', () => {
let action = {
type: 'CATEGORY_CREATE',
payload: { name: 'sample payload', id: "1", budget: 30, timestamp: Date.now() }
};

let result = expenseReducer({}, action);
expect(result[1]).toEqual([]);
});

test('CATEGORY_DELETE should delete the array with the supplied category id', () => {
let action = {
type: 'CATEGORY_DELETE',
payload: { name: 'sample payload', id: "1", budget: 30, timestamp: Date.now() }
};

let result = expenseReducer({ 1: [ { id: 'someid', categoryId: '1', title: 'another title', price: 3 } ] }, action);
expect(result).toEqual({});
});

test('EXPENSE_CREATE should append a expense to the categories array', () => {
let action = {
type: 'EXPENSE_CREATE',
payload: { id: 'someid', categoryId: '1', title: 'another title', price: 34, timestamp: Date.now() }
};

let result = expenseReducer({ 1: [] }, action);
expect(result[1].length).toBe(1);
expect(result[1][0]).toBe(action.payload);
});

test('EXPENSE_UPDATE should update a expense', () => {
let action = {
type: 'EXPENSE_UPDATE',
payload: { id: 'someid', categoryId: '1', title: 'updated title', price: 342, timestamp: Date.now() }
};

let result = expenseReducer({
1: [ { id: 'someid', categoryId: '1', title: 'another title', price: 342, timestamp: Date.now() }, { id: 'someid2', categoryId: '1', title: 'another title2', price: 342, timestamp: Date.now() } ],
2: [ { id: 'someid', categoryId: '2', title: 'another title', price: 342, timestamp: Date.now() }, { id: 'someid2', categoryId: '2', title: 'another title2', price: 342, timestamp: Date.now() } ]
}, action);

expect(result[1][0]).toBe(action.payload);
});

test('EXPENSE_DELETE should delete a expense', () => {
let action = {
type: 'EXPENSE_DELETE',
payload: { id: 'someid', categoryId: '1', title: 'updated title', price: 342, timestamp: Date.now() }
};

let result = expenseReducer({ 1: [ { id: 'someid', categoryId: '1', title: 'another title', price: 342, timestamp: Date.now() } ] }, action);
expect(result[1].length).toBe(0);
});
});
20 changes: 20 additions & 0 deletions lab-nathan/src/actions/category-actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import uuid from 'uuid/v1';

export const categoryCreate = (category) => {
category.id = uuid();
category.timestamp = new Date();
return {
type: 'CATEGORY_CREATE',
payload: category
}
};

export const categoryUpdate = (category) => ({
type: 'CATEGORY_UPDATE',
payload: category
});

export const categoryDelete = (category) => ({
type: 'CATEGORY_DELETE',
payload: category
});
20 changes: 20 additions & 0 deletions lab-nathan/src/actions/expense-actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import uuid from 'uuid/v1';

export const expenseCreate = (expense) => {
expense.id = uuid();
expense.timestamp = new Date();
return {
type: 'EXPENSE_CREATE',
payload: expense
}
};

export const expenseUpdate = (expense) => ({
type: 'EXPENSE_UPDATE',
payload: expense
});

export const expenseDelete = (expense) => ({
type: 'EXPENSE_DELETE',
payload: expense
});
33 changes: 33 additions & 0 deletions lab-nathan/src/components/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import reduxReporter from '../lib/redux-reporter.js';
import reducers from '../reducers/reducers.js';
import Dashboard from './dashboard.js';

const store = createStore(reducers, applyMiddleware(reduxReporter));

class App extends React.Component {
componentDidMount() {
store.subscribe(() => {
console.log('__STATE__', store.getState());
});

store.dispatch({ type: null });
}

render() {
return (
<Provider store={store}>
<section>
<BrowserRouter>
<Route exact path='/' component={Dashboard} />
</BrowserRouter>
</section>
</Provider>
);
}
}

export default App;
Loading