Search code examples
javascriptsinonqunit

How to mock cookies with QUnit and Sinon?


I have this code:

var CookieHelper = function () {
    return {
        GetCookie : function (cookieName) {
            var cookieNameRequest = cookieName + "=";
            var cookiesCollection = document.cookie.split(";");
            for (var i = 0; i < cookiesCollection.length; i++) {
                var cookieValuePair = cookiesCollection[i];
                while (cookieValuePair.charAt(0) == " ") cookieValuePair = cookieValuePair.substring(1, cookieValuePair.length);
                if (cookieValuePair.indexOf(cookieNameRequest) == 0)
                    return cookieValuePair.substring(cookieNameRequest.length, cookieValuePair.length);
            }
            return null;
        },

        DeleteCookie : function (cookieName) {
            CookieHelper.SetCookie(cookieName, "", -1);
        },

        SetCookie : function (cookieName, cookieValue, cookieExpirationDays) {
            var tmpDate = new Date;
            if (cookieExpirationDays) {
                tmpDate.setTime(tmpDate.getTime() + cookieExpirationDays * 24 * 60 * 60 * 1000);
                var expires = "; expires=" + tmpDate.toGMTString();
            } else {
                // if cookieExpirationDays isn't set cookie will expire at the end of the day
                var expirationTime = new Date(tmpDate.getFullYear(), tmpDate.getMonth(), tmpDate.getDate(), 23, 59, 59);
                var expires = "; expires=" + expirationTime.toGMTString();
            }
            document.cookie = cookieName + "=" + cookieValue + expires + "; path=/;" + (location.protocol === "https:" ? "secure=true" : "");
        }
    };
}();

and I need to write unit tests for GetCookie.
I tried with:

QUnit.module('Cookie Helper Tests');

QUnit.test('GetCookie - returns no cookie', function(assert) {
    var stub = sinon.spy(CookieHelper, 'GetCookie');

    var cookieName = 'testCookieName';
    var cookieValue = CookieHelper.GetCookie(cookieName);

    assert.ok(cookieValue == null, 'returns no cookie');    
}); 

I need to mock/stub document.cookie but I am completely new with Sinon and QUnit.
Can someone give me explanation what I did wrong?

Thanks in advance!
Srdjan


Solution

  • Well actually you can't mock properties with Sinon and more over you cannot mock the document.cookies property as it's immutable. What you can do though, is to use a fake double object that mimics the behavior of the original object, as described here.

    For example, if you were running the same test outside of the browser (e.g. in NodeJS) you would do something like that

    const chai = require('chai');
    const sinon = require('sinon');
    const SinonChai = require('sinon-chai');
    
    chai.use(SinonChai);
    chai.should();
    
    context('test', function() {
    
    
      it('should pass',
        (done) => {
    
          var cookieName = 'testCookieName';
    
          document = {
            cookie: cookieName + '=123'
          };
    
          var cookieValue = CookieHelper.GetCookie(cookieName);
    
          console.log(cookieValue);
    
          done();
        });
    
    });
    

    in order to introduce a document object to the context and mimic it's cookies attribute by returning a fixed result.

    Now, there is a workaround for the browser which involves redefining the getter and setter of 'document.cookie' as described here:

    (function (document) {
        var cookies = {};
        document.__defineGetter__('cookie', function () {
            var output = [];
            for (var cookieName in cookies) {
                output.push(cookieName + '=' + cookies[cookieName]);
            }
            return output.join(';');
        });
        document.__defineSetter__('cookie', function (s) {
            var indexOfSeparator = s.indexOf('=');
            var key = s.substr(0, indexOfSeparator);
            var value = s.substring(indexOfSeparator + 1);
            cookies[key] = value;
            return key + '=' + value;
        });
        document.clearCookies = function () {
            cookies = {};
        };
    })(document);