<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Lathonez' Blog</title>
    <description></description>
    <link>http://lathonez.github.io/</link>
    <atom:link href="http://lathonez.github.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Tue, 24 May 2022 13:54:37 +0000</pubDate>
    <lastBuildDate>Tue, 24 May 2022 13:54:37 +0000</lastBuildDate>
    <generator>Jekyll v3.9.2</generator>
    
      <item>
        <title>End to End testing an Ionic2 project</title>
        <description>&lt;p&gt;&lt;strong&gt;Updated for Ionic 3.9.2 and Angular 5.0.3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; - I have an Ionic 2 project on github set up for E2E testing with &lt;a href=&quot;https://angular.github.io/protractor&quot;&gt;protractor&lt;/a&gt;, &lt;a href=&quot;http://github.com/lathonez/clicker&quot;&gt;dive in&lt;/a&gt;, or read on.&lt;/p&gt;

&lt;p&gt;The previous post in this series on &lt;a href=&quot;http://lathonez.github.io/2017/ionic-2-unit-testing/&quot;&gt;Unit Testing&lt;/a&gt; does a bit of intro that I won’t repeat here. For the purposes of this post, it’ll be useful to have the demo app cloned locally.&lt;/p&gt;

&lt;h2 id=&quot;install-dev-dependencies&quot;&gt;Install dev dependencies&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;pre class=&quot;lowlight&quot;&gt;
&lt;code&gt;npm install --save-dev angular-cli @angular/router connect jasmine-reporters jasmine-spec-reporter protractor serve-static ts-node&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;install-config-files-and-boilerplate&quot;&gt;Install config files and boilerplate&lt;/h2&gt;

&lt;p&gt;Into your project’s root:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/angular-cli.json&quot;&gt;.angular-cli.json&lt;/a&gt;: Angular Cli’s config file&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/protractor.conf.js&quot;&gt;protractor.conf.js&lt;/a&gt;: Protractor’s config file&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/tsconfig.ng-cli.json&quot;&gt;tsconfig.ng-cli.json&lt;/a&gt;: Angular Cli’s base compiler config&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Into a newly created &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./e2e&lt;/code&gt; folder in your project’s root:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/e2e/tsconfig.e2e.json&quot;&gt;tsconfig.e2e.json&lt;/a&gt;: Angular Cli’s compiler config&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the lazy:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;pre class=&quot;lowlight&quot;&gt;
&lt;code&gt;for file in angular-cli.json protractor.conf.js tsconfig.ng-cli.json
do
  wget https://raw.githubusercontent.com/lathonez/clicker/master/${file}
done

mkdir e2e
cd e2e

for file in tsconfig.e2e.json
do
  wget https://raw.githubusercontent.com/lathonez/clicker/master/e2e/${file}
done&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;modify-existing-ionic-config-files&quot;&gt;Modify existing Ionic config files:&lt;/h2&gt;

&lt;p&gt;Add jasmine types in Ionic’s &lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/tsconfig.json&quot;&gt;tsconfig.json&lt;/a&gt; (only necessary on Windows):&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;typeRoots&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;node_modules/@types&quot;&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;types&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;
     &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;jasmine&quot;&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add the following to your &lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/.gitignore&quot;&gt;gitignore&lt;/a&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# e2e
/e2e/*.js
/e2e/*.map
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hook ng e2e into your &lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/package.json&quot;&gt;package.json&lt;/a&gt; scripts array:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;scripts&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;e2e&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ionic-app-scripts&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;protractor&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;postinstall&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;webdriver-manager&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;update&quot;&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;a-simple-e2e-test-on-appts&quot;&gt;A simple e2e test on app.ts&lt;/h2&gt;

&lt;p&gt;Create a simple e2e test file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./e2e/app.e2e-spec.ts&lt;/code&gt; to get us going:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;browser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;protractor&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;MyApp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;browser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;should have a title&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;browser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getTitle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;MyApp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;update-the-webdriver&quot;&gt;Update the webdriver&lt;/h2&gt;

&lt;p&gt;As we hooked &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webdriver-manager update&lt;/code&gt; into our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm postinstall&lt;/code&gt; script, we just need to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt;. Thus this step is covered by simply installing your project (in the future):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;x220:~/code/myApp$ npm install

...

&amp;gt; ionic-hello-world@ postinstall /home/lathonez/code/myApp
&amp;gt; webdriver-manager update

...

[16:38:03] I/update - chromedriver: setting permissions to 0755 for /home/lathonez/code/myApp/node_modules/protractor/node_modules/webdriver-manager/selenium/chromedriver_2.25
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;running-the-tests&quot;&gt;Running the tests&lt;/h2&gt;

&lt;p&gt;As we hooked into our &lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/package.json&quot;&gt;package.json&lt;/a&gt; above, we can run the tests with a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm run e2e&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;x220:~/code/myApp$ npm run e2e
(node:31496) fs: re-evaluating native module sources is not supported. If you are using the graceful-fs module, please update it to a more recent version.

&amp;gt; ionic-hello-world@ e2e /home/lathonez/code/myApp
&amp;gt; protractor

[16:40:33] I/direct - Using ChromeDriver directly...
[16:40:33] I/launcher - Running 1 instances of WebDriver
Started
Spec started
.
  MyApp
    ✓ should have a title

1 spec, 0 failures
Finished in 1.631 seconds

Executed 1 of 1 spec SUCCESS in 2 secs.
[16:40:36] I/launcher - 0 instance(s) of WebDriver still running
[16:40:36] I/launcher - chrome #01 passed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;using-docker&quot;&gt;Using Docker?&lt;/h2&gt;

&lt;p&gt;Testing on docker (or any other headless environment), requires the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xvfb&lt;/code&gt;, a virtual frame buffer implementing the X11 protocol.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt-get install xvfb&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e2e&lt;/code&gt; line in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; to include &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xvfb-run&lt;/code&gt;, ensuring protractor has access to the virtual display:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;scripts&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;e2e&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;xvfb-run&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ionic-app-scripts&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;protractor&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For more information see &lt;a href=&quot;https://github.com/lathonez/clicker/issues/114&quot;&gt;issue #144&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;contribute&quot;&gt;Contribute&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://github.com/lathonez/clicker&quot;&gt;Clickers&lt;/a&gt; is a work in progress. If you’d like to help out or have any suggestions, check the &lt;a href=&quot;https://github.com/lathonez/clicker/issues/38&quot;&gt;roadmap sticky&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This blog is &lt;a href=&quot;https://github.com/lathonez/lathonez.github.io&quot;&gt;on github&lt;/a&gt;, if you can improve it, have any suggestions or I’ve failed to keep it up to date, &lt;a href=&quot;https://github.com/lathonez/lathonez.github.io/issues/new&quot;&gt;raise an issue&lt;/a&gt; or a PR.&lt;/p&gt;

&lt;h2 id=&quot;help&quot;&gt;Help!&lt;/h2&gt;

&lt;p&gt;If you can’t get any of this working in your own project, &lt;a href=&quot;https://github.com/lathonez/clicker/issues/new&quot;&gt;raise an issue&lt;/a&gt; and I’ll do my best to help out.&lt;/p&gt;

&lt;p&gt;If you have a general question about e2e testing concepts (e.g. how can I write an e2e test for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;some-module&lt;/code&gt;), see our &lt;a href=&quot;https://github.com/lathonez/clicker/issues/191&quot;&gt;General Testing Help thread&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;say-thanks&quot;&gt;Say “Thanks”&lt;/h2&gt;

&lt;p&gt;If the clicker project helped you out, show it some love by giving it a star on github &amp;lt;3:&lt;/p&gt;

&lt;div align=&quot;center&quot;&gt;&lt;iframe src=&quot;https://ghbtns.com/github-btn.html?user=lathonez&amp;amp;repo=clicker&amp;amp;type=star&amp;amp;count=true&quot; frameborder=&quot;0&quot; scrolling=&quot;0&quot; width=&quot;170px&quot; height=&quot;20px&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;

</description>
        <pubDate>Mon, 15 Jan 2018 01:48:23 +0000</pubDate>
        <link>http://lathonez.github.io/2018/ionic-2-e2e-testing/</link>
        <guid isPermaLink="true">http://lathonez.github.io/2018/ionic-2-e2e-testing/</guid>
        
        <category>ionic2</category>
        
        <category>angular2</category>
        
        <category>testing</category>
        
        
        <category>dev</category>
        
      </item>
    
      <item>
        <title>Unit Testing an Ionic2 project</title>
        <description>&lt;p&gt;&lt;strong&gt;Updated for Ionic 3.9.2 and Angular 5.0.3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This blog and &lt;a href=&quot;http://github.com/lathonez/clicker&quot;&gt;associated project&lt;/a&gt; have been around for over a year, since the early days of Ionic 2. Recently, Ionic have brought out an &lt;a href=&quot;https://github.com/driftyco/ionic-unit-testing-example&quot;&gt;official example repository&lt;/a&gt; for unit testing.&lt;/p&gt;

&lt;p&gt;So why is this blog still relevant? We spent &lt;a href=&quot;https://github.com/lathonez/clicker/issues/239&quot;&gt;a lot of time and effort&lt;/a&gt; migrating the project over to the example setup. We found that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The repo is not mature and has a number of outstanding issues that make it unsuitable for production&lt;/li&gt;
  &lt;li&gt;It is meant to be a very lightweight example and will have minimal support from Ionic&lt;/li&gt;
  &lt;li&gt;It does not use angular/cli for testing, so lacks community support and resources&lt;/li&gt;
  &lt;li&gt;Ionic are ultimately looking to bake testing support directly into ionic-app-scripts anyway, so the example repo is a stop-gap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For ~large apps, or anything that needs production support, I recommend this setup. For small / side projects Ionic’s example will probably suffice.&lt;/p&gt;

&lt;h2 id=&quot;install-dev-dependencies&quot;&gt;Install dev dependencies&lt;/h2&gt;

&lt;p&gt;Install the following npm dev dependencies, or simply merge our &lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/package.json&quot;&gt;package.json&lt;/a&gt; with your own.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;pre class=&quot;lowlight&quot;&gt;
&lt;code&gt;npm install --save-dev @angular/cli @angular/router @types/jasmine @types/node ionic-mocks jasmine-core jasmine-spec-reporter karma karma-chrome-launcher karma-cli karma-jasmine karma-jasmine-html-reporter karma-coverage-istanbul-reporter karma-junit-reporter
&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;install-config-files-and-boilerplate&quot;&gt;Install config files and boilerplate&lt;/h2&gt;

&lt;p&gt;Into your project’s root:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/.angular-cli.json&quot;&gt;.angular-cli.json&lt;/a&gt;: Angular Cli’s config file&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/karma.conf.js&quot;&gt;karma.conf.js&lt;/a&gt;: Karma’s config file&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/tsconfig.ng-cli.json&quot;&gt;tsconfig.ng-cli.json&lt;/a&gt;: Angular Cli’s base compiler config&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Into your project’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./src&lt;/code&gt; folder&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/src/polyfills.ts&quot;&gt;polyfills.ts&lt;/a&gt;: Pollyfills used by Angular Cli&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/src/test.ts&quot;&gt;test.ts&lt;/a&gt;: Main entry point for our unit tests. &lt;strong&gt;Remove references to ClickerServices and Translate!&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/src/tsconfig.spec.json&quot;&gt;tsconfig.spec.json&lt;/a&gt;: Angular Cli’s compiler config for spec files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the lazy:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;pre class=&quot;lowlight&quot;&gt;
&lt;code&gt;for file in .angular-cli.json karma.conf.js tsconfig.ng-cli.json
do
  wget https://raw.githubusercontent.com/lathonez/clicker/master/${file}
done

cd src

for file in polyfills.ts test.ts tsconfig.spec.json
do
  wget https://raw.githubusercontent.com/lathonez/clicker/master/src/${file}
done&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;modify-existing-ionic-config-files&quot;&gt;Modify existing Ionic config files:&lt;/h2&gt;

&lt;p&gt;Add jasmine types in Ionic’s &lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/tsconfig.json&quot;&gt;tsconfig.json&lt;/a&gt; (only necessary on Windows):&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;typeRoots&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;node_modules/@types&quot;&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;types&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;
     &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;jasmine&quot;&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add the following line to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts&lt;/code&gt; object in your &lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/package.json&quot;&gt;package.json&lt;/a&gt; (generating code coverage &lt;a href=&quot;https://github.com/angular/angular-cli/pull/1799&quot;&gt;breaks sourcemaps&lt;/a&gt;, so we add an explicit option for it):&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;test-coverage&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ng test --code-coverage&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ng test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;testts&quot;&gt;test.ts&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/lathonez/clicker/blob/master/src/test.ts&quot;&gt;This file&lt;/a&gt; is worth exploring a little further. We’ve created a couple of functions to remove a lot of the boilerplate around an Ionic testbed setup, we’ll be using these in any of our unit tests that create a Angular 2 components.&lt;/p&gt;

&lt;p&gt;The following function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;configureIonicTestingModule&lt;/code&gt; takes one or more of your components and sets up an Ionic test bed for them:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;kr&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;configureIonicTestingModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestBed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestBed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;configureTestingModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;declarations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;providers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Keyboard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DomController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MenuController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NavController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Platform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;useFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;PlatformMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;useFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ConfigMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ClickersService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;useClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ClickersServiceMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;imports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;FormsModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;IonicModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;ReactiveFormsModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And this is just a wrapper we’ll call from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;beforeEach&lt;/code&gt; to compile your components:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;kr&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;beforeEachCompiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestUtils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;configureIonicTestingModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;compileComponents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestBed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;debugElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;componentInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This means that instead of needing the above code in each of your component’s spec files, you simply need:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nx&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestUtils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;beforeEachCompiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MyComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;compiled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;compiled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;compiled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Alternatively, you can write all this inline in your spec files (as opposed to using TestUtils above):&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;TestBed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;configureTestingModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;declarations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MyComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;providers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Platform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Keyboard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MenuController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NavController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;useFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ConfigMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;imports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;FormsModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;IonicModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;ReactiveFormsModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;compileComponents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestBed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MyComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;detectChanges&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;your-first-unit-test&quot;&gt;Your first unit test&lt;/h2&gt;

&lt;p&gt;Pick one of your components to write a test for and create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;component-name.spec.ts&lt;/code&gt; file for it.&lt;/p&gt;

&lt;p&gt;A simple skeleton unit test file looks like this, where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HelloIonic&lt;/code&gt; is whatever component you’re testing.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ComponentFixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/core/testing&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestUtils&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;               &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;../../test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HelloIonicPage&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./hello-ionic&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ComponentFixture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;HelloIonicPage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Pages: HelloIonic&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestUtils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;beforeEachCompiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;HelloIonicPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;compiled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;compiled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;compiled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})));&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;should create the hello ionic page&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBeTruthy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;You’ll also need to add&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./&lt;/code&gt; to the templateUrl path in your component .ts file:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;templateUrl: 'hello-ionic.html'&lt;/code&gt; becomes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;templateUrl: './hello-ionic.html'&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;running-the-tests&quot;&gt;Running the tests&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm test&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;x220:~/code/myApp$ npm test
(node:17800) fs: re-evaluating native module sources is not supported. If you are using the graceful-fs module, please update it to a more recent version.

&amp;gt; ionic-hello-world@ test /home/lathonez/code/myApp
&amp;gt; ng test

30 10 2016 19:12:00.472:WARN [karma]: No captured browser, open http://localhost:9876/
30 10 2016 19:12:00.491:INFO [karma]: Karma v1.3.0 server started at http://localhost:9878/
30 10 2016 19:12:00.491:INFO [launcher]: Launching browser Chrome with unlimited concurrency
30 10 2016 19:12:00.546:INFO [launcher]: Starting browser Chrome
30 10 2016 19:12:01.732:INFO [Chrome 54.0.2840 (Linux 0.0.0)]: Connected on socket /#-CZqilkRyMTyIn1xAAAA with id 84944674

START:
  Pages: HelloIonic
    ✔ should create the hello ionic page

Finished in 0.776 secs / 0.77 secs

SUMMARY:
✔ 1 test completed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Congrats! You now have unit testing working in your Ionic 2 project.&lt;/p&gt;

&lt;h2 id=&quot;test-coverage&quot;&gt;Test Coverage&lt;/h2&gt;

&lt;p&gt;This set up outputs &lt;a href=&quot;http://ltp.sourceforge.net/coverage/lcov.php&quot;&gt;lcov&lt;/a&gt; coverage to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./coverage&lt;/code&gt; in the root folder of your app. If you browse to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/path/to/myApp/coverage/lcov-report/&lt;/code&gt; in a web browser, you’ll get &lt;a href=&quot;/images/ionic2_unit_testing/lcov-index-screenshot.png&quot;&gt;an overview&lt;/a&gt; of all your tested files. &lt;a href=&quot;/images/ionic2_unit_testing/lcov-app-screenshot.png&quot;&gt;Drill into one&lt;/a&gt; and you get line by line info as to what’s covered.&lt;/p&gt;

&lt;p&gt;You can also use external tools, I highly recommend &lt;a href=&quot;https://codecov.io/github/lathonez/clicker?branch=master&quot;&gt;codecov&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;debugging-setup&quot;&gt;Debugging Setup&lt;/h2&gt;

&lt;p&gt;There are a few fiddly steps to get Angular CLI integrated into your Ionic project. If something isn’t working for you, you have missed a step above. This setup works cross platform and is running on a closed source project with 400+ unit tests.&lt;/p&gt;

&lt;p&gt;Before raising an issue, please follow these basic steps to debug the setup:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;check you are on node LTS&lt;/li&gt;
  &lt;li&gt;remove and reinstall node_modules&lt;/li&gt;
  &lt;li&gt;clone a copy of clicker and compare the relevant files with your own using a diff tool (meld)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have performed these steps and still have no luck, please raise an issue (see below) - note that we will probably need access to your source code to help out.&lt;/p&gt;

&lt;h2 id=&quot;debugging-the-tests&quot;&gt;Debugging the Tests&lt;/h2&gt;

&lt;p&gt;Sometimes it’s useful to debug our tests in the Chrome console.&lt;/p&gt;

&lt;p&gt;Hit the &lt;a href=&quot;/images/ionic2_unit_testing/karma-debug-screenshot.png&quot;&gt;Debug&lt;/a&gt; button and another tab will open. Open the dev console and you can see the &lt;a href=&quot;/images/ionic2_unit_testing/karma-console-screenshot.png&quot;&gt;output of all your tests&lt;/a&gt;, along with any errors which can be debugged as per usual.&lt;/p&gt;

&lt;h2 id=&quot;contribute&quot;&gt;Contribute&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/lathonez/clicker&quot;&gt;Clicker&lt;/a&gt; is a work in progress. If you’d like to help out or have any suggestions, check the &lt;a href=&quot;https://github.com/lathonez/clicker/issues/38&quot;&gt;roadmap sticky&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This blog is &lt;a href=&quot;https://github.com/lathonez/lathonez.github.io&quot;&gt;on github&lt;/a&gt;, if you can improve it, have any suggestions or I’ve failed to keep it up to date, &lt;a href=&quot;https://github.com/lathonez/lathonez.github.io/issues/new&quot;&gt;raise an issue&lt;/a&gt; or a PR.&lt;/p&gt;

&lt;h2 id=&quot;help&quot;&gt;Help!&lt;/h2&gt;

&lt;p&gt;If you can’t get any of this working in your own project - follow the Debugging Setup, &lt;a href=&quot;https://github.com/lathonez/clicker/issues/new&quot;&gt;raise an issue&lt;/a&gt; and I’ll do my best to help out.&lt;/p&gt;

&lt;p&gt;If you have a general question about unit testing concepts (e.g. how can I write a unit test for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;some-module&lt;/code&gt;), see our &lt;a href=&quot;https://github.com/lathonez/clicker/issues/191&quot;&gt;General Testing Help thread&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;say-thanks&quot;&gt;Say “Thanks”&lt;/h2&gt;

&lt;p&gt;If the clicker project helped you out, show it some love by giving it a star on github &amp;lt;3:&lt;/p&gt;

&lt;div align=&quot;center&quot;&gt;&lt;iframe src=&quot;https://ghbtns.com/github-btn.html?user=lathonez&amp;amp;repo=clicker&amp;amp;type=star&amp;amp;count=true&quot; frameborder=&quot;0&quot; scrolling=&quot;0&quot; width=&quot;170px&quot; height=&quot;20px&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
</description>
        <pubDate>Mon, 15 Jan 2018 01:48:23 +0000</pubDate>
        <link>http://lathonez.github.io/2018/ionic-2-unit-testing/</link>
        <guid isPermaLink="true">http://lathonez.github.io/2018/ionic-2-unit-testing/</guid>
        
        <category>ionic2</category>
        
        <category>angular2</category>
        
        <category>testing</category>
        
        
        <category>dev</category>
        
      </item>
    
      <item>
        <title>Mitsubishi L300 4x4 Camper Coversion</title>
        <description>&lt;h2 id=&quot;bridget-the-van&quot;&gt;Bridget the Van&lt;/h2&gt;

&lt;p&gt;In January 2017 Orla and I were living in Sydney. We needed a car. We were torn between a “sensible” car we could sleep in, like a Forester, or a van project.&lt;/p&gt;

&lt;p&gt;We chose bridget and the rest is history. Her name comes from the NSW rego - BR27JG.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/fav.jpeg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:60vh&quot; src=&quot;http://lathonez.com/images/bridgey/fav.jpeg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/done-2.jpeg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:25vh&quot; src=&quot;http://lathonez.com/images/bridgey/done-2.jpeg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/done-3.jpeg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:25vh&quot; src=&quot;http://lathonez.com/images/bridgey/done-3.jpeg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/done-4.jpeg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:25vh&quot; src=&quot;http://lathonez.com/images/bridgey/done-4.jpeg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/done-1.jpeg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:25vh&quot; src=&quot;http://lathonez.com/images/bridgey/done-1.jpeg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;why-an-l300&quot;&gt;Why an L300?&lt;/h2&gt;

&lt;p&gt;We had the following requirements for a camper:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Not have terrible fuel consumption (no V6 / V8)&lt;/li&gt;
  &lt;li&gt;4x4&lt;/li&gt;
  &lt;li&gt;Short Wheel Base so we could park it in town (and it could get places)&lt;/li&gt;
  &lt;li&gt;Big enough for a permanent bed / sofa + kitchen&lt;/li&gt;
  &lt;li&gt;Be on NSW plates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Needing a 4x4 with good fuel consumption removes a bunch of contenders:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Standard vans used in conversions lack 4x4 (Hiace / Econo / straight Mitsi’s / Kias)&lt;/li&gt;
  &lt;li&gt;Any 4wd big enough to be seriously useasble (without a roof tent). A troopy would have been ideal but any we could find were V6 or above. Ditto patrol / cruisy. Hilux too small.&lt;/li&gt;
  &lt;li&gt;Post-factory 4x4 (sprinter / transit) conversions are usually LWB and always over budget&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The only other van we found that satisfied all of the above was a T4 syncro bus.&lt;/p&gt;

&lt;p&gt;Reasons we picked bridget:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Proper 4x4 (hi / lo range gearbox + chasis off a Pajero) with 23” Rugged T/As all round. &lt;a href=&quot;https://www.youtube.com/watch?v=KikxgRkbV-c&quot;&gt;Bridget could go anywhere&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Only 30k on her since recon’d engine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Retrospectively the conversion would have been easier on a T4 (as it’s a T4 and there are so many examples), but we’re glad we went with Bridget.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/off-road.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:60vh&quot; src=&quot;http://lathonez.com/images/bridgey/off-road.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;past-life&quot;&gt;Past Life&lt;/h2&gt;

&lt;p&gt;We bought Bridget off a mechanic in Hornsby. He’d built her out of two 4x4 L300s he salvaged. Originally he wanted to put a turbo diesel in her, but that didn’t fly for some reason, so we were left with the 2.4 petrol EFI.&lt;/p&gt;

&lt;p&gt;Aside from the engine recon and sticking 30k on the clock, he did the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Bull bar&lt;/li&gt;
  &lt;li&gt;Navara Spot Lights&lt;/li&gt;
  &lt;li&gt;Tints&lt;/li&gt;
  &lt;li&gt;Roof Bars&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.toughdogdealer.com.au/shock-absorbers.htm&quot;&gt;Tough dog shocks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tiresize.com/tires/BFGoodrich/Rugged-Terrain-TA-235-75R15.htm&quot;&gt;BF Goodrich Rugged Terrain 29”s&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Rust Proofing&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/old-1.jpeg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/old-1.jpeg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/old-2.jpeg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/old-2.jpeg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;remedial-work&quot;&gt;Remedial Work&lt;/h2&gt;

&lt;p&gt;Before we could get cracking with the conversion, there was a bunch of stuff that needed sorting out, mostly electrical:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Radio wasn’t wired properly (A/T missing)&lt;/li&gt;
  &lt;li&gt;Spot lights were in a separate switch mounted on the steering column&lt;/li&gt;
  &lt;li&gt;Driving lights were wired straight into the headlights (no relay), which was burning out the circuitry in the lighting stalk&lt;/li&gt;
  &lt;li&gt;Horn was broken&lt;/li&gt;
  &lt;li&gt;Indicator fuse kept blowing from anderson plug on the tow bar&lt;/li&gt;
  &lt;li&gt;No central locking&lt;/li&gt;
  &lt;li&gt;Original insulation on the floor was starting to melt / degrade&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We took the dash off, sorted out all the electrical issues, installed remote central locking and some reversing sensors for good measure.&lt;/p&gt;

&lt;p&gt;Next we started scraping the tar smelling insulation off the back floor, a few days of scraping (and much inhaled acetone) later we were done.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/dash-off.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/dash-off.jpg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/masks.png&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/masks.png&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/floor-clean.png&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/floor-clean.png&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;insulation&quot;&gt;Insulation&lt;/h2&gt;

&lt;p&gt;To keep the van cool in the summer and warm in the winter, it’s heavily insulated.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Floor:  9mm ply atop &lt;a href=&quot;http://www.ametalin.com/insulation-products/thermal-brane-4-insulation&quot;&gt;thermalbrane&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Walls:  7mm ply packed with &lt;a href=&quot;http://www.knaufinsulation.com.au/content/earthwool-external-wall-batts&quot;&gt;earthwooll&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Roof:   3mm ply under &lt;a href=&quot;http://www.ametalin.com/insulation-products/thermal-brane-4-insulation&quot;&gt;thermalbrane&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/lay-insulate.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/lay-insulate.jpg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/playwood.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/playwood.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;floor--wall-covering&quot;&gt;Floor / Wall Covering&lt;/h2&gt;

&lt;p&gt;For the floors we used Wood-look lino instead of laminate for $$, water resistance and less height.&lt;/p&gt;

&lt;p&gt;For the walls, we used grey marine carpet. It’s hard waring, inoffensive and something we could get to stick to the plywood.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/floor-wall-cover.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:60vh&quot; src=&quot;http://lathonez.com/images/bridgey/floor-wall-cover.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;wheel-arches&quot;&gt;Wheel Arches&lt;/h2&gt;

&lt;p&gt;We boxed the wheel arches in 7mm ply, which we covered in the same marine carpet as the walls. We put hinged lids on top so we could use what limited storage they offered, in 12mm pine DAR stained and varnished.&lt;/p&gt;

&lt;p&gt;We’ve used the same wood finish all over the van.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/wheel-arch.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:60vh&quot; src=&quot;http://lathonez.com/images/bridgey/wheel-arch.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;engine-box&quot;&gt;Engine Box&lt;/h2&gt;

&lt;p&gt;The engine in the van is under the front seats, so you get a bulge where the firewall of the engine comes into the back of the van.&lt;/p&gt;

&lt;p&gt;We to boxed this off to get everything as square as possible. This also added a bit of storage where the bulge tapers away from the middle of the engine, plus allowing us to stuff it with insulation to keep things cooler.&lt;/p&gt;

&lt;p&gt;Boxing method ditto wheel arches.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/engine-box.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:60vh&quot; src=&quot;http://lathonez.com/images/bridgey/engine-box.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;sofabed&quot;&gt;Sofabed&lt;/h2&gt;

&lt;p&gt;When working on the conversion we had one thing in mind - we wanted the van to be really comfortable and an environment you’d be happy spending some time in. Most of the vans we see on the road are very basic. The ones that are done well often have the bed permanently in “bed” mode, and really close to the roof. This is great for storage but doesn’t make for a nice space to chill out.&lt;/p&gt;

&lt;p&gt;We designed the sofabed to be as low as we could whilst still being comfortable to sit on and offering enough room for the house battery and electrics to fit underneath. We also wanted the top of the seat / mattress to line up with the engine box, so you could use the extra space to stretch out.&lt;/p&gt;

&lt;p&gt;The bed is made of two halves, each of which have offset slats.&lt;/p&gt;

&lt;p&gt;In “Sofa” mode, the two halves are pushed together and there is no space between the slats. The two halves together make the base of the sofa, while the back is the wall of the van.&lt;/p&gt;

&lt;p&gt;To turn the sofa into a bed, you pull one of the halves out towards you, which leaves a gap between the slats (same as a normal double bed). There’s a small leg that screws into the floor near the passenger door to offer extra support (this area takes a lot of stress when you get in and out of the van).&lt;/p&gt;

&lt;p&gt;The whole bed is hinged and lifts up via a pneumatic stay to give access to storage underneath.&lt;/p&gt;

&lt;p&gt;For the mattress we took advice from &lt;a href=&quot;http://homeupholsterer.com.au/Foam-Cut-to-Size&quot;&gt;the foam shop we went to&lt;/a&gt; who are specialists. The custom made foam mattress (including the upholstery) is our single most expensive item in the conversion.&lt;/p&gt;

&lt;p&gt;The bed has the same dimensions as a double, but is much longer with the engine box and kitchen top taken into consideration.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/bed-1.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/bed-1.jpg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/bed-2.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/bed-2.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/foam.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:60vh&quot; src=&quot;http://lathonez.com/images/bridgey/bed-foam.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;roof--door-panels&quot;&gt;Roof / Door Panels&lt;/h2&gt;

&lt;p&gt;These are mostly an aesthetic item, though the roof panels are also insulated with &lt;a href=&quot;http://www.ametalin.com/insulation-products/thermal-brane-4-insulation&quot;&gt;thermalbrane&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We removed the existing van panels and cut duplicates out of 3mm mdf, replacing the push-tacs with new ones.&lt;/p&gt;

&lt;p&gt;The door panels are covered in hard wearing outdoor furniture material, the roof panels are lino.&lt;/p&gt;

&lt;p&gt;We also replaced the original grey roof slats with the stained pine.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/door-card-upholst.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:25vh&quot; src=&quot;http://lathonez.com/images/bridgey/door-card-upholst.jpg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/door-card-pre.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:25vh&quot; src=&quot;http://lathonez.com/images/bridgey/door-card-pre.jpg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/door-card-on.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:25vh&quot; src=&quot;http://lathonez.com/images/bridgey/door-card-on.jpg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/roof-panel.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:25vh&quot; src=&quot;http://lathonez.com/images/bridgey/roof-panel.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;kitchen&quot;&gt;Kitchen&lt;/h2&gt;

&lt;p&gt;The kitchen was the most fiddly / technically challenging part of the conversion.&lt;/p&gt;

&lt;p&gt;We wanted the worktop to be about as high as a standard kitchen counter top. As the van is lifted this didn’t give us a lot to work with, but it did tie in with being the same height as the engine box.&lt;/p&gt;

&lt;p&gt;We also wanted to be able to have a “lid” on top of the kitchen, so when not using it you can lounge about the van as if it isn’t there.&lt;/p&gt;

&lt;p&gt;Due to the above constraints we were limited in the fixtures available to us:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Fridge: The fridge is 20 litres and cools to about 20 degrees below the ambient temperature. The fridge is hidden in the worktop via a push-catch and is controlled by a digital control panel on the front of the kitchen.&lt;/li&gt;
  &lt;li&gt;Sink: The sink is about 15 litres, plenty big enough to do washing up. The faucet swings up and down to fit under the closed kitchen lid.&lt;/li&gt;
  &lt;li&gt;Water: The water tank is 30L, installed where the spare wheel usually lives (spare is now on the roof). A self-priming pump drives the water flow to the sink.&lt;/li&gt;
  &lt;li&gt;Grey water: We sacrificed a waste water tank for more drinking water storage. The waste water drain is behind the rear left wheel, we just use a bucket. On reflection we’re glad we did this than have less drinking water capacity. We fill the tank every 3 days as it is.&lt;/li&gt;
  &lt;li&gt;Cupboards / Drawers: There are two cupboards and two drawers in the kitchen. We found the storage to be sufficient (we have no other kitchen storage on the roof or otherwise).&lt;/li&gt;
  &lt;li&gt;Stove: We sacrificed an inbuilt stove, for kitchen storage. Additionally we didn’t want to be cooking right in the back of the van anyway (cooking smells mean stinky van). We just use a portable butane stove (small cans).&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/kitchen-done.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:60vh&quot; src=&quot;http://lathonez.com/images/bridgey/kitchen-done.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/kitchen-1.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/kitchen-1.jpg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/kitchen-2.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/kitchen-2.jpg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/kitchen-3.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/kitchen-3.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;cupboards&quot;&gt;Cupboards&lt;/h2&gt;

&lt;p&gt;To make the van feel less “van” like inside - e.g. cover up the bare white metal and square things off, we built three internal cupboards, two on either side of the kitchen and one above.&lt;/p&gt;

&lt;p&gt;We installed cornicing which we use to hide the light strips and cut a couple of pieces of cladding to cover remaining van metal.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/cupboard.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:60vh&quot; src=&quot;http://lathonez.com/images/bridgey/cupboard.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;lighting&quot;&gt;Lighting&lt;/h2&gt;

&lt;p&gt;There are four different lights in the living area:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Original main cargo light with a super bright LED instead of the original bulb, wired to the house battery. Can be switched to come on via opening the door or flicking the light switch. We only really use this when we’re cleaning.&lt;/li&gt;
  &lt;li&gt;Two “Warm” LED light strips (one on each side, separately switched). These give a lovely background light for relaxing in the evening. Use these all the time.&lt;/li&gt;
  &lt;li&gt;Two “White” LED spot lights above the worktop (switched together). We use these only when cooking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/lights-one.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/lights-one.jpg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/lights-two.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/lights-two.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/switches.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:40vh&quot; src=&quot;http://lathonez.com/images/bridgey/switches.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;house-electrics&quot;&gt;House Electrics&lt;/h2&gt;

&lt;p&gt;As leccy is required for lots of various jobs along the way (kitchen / lighting), this went in over time.&lt;/p&gt;

&lt;p&gt;The setup has been working well for us with a couple hours driving a day to charge the house battery.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;120 amp/hour AGM house battery&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.batteriesdirect.com.au/shop/product/23370/ctek-d250s-dual.html&quot;&gt;Ctek Dual DC-DC charger&lt;/a&gt;. These things are legit.&lt;/li&gt;
  &lt;li&gt;100w solar panel permanently mounted on the roof&lt;/li&gt;
  &lt;li&gt;2400w (max) / 1200w stable sine wave AC inverter, with 2x 240v power outlets&lt;/li&gt;
  &lt;li&gt;2 * 2.5 amp USB outlets&lt;/li&gt;
  &lt;li&gt;Bluetooth battery monitor. Provides real time house battery voltage + low voltage alarm&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/leccy.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:60vh&quot; src=&quot;http://lathonez.com/images/bridgey/leccy.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;roof-storage&quot;&gt;Roof Storage&lt;/h2&gt;

&lt;p&gt;The van came with a beast of a steel roof rack. We extended it to build a cage which can house various waterproof items:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;2x Tables&lt;/li&gt;
  &lt;li&gt;2x Chairs&lt;/li&gt;
  &lt;li&gt;2x Stoves&lt;/li&gt;
  &lt;li&gt;Parasol&lt;/li&gt;
  &lt;li&gt;10 litre backup water&lt;/li&gt;
  &lt;li&gt;Waste water bucket&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally we use 2 galvanised steel toolboxes (about 64L each) to store stuff we don’t use every day but don’t want to get wet (bags, shoes, tools, etc).&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/roof.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:30vh&quot; src=&quot;http://lathonez.com/images/bridgey/roof.jpg&quot; /&gt;&lt;/a&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/awning.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:30vh&quot; src=&quot;http://lathonez.com/images/bridgey/awning.jpg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;We also fitted a 2.5 x 3m awning which is great for those sunny (or rainy) days.&lt;/p&gt;

&lt;h2 id=&quot;curtains&quot;&gt;Curtains&lt;/h2&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/curtains.png&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:30vh&quot; src=&quot;http://lathonez.com/images/bridgey/curtains.png&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;I found a &lt;a href=&quot;https://www.ebay.co.uk/itm/142211717441&quot;&gt;guy on ebay&lt;/a&gt; making ultra low profile curtain rails to measure out of steel / nylon. These are excellent. We got some block-out curtains from Spotlight that keep the van nice and dark.&lt;/p&gt;

&lt;p&gt;We also put a roll-up mozzie-screen between the kitchen cupboards so we can sit with the back door open without any unwanted visitors.&lt;/p&gt;

&lt;h2 id=&quot;misc-van-stuff&quot;&gt;Misc van stuff&lt;/h2&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;http://lathonez.com/images/bridgey/cockpit.jpeg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;max-width:30vh&quot; src=&quot;http://lathonez.com/images/bridgey/cockpit.jpeg&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;We’ve made the following improvements to the “van” / driving area, in addition to the camper conversion.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Retro steering wheel / gear knob&lt;/li&gt;
  &lt;li&gt;Tacho (so weird driving stick without a tacho!)&lt;/li&gt;
  &lt;li&gt;Dash carpet&lt;/li&gt;
  &lt;li&gt;Marine voltage meter / USB / 12V socket&lt;/li&gt;
  &lt;li&gt;Added extra engine insulation (earthwool)&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Thu, 30 Nov 2017 01:48:23 +0000</pubDate>
        <link>http://lathonez.github.io/2017/bridget/</link>
        <guid isPermaLink="true">http://lathonez.github.io/2017/bridget/</guid>
        
        <category>vanlife</category>
        
        <category>camper</category>
        
        <category>conversion</category>
        
        <category>combi</category>
        
        <category>L300</category>
        
        <category>delicia</category>
        
        
        <category>auto</category>
        
      </item>
    
      <item>
        <title>Copying a row from one database to another</title>
        <description>&lt;p&gt;How can I copy a row from our dev database to our production database?&lt;/p&gt;

&lt;p&gt;Most engineers would give an answer for this, varying depending on their background and the DBMS. The common ones are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Use the tool that came with your DBMS! &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.7/en/mysqldump.html&quot;&gt;mysqldump&lt;/a&gt; or &lt;a href=&quot;https://www.postgresql.org/docs/9.1/static/app-pgdump.html&quot;&gt;pg_dump&lt;/a&gt; in the context of this post.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/5.7/en/select-into.html&quot;&gt;Select&lt;/a&gt; / &lt;a href=&quot;https://www.postgresql.org/docs/9.2/static/sql-copy.html&quot;&gt;copy&lt;/a&gt; to outfile&lt;/li&gt;
  &lt;li&gt;Use &lt;a href=&quot;http://stackoverflow.com/questions/20949346/how-to-copy-rows-from-one-mysql-database-to-another&quot;&gt;raw sql with a connection to each db&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Try &lt;a href=&quot;http://www.sql-workbench.net/&quot;&gt;sqlworkbench&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Turn on &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.7/en/replication.html&quot;&gt;replication&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Roll your own script&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The purpose of this post is to convince you that there’s a better way, a python tool we’ve written called &lt;a href=&quot;https://github.com/lathonez/clone-row&quot;&gt;CloneRow.py&lt;/a&gt;. It currently supports mysql and postgres. If there’s a decent python lib for your DB we’ll write an adapter (&lt;a href=&quot;https://github.com/lathonez/clone-row/issues&quot;&gt;open an issue&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&quot;clonerowpy&quot;&gt;CloneRow.py&lt;/h2&gt;

&lt;p&gt;We came up with a one liner that adheres to the &lt;a href=&quot;http://www.tldp.org/LDP/GNU-Linux-Tools-Summary/html/c1089.htm&quot;&gt;unix tools philosophy&lt;/a&gt;. To copy a row in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my_table&lt;/code&gt; from development to production, where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my_table.my_column&lt;/code&gt; equals &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my_filter&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CloneRow.py dev prod my_table my_column my_filter&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;DEV:~$ CloneRow.py dev prod my_table my_column my_filter
2016-08-27 05:29:18 Reading configuration..
2016-08-27 05:29:18 The following columns will be ignored: id last_updated
2016-08-27 05:29:18 attempting to connect to local..
2016-08-27 05:29:18 connected to root@local:my_db - Database version : 90503
2016-08-27 05:29:18 attempting to connect to prod..
2016-08-27 05:29:20 connected to lathonez@prod:my_db - Database version : 90502
2016-08-27 05:29:20 getting local row..
2016-08-27 05:29:20 getting prod row..
2016-08-27 05:29:21 checking encoding..
2016-08-27 05:29:21 source encoding UTF8
2016-08-27 05:29:21 target encoding UTF8
2016-08-27 05:29:21 finding deltas..
2016-08-27 05:29:21
2016-08-27 05:29:21 |--------------------------------|Data Changes|--------------------------------|
2016-08-27 05:29:21   The following columns will be updated on prod
2016-08-27 05:29:21     -updated_column_one
2016-08-27 05:29:21     -updated_column_two
2016-08-27 05:29:21 |------------------------------------------------------------------------------|
2016-08-27 05:29:21
2016-08-27 05:29:21 backing up target row..
2016-08-27 05:29:21 backup file can be found at /tmp/my_table-my_column-my_filter-1472275758838.backup on this machine
2016-08-27 05:29:21 dumping update sql to disk..
2016-08-27 05:29:21 update sql is available for inspection at /tmp/my_table-my_column-my_filter-1472275758838.sql on this machine
2016-08-27 05:29:22 Row has been cloned successfully..
2016-08-27 05:29:22 Type 'r' to (r)estore from backup, anything else to exit

2016-08-28 09:19:39
2016-08-28 09:19:39 |---------------------------|Manual Rollback Steps|----------------------------|
2016-08-28 09:19:39   To rollback manually, run the following steps on this machine
2016-08-28 09:19:39     psql --host 127.0.0.1 --port 5432 --user my_user --pass my_pass
2016-08-28 09:19:39     begin;
2016-08-28 09:19:39     delete from my_table where my_column = 'my_filter';
2016-08-28 09:19:39     -- if more than one row has been deleted above run `rollback;`
2016-08-28 09:19:39     copy my_table from '/tmp/my_table-my_column-my_filter-1472275758838.backup';
2016-08-28 09:19:39     commit;
2016-08-28 09:19:39 |------------------------------------------------------------------------------|
2016-08-28 09:19:39
2016-08-28 09:19:39 operation completed successfully, have a fantastic day
2016-08-28 09:19:39 housekeeping..

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Copy a single row from one database to another, given a column and a filter to apply&lt;/li&gt;
  &lt;li&gt;Fail-safe operation, with automated and manual rollback procedures provided&lt;/li&gt;
  &lt;li&gt;Ignore columns that you’ll never want to copy (serials, ids)&lt;/li&gt;
  &lt;li&gt;Display which columns will be modified in the update (deltas)&lt;/li&gt;
  &lt;li&gt;Allow the user to check the target system before ‘committing’ the changes&lt;/li&gt;
  &lt;li&gt;An &lt;a href=&quot;https://github.com/lathonez/clone-row/blob/master/CloneRow.example.cfg&quot;&gt;ssh_config like&lt;/a&gt; connection alias system&lt;/li&gt;
  &lt;li&gt;Ignore schema differences where possible (whilst warning the user)&lt;/li&gt;
  &lt;li&gt;Check that encoding matches on source and target&lt;/li&gt;
  &lt;li&gt;Hint at schema changes required to bring source and target tables in line&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the above looks interesting to you, why not head on over to &lt;a href=&quot;https://github.com/lathonez/clone-row&quot;&gt;github&lt;/a&gt; and give it a try?&lt;/p&gt;

&lt;p&gt;Still need convincing? Read on.&lt;/p&gt;

&lt;h2 id=&quot;use-case-1-releasing-to-prod-insert&quot;&gt;Use Case #1: Releasing to prod (INSERT)&lt;/h2&gt;

&lt;p&gt;We have a configuration table for each of our clients, where one row contains many config items for a single client. Currently this table is 39 columns wide.&lt;/p&gt;

&lt;p&gt;When developing for a new client, you add the configuration it needs into the config table. When you’re done, the config table represents a perfect view of that client’s configuration, if you could only get it onto prod.&lt;/p&gt;

&lt;p&gt;The standard procedure was: “open phpmyadmin and paste everything in, column by column”. Not only is this error prone but also extremely time consuming.&lt;/p&gt;

&lt;p&gt;We eventually wrote a simple mysqldump wrapper script for this. I expect there are lots of similar things out there.&lt;/p&gt;

&lt;h2 id=&quot;use-case-2-releasing-to-prod-update&quot;&gt;Use Case #2: Releasing to prod (UPDATE)&lt;/h2&gt;

&lt;p&gt;You’ve just finished updating an existing client on prod. Said config table is frequently updated on production after the initial release.&lt;/p&gt;

&lt;p&gt;Best case scenario: It was an easy change with only one option updated. You remember what that option is.&lt;/p&gt;

&lt;p&gt;Typical scenario: The change started simple, dragged on for a number of days (if not weeks), involving multiple config options. You vaguely remember which ones you changed.. or do you?&lt;/p&gt;

&lt;p&gt;Again, the standard procedure was: “open phpmyadmin and paste in whatever you changed”&lt;/p&gt;

&lt;p&gt;If you remembered the columns you’d updated and they hadn’t been changed on prod since you started dev, you’d be ok. If you’d forgotten (and had to blat the whole row), or there had been updates in the interim, you’d be screwed.&lt;/p&gt;

&lt;h2 id=&quot;use-case-3-updating-development-update&quot;&gt;Use Case #3 Updating Development (UPDATE)&lt;/h2&gt;

&lt;p&gt;Similar case to above, though obviously not as mission critical (though your work is on the dev database and what happens if you overwrite it?).&lt;/p&gt;

&lt;p&gt;The ideal workflow:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;start dev: update development database with the configuration row from prod&lt;/li&gt;
  &lt;li&gt;finish dev: pull the prod row back in again, so we can see if any changes have happened in the interim&lt;/li&gt;
  &lt;li&gt;release: merge config changes (from above) if necessary in the dev database, then push that row to prod&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clearly without proper tooling this was never going to happen. When possible, we’d refresh the entire dev database from prod, though more often than not there were loose changes on in the dev database which prevented this.&lt;/p&gt;

&lt;h2 id=&quot;clonerowpy-vs-import--export&quot;&gt;CloneRow.py vs import / export&lt;/h2&gt;

&lt;p&gt;By import / export, I’m referring to the following from the intro, which all work in broadly the same way: export a row from one database, import it into another.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;dump tools&lt;/li&gt;
  &lt;li&gt;copying / selecting to outfile&lt;/li&gt;
  &lt;li&gt;using raw sql with a connection to each database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;dump tools&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;pre class=&quot;lowlight&quot;&gt;
&lt;code&gt;# run dump command
mysqldump --host myhost.com --user my_user --port 3306 --no-create-info --databases my_db --tables my_table --where my_column=myfilter &amp;gt; dump.out
# copy dump file to the target server
scp dump.out myhost.com:/tmp
# connect to target database
DELETE FROM my_table WHERE my_column = 'my_filter';
# load dump sql
SOURCE '/tmp/dump.out'&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;copy / select to outfile&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;pre class=&quot;lowlight&quot;&gt;
&lt;code&gt;# select to outfile
SELECT * INTO OUTFILE LOCAL 'dump.out'
  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '&quot;'
  LINES TERMINATED BY '\n'
  FROM my_table
  WHERE my_column='my_filter';
# copy the file to the target server
scp /exportdata/customers.txt myhost.com:/tmp
# connect to target database
DELETE FROM my_table WHERE my_column='my_filter';
LOAD DATA LOCAL INFILE '/tmp/dump.out';
&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;raw sql&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;pre class=&quot;lowlight&quot;&gt;
&lt;code&gt;DELETE FROM target_database.my WHERE some_id = 123;
INSERT INTO to_database.to_table SELECT * FROM from_database WHERE some_id = 123;&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;These are all overly complicated for your average developer (in my experience).&lt;/li&gt;
  &lt;li&gt;They’re time consuming. Even if you do this on a daily basis and get good at it, there are multiple steps in each.&lt;/li&gt;
  &lt;li&gt;They’re prone to error. What happens if you get one of your where clauses wrong?&lt;/li&gt;
  &lt;li&gt;They don’t do any comparison of data.&lt;/li&gt;
  &lt;li&gt;They don’t allow an easy rollback&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;clonerowpy-vs-phpmyadmin-etc&quot;&gt;CloneRow.py vs phpmyadmin (etc)&lt;/h2&gt;

&lt;p&gt;Opening two phpmyadmin windows (one for source and one for target), does give you a kind of visual diff, however:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It is time consuming&lt;/li&gt;
  &lt;li&gt;It is error prone particularly for wide tables&lt;/li&gt;
  &lt;li&gt;There’s no easy roll back&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If using import / export, you lose the visual comparison and risk updating the wrong data.&lt;/p&gt;

&lt;h2 id=&quot;clonerowpy-vs-sqlworkbench&quot;&gt;CloneRow.py vs sqlworkbench&lt;/h2&gt;

&lt;p&gt;Sqlworkbench is extremely powerful and versatile; it’s basically an abstraction over JDBC, allowing you to write sql-esque commands on top of the adapter. You can also define connection profiles which remove a lot of the headache from repeated operations.&lt;/p&gt;

&lt;p&gt;However, I found it to be a lacking in dbms specific nuances. Jack of all trades (NOT the unix tools philosophy!):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The dump / export format was inconsistent and couldn’t be easily used with the import. This was solved easily enough with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sed&lt;/code&gt; in the wrapper script, but not ideal.&lt;/li&gt;
  &lt;li&gt;The postgres JSON type seemed to be unsupported. The JSON output by sqlworkbench wasn’t the same as in pg_dump, more to the point it was invalid JSON. The issue was around escaping quotes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I recommend looking at sqlworkbench, as it may be appropriate for your use case and it’s a great tool for the right job. I see it as analagous to a [python database adapter][http://initd.org/psycopg/], you have to do a lot of scripting around it.&lt;/p&gt;

&lt;p&gt;An sqlworkbench script looks like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;pre class=&quot;lowlight&quot;&gt;
&lt;code&gt;-WbCopy
 --sourceProfile=$[source_con]
 --targetProfile=$[target_con]
 --mode=update,insert
 --keyColumns=$[column]
 --sourceTable=my_db.$[table]
 --targetTable=my_db.$[table]
 --sourceWhere=$[column]='$[filter]'
 -;&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Which you invoke via with Java (in a wrapper script):&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java -jar sqlworkbench.jar -vardef='vars.def' -script='export.script'&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;clonerowpy-vs-replication&quot;&gt;CloneRow.py vs Replication&lt;/h2&gt;

&lt;p&gt;Production to Development replication handles Use Case #3 (Updating Development) extremely well. However:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It can be time consuming to set up if you do not have the skill set.&lt;/li&gt;
  &lt;li&gt;It puts strain on the prod database. It can be difficult to justify replication out of prod, when all you gain is updating development or test environments.&lt;/li&gt;
  &lt;li&gt;If you have developers working on their own databases, replication isn’t an option.&lt;/li&gt;
  &lt;li&gt;Whilst it solves Use Case #3, it does not address #1 or #2.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;clonerowpy-vs-rolling-your-own-script&quot;&gt;CloneRow.py vs rolling your own script&lt;/h2&gt;

&lt;p&gt;The vast majority of solutions out there will be script(s) written in house. CloneRow.py started off that way. Rolling your own script has a clear advantage that, it can do literally whatever you need it to do. However, it does have some disadvantes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You have to actually roll it. We spent a lot of time getting CloneRow.py from zero to where it is now.&lt;/li&gt;
  &lt;li&gt;There will be bugs. There are bugs in CloneRow.py, but the advantages of using an open source tool used by others is, that we can identify the bugs and fix them together.&lt;/li&gt;
  &lt;li&gt;You have to maintain it. In my experience such tools are written by a single engineer; other users have very little idea of how it works, or what to do when it goes wrong. This is fine as long as the author is still around when it goes wrong or needs updating, and has the time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;contribute&quot;&gt;Contribute&lt;/h2&gt;

&lt;p&gt;This blog is &lt;a href=&quot;https://github.com/lathonez/lathonez.github.io&quot;&gt;on github&lt;/a&gt;, if you can improve it, have any suggestions or I’ve failed to keep it up to date, &lt;a href=&quot;https://github.com/lathonez/lathonez.github.io/issues/new&quot;&gt;raise an issue&lt;/a&gt; or a PR.&lt;/p&gt;

</description>
        <pubDate>Fri, 26 Aug 2016 12:34:23 +0000</pubDate>
        <link>http://lathonez.github.io/2016/clone-row/</link>
        <guid isPermaLink="true">http://lathonez.github.io/2016/clone-row/</guid>
        
        <category>devops</category>
        
        <category>release</category>
        
        <category>databases</category>
        
        <category>php</category>
        
        <category>mysql</category>
        
        <category>copying</category>
        
        <category>merging</category>
        
        
        <category>devops</category>
        
      </item>
    
      <item>
        <title>Securing a docker registry behind Apache</title>
        <description>&lt;p&gt;We recently went to setup a docker registry on our production build server. We wanted the quickest / easiest way to get the registry going but didn’t know where to start. This information is all out there but not in one place (that I found).&lt;/p&gt;

&lt;p&gt;Basically if you’ve already got apache running on the target server, getting everything going is incredibly simple. If you don’t run apache this guide will not useful for you.&lt;/p&gt;

&lt;h2 id=&quot;securing-the-registry&quot;&gt;Securing the registry&lt;/h2&gt;

&lt;p&gt;TLS &lt;a href=&quot;https://docs.docker.com/registry/deploying/#/running-a-domain-registry&quot;&gt;is mandatory&lt;/a&gt; when running a remote docker registry. We used &lt;a href=&quot;https://letsencrypt.org/how-it-works/&quot;&gt;letsencrypt&lt;/a&gt; to obtain our certificates.&lt;/p&gt;

&lt;p&gt;If you don’t already have one, create an apache vhost with a subdomain for your registry. This is just so &lt;a href=&quot;https://certbot.eff.org/&quot;&gt;certbot&lt;/a&gt; will prompt you to generate the certificate for it.&lt;/p&gt;

&lt;div class=&quot;language-conf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;&lt;span class=&quot;n&quot;&gt;VirtualHost&lt;/span&gt; *:&lt;span class=&quot;m&quot;&gt;80&lt;/span&gt;&amp;gt;
    &lt;span class=&quot;n&quot;&gt;ServerAdmin&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dev&lt;/span&gt;@&lt;span class=&quot;n&quot;&gt;example&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ServerName&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;docker&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;example&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;
&amp;lt;/&lt;span class=&quot;n&quot;&gt;VirtualHost&lt;/span&gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install and run &lt;a href=&quot;https://certbot.eff.org/&quot;&gt;certbot&lt;/a&gt;. It’ll prompt you for the necessary info and configure apache with the certifcates it receives from letsencrypt.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./path/to/certbot-auto --apache&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;virtual-host-entry&quot;&gt;Virtual Host Entry&lt;/h2&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://github.com/ripienaar/&quot;&gt;R.I.Pienaar&lt;/a&gt; for this. I was banging my head against the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProxyPreserveHost&lt;/code&gt; line until I found it on his &lt;a href=&quot;https://www.devco.net/archives/2015/01/21/running-a-secure-docker-registry-behind-apache.php&quot;&gt;blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now you’ve got the certs, update your registry’s vhost. Main things to note:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;using the SSL Cert we’ve just got from letsencrypt&lt;/li&gt;
  &lt;li&gt;Proxying any requests to the registry through to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://127.0.0.1:5000&lt;/code&gt; where the registry will be running&lt;/li&gt;
  &lt;li&gt;Basic auth using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;htpasswd&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don’t want auth (e.g. username:password) for your registry, remove the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;Location&amp;gt;&lt;/code&gt; entries.&lt;/p&gt;

&lt;div class=&quot;language-conf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;&lt;span class=&quot;n&quot;&gt;VirtualHost&lt;/span&gt; *:&lt;span class=&quot;m&quot;&gt;443&lt;/span&gt;&amp;gt;

        &lt;span class=&quot;n&quot;&gt;ServerName&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;docker&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;example&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ServerAdmin&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dev&lt;/span&gt;@&lt;span class=&quot;n&quot;&gt;example&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;SSLEngine&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;On&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;SSLCertificateFile&lt;/span&gt; /&lt;span class=&quot;n&quot;&gt;etc&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;letsencrypt&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;live&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;example&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;cert&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;pem&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;SSLCertificateKeyFile&lt;/span&gt; /&lt;span class=&quot;n&quot;&gt;etc&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;letsencrypt&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;live&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;example&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;privkey&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;pem&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;SSLCertificateChainFile&lt;/span&gt; /&lt;span class=&quot;n&quot;&gt;etc&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;letsencrypt&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;live&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;example&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;chain&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;pem&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;ProxyPreserveHost&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ProxyPass&lt;/span&gt; / &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;://&lt;span class=&quot;m&quot;&gt;127&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;:&lt;span class=&quot;m&quot;&gt;5000&lt;/span&gt;/
        &lt;span class=&quot;n&quot;&gt;ProxyPassReverse&lt;/span&gt; / &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;://&lt;span class=&quot;m&quot;&gt;127&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;.&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;:&lt;span class=&quot;m&quot;&gt;5000&lt;/span&gt;/

        &amp;lt;&lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt; /&amp;gt;
                &lt;span class=&quot;n&quot;&gt;Order&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deny&lt;/span&gt;,&lt;span class=&quot;n&quot;&gt;allow&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Allow&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;

                &lt;span class=&quot;n&quot;&gt;AuthName&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Registry Authentication&quot;&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;AuthType&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;basic&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;AuthUserFile&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/opt/registry-htpasswd/.htpasswd&quot;&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;valid&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;
        &amp;lt;/&lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&amp;gt;

        &lt;span class=&quot;c&quot;&gt;# Allow ping and users to run unauthenticated.
&lt;/span&gt;        &amp;lt;&lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt; /&lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;/&lt;span class=&quot;err&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ping&lt;/span&gt;&amp;gt;
                &lt;span class=&quot;n&quot;&gt;Satisfy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Allow&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;
        &amp;lt;/&lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&amp;gt;

        &lt;span class=&quot;c&quot;&gt;# Allow ping and users to run unauthenticated.
&lt;/span&gt;        &amp;lt;&lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt; /&lt;span class=&quot;err&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ping&lt;/span&gt;&amp;gt;
               &lt;span class=&quot;n&quot;&gt;Satisfy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;
               &lt;span class=&quot;n&quot;&gt;Allow&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;
        &amp;lt;/&lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&amp;gt;

&amp;lt;/&lt;span class=&quot;n&quot;&gt;VirtualHost&lt;/span&gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;authentication&quot;&gt;Authentication&lt;/h2&gt;

&lt;p&gt;Skip if you don’t want the username / password authentication for your registry.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;pre class=&quot;lowlight&quot;&gt;
&lt;code&gt;mkdir /opt/registry-htpasswd
cd /opt/registry-htpasswd
htpasswd -bc .htpasswd username password&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;storage&quot;&gt;Storage&lt;/h2&gt;

&lt;p&gt;It’s &lt;a href=&quot;https://docs.docker.com/registry/deploying/#/storage&quot;&gt;good practice&lt;/a&gt; to specify a storage folder for your registry.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mkdir /opt/registry-data&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;running-the-registry&quot;&gt;Running the Registry&lt;/h2&gt;

&lt;p&gt;As we’re using Apache for TLS and auth, running the registry is straightforward:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;pre class=&quot;lowlight&quot;&gt;
&lt;code&gt;docker run -d -p 5000:5000 \
    --restart=always \
    --name registry \
    -v /opt/registry-data:/var/lib/registry \
    registry:2&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;using-the-registry&quot;&gt;Using the Registry&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;pre class=&quot;lowlight&quot;&gt;
&lt;code&gt;docker login docker.example.io
docker push docker.example.io/example_image:latest&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;contribute&quot;&gt;Contribute&lt;/h2&gt;

&lt;p&gt;This blog is &lt;a href=&quot;https://github.com/lathonez/lathonez.github.io&quot;&gt;on github&lt;/a&gt;, if you can improve it, have any suggestions or I’ve failed to keep it up to date, &lt;a href=&quot;https://github.com/lathonez/lathonez.github.io/issues/new&quot;&gt;raise an issue&lt;/a&gt; or a PR.&lt;/p&gt;

</description>
        <pubDate>Wed, 20 Jul 2016 12:34:23 +0000</pubDate>
        <link>http://lathonez.github.io/2016/docker-registry-apache-letsencrypt/</link>
        <guid isPermaLink="true">http://lathonez.github.io/2016/docker-registry-apache-letsencrypt/</guid>
        
        <category>docker</category>
        
        <category>registry</category>
        
        <category>apache</category>
        
        <category>letsencrypt</category>
        
        
        <category>dev</category>
        
      </item>
    
      <item>
        <title>Unify DI Boilerplate</title>
        <description>&lt;p&gt;When setting up dependency injection for &lt;a href=&quot;http://github.com/lathonez/clicker&quot;&gt;my demo project&lt;/a&gt; I follwed this &lt;a href=&quot;https://developers.livechatinc.com/blog/testing-angular-2-apps-dependency-injection-and-components&quot;&gt;excellent blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This post demonstrates how to unify boilerplate necessary for dependency injection away from your test specs into a single file.&lt;/p&gt;

&lt;h2 id=&quot;what-boilerplate&quot;&gt;What boilerplate?&lt;/h2&gt;

&lt;p&gt;Below is a very simple test spec with dependency injection component we’re testing. As you can see, it’s 99% boilerplate, lots of imports along with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;beforeEach&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;beforeEachProvider&lt;/code&gt; functions.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;beforeEachProviders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;injectAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                               &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/core/testing&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;ComponentFixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;TestComponentBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                               &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/compiler/testing&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;provide&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;              &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Page2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./page2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Utils&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;../../services/utils&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ConfigMock&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;           &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./mocks&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;NavController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;NavParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;Platform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                               &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ionic-angular&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;page2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Page2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;page2Fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ComponentFixture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Page2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;beforeEachProviders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;NavController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;useClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MockClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;NavParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;useClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MockClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;useClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MockClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;useClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MockClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Platform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;useClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MockClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;injectAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TestComponentBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;tcb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestComponentBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tcb&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Page2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;componentFixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ComponentFixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;page2Fixture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;componentFixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;page2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;componentFixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;componentInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;page2Fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;detectChanges&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;promiseCatchHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;initialises&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;page2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBeNull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;page2Fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBeNull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For a few files this is fine. In a larger project with tens of spec files, maintaining this boilerplate became a headache for us;  Angular 2 and Ionic 2 were evolving and the imports and providers kept changing.&lt;/p&gt;

&lt;p&gt;It’s also not great having to read ~50 lines of boilerplate at the top of each file before you can see what’s being tested.&lt;/p&gt;

&lt;h2 id=&quot;unifying-the-boilerplate&quot;&gt;Unifying the boilerplate&lt;/h2&gt;

&lt;p&gt;We set out to remove as many of the imports as we could, as well as outsourcing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;beforeEach&lt;/code&gt; functions into a single file.&lt;/p&gt;

&lt;p&gt;Here’s the what we ended up with:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                              &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ComponentFixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestComponentBuilder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;     &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/compiler/testing&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;injectAsync&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                                &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/core/testing&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Control&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                                    &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/common&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NavController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Platform&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ionic-angular&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ClickersMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ConfigMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NavMock&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./mocks&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Utils&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                                      &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;../app/services/utils&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Clickers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                                   &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;../app/services/clickers&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestUtils&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                                  &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./testUtils&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;providers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;useClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ConfigMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Clickers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;useClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ClickersMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required by ClickerButton&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;useClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ConfigMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// required by ClickerList&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;NavController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;useClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NavMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// required by ClickerList&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;provide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Platform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;useClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ConfigMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// -&amp;gt; IonicApp&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;injectAsyncWrapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Function&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;injectAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TestComponentBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;asyncCallbackFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Function&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;detectChanges&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;beforeEachFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;tcb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestComponentBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tcb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ComponentFixture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;testSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;testSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;componentInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;testSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;control&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Control&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;detectChanges&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;detectChanges&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;beforeEachFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;beforeEachFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;testSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;promiseCatchHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;injectAsyncWrapper&lt;/code&gt; wraps &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;injectAsync&lt;/code&gt;, executing the callback passed in when TestComponentBuilder has completed. The main win from this is that you don’t need to import &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestComponentBuilder&lt;/code&gt; in each of your specs.&lt;/p&gt;

&lt;p&gt;The heavy lifting is done in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asyncCallbackFactory&lt;/code&gt;, which takes the following arguments:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;component:&lt;/strong&gt; The coponent class we’re currently testing&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;testSpec:&lt;/strong&gt; A reference to the test spec. This is used so we can set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;component&lt;/code&gt; (instance) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fixture&lt;/code&gt; variables in the test spet without needing further boilerplate.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;detectChanges:&lt;/strong&gt; Should we invoke &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;detectChanges()&lt;/code&gt; against the component fixture in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;beforeEach&lt;/code&gt;? This is useful in cases when you need to do initial / bespoke setup on the component instance before detecting changes. Usually this would be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;beforeEachFn:&lt;/strong&gt; Sometimes you need to run an additional function before each test, nothing to do with DI, your standard beforeEach. Before this change you’d have this code in-lined inside createAsync callback.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/lathonez/clicker/commit/4769372596756ec60e876de07e484a01ad181de6#diff-81c66575523ad4932b8772dceb8eab4c&quot;&gt;This diff&lt;/a&gt; is a good example of the above arguments in use after the boilerplate has been removed.&lt;/p&gt;

&lt;h2 id=&quot;resultant-spec&quot;&gt;Resultant Spec&lt;/h2&gt;

&lt;p&gt;As we import from our unified &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;diExports&lt;/code&gt; file, most of the boilerplate has been removed:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;beforeEachProviders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@angular/core/testing&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;asyncCallbackFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;injectAsyncWrapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;providers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestUtils&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;../../../test/diExports&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Page2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;                                                          &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./page2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Page2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;beforeEachProviders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;providers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;injectAsyncWrapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;asyncCallbackFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Page2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)));&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;initialises&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBeNull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBeNull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can see the full commit of the above change &lt;a href=&quot;https://github.com/lathonez/clicker/commit/4769372596756ec60e876de07e484a01ad181de6&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;contribute&quot;&gt;Contribute&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/lathonez/clicker&quot;&gt;Clickers&lt;/a&gt; is a work in progress. If you’d like to help out or have any suggestions, check the [roadmap sticky][clicker-issue-38].&lt;/p&gt;

&lt;p&gt;This blog is &lt;a href=&quot;https://github.com/lathonez/lathonez.github.io&quot;&gt;on github&lt;/a&gt;, if you can improve it, have any suggestions or I’ve failed to keep it up to date, &lt;a href=&quot;https://github.com/lathonez/lathonez.github.io/issues/new&quot;&gt;raise an issue&lt;/a&gt; or a PR.&lt;/p&gt;

&lt;h2 id=&quot;help&quot;&gt;Help!&lt;/h2&gt;

&lt;p&gt;If you can’t get any of this working in your own project, [raise an issue][clicker-issue-new] and I’ll do my best to help out.&lt;/p&gt;

&lt;div align=&quot;center&quot;&gt;&lt;iframe src=&quot;https://ghbtns.com/github-btn.html?user=lathonez&amp;amp;repo=clicker&amp;amp;type=star&amp;amp;count=true&quot; frameborder=&quot;0&quot; scrolling=&quot;0&quot; width=&quot;170px&quot; height=&quot;20px&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;

</description>
        <pubDate>Sat, 18 Jun 2016 20:34:23 +0000</pubDate>
        <link>http://lathonez.github.io/2016/unify-di-boilerplate/</link>
        <guid isPermaLink="true">http://lathonez.github.io/2016/unify-di-boilerplate/</guid>
        
        <category>angular2</category>
        
        <category>testing</category>
        
        <category>di</category>
        
        <category>test</category>
        
        
        <category>dev</category>
        
      </item>
    
      <item>
        <title>Excluding files from a Cordova build</title>
        <description>&lt;p&gt;Quick post to explain how to remove files from a Cordova (also works for Ionic2) project at build time.&lt;/p&gt;

&lt;p&gt;See the &lt;a href=&quot;https://github.com/lathonez/clicker/issues/15&quot;&gt;original issue on github&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;why-would-i-need-to-do-this&quot;&gt;Why would I need to do this?&lt;/h2&gt;

&lt;p&gt;Your project lifecycle creates artifacts in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www/build&lt;/code&gt; that you do not want going into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.apk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In our case we needed to delete the output of our test build phase from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www/build/test&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;dont-touch-the-builder&quot;&gt;Don’t touch the builder&lt;/h2&gt;

&lt;p&gt;Originally it seemed the correct approach would be to &lt;a href=&quot;http://stackoverflow.com/questions/21142848/cordova-build-ignore-files&quot;&gt;override the builder configuration&lt;/a&gt;. However that brings with it a few problems:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The builders are platform specific (e.g. if you build Android and iOS you’ll need two changes)&lt;/li&gt;
  &lt;li&gt;There are different builders for Android - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ant&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gradle&lt;/code&gt; - depending on which version of Cordova you’re running&lt;/li&gt;
  &lt;li&gt;Currently the &lt;a href=&quot;http://stackoverflow.com/a/25927034/5083721&quot;&gt;override does not work&lt;/a&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gradle&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;use-the-cordova-build-hooks&quot;&gt;Use the Cordova build hooks&lt;/h2&gt;

&lt;p&gt;We went for an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;after_prepare&lt;/code&gt; &lt;a href=&quot;https://cordova.apache.org/docs/en/dev/guide/appdev/hooks/&quot;&gt;Cordova hook&lt;/a&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cordova build&lt;/code&gt; is shorthand for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cordova prepare&lt;/code&gt; then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cordova compile&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cordova prepare&lt;/code&gt; copies your assets over in prepraration for compilation.&lt;/p&gt;

&lt;p&gt;We can therefore make use of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;after_prepare&lt;/code&gt; hook to remove these assets from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;platform/**/assets&lt;/code&gt; so they don’t make their way into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.apk&lt;/code&gt;, whilst leaving the output in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www/build&lt;/code&gt; intact.&lt;/p&gt;

&lt;p&gt;If you add your hook into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./hooks/after_prepare&lt;/code&gt;, no changes to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.xml&lt;/code&gt; are required - &lt;a href=&quot;https://cordova.apache.org/docs/en/dev/guide/appdev/hooks/&quot;&gt;more info&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Node is recommended for the hooks to keep your project cross-plaform. Here’s what we came up with, inspired by an existing hook in Ionic’s &lt;a href=&quot;https://github.com/driftyco/ionic2-app-base/blob/master/hooks/after_prepare/010_add_platform_class.js&quot;&gt;app base&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#!/usr/bin/env node
&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;del&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;del&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rootdir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rootdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// go through each of the platform directories that have been prepared&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;platforms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;CORDOVA_PLATFORMS&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;CORDOVA_PLATFORMS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;platforms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// open up the index.html file at the www root&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;platform&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;platforms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testBuildPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;platform&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;android&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;testBuildPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;platforms&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;assets&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;www&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;testBuildPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;platforms&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;www&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;existsSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;testBuildPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Removing test build from assets after prepare: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testBuildPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;del&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;testBuildPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Test build @ &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testBuildPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; does not exist for removal&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cordova build&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ionic build&lt;/code&gt;, Cordova will invoke your hook after it has prepared your code for compilation, removing those pesky files.&lt;/p&gt;

&lt;h2 id=&quot;contribute&quot;&gt;Contribute&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/lathonez/clicker&quot;&gt;Clickers&lt;/a&gt; is a work in progress. If you’d like to help out or have any suggestions, check the &lt;a href=&quot;https://github.com/lathonez/clicker/issues/38&quot;&gt;roadmap sticky&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This blog is &lt;a href=&quot;https://github.com/lathonez/lathonez.github.io&quot;&gt;on github&lt;/a&gt;, if you can improve it, have any suggestions or I’ve failed to keep it up to date, &lt;a href=&quot;https://github.com/lathonez/lathonez.github.io/issues/new&quot;&gt;raise an issue&lt;/a&gt; or a PR.&lt;/p&gt;

&lt;h2 id=&quot;help&quot;&gt;Help!&lt;/h2&gt;

&lt;p&gt;If you can’t get any of this working in your own project, &lt;a href=&quot;https://github.com/lathonez/clicker/issues/new&quot;&gt;raise an issue&lt;/a&gt; and I’ll do my best to help out.&lt;/p&gt;

</description>
        <pubDate>Sun, 28 Feb 2016 11:34:23 +0000</pubDate>
        <link>http://lathonez.github.io/2016/cordova-remove-assets/</link>
        <guid isPermaLink="true">http://lathonez.github.io/2016/cordova-remove-assets/</guid>
        
        <category>ionic2</category>
        
        <category>cordova</category>
        
        <category>gradle</category>
        
        
        <category>dev</category>
        
      </item>
    
  </channel>
</rss>
