From 81cab612c0d7e52b575692065b41d06519abb1b0 Mon Sep 17 00:00:00 2001 From: jfusco Date: Sat, 1 Apr 2017 11:52:42 -0400 Subject: [PATCH 1/4] Add initial files for unit testing Add initial karma.confg file with settings and proper loaders. Add karma and other dependencies to package.json Update some outdated libraries in package.json --- karma.conf.js | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 29 ++++++++++++++++++++--------- 2 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 karma.conf.js diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..f7a6989 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,50 @@ +'use strict'; + +var webpack = require('karma-webpack'); +var path = require('path'); + +module.exports = function (config) { + config.set({ + frameworks: ['jasmine'], + files: ['__tests__/*-test.js'], + plugins: [webpack, 'karma-jasmine', 'karma-phantomjs-launcher', 'karma-spec-reporter', 'karma-coverage'], + browsers: ['PhantomJS'], + preprocessors: { + '__tests__/*-test.js': ['webpack'] + }, + coverageReporter: { + dir: './coverage', + reporters: [ + { type: 'lcov', subdir: 'reports' } + ] + }, + colors: true, + reporters: ['spec', 'coverage'], + webpack: { + module: { + rules: [ + { + test: /\.js?$/, + loader: 'babel-loader', + exclude: /(node_modules)/ + }, + { + enforce: 'pre', + test: /\.js/, + loader: 'isparta-loader', + exclude: /(__tests__|node_modules)/ + } + ], + noParse: [ + /node_modules\/sinon\// + ] + }, + resolve: { + alias: { + 'sinon': 'sinon/pkg/sinon.js' + } + } + }, + webpackMiddleware: { noInfo: true } + }); +}; diff --git a/package.json b/package.json index bf82e80..e4327e1 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,9 @@ } ], "scripts": { + "test": "karma start --single-run --no-auto-watch", "dev": "cross-env NODE_ENV=development gulp", - "build": "cross-env NODE_ENV=production gulp dist", - "test": "echo \"Error: no test specified\" && exit 1", + "build": "npm run test && cross-env NODE_ENV=production gulp dist", "version": "git add .", "postversion": "git push && git push --tags" }, @@ -33,14 +33,14 @@ "babel-preset-stage-0": "^6.22.0", "beepbeep": "^1.2.1", "browser-sync": "^2.18.8", - "cross-env": "^3.2.3", + "cross-env": "^4.0.0", "del": "^2.2.2", - "eslint": "^3.18.0", + "eslint": "^3.19.0", "eslint-config-standard": "^7.1.0", - "eslint-loader": "^1.7.0", + "eslint-loader": "^1.7.1", "eslint-plugin-promise": "^3.5.0", "eslint-plugin-standard": "^2.1.1", - "file-loader": "^0.10.1", + "file-loader": "^0.11.1", "gulp": "^3.9.1", "gulp-combine-mq": "^0.4.0", "gulp-cssnano": "^2.1.2", @@ -51,22 +51,33 @@ "gulp-plumber": "^1.1.0", "gulp-sass": "^3.1.0", "gulp-sass-glob": "^1.0.8", - "gulp-sourcemaps": "^2.4.1", + "gulp-sourcemaps": "^2.5.0", "gulp-util": "^3.0.8", "gulp-watch": "^4.3.11", "gulp.spritesmith": "^6.3.0", + "isparta-loader": "^2.0.0", + "istanbul": "^0.4.5", + "istanbul-instrumenter-loader": "^2.0.0", + "jasmine-core": "^2.5.2", + "karma": "^1.5.0", + "karma-coverage": "^1.1.1", + "karma-jasmine": "^1.1.0", + "karma-phantomjs-launcher": "^1.0.4", + "karma-spec-reporter": "0.0.30", + "karma-webpack": "^2.0.3", "progress-bar-webpack-plugin": "^1.9.3", "run-sequence": "^1.2.2", + "sinon": "^2.0.0", "url-loader": "^0.5.8", "webpack": "^2.2.1", "webpack-dev-middleware": "^1.10.1", - "webpack-hot-middleware": "^2.17.1", + "webpack-hot-middleware": "^2.18.0", "webpack-stream": "^3.2.0" }, "dependencies": { "font-awesome": "^4.7.0", "jquery": "^3.1.1", - "normalize.css": "^5.0.0", + "normalize.css": "^6.0.0", "slick-carousel": "^1.6.0" } } From 3fdb301e80b04e5bd4f1817275b725f6166239f7 Mon Sep 17 00:00:00 2001 From: jfusco Date: Sat, 1 Apr 2017 23:21:30 -0400 Subject: [PATCH 2/4] Add initial jasmine tests Add jasmine and karma-jasmine to the project. Add coverage reporter and configuration to karma.config Add tests for default instantiation of GitHub component Add initial test for ajax requests to test spies Add helper object to mock out json response from API Add needed devDependencies to project to complete unit testing --- .gitignore | 1 + __tests__/Github-test.js | 89 +++++++ __tests__/__helpers__/GithubResponse.js | 38 +++ coverage/reports/lcov-report/base.css | 213 ++++++++++++++++ coverage/reports/lcov-report/index.html | 97 ++++++++ .../lcov-report/modules/Github.js.html | 231 ++++++++++++++++++ .../reports/lcov-report/modules/index.html | 97 ++++++++ coverage/reports/lcov-report/prettify.css | 1 + coverage/reports/lcov-report/prettify.js | 1 + .../reports/lcov-report/sort-arrow-sprite.png | Bin 0 -> 209 bytes coverage/reports/lcov-report/sorter.js | 158 ++++++++++++ coverage/reports/lcov.info | 86 +++++++ karma.conf.js | 9 +- package.json | 5 +- src/js/modules/Github.js | 6 +- webpack.config.babel.js | 2 +- 16 files changed, 1030 insertions(+), 4 deletions(-) create mode 100644 __tests__/Github-test.js create mode 100644 __tests__/__helpers__/GithubResponse.js create mode 100644 coverage/reports/lcov-report/base.css create mode 100644 coverage/reports/lcov-report/index.html create mode 100644 coverage/reports/lcov-report/modules/Github.js.html create mode 100644 coverage/reports/lcov-report/modules/index.html create mode 100644 coverage/reports/lcov-report/prettify.css create mode 100644 coverage/reports/lcov-report/prettify.js create mode 100644 coverage/reports/lcov-report/sort-arrow-sprite.png create mode 100644 coverage/reports/lcov-report/sorter.js create mode 100644 coverage/reports/lcov.info diff --git a/.gitignore b/.gitignore index a07fbad..db63b9a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ npm-debug.log *.sublime-project *.sublime-workspace +*.DS_Store diff --git a/__tests__/Github-test.js b/__tests__/Github-test.js new file mode 100644 index 0000000..288acbd --- /dev/null +++ b/__tests__/Github-test.js @@ -0,0 +1,89 @@ +import 'babel-polyfill' +import $ from 'jquery' +import 'jasmine-jquery' +import 'jasmine-ajax' +import GithubResponse from './__helpers__/GithubResponse' +import { GitHub } from '../src/js/modules/Github' + +jasmine.getFixtures().fixturesPath = 'base/src/modules' + +describe('Github.js', () => { + let github = null + + beforeEach(() => { + // In case we want to sandbox any module, we can use this + /* + github = sandbox({ + class: 'github' + }) + */ + + // OR + + // We don't need the github variable if we setFixtures :) + /* + setFixtures(sandbox({ + class: 'github' + })) + */ + + github = new GitHub('jfusco') + }) + + afterEach(() => { + github = null + }) + + it('exists in DOM', () => { + loadFixtures('github.html') + + expect($('.github')).toBeInDOM() + }) + + it('should error if no username is passed in', () => { + // Test undefined + expect((() => { + new GitHub() + }) + ).toThrowError(Error) + + // Test empty string + expect((() => { + new GitHub('') + }) + ).toThrowError(Error) + }) + + it('should set this.el to jQuery object', () => { + expect(github.el instanceof $).toBe(true) + }) + + it('should set a username', () => { + expect(github.username).toBe('jfusco') + }) +}) + +describe('Github - render', () => { + beforeEach(() => { + loadFixtures('github.html') + + jasmine.Ajax.install(); + }) + + afterEach(() => { + jasmine.Ajax.uninstall(); + }) + + it('should make a call to get user info', () => { + const github = new GitHub('DennisMartinez') + + const spy = spyOn($, 'getJSON') + + jasmine.Ajax.stubRequest(`https://api.github.com/users/${github.username}`) + .andReturn(GithubResponse) + + github.getUserData() + + expect(spy).toHaveBeenCalled() + }) +}) diff --git a/__tests__/__helpers__/GithubResponse.js b/__tests__/__helpers__/GithubResponse.js new file mode 100644 index 0000000..78a8fb1 --- /dev/null +++ b/__tests__/__helpers__/GithubResponse.js @@ -0,0 +1,38 @@ +export default { + users: { + status: 200, + contentType: 'application/json', + responseText: { + avatar_url: "https://avatars1.githubusercontent.com/u/1375616?v=3", + bio: "mek a d weeb fun", + blog: null, + company: "Verndale", + created_at: "2012-01-24T16:19:15Z", + email: "denniswaltermartinez@gmail.com", + events_url: "https://api.github.com/users/DennisMartinez/events{/privacy}", + followers: 13, + followers_url: "https://api.github.com/users/DennisMartinez/followers", + following: 15, + following_url: "https://api.github.com/users/DennisMartinez/following{/other_user}", + gists_url: "https://api.github.com/users/DennisMartinez/gists{/gist_id}", + gravatar_id: "", + hireable: true, + html_url: "https://github.com/DennisMartinez", + id: 1375616, + location: "CO", + login: "DennisMartinez", + name: "Dennis Martinez", + organizations_url: "https://api.github.com/users/DennisMartinez/orgs", + public_gists: 20, + public_repos: 10, + received_events_url: "https://api.github.com/users/DennisMartinez/received_events", + repos_url: "https://api.github.com/users/DennisMartinez/repos", + site_admin: false, + starred_url: "https://api.github.com/users/DennisMartinez/starred{/owner}{/repo}", + subscriptions_url: "https://api.github.com/users/DennisMartinez/subscriptions", + type: "User", + updated_at: "2017-03-25T16:42:02Z", + url: "https://api.github.com/users/DennisMartinez" + } + } +} diff --git a/coverage/reports/lcov-report/base.css b/coverage/reports/lcov-report/base.css new file mode 100644 index 0000000..29737bc --- /dev/null +++ b/coverage/reports/lcov-report/base.css @@ -0,0 +1,213 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.medium .chart { border:1px solid #f9cd0b; } +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } +/* light gray */ +span.cline-neutral { background: #eaeaea; } + +.cbranch-no { background: yellow !important; color: #111; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/coverage/reports/lcov-report/index.html b/coverage/reports/lcov-report/index.html new file mode 100644 index 0000000..0cc2638 --- /dev/null +++ b/coverage/reports/lcov-report/index.html @@ -0,0 +1,97 @@ + + + + Code coverage report for All files + + + + + + + +
+
+

+ / +

+
+
+ 88.57% + Statements + 62/70 +
+
+ 85.71% + Branches + 24/28 +
+
+ 100% + Functions + 18/18 +
+
+ 53.85% + Lines + 7/13 +
+
+ 9 statements, 3 functions, 9 branches + Ignored      +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
modules/
88.57%62/7085.71%24/28100%18/1853.85%7/13
+
+
+ + + + + + + diff --git a/coverage/reports/lcov-report/modules/Github.js.html b/coverage/reports/lcov-report/modules/Github.js.html new file mode 100644 index 0000000..2586943 --- /dev/null +++ b/coverage/reports/lcov-report/modules/Github.js.html @@ -0,0 +1,231 @@ + + + + Code coverage report for modules/Github.js + + + + + + + +
+
+

+ all files / modules/ Github.js +

+
+
+ 88.57% + Statements + 62/70 +
+
+ 85.71% + Branches + 24/28 +
+
+ 100% + Functions + 18/18 +
+
+ 53.85% + Lines + 7/13 +
+
+ 9 statements, 3 functions, 9 branches + Ignored      +
+
+
+
+

+
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55  +  +  +  +  +  + +  +  + + + +  +  + + +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
/**
+ * Example module using async/await, pulling from a user on github.
+ *
+ * Note:
+ *   jQuery is used in the example but the project is not concrete to jQuery.
+ */
+import $ from 'jquery'
+ 
+export class GitHub {
+  constructor(username) {
+    if (typeof username === 'undefined' || username === '') {
+      throw new Error('You must provide a username')
+    }
+ 
+    this.el = $('.github')
+    this.username = username
+  }
+ 
+  async getUserData() {
+    return await $.getJSON(`https://api.github.com/users/${this.username}`)
+  }
+ 
+  // Just an example, you may want to use a templating engine.
+  render({ avatar_url: avatarUrl, html_url: url, company, name, bio, email }) {
+    const template = `
+      <div class="github-avatar">
+        <img src="${avatarUrl}" alt="${name}">
+      </div>
+      <div class="github-info">
+        <ul>
+          <li><strong>GitHub:</strong> <a href="${url}" target="_blank">${url}</a></li>
+          <li><strong>Company:</strong> ${company}</li>
+          <li><strong>Email:</strong> ${email}</li>
+        </ul>
+ 
+        <h4>Bio</h4>
+        <p>${bio}</p>
+      </div>
+    `
+ 
+    // An example of how we can add some logs or blocks of code in development only
+    // On a production build, webpack will remove this entire block of code, including the if check
+    if (__DEV__) console.log('Template created')
+ 
+    // Breaks the Single Responsibility principle, but again, only an example.
+    // https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)
+    this.el.html(template)
+ 
+    if (__DEV__) console.log('Template rendered')
+ 
+    return template
+  }
+}
+ 
+ 
+
+
+ + + + + + + diff --git a/coverage/reports/lcov-report/modules/index.html b/coverage/reports/lcov-report/modules/index.html new file mode 100644 index 0000000..aac376b --- /dev/null +++ b/coverage/reports/lcov-report/modules/index.html @@ -0,0 +1,97 @@ + + + + Code coverage report for modules/ + + + + + + + +
+
+

+ all files modules/ +

+
+
+ 88.57% + Statements + 62/70 +
+
+ 85.71% + Branches + 24/28 +
+
+ 100% + Functions + 18/18 +
+
+ 53.85% + Lines + 7/13 +
+
+ 9 statements, 3 functions, 9 branches + Ignored      +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
Github.js
88.57%62/7085.71%24/28100%18/1853.85%7/13
+
+
+ + + + + + + diff --git a/coverage/reports/lcov-report/prettify.css b/coverage/reports/lcov-report/prettify.css new file mode 100644 index 0000000..b317a7c --- /dev/null +++ b/coverage/reports/lcov-report/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/coverage/reports/lcov-report/prettify.js b/coverage/reports/lcov-report/prettify.js new file mode 100644 index 0000000..ef51e03 --- /dev/null +++ b/coverage/reports/lcov-report/prettify.js @@ -0,0 +1 @@ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/coverage/reports/lcov-report/sort-arrow-sprite.png b/coverage/reports/lcov-report/sort-arrow-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..03f704a609c6fd0dbfdac63466a7d7c958b5cbf3 GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>Jii$m5978H@?Fn+^JD|Y9yzj{W`447Gxa{7*dM7nnnD-Lb z6^}Hx2)'; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function (a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function (a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function () { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i =0 ; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function () { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(cols); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/coverage/reports/lcov.info b/coverage/reports/lcov.info new file mode 100644 index 0000000..9758f17 --- /dev/null +++ b/coverage/reports/lcov.info @@ -0,0 +1,86 @@ +TN: +SF:/Users/Rinzler/Projects/Personal/build-tools/src/js/modules/Github.js +FN:12,(anonymous_1) +FN:12,defineProperties +FN:12,(anonymous_3) +FN:24,_interopRequireDefault +FN:26,_asyncToGenerator +FN:26,(anonymous_6) +FN:26,(anonymous_7) +FN:26,step +FN:26,(anonymous_9) +FN:26,(anonymous_10) +FN:28,_classCallCheck +FN:30,(anonymous_12) +FN:31,GitHub +FN:44,(anonymous_14) +FN:45,_callee +FN:46,_callee$ +FN:64,getUserData +FN:75,render +FNF:18 +FNH:18 +FNDA:1,(anonymous_1) +FNDA:1,defineProperties +FNDA:1,(anonymous_3) +FNDA:2,_interopRequireDefault +FNDA:1,_asyncToGenerator +FNDA:1,(anonymous_6) +FNDA:1,(anonymous_7) +FNDA:1,step +FNDA:0,(anonymous_9) +FNDA:0,(anonymous_10) +FNDA:7,_classCallCheck +FNDA:1,(anonymous_12) +FNDA:7,GitHub +FNDA:1,(anonymous_14) +FNDA:1,_callee +FNDA:1,_callee$ +FNDA:1,getUserData +FNDA:0,render +DA:0,7 +DA:7,1 +DA:10,7 +DA:11,7 +DA:12,2 +DA:15,5 +DA:16,5 +DA:24,0 +DA:25,0 +DA:43,0 +DA:47,0 +DA:49,0 +DA:51,0 +LF:13 +LH:7 +BRDA:12,1,0,2 +BRDA:12,1,1,2 +BRDA:12,2,0,2 +BRDA:12,2,1,0 +BRDA:12,3,0,1 +BRDA:12,3,1,0 +BRDA:12,4,0,0 +BRDA:12,4,1,1 +BRDA:24,5,0,0 +BRDA:24,5,1,2 +BRDA:24,6,0,2 +BRDA:24,6,1,2 +BRDA:26,7,0,0 +BRDA:26,7,1,1 +BRDA:28,8,0,0 +BRDA:28,8,1,7 +BRDA:34,9,0,2 +BRDA:34,9,1,5 +BRDA:34,10,0,7 +BRDA:34,10,1,6 +BRDA:48,11,0,1 +BRDA:48,11,1,0 +BRDA:48,11,2,0 +BRDA:48,11,3,0 +BRDA:87,12,0,0 +BRDA:87,12,1,0 +BRDA:93,13,0,0 +BRDA:93,13,1,0 +BRF:28 +BRH:24 +end_of_record diff --git a/karma.conf.js b/karma.conf.js index f7a6989..ce8b56c 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -6,7 +6,14 @@ var path = require('path'); module.exports = function (config) { config.set({ frameworks: ['jasmine'], - files: ['__tests__/*-test.js'], + files: [ + '__tests__/*-test.js', + { + pattern: 'src/modules/**/*.html', + served: true, + included: false + } + ], plugins: [webpack, 'karma-jasmine', 'karma-phantomjs-launcher', 'karma-spec-reporter', 'karma-coverage'], browsers: ['PhantomJS'], preprocessors: { diff --git a/package.json b/package.json index e4327e1..316a9b8 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "babel-eslint": "^7.2.1", "babel-loader": "^6.4.0", "babel-plugin-transform-runtime": "^6.23.0", + "babel-polyfill": "^6.23.0", "babel-preset-es2015": "^6.22.0", "babel-preset-stage-0": "^6.22.0", "beepbeep": "^1.2.1", @@ -58,7 +59,9 @@ "isparta-loader": "^2.0.0", "istanbul": "^0.4.5", "istanbul-instrumenter-loader": "^2.0.0", - "jasmine-core": "^2.5.2", + "jasmine-ajax": "^3.3.1", + "jasmine-core": "^2.3.4", + "jasmine-jquery": "^2.1.1", "karma": "^1.5.0", "karma-coverage": "^1.1.1", "karma-jasmine": "^1.1.0", diff --git a/src/js/modules/Github.js b/src/js/modules/Github.js index febe37f..e31df21 100644 --- a/src/js/modules/Github.js +++ b/src/js/modules/Github.js @@ -2,12 +2,16 @@ * Example module using async/await, pulling from a user on github. * * Note: - * jQuery is used in the example but the project is not concreate to jQuery. + * jQuery is used in the example but the project is not concrete to jQuery. */ import $ from 'jquery' export class GitHub { constructor(username) { + if (typeof username === 'undefined' || username === '') { + throw new Error('You must provide a username') + } + this.el = $('.github') this.username = username } diff --git a/webpack.config.babel.js b/webpack.config.babel.js index fd5ff44..bc93d61 100644 --- a/webpack.config.babel.js +++ b/webpack.config.babel.js @@ -8,7 +8,7 @@ const env = process.env.NODE_ENV || 'development' * Base Configuration. */ const config = { - devtool: 'cheap-eval-source-map', + devtool: env === 'production' ? '#eval' : '#eval-source-map', entry: { app: [ resolve(__dirname, 'src/js/app.js') From 3f318cecb9d475e89c11c6d2fc31b497e23fc990 Mon Sep 17 00:00:00 2001 From: jfusco Date: Sun, 2 Apr 2017 10:53:00 -0400 Subject: [PATCH 3/4] Finish ajax request/response unit test --- __tests__/Github-test.js | 39 +++++++---- __tests__/__helpers__/GithubResponse.js | 69 +++++++++---------- coverage/reports/lcov-report/index.html | 2 +- .../lcov-report/modules/Github.js.html | 2 +- .../reports/lcov-report/modules/index.html | 2 +- coverage/reports/lcov.info | 16 ++--- 6 files changed, 69 insertions(+), 61 deletions(-) diff --git a/__tests__/Github-test.js b/__tests__/Github-test.js index 288acbd..0f7cb3e 100644 --- a/__tests__/Github-test.js +++ b/__tests__/Github-test.js @@ -7,7 +7,7 @@ import { GitHub } from '../src/js/modules/Github' jasmine.getFixtures().fixturesPath = 'base/src/modules' -describe('Github.js', () => { +describe('Github.js - instantiation', () => { let github = null beforeEach(() => { @@ -63,27 +63,38 @@ describe('Github.js', () => { }) }) -describe('Github - render', () => { - beforeEach(() => { - loadFixtures('github.html') +describe('Github.js - ajax', () => { + const github = new GitHub('DennisMartinez') - jasmine.Ajax.install(); - }) + let request + + beforeEach(done => { + jasmine.Ajax.install() + + github.getUserData() + + request = jasmine.Ajax.requests.mostRecent() + request.respondWith(GithubResponse) + + done() + }); afterEach(() => { jasmine.Ajax.uninstall(); }) - it('should make a call to get user info', () => { - const github = new GitHub('DennisMartinez') + it('sends the request to the right end point', () => { + expect(request.url).toBe('https://api.github.com/users/DennisMartinez') + }); - const spy = spyOn($, 'getJSON') + it('uses the correct method', () => { + expect(request.method).toBe('GET') + }); - jasmine.Ajax.stubRequest(`https://api.github.com/users/${github.username}`) - .andReturn(GithubResponse) - - github.getUserData() + it('should return the correct data', () => { + const data = JSON.parse(request.responseText) - expect(spy).toHaveBeenCalled() + expect(typeof data).toBe('object') + expect(data.name).toBe('Dennis Martinez') }) }) diff --git a/__tests__/__helpers__/GithubResponse.js b/__tests__/__helpers__/GithubResponse.js index 78a8fb1..5e3c89b 100644 --- a/__tests__/__helpers__/GithubResponse.js +++ b/__tests__/__helpers__/GithubResponse.js @@ -1,38 +1,35 @@ export default { - users: { - status: 200, - contentType: 'application/json', - responseText: { - avatar_url: "https://avatars1.githubusercontent.com/u/1375616?v=3", - bio: "mek a d weeb fun", - blog: null, - company: "Verndale", - created_at: "2012-01-24T16:19:15Z", - email: "denniswaltermartinez@gmail.com", - events_url: "https://api.github.com/users/DennisMartinez/events{/privacy}", - followers: 13, - followers_url: "https://api.github.com/users/DennisMartinez/followers", - following: 15, - following_url: "https://api.github.com/users/DennisMartinez/following{/other_user}", - gists_url: "https://api.github.com/users/DennisMartinez/gists{/gist_id}", - gravatar_id: "", - hireable: true, - html_url: "https://github.com/DennisMartinez", - id: 1375616, - location: "CO", - login: "DennisMartinez", - name: "Dennis Martinez", - organizations_url: "https://api.github.com/users/DennisMartinez/orgs", - public_gists: 20, - public_repos: 10, - received_events_url: "https://api.github.com/users/DennisMartinez/received_events", - repos_url: "https://api.github.com/users/DennisMartinez/repos", - site_admin: false, - starred_url: "https://api.github.com/users/DennisMartinez/starred{/owner}{/repo}", - subscriptions_url: "https://api.github.com/users/DennisMartinez/subscriptions", - type: "User", - updated_at: "2017-03-25T16:42:02Z", - url: "https://api.github.com/users/DennisMartinez" - } - } + status: 200, + responseText: JSON.stringify({ + avatar_url: "https://avatars1.githubusercontent.com/u/1375616?v=3", + bio: "mek a d weeb fun", + blog: null, + company: "Verndale", + created_at: "2012-01-24T16:19:15Z", + email: "denniswaltermartinez@gmail.com", + events_url: "https://api.github.com/users/DennisMartinez/events{/privacy}", + followers: 13, + followers_url: "https://api.github.com/users/DennisMartinez/followers", + following: 15, + following_url: "https://api.github.com/users/DennisMartinez/following{/other_user}", + gists_url: "https://api.github.com/users/DennisMartinez/gists{/gist_id}", + gravatar_id: "", + hireable: true, + html_url: "https://github.com/DennisMartinez", + id: 1375616, + location: "CO", + login: "DennisMartinez", + name: "Dennis Martinez", + organizations_url: "https://api.github.com/users/DennisMartinez/orgs", + public_gists: 20, + public_repos: 10, + received_events_url: "https://api.github.com/users/DennisMartinez/received_events", + repos_url: "https://api.github.com/users/DennisMartinez/repos", + site_admin: false, + starred_url: "https://api.github.com/users/DennisMartinez/starred{/owner}{/repo}", + subscriptions_url: "https://api.github.com/users/DennisMartinez/subscriptions", + type: "User", + updated_at: "2017-03-25T16:42:02Z", + url: "https://api.github.com/users/DennisMartinez" + }) } diff --git a/coverage/reports/lcov-report/index.html b/coverage/reports/lcov-report/index.html index 0cc2638..fd9a3ac 100644 --- a/coverage/reports/lcov-report/index.html +++ b/coverage/reports/lcov-report/index.html @@ -81,7 +81,7 @@

diff --git a/coverage/reports/lcov-report/modules/Github.js.html b/coverage/reports/lcov-report/modules/Github.js.html index 2586943..8c4fd58 100644 --- a/coverage/reports/lcov-report/modules/Github.js.html +++ b/coverage/reports/lcov-report/modules/Github.js.html @@ -215,7 +215,7 @@

diff --git a/coverage/reports/lcov-report/modules/index.html b/coverage/reports/lcov-report/modules/index.html index aac376b..3c25af3 100644 --- a/coverage/reports/lcov-report/modules/index.html +++ b/coverage/reports/lcov-report/modules/index.html @@ -81,7 +81,7 @@

diff --git a/coverage/reports/lcov.info b/coverage/reports/lcov.info index 9758f17..0b9b1aa 100644 --- a/coverage/reports/lcov.info +++ b/coverage/reports/lcov.info @@ -25,18 +25,18 @@ FNDA:1,defineProperties FNDA:1,(anonymous_3) FNDA:2,_interopRequireDefault FNDA:1,_asyncToGenerator -FNDA:1,(anonymous_6) -FNDA:1,(anonymous_7) -FNDA:1,step +FNDA:4,(anonymous_6) +FNDA:4,(anonymous_7) +FNDA:4,step FNDA:0,(anonymous_9) FNDA:0,(anonymous_10) FNDA:7,_classCallCheck FNDA:1,(anonymous_12) FNDA:7,GitHub FNDA:1,(anonymous_14) -FNDA:1,_callee -FNDA:1,_callee$ -FNDA:1,getUserData +FNDA:4,_callee +FNDA:4,_callee$ +FNDA:4,getUserData FNDA:0,render DA:0,7 DA:7,1 @@ -66,14 +66,14 @@ BRDA:24,5,1,2 BRDA:24,6,0,2 BRDA:24,6,1,2 BRDA:26,7,0,0 -BRDA:26,7,1,1 +BRDA:26,7,1,4 BRDA:28,8,0,0 BRDA:28,8,1,7 BRDA:34,9,0,2 BRDA:34,9,1,5 BRDA:34,10,0,7 BRDA:34,10,1,6 -BRDA:48,11,0,1 +BRDA:48,11,0,4 BRDA:48,11,1,0 BRDA:48,11,2,0 BRDA:48,11,3,0 From a4d2e93033ed3e6af833e5cb54012712c3dedf36 Mon Sep 17 00:00:00 2001 From: jfusco Date: Sun, 2 Apr 2017 19:23:49 -0400 Subject: [PATCH 4/4] Add tests for rendering Github component Add unit testing support links in README file. Add rendering tests for github information in component. Add test task in package.json file. Finish ajax testing for fetching user info. Fix testing suite __DEV__ reference by adding webpack plugin to karma config. --- README.md | 11 ++- __tests__/Github-test.js | 79 ++++++++++++++----- .../{GithubResponse.js => GithubResponses.js} | 12 ++- coverage/reports/lcov-report/index.html | 30 +++---- .../lcov-report/modules/Github.js.html | 48 +++++------ .../reports/lcov-report/modules/index.html | 30 +++---- coverage/reports/lcov.info | 60 +++++++------- karma.conf.js | 17 ++-- package.json | 3 +- src/js/app.js | 6 +- 10 files changed, 180 insertions(+), 116 deletions(-) rename __tests__/__helpers__/{GithubResponse.js => GithubResponses.js} (87%) diff --git a/README.md b/README.md index 6223c20..4a37665 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,16 @@ A list of features in this kit. * Font Support * Supported but no tooling, only copies from one folder to another. * Unit Test Support - * TODO: [Ava](https://www.npmjs.com/package/ava), Maybe? + * Karma test suite ([karma](https://www.npmjs.com/package/karma)) + * [karma-phantomjs-launcher](https://www.npmjs.com/package/karma-phantomjs-launcher) + * Jasmin framework ([jasmin](https://www.npmjs.com/package/jasmine)) + * [jasmine-ajax](https://github.com/jasmine/jasmine-ajax) + * [jasmine-jquery](https://www.npmjs.com/package/jasmine-jquery) + * Test coverage + * [karma-spec-reporter](https://www.npmjs.com/package/karma-spec-reporter) + * [karma-coverage](https://www.npmjs.com/package/karma-coverage) + * [istanbul](https://www.npmjs.com/package/istanbul) + * [isparta-loader](https://www.npmjs.com/package/isparta-loader) * Utility Support * Conditional Pipe Control ([gulp-if](https://www.npmjs.com/package/gulp-if)) * Pipe Cleaner ([gulp-plumber](https://www.npmjs.com/package/gulp-plumber)) diff --git a/__tests__/Github-test.js b/__tests__/Github-test.js index 0f7cb3e..5e0a968 100644 --- a/__tests__/Github-test.js +++ b/__tests__/Github-test.js @@ -2,7 +2,7 @@ import 'babel-polyfill' import $ from 'jquery' import 'jasmine-jquery' import 'jasmine-ajax' -import GithubResponse from './__helpers__/GithubResponse' +import { ok200, notFound404 } from './__helpers__/GithubResponses' import { GitHub } from '../src/js/modules/Github' jasmine.getFixtures().fixturesPath = 'base/src/modules' @@ -11,22 +11,6 @@ describe('Github.js - instantiation', () => { let github = null beforeEach(() => { - // In case we want to sandbox any module, we can use this - /* - github = sandbox({ - class: 'github' - }) - */ - - // OR - - // We don't need the github variable if we setFixtures :) - /* - setFixtures(sandbox({ - class: 'github' - })) - */ - github = new GitHub('jfusco') }) @@ -74,7 +58,7 @@ describe('Github.js - ajax', () => { github.getUserData() request = jasmine.Ajax.requests.mostRecent() - request.respondWith(GithubResponse) + request.respondWith(ok200) done() }); @@ -95,6 +79,65 @@ describe('Github.js - ajax', () => { const data = JSON.parse(request.responseText) expect(typeof data).toBe('object') + expect(request.status).toBe(200) expect(data.name).toBe('Dennis Martinez') + expect(data.company).toBe('Verndale') + }) +}) + +describe('Github.js - render', () => { + let github = null, + gitHubAvatar, + gitHubInfo + + const data = JSON.parse(ok200.responseText) + + beforeEach(() => { + loadFixtures('github.html') + + github = new GitHub('DennisMartinez') + github.render(data) + + gitHubAvatar = $('.github-avatar') + gitHubInfo = $('.github-info') + }) + + afterEach(() => { + github = null + gitHubAvatar = null + gitHubInfo = null + }) + + describe('avatar', () => { + it('should exist', () => { + expect(gitHubAvatar).toBeInDOM() + }) + + it('should render avatar attributes', () => { + const $avatar = gitHubAvatar.find('img') + + expect($avatar.attr('src')).toBe(data.avatar_url) + expect($avatar.attr('alt')).toBe(data.name) + }) + }) + + describe('info', () => { + it('should exist', () => { + expect(gitHubInfo).toBeInDOM() + }) + + it('should render user info', () => { + const $gitHubLink = gitHubInfo.find('a') + const $company = gitHubInfo.find('li:nth-child(2)') + const $email = gitHubInfo.find('li:nth-child(3)') + const $bio = gitHubInfo.find('p') + + expect($gitHubLink.attr('href')).toBe(data.html_url) + expect($gitHubLink.text()).toBe(data.html_url) + + expect($company.text()).toBe(`Company: ${data.company}`) + expect($email.text()).toBe(`Email: ${data.email}`) + expect($bio.text()).toBe(data.bio) + }) }) }) diff --git a/__tests__/__helpers__/GithubResponse.js b/__tests__/__helpers__/GithubResponses.js similarity index 87% rename from __tests__/__helpers__/GithubResponse.js rename to __tests__/__helpers__/GithubResponses.js index 5e3c89b..b29de3e 100644 --- a/__tests__/__helpers__/GithubResponse.js +++ b/__tests__/__helpers__/GithubResponses.js @@ -1,4 +1,5 @@ -export default { +// 200 +export const ok200 = { status: 200, responseText: JSON.stringify({ avatar_url: "https://avatars1.githubusercontent.com/u/1375616?v=3", @@ -33,3 +34,12 @@ export default { url: "https://api.github.com/users/DennisMartinez" }) } + +// 404 +export const notFound404 = { + status: 404, + responseText: JSON.stringify({ + documentation_url: "https://developer.github.com/v3", + message: "Not Found" + }) +} diff --git a/coverage/reports/lcov-report/index.html b/coverage/reports/lcov-report/index.html index fd9a3ac..7a7c038 100644 --- a/coverage/reports/lcov-report/index.html +++ b/coverage/reports/lcov-report/index.html @@ -20,14 +20,14 @@

- 88.57% + 97.14% Statements - 62/70 + 68/70
- 85.71% + 92.86% Branches - 24/28 + 26/28
100% @@ -35,12 +35,12 @@

18/18

- 53.85% + 100% Lines - 7/13 + 13/13
- 9 statements, 3 functions, 9 branches + 9 statements, 2 functions, 9 branches Ignored     
@@ -64,15 +64,15 @@

modules/ -
- 88.57% - 62/70 - 85.71% - 24/28 +
+ 97.14% + 68/70 + 92.86% + 26/28 100% 18/18 - 53.85% - 7/13 + 100% + 13/13 @@ -81,7 +81,7 @@

diff --git a/coverage/reports/lcov-report/modules/Github.js.html b/coverage/reports/lcov-report/modules/Github.js.html index 8c4fd58..31e2ce5 100644 --- a/coverage/reports/lcov-report/modules/Github.js.html +++ b/coverage/reports/lcov-report/modules/Github.js.html @@ -20,14 +20,14 @@

- 88.57% + 97.14% Statements - 62/70 + 68/70
- 85.71% + 92.86% Branches - 24/28 + 26/28
100% @@ -35,12 +35,12 @@

18/18

- 53.85% + 100% Lines - 7/13 + 13/13
- 9 statements, 3 functions, 9 branches + 9 statements, 2 functions, 9 branches Ignored     
@@ -110,13 +110,13 @@

    - - +11× +11×     - - + +       @@ -124,8 +124,8 @@

      -  -  + +       @@ -143,15 +143,15 @@

      -  +       -  +   -  +   -  +       @@ -178,8 +178,8 @@

}   // Just an example, you may want to use a templating engine. - render({ avatar_url: avatarUrl, html_url: url, company, name, bio, email }) { - const template = ` + render({ avatar_url: avatarUrl, html_url: url, company, name, bio, email }) { + const template = ` <div class="github-avatar"> <img src="${avatarUrl}" alt="${name}"> </div> @@ -197,15 +197,15 @@

  // An example of how we can add some logs or blocks of code in development only // On a production build, webpack will remove this entire block of code, including the if check - if (__DEV__) console.log('Template created') + Iif (__DEV__) console.log('Template created')   // Breaks the Single Responsibility principle, but again, only an example. // https://en.wikipedia.org/wiki/SOLID_(object-oriented_design) - this.el.html(template) + this.el.html(template)   - if (__DEV__) console.log('Template rendered') + Iif (__DEV__) console.log('Template rendered')   - return template + return template } }   @@ -215,7 +215,7 @@

diff --git a/coverage/reports/lcov-report/modules/index.html b/coverage/reports/lcov-report/modules/index.html index 3c25af3..61d697e 100644 --- a/coverage/reports/lcov-report/modules/index.html +++ b/coverage/reports/lcov-report/modules/index.html @@ -20,14 +20,14 @@

- 88.57% + 97.14% Statements - 62/70 + 68/70
- 85.71% + 92.86% Branches - 24/28 + 26/28
100% @@ -35,12 +35,12 @@

18/18

- 53.85% + 100% Lines - 7/13 + 13/13
- 9 statements, 3 functions, 9 branches + 9 statements, 2 functions, 9 branches Ignored     
@@ -64,15 +64,15 @@

Github.js -
- 88.57% - 62/70 - 85.71% - 24/28 +
+ 97.14% + 68/70 + 92.86% + 26/28 100% 18/18 - 53.85% - 7/13 + 100% + 13/13 @@ -81,7 +81,7 @@

diff --git a/coverage/reports/lcov.info b/coverage/reports/lcov.info index 0b9b1aa..77ed016 100644 --- a/coverage/reports/lcov.info +++ b/coverage/reports/lcov.info @@ -25,34 +25,34 @@ FNDA:1,defineProperties FNDA:1,(anonymous_3) FNDA:2,_interopRequireDefault FNDA:1,_asyncToGenerator -FNDA:4,(anonymous_6) -FNDA:4,(anonymous_7) -FNDA:4,step +FNDA:3,(anonymous_6) +FNDA:3,(anonymous_7) +FNDA:3,step FNDA:0,(anonymous_9) FNDA:0,(anonymous_10) -FNDA:7,_classCallCheck +FNDA:11,_classCallCheck FNDA:1,(anonymous_12) -FNDA:7,GitHub +FNDA:11,GitHub FNDA:1,(anonymous_14) -FNDA:4,_callee -FNDA:4,_callee$ -FNDA:4,getUserData -FNDA:0,render -DA:0,7 +FNDA:3,_callee +FNDA:3,_callee$ +FNDA:3,getUserData +FNDA:4,render +DA:0,11 DA:7,1 -DA:10,7 -DA:11,7 +DA:10,11 +DA:11,11 DA:12,2 -DA:15,5 -DA:16,5 -DA:24,0 -DA:25,0 -DA:43,0 -DA:47,0 -DA:49,0 -DA:51,0 +DA:15,9 +DA:16,9 +DA:24,4 +DA:25,4 +DA:43,4 +DA:47,4 +DA:49,4 +DA:51,4 LF:13 -LH:7 +LH:13 BRDA:12,1,0,2 BRDA:12,1,1,2 BRDA:12,2,0,2 @@ -66,21 +66,21 @@ BRDA:24,5,1,2 BRDA:24,6,0,2 BRDA:24,6,1,2 BRDA:26,7,0,0 -BRDA:26,7,1,4 +BRDA:26,7,1,3 BRDA:28,8,0,0 -BRDA:28,8,1,7 +BRDA:28,8,1,11 BRDA:34,9,0,2 -BRDA:34,9,1,5 -BRDA:34,10,0,7 -BRDA:34,10,1,6 -BRDA:48,11,0,4 +BRDA:34,9,1,9 +BRDA:34,10,0,11 +BRDA:34,10,1,10 +BRDA:48,11,0,3 BRDA:48,11,1,0 BRDA:48,11,2,0 BRDA:48,11,3,0 BRDA:87,12,0,0 -BRDA:87,12,1,0 +BRDA:87,12,1,4 BRDA:93,13,0,0 -BRDA:93,13,1,0 +BRDA:93,13,1,4 BRF:28 -BRH:24 +BRH:26 end_of_record diff --git a/karma.conf.js b/karma.conf.js index ce8b56c..0ab7ab6 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,7 +1,8 @@ 'use strict'; -var webpack = require('karma-webpack'); -var path = require('path'); +var karmaWebpack = require('karma-webpack') +var webpack = require('webpack') +var path = require('path') module.exports = function (config) { config.set({ @@ -14,7 +15,7 @@ module.exports = function (config) { included: false } ], - plugins: [webpack, 'karma-jasmine', 'karma-phantomjs-launcher', 'karma-spec-reporter', 'karma-coverage'], + plugins: [karmaWebpack, 'karma-jasmine', 'karma-phantomjs-launcher', 'karma-spec-reporter', 'karma-coverage'], browsers: ['PhantomJS'], preprocessors: { '__tests__/*-test.js': ['webpack'] @@ -46,11 +47,11 @@ module.exports = function (config) { /node_modules\/sinon\// ] }, - resolve: { - alias: { - 'sinon': 'sinon/pkg/sinon.js' - } - } + plugins: [ + new webpack.DefinePlugin({ + '__DEV__': process.env.NODE_ENV === 'development' + }) + ] }, webpackMiddleware: { noInfo: true } }); diff --git a/package.json b/package.json index 316a9b8..18d54bf 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ ], "scripts": { "test": "karma start --single-run --no-auto-watch", - "dev": "cross-env NODE_ENV=development gulp", + "start": "cross-env NODE_ENV=development gulp", "build": "npm run test && cross-env NODE_ENV=production gulp dist", "version": "git add .", "postversion": "git push && git push --tags" @@ -70,7 +70,6 @@ "karma-webpack": "^2.0.3", "progress-bar-webpack-plugin": "^1.9.3", "run-sequence": "^1.2.2", - "sinon": "^2.0.0", "url-loader": "^0.5.8", "webpack": "^2.2.1", "webpack-dev-middleware": "^1.10.1", diff --git a/src/js/app.js b/src/js/app.js index 3f255d1..3e0ec06 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -7,9 +7,11 @@ render('.github', async () => { const { GitHub } = await import(`./modules/Github`) const github = new GitHub('DennisMartinez') - github - .getUserData() + github.getUserData() .then(data => github.render(data)) + .catch(err => { + console.log(err) + }) }) /**