diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..75ce18e9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/bower_components +/node_modules diff --git a/.jshintrc b/.jshintrc index cd595a55..0fca0917 100644 --- a/.jshintrc +++ b/.jshintrc @@ -89,5 +89,5 @@ "yui" : false, // Yahoo User Interface // Custom Globals - "globals" : { "toDoList": true, "angular": true } // additional predefined global variables + "globals" : { "todoList": true, "angular": true } // additional predefined global variables } diff --git a/.travis.yml b/.travis.yml index fd8e40aa..a4b04d75 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ script: - node_modules/.bin/protractor test/e2e/conf.js --browser=firefox language: node_js node_js: - - "0.10" + - "5.4.1" before_script: - bower install - "export DISPLAY=:99.0" diff --git a/README.md b/README.md index 29dc834e..5e723508 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,11 @@ -# Todo Challenge +# Makers Academy Weekend Challenge: Todo List -* Deadline: submit completed pull request by 9am on Monday -* You may use whatever level of JavaScript you feel comfortable with - pure JS, jQuery, Angular, or whatever weird and wonderful framework you want to try. Extra points for DogeScript +The task is to build a Todo list as a mini front-end application. The main technologies used will be JavaScript, Angular, CSS and HTMl. I will be using TDD to drive the production of the app. -Steps -------- - -1. Fill out your learning plan self review for the week: https://github.com/makersacademy/learning_plan -2. Fork this repo, and clone to your local machine -3. Complete the following challenge: - -## Challenge - -![Todo mockup](https://makersacademy.mybalsamiq.com/mockups/2914603.png?key=afabb09aef2901a2732515ae4349c1ec0458294b) - -Build a Todo list as a mini front-end application. You don't have to use a database, the front-end is more important - you can use an appropriate data structure stored somewhere in your JavaScript (this time only!) +Testing frameworks will include Karma for back-end and Protractor for front-end and user experience. Here are the core user stories: +================ ``` As a forgetful person @@ -30,11 +19,7 @@ So that I have more time to think about other things As a person who actually gets stuff done I want to mark my tasks as done So that I don't do them twice -``` - -Here are some other user stories you may choose to implement: -``` As a person with a lot of tasks I want to be able to filter my tasks by "All", "Active", "Complete" So that I only see the relevant tasks @@ -48,26 +33,36 @@ I want to be able to clear my completed tasks So I never see them again ``` -As you may imagine, implementing a To-do list is very much a solved problem. However, we are mainly interested in seeing how you approach testing and design. We are looking for: - -* well written, well structured acceptance and unit tests -* clear and expressive JavaScript -* good HTML5 markup +# Screen Shot -Don't worry about deployment, and make sure you read the CONTRIBUTING.md when submitting a pull request. +![myimage-alt-tag](/Users/TY/Desktop/todo-screenshot.png) -## Extensions +Setup +======== -* Deploy the app -* Create a persistance layer (e.g. MongoDB), or use LocalStorage or the filesystem through Node -* Make it look purdy (CSS) - try a framework like Bootstrap or Foundation +* Clone this repo and change into it with ``` cd todo_challenge```. +* If you don't already have them, install node and bower with ```$ brew install node``` and then ```$ npm install bower```. +* Install package dependencies by with ```$ npm install``` and ```$ bower install```. -## CI +Usage +======== -Read the `.travis.yml` if any of the steps below don't make sense! +* Launch the app within your browser with ```$ open index.html```. +* To add a task, simply fill in the box and hit the ```Add Todo``` button. +* To mark a task as done just click the checkbox. +* You can remove completed todos with the ```Remove Completed Todo``` +* If you want to view just the active, completed or all todos you can use the buttons directly above the list. +* To permanently remove all todos, just use the ```Clear List``` button at the bottom. -* Make sure you have set up `npm test` in your `package.json` so that it runs your Karma tests -* Make sure you have your Protractor config file at `e2e/conf.js` -* Make sure `npm start` spins up whatever serves up your app - `http-server`, Sinatra or Node +Tests +============= -Good luck! +* To run the Karma tests for the Angular controller, you will need to have the Karma CLI installed, ```$ npm install -g karma-cli```. +* The tests can now be run with ```$ karma start spec/karma.conf.js```. +* When finished just use ```ctrl + c``` to exit. +* The Protractor tests require that you have the Java Development Kit installed. * You can check if you have it with ```$ java -version```. If you don't, you can get it from here. +* Protractor will also need to be installed globally with ```$ npm install -g protractor```. This will also install webdriver-manager. +* webdriver-manager will need to be updated to make sure it has the correct binaries to get an instance of Selenium Server running (what we'll be using for the tests). Do this with ```webdriver-manager update```. +* Now launch it with ```webdriver-manager start```. +* Now the app will need serving, do so with ```http-server```. +* Finally run the tests with ```$ protractor test/e2e/conf.js```. diff --git a/bower.json b/bower.json new file mode 100644 index 00000000..1ed95ff7 --- /dev/null +++ b/bower.json @@ -0,0 +1,28 @@ +{ + "name": "todo_challenge", + "homepage": "https://github.com/TY231618/todo_challenge", + "authors": [ + "Tony Young " + ], + "description": "", + "main": "", + "moduleType": [], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "jquery": "^2.2.0", + "bootstrap": "^3.3.6", + "angular": "^1.4.9", + "angular-resource": "^1.4.9" + }, + "devDependencies": { + "angular-mocks": "^1.4.9", + "angular-route": "^1.4.9" + } +} diff --git a/css/main.css b/css/main.css new file mode 100644 index 00000000..ad5d196e --- /dev/null +++ b/css/main.css @@ -0,0 +1,32 @@ +body { + text-align: center; + background-image: url(/Users/TY/Desktop/stickynote.jpg); +} + +h2 { + font-family: Sans-Serif; + width:800px; + margin:10px auto; + text-align:left; + padding:10px; + padding-left: 300px; +} + +.done { + text-decoration: line-through; color: #ccc; +} + +.center{ + width:200px; + margin:0 auto; + text-align:left; +} + +p { + position: fixed; + bottom: 200px; + right: 800px; + font-family: Sans-Serif; + text-decoration: underline; + font-weight: bold; +} diff --git a/index.html b/index.html new file mode 100644 index 00000000..4fccf157 --- /dev/null +++ b/index.html @@ -0,0 +1,47 @@ + + + + + + + Todo List Challenge + + + + + + + + + + + + + +
+
+
+ +

+ + + + + + + +
+ +

+

My list of todos.....

+ +

Number of Todos: {{todoCtrl.countTodo()}}

+ +
+ + diff --git a/js/app.js b/js/app.js new file mode 100644 index 00000000..148358c7 --- /dev/null +++ b/js/app.js @@ -0,0 +1 @@ +var todoList = angular.module('TodoList', ['ngResource']); diff --git a/js/todoListController.js b/js/todoListController.js new file mode 100644 index 00000000..8c0e912b --- /dev/null +++ b/js/todoListController.js @@ -0,0 +1,65 @@ +todoList.controller('TodoListController', function() { + var self = this; + + self.todos = []; + self.filteredTodoList = []; + self.oldList = []; + + self.addTodo = function(newTodo){ + self.allTodo(); + self.todos.push({title: newTodo, done: false}); + self.newTodo = ''; + self.filteredTodoList = self.todos; + + }; + + self.removeTodo = function () { + self.allTodo(); + self.oldList = self.todos; + self.todos = []; + + + for (var i = 0; i < self.oldList.length; i++) { + if (!self.oldList[i].done) { + self.todos.push(self.oldList[i]); + } + } + self.filteredTodoList = self.todos; + + } + + self.completedTodo = function () { + self.oldList = self.filteredTodoList; + self.todos = []; + + for (var i = 0; i < self.oldList.length; i++) { + if (self.oldList[i].done) { + self.todos.push(self.oldList[i]); + } + } + } + + self.activeTodo = function () { + self.oldList = self.filteredTodoList; + self.todos = []; + + for (var i = 0; i < self.oldList.length; i++) { + if (!self.oldList[i].done) { + self.todos.push(self.oldList[i]); + } + } + } + + self.allTodo = function () { + self.todos = self.filteredTodoList; + } + + self.countTodo = function () { + return self.todos.length; + } + + self.clearAll = function() { + self.todos = []; + self.filteredTodoList = []; + } +}); diff --git a/package.json b/package.json new file mode 100644 index 00000000..162c5398 --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "todo_challenge", + "version": "1.0.0", + "description": "* Deadline: submit completed pull request by 9am on Monday * You may use whatever level of JavaScript you feel comfortable with - pure JS, jQuery, Angular, or whatever weird and wonderful framework you want to try. Extra points for DogeScript", + "main": "index.js", + "directories": { + "doc": "docs" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/TY231618/todo_challenge.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/TY231618/todo_challenge/issues" + }, + "homepage": "https://github.com/TY231618/todo_challenge#readme", + "devDependencies": { + "jasmine-core": "^2.4.1", + "karma": "^0.13.19", + "karma-chrome-launcher": "^0.2.2", + "karma-jasmine": "^0.3.6", + "karma-phantomjs-launcher": "^1.0.0", + "phantomjs": "^2.1.3", + "protractor": "^3.0.0" + }, + "dependencies": { + "http-server": "^0.8.5" + } +} diff --git a/test/e2e/conf.js b/test/e2e/conf.js new file mode 100644 index 00000000..367e45b1 --- /dev/null +++ b/test/e2e/conf.js @@ -0,0 +1,4 @@ +exports.config = { + seleniumAddress: 'http://localhost:4444/wd/hub', + specs: ['todoListFeature.js'] +} diff --git a/test/e2e/todoListFeature.js b/test/e2e/todoListFeature.js new file mode 100644 index 00000000..a78ab1df --- /dev/null +++ b/test/e2e/todoListFeature.js @@ -0,0 +1,12 @@ +describe('Todo List', function() { + + + beforeEach(function() { + browser.get('http://localhost:8080'); + }); + + it('has a title', function() { + expect(browser.getTitle()).toEqual('Todo List Challenge'); + }); + +}); diff --git a/test/karma.conf.js b/test/karma.conf.js new file mode 100644 index 00000000..e0998aef --- /dev/null +++ b/test/karma.conf.js @@ -0,0 +1,68 @@ +// Karma configuration +// Generated on Thu Nov 27 2014 10:43:21 GMT+0000 (GMT) + +module.exports = function(config) { + config.set({ + + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '../', + + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine'], + + + // list of files / patterns to load in the browser + files: [ + 'bower_components/angular/angular.js', + 'bower_components/angular-route/angular-route.js', + 'bower_components/angular-resource/angular-resource.js', + 'bower_components/angular-mocks/angular-mocks.js', + 'js/**/*.js', + 'test/**/*.spec.js' + ], + + + // list of files to exclude + exclude: [], + + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: {}, + + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress'], + + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['PhantomJS'], + + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false + }); +}; diff --git a/test/todoListControllerFeature.spec.js b/test/todoListControllerFeature.spec.js new file mode 100644 index 00000000..fb3b34d9 --- /dev/null +++ b/test/todoListControllerFeature.spec.js @@ -0,0 +1,97 @@ +describe('TodoListController', function() { + beforeEach(module('TodoList')); + + var ctrl; + + beforeEach(inject(function($controller) { + ctrl = $controller('TodoListController'); + })); + + it('initialises with an empty search result and term', function() { + expect(ctrl.searchResult).toBeUndefined(); + expect(ctrl.searchTerm).toBeUndefined(); + }); + + describe('new todo', function(){ + it('adds a todo to a list', function(){ + ctrl.addTodo('set alarm'); + expect(ctrl.newTodo).toEqual(''); + expect(ctrl.todos[0].title).toEqual("set alarm"); + }); + + it('new todos are not completed', function(){ + ctrl.addTodo('set alarm'); + expect(ctrl.todos[0].done).toEqual(false) + }) + }); + + describe('#removeTodo', function(){ + it('', function() { + ctrl.addTodo('set alarm'); + ctrl.todos[0].done = true; + ctrl.removeTodo(); + expect(ctrl.todos.length).toEqual(0); + }) + }) + + describe('#completedTodo', function () { + it('displays all completed todos', function () { + ctrl.addTodo('set alarm'); + ctrl.addTodo('make breakfast'); + ctrl.todos[0].done = true; + ctrl.completedTodo(); + expect(ctrl.todos.length).toEqual(1); + }); + }); + + describe('#activeTodo', function () { + it('displays all active todos', function () { + ctrl.addTodo('set alarm'); + ctrl.addTodo('make breakfast'); + ctrl.todos[0].done = true; + ctrl.activeTodo(); + expect(ctrl.todos.length).toEqual(1); + }); + }); + + describe('#allTodo', function () { + it('displays all todos', function () { + ctrl.addTodo('set alarm'); + ctrl.addTodo('make breakfast'); + ctrl.todos[0].done = true; + ctrl.activeTodo(); + expect(ctrl.todos.length).toEqual(1); + }); + }); + + describe('#countTodo', function () { + it('displays number of todos for all, active and completed lists', function () { + ctrl.addTodo('set alarm'); + ctrl.addTodo('make breakfast'); + ctrl.addTodo('go gym'); + ctrl.todos[0].done = true; + ctrl.activeTodo(); + expect(ctrl.todos.length).toEqual(2); + ctrl.completedTodo(); + expect(ctrl.todos.length).toEqual(1); + ctrl.allTodo(); + expect(ctrl.todos.length).toEqual(3); + }); + }); + + describe('#clearAll', function () { + it('displays all todos', function () { + ctrl.addTodo('set alarm'); + ctrl.addTodo('make breakfast'); + ctrl.addTodo('go gym'); + ctrl.todos[0].done = true; + ctrl.clearAll(); + ctrl.activeTodo(); + expect(ctrl.todos.length).toEqual(0); + ctrl.completedTodo(); + expect(ctrl.todos.length).toEqual(0); + ctrl.allTodo(); + expect(ctrl.todos.length).toEqual(0); + }); + }); +});