Is it possible to mock [removed] in JavaScript?

后端 未结 6 523
猫巷女王i
猫巷女王i 2020-12-14 07:39

document.cookie is like a string, but it is not a string. To quote the example from the Mozilla doc:

document.cookie = \"name=oeschger\";
docume         


        
相关标签:
6条回答
  • 2020-12-14 08:11

    You could create an object with a cookie setter and getter. Here is a very simple implementation:

    var mock = {
        value_: '', 
    
        get cookie() {
            return this.value_;
        },
    
        set cookie(value) {
            this.value_ += value + ';';
        }
    };
    

    Might not work in all browsers though (especially IE). Update: It only works in browsers supporting ECMAScript 5!

    More about getter and setters.

    mock.cookie = "name=oeschger";
    mock.cookie = "favorite_food=tripe";
    alert(mock.cookie);
    // displays: name=oeschger;favorite_food=tripe;
    

    DEMO

    0 讨论(0)
  • 2020-12-14 08:15

    I know this is an old topic, but in my case expiring cookies was necessary so here's a solution that combines the above answers and a setTimeout call to expire cookies after X seconds:

    const fakeCookies = {
        // cookie jar
        all: {},
    
        // timeouts
        timeout: {},
    
        // get a cookie
        get: function(name)
        {
            return this.all[ name ]
        },
    
        // set a cookie
        set: function(name, value, expires_seconds)
        {
            this.all[ name ] = value;
    
            if ( expires_seconds ) {
                ! this.timeout[ name ] || clearTimeout( this.timeout[ name ] )
                this.timeout[ name ] = setTimeout(() => this.unset(name), parseFloat(expires_seconds) * 1000)
            }
        },
    
        // delete a cookie
        unset: function(name)
        {
            delete this.all[ name ]
        }    
    }
    
    0 讨论(0)
  • 2020-12-14 08:17

    This implementation allows overwriting cookies, and adds document.clearCookies()

    (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);
    
    0 讨论(0)
  • 2020-12-14 08:18

    I figured out that jasmine has spyOnProperty which can be used for when you want to spy on getter and setters of objects. So I solved my issue with this:

    const cookie: string = 'my-cookie=cookievalue;';    
    spyOnProperty(document, 'cookie', 'get').and.returnValue(cookie);
    
    0 讨论(0)
  • 2020-12-14 08:22

    @Felix Kling's answer is right on, I just wanted to point out that there is an alternate syntax for defining setters and getters in ECMAScript 5:

    function MockCookie() {
      this.str = '';
      this.__defineGetter__('cookie', function() {
        return this.str;
      });
      this.__defineSetter__('cookie', function(s) {
        this.str += (this.str ? ';' : '') + s;
        return this.str;
      });
    }
    var mock = new MockCookie();
    mock.cookie = 'name=oeschger';
    mock.cookie = 'favorite_food=tripe';
    mock.cookie; // => "name=oeschger;favorite_food=tripe"
    

    And again, most browsers support ECMAScript 5 (defined by ECMA-262 5th Edition) but not MSIE (or JScript).

    0 讨论(0)
  • 2020-12-14 08:22

    Personally i was unable to hijack the document object. A simple solution which seems to work for me was the following...

    At the top of my test script i define a fakeCookie object:

    var fakeCookie = {
        cookies: [],
        set: function (k, v) {
            this.cookies[k] = v;
        },
        get: function (k) {
            return this.cookies[k];
        },
        reset: function () {
            this.cookies = [];
        }
    };
    

    Then in my beforeEach() i define my cookie stub. This basically intercepts calls to jQuery.cookie and (instead!) call the callback function that i have defined (see below):

    beforeEach(function() {
        var cookieStub = sinon.stub(jQuery, "cookie", function() {
            if (arguments.length > 1) {
                fakeCookie.set(arguments[0], arguments[1]);
            }
            else {
                return fakeCookie.get(arguments[0]);
            }
        });
    });
    

    Any time that i get or set a cookie value it uses my fakeCookie instead of the real jQuery.cookie. It does this by looking at the number of parameters passed and deduces whether its a get/set. I literally pasted this in and it all worked straight off the bat. Hope this helps!!

    0 讨论(0)
提交回复
热议问题