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
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "",
"main": "src/server.js",
"scripts": {
"start:fe:dev": "webpack-dev-server --hot --inline --content-base static",
"test": "tape -r babel-register 'src/**/*spec.js'"
},
"babel": {
Expand All @@ -19,7 +20,10 @@
"babel-preset-stage-0": "^6.5.0"
},
"devDependencies": {
"babel-loader": "^6.2.10",
"babel-register": "^6.14.0",
"tape": "^4.6.0"
"tape": "^4.6.0",
"webpack": "^1.14.0",
"webpack-dev-server": "^1.16.2"
}
}
Empty file added src/Todo.js
Empty file.
59 changes: 59 additions & 0 deletions src/Todo.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import test from 'tape';
import Todo from './Todo';

test( 'Todo', t => {
let actual, expected, todo;
let testTodo = {
id: 'test',
title: 'Test',
complete: true,
};

todo = Todo( testTodo ); // use new if using a constructor

actual = todo.getId();
expected = testTodo.id;
t.equal( actual, expected, 'with object, should store the id' );

actual = todo.getTitle();
expected = testTodo.title;
t.equal( actual, expected, 'with object, should store the title' );

actual = todo.isComplete();
expected = testTodo.complete;
t.equal( actual, expected, 'with object, should store the completion' );

todo = Todo( 'Test' ); // use new if using a constructor

actual = typeof todo.getId();
expected = 'string';
t.equal( actual, expected, 'with title, should generate an id' );

actual = todo.getTitle();
expected = 'Test';
t.equal( actual, expected, 'with title, should store the title' );

actual = todo.isComplete();
expected = false;
t.equal( actual, expected, 'with title, should default to not complete' );

todo = Todo( 'Test' ); // use new if using a constructor
todo.toggleComplete();
actual = todo.isComplete();
expected = true;
t.equal( actual, expected, 'toggleComplete should complete uncompleted todos' );

todo.toggleComplete();
actual = todo.isComplete();
expected = false;
t.equal( actual, expected, 'toggleComplete should uncomplete completed todos' );

todo = Todo( 'Test' ); // use new if using a constructor
todo.setTitle( 'New' );
actual = todo.getTitle();
expected = 'New';
t.equal( actual, expected, 'setTitle should change the title' );

t.end();
});

Empty file added src/TodoApp.js
Empty file.
70 changes: 70 additions & 0 deletions src/TodoApp.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import test from 'tape';
import TodoApp from './TodoApp';
import Todo from './Todo';

test( 'TodoApp', t => {
let actual, expected, app;

// app = TodoApp(); // use new if using a constructor

actual = app.isFiltered();
expected = false;
t.deepEqual( actual, expected, 'should begin without a filter' );

actual = app.getTodos();
expected = [];
t.deepEqual( actual, expected, 'should begin an empty set of todos' );

app.addTodo( 'Test' );

actual = app.getTodos().length;
expected = 1;
t.equal( actual, expected, 'addTodo should add a todo' );

let [ todo ] = app.getTodos();
actual = typeof todo.getTitle;
actual = 'function';
t.ok( actual, 'addTodo should add todos as Todo instances' );

actual = todo.getTitle();
expected = 'Test';
t.equal( actual, expected, 'addTodo should set the title of the todo to that passed' );

app.toggleFilter();
todo.toggleComplete();
actual = app.getTodos().length;
expected = 0;
t.equal( actual, expected, 'should use filter to hide todos' );

app.toggleFilter();
actual = app.getTodos().length;
expected = 1;
t.equal( actual, expected, 'should show all todos when filter removed' );

app.rmTodo( todo.getId() );
actual = app.getTodos().length;
expected = 0;
t.equal( actual, expected, 'rmTodo should remove a todo by its id' );

app.setTodos([ Todo( '1' ), Todo( '2' ) ]); // use new if using a constructor
actual = app.getTodos().length;
expected = 2;
t.equal( actual, expected, 'setTodos should replace all todos witht those provided' );

app = TodoApp(); // use new if using a constructor
app.addTodo({ id: '1', complete: false, title: 'One' });
app.addTodo({ id: '2', complete: false, title: 'Two' });

app.toggleComplete( '1' );
let [ todo1, todo2 ] = app.getTodos();
t.equal( todo1.isComplete(), true, 'toggleComplete should toggle the status of the todo' );
t.equal( todo2.isComplete(), false, 'toggleComplete should not toggle other todos' );

app.setTitle( '2', 'New' );
[ todo1, todo2 ] = app.getTodos();
t.equal( todo1.getTitle(), 'One', 'setTitle should not change other todos' );
t.equal( todo2.getTitle(), 'New', 'setTitle should change the title of the todo' );

t.end();
});

60 changes: 27 additions & 33 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,35 @@
export function double ( x ) {
return x * 2;
}

export function doubleXTimes ( x, num ) {
let result = x;

// i++ === i = i + 1
// what is the difference between using let and var?
for ( let i = 0; i < num; i++ ) {
// result = result * 2;
result = double( result ); // internal implementation detail
}
function onReady () {
const addTodoForm = document.getElementById( 'addTodoForm' );
const todoList = document.getElementById( 'todoList' );
const newTodoText = document.getElementById( 'newTodoText' );

return result;
}
// <ul></ul>
todoList.textContent = '';

export const doubleEach = arr => arr.map( x => double( x ) );
addTodoForm.addEventListener( 'submit', event => {
event.preventDefault();
const title = newTodoText.value;

// export function doubleEach ( arr ) {
// // let result = [];
// add it to the list
// create an li
// <li>{title}</li>
const newLi = document.createElement( 'li' );
newLi.textContent = title; // vs newLi.innerHTML

// return arr.map( x => double( x ) );
// // return arr.map( function ( x ) {
// // return double ( x );
// // });
newLi.addEventListener( 'click', () => {
newLi.classList.toggle( 'todo--complete' );
});

// // arr.forEach( x => result.push( double( x ) ) );
// // arr.forEach( function ( x, i ) {
// // // result.push( double( x ) );
// // result.push( double( arr[ i ] ) );
// // });
// put it in the ul
todoList.appendChild( newLi );

// // for ( let i = 0; i < arr.length; i++ ) {
// // // result.push( arr[i] * 2 );
// // result.push( double( arr[i] ) );
// // }
newTodoText.value = '';
});
}

// // return result;
// }
if ( document.readyState !== 'loading' ) {
onReady();
} else {
document.addEventListener( 'DOMContentLoaded', onReady );
}

35 changes: 0 additions & 35 deletions src/spec.js
Original file line number Diff line number Diff line change
@@ -1,35 +0,0 @@
import test from 'tape';
import { double, doubleXTimes, doubleEach } from './index';

test( 'double fn', function ( test ) {
// GWT: Given-When-Then
const actual = double( 2 );
let expected = 4;

test.equal( actual, expected, 'should double the number' );

test.end();
});

test( 'doubleXTimes', function ( test ) {
const actual = doubleXTimes( 2, 4 );
const expected = 32;

test.equal( actual, expected, 'should double the number four times' );

test.end();
});

test( 'doubleEach', function ( test ) {
const actual = doubleEach([ 0, 1, 2, 3, 4 ]);
const expected = [ 0, 2, 4, 6, 8 ];

// { one: 1 } !== { one: 1 }
// { one: { two: 2 } } !== { one: { two: 2 } }
// but they are deeply equal

test.deepEqual( actual, expected, 'should double the number four times' );

test.end();
});

46 changes: 46 additions & 0 deletions src/spy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export const spyOn = ( target, method ) => {
let spy = {
calls: [],

reset () {
this.calls = [];
},
};

const oldMethod = target[ method ];
target[ method ] = ( ...args ) => {
spy.calls.push({
args: args,
});

return oldMethod.apply( target, args );
};

return spy;
};

export const createSpy = oldMethod => {
let spy;

spy = function ( ...args ) {
spy.calls.push({
args: args,
});

spy.called = true;

if ( oldMethod ) {
return oldMethod( ...args );
}
};

spy.reset = () => {
spy.calls = [];
spy.called = false;
};

spy.reset();

return spy;
};

35 changes: 35 additions & 0 deletions static/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">

<title>Todo App</title>
<style>
/**
* Block-Element-Modifer (BEM)
*/
.todo--complete {
text-decoration: line-through;
}
</style>
</head>
<body>
<h1>The Todo App!</h1>

<form id="addTodoForm">
<label for="newTodoText">New Todo:</label>
<input type="text" id="newTodoText" />
<button type="submit">Add Todo!</button>
</form>

<button id="toggleBtn">Toggle Filter</button>

<ul id="todoList">
<!-- todo items go here -->
<li>Loading...</li>
</ul>

<script src="/static/bundle.js"></script>
</body>
</html>

31 changes: 31 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
var path = require( 'path' );
var webpack = require( 'webpack' );

module.exports = {
devtool: 'source-map',

entry: './src',

output: {
path: path.join( __dirname, 'dist' ),
filename: 'bundle.js',
publicPath: '/static/',
},

plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({ sourceMap: true }),
],

module: {
loaders: [
{
test: /\.js$/,
loaders: [ 'babel-loader' ],
include: path.join( __dirname, 'src' ),
},
],
}
};