{"id":2603,"date":"2018-06-02T12:52:50","date_gmt":"2018-06-02T17:52:50","guid":{"rendered":"http:\/\/osric.com\/chris\/accidental-developer\/?p=2603"},"modified":"2018-06-02T12:52:50","modified_gmt":"2018-06-02T17:52:50","slug":"javascript-unit-tests-with-travisci-and-qunit","status":"publish","type":"post","link":"https:\/\/osric.com\/chris\/accidental-developer\/2018\/06\/javascript-unit-tests-with-travisci-and-qunit\/","title":{"rendered":"Javascript Unit Tests with TravisCI and QUnit"},"content":{"rendered":"<p>I wanted to make an update to my <a href=\"https:\/\/www.osric.com\/bingo-card-generator\/\">Bingo Card Generator<\/a>. Previously I&#8217;d added <a href=\"https:\/\/osric.com\/chris\/accidental-developer\/2018\/01\/using-jshint-with-travis-ci\/\">automated tests for JSHint via TravisCI<\/a> to test for code formatting, but now I wanted to actually test code functionality. I decided to add a simple unit test using <a href=\"https:\/\/qunitjs.com\/\">QUnit<\/a>.<\/p>\n<p>I made a lot of mistakes trying to get this to work (probably because I didn&#8217;t read the documentation!), so I&#8217;ve included all my steps and missteps below in case they are useful to someone else:<br \/>\n<!--more--><\/p>\n<p>I installed <code>qunit<\/code> in my development environment:<\/p>\n<pre><code>npm --global install qunit<\/code><\/pre>\n<p>I created a <code>test<\/code> folder in my project:<\/p>\n<pre><code>mkdir test<\/code><\/pre>\n<p>I added a simple test:<\/p>\n<pre><code>removeEmptyElements = function (arr) {\r\n    \"use strict\";\r\n    var newArray = [], i = 0;\r\n    for (i = 0; i &lt; arr.length; i += 1) {\r\n        if (arr[i]) {\r\n            newArray.push(arr[i]);\r\n        }\r\n    }\r\n    return newArray;\r\n}\r\n\r\nQUnit.test(\"RemoveEmptyElements\", function(assert) {\r\n\t\"use strict\";\r\n\tvar testInput = \",,,A,,B,,,C,\";\r\n\tvar testArray = testInput.split(\",\")\r\n\tvar cleanedArray = removeEmptyElements(testArray);\r\n\tassert.equal(cleanedArray.length, 3, \"Array has 3 elements\")\r\n    assert.ok(cleanedArray[0] === \"A\", \"First element is A\");\r\n    assert.ok(cleanedArray[1] === \"B\", \"Second element is B\");\r\n    assert.ok(cleanedArray[2] === \"C\", \"Third element is C\");\r\n});<\/code><\/pre>\n<p>The test runs in my development environment:<\/p>\n<pre><code>$ qunit\r\nTAP version 13\r\nok 1 RemoveEmptyElements\r\n1..1\r\n# pass 1\r\n# skip 0\r\n# todo 0\r\n# fail 0<\/code><\/pre>\n<p>Now, how do I integrate this new test with TravisCI?<\/p>\n<p>First, I added <code>qunit<\/code> to <code>devDependencies<\/code> in <code>package.json<\/code>:<\/p>\n<pre><code>  \"devDependencies\": {\r\n    \"jshint\": \"^2.6.0\",\r\n    \"quinit\": \"^2.6.1\"\r\n  },<\/code><\/pre>\n<p>Then I tried adding <code>qunit<\/code> to <code>scripts<\/code> in <code>package.json<\/code>:<\/p>\n<pre><code>  \"scripts\": {\r\n    \"jshint\": \".\/node_modules\/jshint\/bin\/jshint images.js\",\r\n    \"qunit\": \".\/node_modules\/qunit\/bin\/qunit\"\r\n  }<\/code><\/pre>\n<p>I committed the changes to my local git repo and pushed them to GitHub. This triggered TravisCI to run tests, which failed:<\/p>\n<pre><code>npm ERR! code E404\r\nnpm ERR! 404 Not Found: quinit@^2.6.1<\/code><\/pre>\n<p>OK, maybe I&#8217;m not the greatest typist. That should be <strong><code>qunit<\/code><\/strong>, not <code>quinit<\/code>.<\/p>\n<p>After that fix I received a different message from TravisCI:<\/p>\n<pre><code>&gt; BingoCardGenerator@0.0.2 test \/home\/travis\/build\/cherdt\/BingoCardGenerator\r\n&gt; echo 'Error: no test specified'\r\nError: no test specified<\/code><\/pre>\n<p>TravisCI says it passed, but no tests were run. It turns out the <code>scripts<\/code> object in <code>package.json<\/code> needs to contain a <code>test<\/code> element (I thought I was being more descriptive by calling the elements <code>jshint<\/code> and <code>qunit<\/code>):<\/p>\n<pre><code>  \"scripts\": {\r\n    \"test\": \".\/node_modules\/jshint\/bin\/jshint images.js\",\r\n    \"test\": \".\/node_modules\/qunit\/bin\/qunit\"\r\n  }<\/code><\/pre>\n<p>This led to a new problem. I had anticipated that two key-value pairs with identical keys (<code>test<\/code>) might be an issue. Only the <code>qunit<\/code> test ran, no sign of <code>jshint<\/code> in the TravisCI output.<\/p>\n<p>This is when I finally decided to read some documentation. If you want to run multiple test engines, you need a script to trigger each of them. See the section <a href=\"https:\/\/docs.travis-ci.com\/user\/customizing-the-build\/#implementing-complex-build-steps\">Implementing Complex Build Steps<\/a> in the TravisCI documentation.<\/p>\n<p>I created a bash script to run both <code>jshint<\/code> and <code>qunit<\/code>:<\/p>\n<pre><code>#!\/bin\/bash\r\n\r\nIS_FAILED=0\r\n\r\necho \"Running jshint...\"\r\nif jshint images.js simulation.js\r\nthen\r\n\techo \"jshint passed!\"\r\nelse\r\n\techo \"jshint failed!\"\r\n\tIS_FAILED=1\r\nfi\r\necho\r\n\r\necho \"Running qunit tests...\"\r\nif qunit\r\nthen\r\n\techo \"qunit tests passed\"\r\nelse\r\n\techo \"qunit tests failed\"\r\n\tIS_FAILED=1\r\nfi\r\necho\r\n\r\nexit $IS_FAILED<\/code><\/pre>\n<p>I added that script as the test in <code>packages.json<\/code>:<\/p>\n<pre><code>  \"scripts\": {\r\n    \"test\": \"sh .\/test.sh\"\r\n  }<\/code><\/pre>\n<p>Note that TravisCI uses the exit code of this script to determine if you have a passing or failing build. The TravisCI example uses <code>set -ev<\/code> in the bash script; the <code>-e<\/code> option will cause the script to exit on any error. (If the error occurred in the first test, though, you might not see the results of subsequent tests, so I decided to run the <code>qunit<\/code> tests even if <code>jshint<\/code> failed.)<\/p>\n<p>That worked &#8212; both tests ran and everything passed!<\/p>\n<p>I decided to make one more change. I moved <code>test.sh<\/code> to <code>scripts\/run-tests.sh<\/code> (to match the TravisCI example). I also updated <code>packages.json<\/code> accordingly:<\/p>\n<pre><code>  \"scripts\": {\r\n    \"test\": \"sh .scripts\/run-tests.sh\"\r\n  }<\/code><\/pre>\n<p>This time it failed! TravisCI displayed the following error:<\/p>\n<pre><code>sh: 0: Can't open .scripts\/run-tests.sh<\/code><\/pre>\n<p>Of course! That&#8217;s a bad path. I updated it to:<\/p>\n<pre><code>  \"scripts\": {\r\n    \"test\": \"sh .\/scripts\/run-tests.sh\"\r\n  }<\/code><\/pre>\n<p>Everything works! Now I just need to write more unit tests.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wanted to make an update to my Bingo Card Generator. Previously I&#8217;d added automated tests for JSHint via TravisCI to test for code formatting, but now I wanted to actually test code functionality. I decided to add a simple unit test using QUnit. I made a lot of mistakes trying to get this to &hellip; <a href=\"https:\/\/osric.com\/chris\/accidental-developer\/2018\/06\/javascript-unit-tests-with-travisci-and-qunit\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Javascript Unit Tests with TravisCI and QUnit<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[56],"tags":[350,502,481,322,238],"class_list":["post-2603","post","type-post","status-publish","format-standard","hentry","category-testing","tag-javascript","tag-qunit","tag-travis-ci","tag-unit-testing","tag-unit-tests"],"_links":{"self":[{"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/posts\/2603","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/comments?post=2603"}],"version-history":[{"count":6,"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/posts\/2603\/revisions"}],"predecessor-version":[{"id":2609,"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/posts\/2603\/revisions\/2609"}],"wp:attachment":[{"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/media?parent=2603"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/categories?post=2603"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/tags?post=2603"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}