diff --git a/README.md b/README.md index 4171bc5..c49ff7b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,21 @@ # Thoughter -Definitely not a Twitter clone. +This project was created for Iron Yard Students to practice Unit testing with +Karma, Mocha and Chai. + +## How to use: + +App uses grunt as a dev dependency. Grunt is configured to copy app js html and +scss files into build directory. Prior to copying js files are linted and tested +using js hint and karma. + +## To set up: + +1. Fork directory from https://github.com/ElizabethBoles/thoughter +2. Run ```npm install``` in your terminal which downloads necessary app dependencies +and developer dependencies (jQuery, Grunt and Grunt task managers). +3. Run ```Grunt build``` to create build directory which then can be used to view app +in preferred browser. + +Testing code and Grunt configuration created by Elizabeth Boles. diff --git a/gruntfile.js b/gruntfile.js new file mode 100644 index 0000000..a3c9b43 --- /dev/null +++ b/gruntfile.js @@ -0,0 +1,117 @@ +module.exports = function configureGrunt(gruntConfig){ + gruntConfig.initConfig({ + clean: [ 'build/' ],//cleaning + + copy: { + + copythehtml: { + files: [ + { + cwd: 'src/',//to get into source + src: [ '*.html' ],//anything that has a html at end + dest: 'build/',//copy file and put that copy in this build dir + expand: true + } + ] + }, + copythejs: { + files: [ + { + cwd: 'src/js/', + src: ['*.js'], + dest: 'build/js/', // slash at the end means i want you to find the js and go in it and thats where i want you to put the files + expand: true + } + ] + }, + copythejquery: {//copying dependency files into js build folder so my app has proper linkage + files: [ + { + cwd: 'node_modules/jquery/dist/', + src: ['jquery.js'],//jquery is js + dest: 'build/js/vendor/',//so now we know the jquery file will be copied into our build/js/vendor folder//then when you run it you can see its created on right + expand: true + } + ] + } + }, + + sass: {//within the sass what we're creating is a task that looks for + //all our sass/css and then compiling all of it into one pile called + //style.css and putting our style.css file in our build directory + //style.css will only ever be in the build + all: {// + // + files: { + //dest/source + //dest - where were gunna put whatever we say is our source into + //> creates a new file called style.css and puts in our main.scss + //and everything that exports into it + 'build/style.css' : 'src/sass/main.scss' + } + } + + }, + + jshint: {//linting + + appjs: { + options: { + jshintrc: '.jshintrc' + }, + files: { + src: [ 'src/**/*.js' ] + } + } + + }, + + karma: {//testing + //configuring karma with grunt letting grunt know that karma works + //with mocha and chai frame works and to launch testing within karma browser + all: { + options: { + frameworks: [ 'mocha', 'chai' ], + browsers: [ 'Chrome' ], + singleRun: true, + files: [//test all of the files that end in extension .js + //when i use my sinnon server find node modules file with that code + //and test code is written my test/specs folder with any file that has + //a .js extention + 'src/**/*.js', + 'node_modules/sinon/pkg/sinon-2.0.0.js', + 'test/specs/**/*.js' + ], + preprocessors: {//what files we want to be pre processed + 'src/**/*.js': ['coverage'],//all the files were testing + //want coverage plug in to watch during those tests + //then generate a summary + //coverage is the plug in and dots is part of how they report + //back + }, + reporters: ['dots', 'coverage'],//in that summary i want + //dots which shows me the number of tests and a color + //indication of whether or not they passed + coverageReporter: { + type: 'text-summary'//so it doesnt come out looking all codey + //makes it look clean in terminal + } + } + } + + } + + + }); + require('load-grunt-tasks')(gruntConfig); + //whenever i run grunt build in my terminal do these things in this order + //out of convention building our build directory + //we dont want to put anything in our build directory thats broken + //thats why first jshint to make sure theres no syntax errors and then why + //i test my files next to make sure nothing breaks and then if those two pass + //i know i have good code so i can copy those files and put into build directory + //the clean task deletes the whole build directory and is the first task that runs + //build = running all of these tasks. you can name it whatever + gruntConfig.registerTask( 'build', [ 'clean', 'jshint', 'karma', 'copy', 'sass' ] ); + //gruntConfig.registerTask( 'watch', ['build']); +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..8ffb0cf --- /dev/null +++ b/package.json @@ -0,0 +1,39 @@ +{ + "name": "dandatesting", + "version": "1.0.0", + "description": "", + "main": "thoughter/src/js/recent-thoughts.js", + "scripts": { + "test": "karma start thought.conf.js" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/ElizabethBoles/thoughter.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/ElizabethBoles/thoughter/issues" + }, + "homepage": "https://github.com/ElizabethBoles/thoughter#readme", + "devDependencies": { + "chai": "^3.5.0", + "grunt": "^1.0.1", + "grunt-contrib-clean": "^1.0.0", + "grunt-contrib-copy": "^1.0.0", + "grunt-contrib-jshint": "^1.1.0", + "grunt-contrib-sass": "^1.0.0", + "grunt-karma": "^2.0.0", + "karma": "^1.5.0", + "karma-chai": "^0.1.0", + "karma-chrome-launcher": "^2.0.0", + "karma-coverage": "^1.1.1", + "karma-mocha": "^1.3.0", + "load-grunt-tasks": "^3.5.2", + "mocha": "^3.2.0", + "sinon": "^2.0.0" + }, + "dependencies": { + "jquery": "^3.2.0" + } +} diff --git a/src/index.html b/src/index.html index d257fa8..e40156f 100644 --- a/src/index.html +++ b/src/index.html @@ -16,6 +16,8 @@

Thoughter

- + + + diff --git a/src/js/new-thought.js b/src/js/new-thought.js index f56e972..30c790d 100644 --- a/src/js/new-thought.js +++ b/src/js/new-thought.js @@ -28,7 +28,7 @@ console.error('Looks like a bad status code:', res.status); return Promise.reject('Sorry, but there was a problem with your request.'); } else { - return res.json() + return res.json(); } }); }; diff --git a/src/js/recent-thoughts.js b/src/js/recent-thoughts.js index c548e79..e43ed60 100644 --- a/src/js/recent-thoughts.js +++ b/src/js/recent-thoughts.js @@ -2,28 +2,38 @@ 'use strict'; window.thoughter = window.thoughter || {}; + //name space /** * Shows the provided thought data on the page in the `.recent` element * * @param {Array} thoughts The array of thought objects to display + *this function takes an array as an arg and does a lot of dom manipulation + *so what we're gunna test is whethere or not the corrext dom manip is happening * @return {void} */ window.thoughter.showRecent = function showRecent(thoughts = []) { if (!Array.isArray(thoughts)) { return; } - - recent = document.querySelector('.recent'); + //element(ex section/main) with a class of recent + //trying to find something with the class of recent + let recent = document.querySelector('.recent'); + //when it finds something with the class of recent thoughts.forEach(function showThought(thought) { + //for each thought do the stuff down here + //if each thought does not have thought.content, thought.createTime + //or a thought.id then return and dont do that stuff if (!thought.content || !thought.createTime || !thought.id) { - return; + return;//dont want to go down cus ill get an error } - + //it creates for each thought a new article element and then + //appends it to the recent element let thoughtUI = document.createElement('article'); thoughtUI.classList.add('panel'); thoughtUI.classList.add('panel-info'); thoughtUI.setAttribute('id', 'thought-' + thought.id); + //66 thoughtUI.innerHTML = `
Posted ${thoughts.createTime}

${thought.content}

@@ -38,7 +48,9 @@ * @param {Number} count How many thoughts to limit to, must be a positive number (defaults to 10) * @return {Promise} The resolved promise will have the data array as the argument */ - window.thoughter.getRecent = function getRecent(count = 10) { + window.thoughter.getRecent = function getRecent(numb = 10) { + let count = numb; + if (typeof(count) !== 'number' || count < 1) { return Promise.reject('Sorry, but the count must be a positive number'); } diff --git a/src/sass/main.scss b/src/sass/main.scss index affe303..8710b24 100644 --- a/src/sass/main.scss +++ b/src/sass/main.scss @@ -2,5 +2,4 @@ @import 'variables'; @import 'header'; @import 'login'; -@import 'new-thought'; @import 'recent'; diff --git a/test/specs/recent-thoughts.spec.js b/test/specs/recent-thoughts.spec.js new file mode 100644 index 0000000..79ea683 --- /dev/null +++ b/test/specs/recent-thoughts.spec.js @@ -0,0 +1,134 @@ + (function() { + 'use strict'; + //this is where i created the 3 thoughts + let expect = window.chai.expect; + //because lazy + let hi = {}; + hi.content = 'hi'; + hi.createTime = new Date(); + hi.id = 'xxxx'; + let bye = {}; + bye.content = 'bye'; + bye.createTime = new Date(); + bye.id = 'yyyy'; + let hibye = {}; + hibye.content = 'hibye'; + hibye.createTime = new Date(); + hibye.id = 'zzzz'; + + describe('recent-thoughts.js', function() { + //describes recent-thoughts.js file + it('should know that the nameSpace exists', function(){ + //name spaces are an object so we want it to be an object + expect(window.thoughter).to.be.a('object'); + }); + + describe('showRecent function', function() { + //describes first function im testing + //which is .showRecent + //going to need a fixture for this test suite + //create an element with a class of recent + beforeEach(function() { + //everything im doing in my before and after is not connected + //to the recent-thoughts.js + //but im getting the info from recent-thoughts.js + //and im trying to recreate what it's trying to do + let mainTag = document.createElement('main'); + //before i run this test making sure there is an + //existing element with a class of recent + //when i run my test line 20 will work because i created + //the element with the class of recent + mainTag.classList.add('recent'); + //document.createElement('body'); + document.querySelector('body').appendChild(mainTag); + }); + //now im removing it -idempoden + //if i dont remove it as i go to my other tests having that + //fixture there might cause failures + afterEach(function() { + let mainTag = document.querySelector('main'); + mainTag.parentNode.removeChild(mainTag); + //after each test assertion in this describe i find + //a main/tag element and remove it + }); + //keep on same cus its not imbeded in fn + it('should create a new article element for every thought', function(){ + window.thoughter.showRecent([hi, bye, hibye]);//3 thoughts + //create a variable so i dont have to type doc.querselect everytime + let recentElement = document.querySelector('.recent'); + //testing that the recent element has children and that it has more + //then one + expect(recentElement.childNodes.length).to.equal(3); + //selected recent element dug into child nodes got length of child nodes + //and tested if the length was equal to the amount of thoughts i gave the fn + //console.log(window.thoughter.showRecent); + //want to test that articles are being created + //console.info(document.querySelector('.recent')); + //expect(recentElement.childNodes[1].id).to.equal('thought-yyyy'); + //console.log(recentElement.childNodes[1]); + //tapping into first article + }); + it('should pass an array with 1obj', function(){ + let recentElement = document.querySelector('main.recent'); + window.thoughter.showRecent([hi]); + expect(recentElement.childNodes.length).to.equal(1); + }); + it('should pass in an empty array', function(){ + let article = document.querySelector('main.recent'); + window.thoughter.showRecent([]); + expect(article.length).to.equal(); + }); + }); + //where new describe begins - 3rd one + //every function has its own describe + describe('get recent', function(){ + let server; + + beforeEach(function(){ + server = sinon.fakeServer.create(); + server.autoRespond = true; + server.respondWith( + 'GET', + 'http://thoughter.herokuapp.com/api/Thoughts?filter={"order":"createTime DESC","limit":3}', + [ + 200, + { 'Content-Type': 'application/json' }, + //moching out what the fetch returns in its response + '["hi", "bye", "hibye"]' + ] + //the function that im testing fetches at a specific url so to test that fetch + //setting up a fake server connected to that specific url so that the real + //function hits server and not the API + // + ); + }); + + afterEach(function() { + server.restore(); + }); + it('should return data back from server', function(){ + let result = window.thoughter.getRecent(); + // expect( result ).to.be.an('object'); + expect(result.then).to.be.a('function'); + expect(result.catch).to.be.a('function'); + + result + .then(function(data) { + expect(data).to.be.an('array'); + expect(data.length).to.equal(3); + //expect data and we know data is an + //array and has a length of 3 + //expect the first index in the data array + //to equal hi and it should equal hi because + //thats what i told my moc server to type + expect(data[0]).to.equal('hi'); + tellMochaWeAreDone(); + }) + .catch(function(err) { + tellMochaWeAreDone(err); + }); + }); + }); + + }); + }()); diff --git a/thought.conf.js b/thought.conf.js new file mode 100644 index 0000000..cd1a8fc --- /dev/null +++ b/thought.conf.js @@ -0,0 +1,12 @@ +module.exports = function karmConfig( config ) { + config.set({ + frameworks: [ 'mocha', 'chai' ], + browsers: [ 'Chrome' ], + singleRun: true, + files: [ + 'thoughter/src/**/*.js', + 'node_modules/sinon/pkg/sinon-2.0.0.js', + 'thoughter/test/specs/**/*.js' + ] + }); +};