Search code examples
ionic-frameworkjasminekarma-jasminecouchbase-lite

Ionic Couchbase Lite Karma Jasmine Unit Testing


After some struggle, I successfully have jasmine tests running using karma, but I can't seem to find an answer to this question:

How can I run my jasmine tests on an actual device to test functions related couchbase lite database?

I am using this: https://github.com/couchbaselabs/ng-couchbase-lite

This is my test:

     describe('SetupService tests', function() {
        
        it('SetupService should instantiate', function() { 
            expect(SetupService).toBeDefined();
        }); 
        
        it('it should instantiate database', function() { 
            var database = null; 
            SetupService.setupConfig();
            expect(database).not.toBeNull();
        });  
    });

So I need to run the tests on an actual device so the db can successfully be created. I am new to unit testing and currently only using karam cli.

The setup config showing that it requires couchbase lite and cordova:

    var setupConfig = function() {
         console.log("set up config");
         var deferred = $q.defer();

         if(!window.cblite) { 
             deferred.reject('Couchbase Lite not installed');  
         } 
         else {
             cblite.getURL(function(err, url) {
                 console.log("cblite get url");
                 if(err) {
                     console.log(err);
                     deferred.reject("There was an error getting the database URL");  
                 }
                 else{
                     database = new $couchbase(url, appDbName);  
                     database.createDatabase().then(function(result) {
                         var views = setupViews();
                         database.createDesignDocument("_design/todo", views);
                         database.listen();
                         deferred.resolve(true); 
                     }, function(error) {
                         // we will not reject this err, as it is caused when a db already exists
                         // so it will happen everytime
                         deferred.resolve(err);  
                     });
                 } 
             }); 
         } 

         return deferred.promise;
     };

Solution

    1. Create a folder called tests in www/

      .

    2. Download latest standalone jasmine zip from Here

      a. Put the lib folder in www/tests

      b. Copy SpecRunner.html to www/

    .

    1. Make your SpecRunner.html look exactly like your index.html

    .

    1. Then add jasmine css and scripts to SpecRunner.html just before </head>

      <link rel="shortcut icon" type="image/png" href="tests/lib/jasmine-x.x.x/jasmine_favicon.png">
      <link rel="stylesheet" href="tests/lib/jasmine-x.x.x/jasmine.css">
      <style>
          .jasmine_html-reporter{
              width: 100%;
              margin: 200px 0px;
          } 
      </style> 
      
    2. At the end of the body tag, add jasmine lib scripts:

      <script src="tests/lib/jasmine-x.x.x/jasmine.js"></script>
      <script src="tests/lib/jasmine-x.x.x/jasmine-html.js"></script>
      <script src="tests/lib/jasmine-x.x.x/boot.js"></script>
      

    .

    1. Open boot.js in www/tests/lib/jasmine-x.x.x/boot.js

      Look for the window.load function and replace with this:

        window.onload = function() {
          if (currentWindowOnload) {
            currentWindowOnload();
          }
          jasmine.initialize  = htmlReporter.initialize;
          jasmine.execute     = env.execute;
        };
      

    .

    1. In the ctrl of you starting page, add this when everything has loaded:

           if(window.jasmine){  
               console.log("---------------------------------------------------------");
               console.log("STARTING JASMINE...");  
               jasmine.initialize();
               jasmine.execute(); 
               console.log("---------------------------------------------------------");
               console.log("JASMINE INITIALED");
               console.log("---------------------------------------------------------");
           }
      

      I personally bootstrap angular manually, so I start jasmine after angular is bootstrapped and my main Ctrl is loaded:

      window.ionic.Platform.ready(function() {
          console.log("device ready");  
          angular.element(document).ready(function() {
              angular.bootstrap(document, ['myApp']); 
          }); 
      }); 
      

      Then in my Ctrl after I've loaded a document from Couchbase, I start jasmine.

    .

    1. Finally to Run Tests:

      rename index.html to index_backup.html rename SpecRunner.html to index.html

      and run ionic run android --device

    .

    1. Automate Step 8 using Makefile:

      set-test: 
          @if [ -f "www/SpecRunner.html" ]; \
          then \
              mv www/index.html www/index_backup.html; \
              mv www/SpecRunner.html www/index.html; \
          else \
              echo "test already set"; \
          fi
      
      unset-test:
          @if [ -f "www/SpecRunner.html" ]; \
          then \
              echo "test already unset"; \
          else \
              mv www/index.html www/SpecRunner.html;  \
              mv www/index_backup.html www/index.html; \
          fi       
      test:  
          make set-test    
          ionic run android --device 
      
    2. Sample Test

      describe('AccountsCtrl', function() { 
      
          var $scope;
          var app; 
          var $ionicSideMenu;
          var helper;
      
          var params = {
              name : 'Test Person',
              id: '112654'
          };
      
      
          beforeAll(function(done){  
              app = AppService;
              helper = getService("ActivitiesHelper");  
              $state.go('app.activities',params);  
      
          // wait for the state to change
              setTimeout(function(){ 
                  $scope = getScope("activities"); 
                  done();
              },1000) 
      
          });
      
      
          it('expects $scope.app to be defined', function() { 
              expect($scope.app).toBeDefined();
          });     
      
      
      });