是否可以在 JavaScript 中模拟 document.cookie?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6456429/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 21:49:16  来源:igfitidea点击:

Is it possible to mock document.cookie in JavaScript?

javascriptunit-testing

提问by thisgeek

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

document.cookie就像一个字符串,但它不是一个字符串。引用Mozilla 文档中的示例:

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

If you tried to make a mock cookie using only a string, you would notget the same results:

如果您尝试仅使用字符串制作模拟 cookie,则不会得到相同的结果:

var mockCookie = "";
mockCookie = "name=oeschger";
mockCookie = "favorite_food=tripe";
alert(mockCookie);
// displays: favorite_food=tripe

So, if you wanted to unit test a module that operates on the cookie, and if you wanted to use a mock cookie for those tests, could you? How?

因此,如果您想对一个对 cookie 进行操作的模块进行单元测试,并且如果您想对这些测试使用模拟 cookie,您可以吗?如何?

采纳答案by Felix Kling

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

您可以使用cookiesetter 和 getter创建一个对象。这是一个非常简单的实现:

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!

虽然可能不适用于所有浏览器(尤其是 IE)。更新:它仅适用于支持 ECMAScript 5 的浏览器!

More about getter and setters.

更多关于 getter 和 setter 的信息

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

DEMO

演示

回答by mcintyre321

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

此实现允许覆盖 cookie,并添加 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);

回答by maerics

@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:

@Felix Kling 的回答是正确的,我只是想指出在 ECMAScript 5 中定义 setter 和 getter 有另一种语法:

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 notMSIE (or JScript).

同样,大多数浏览器支持 ECMAScript 5(由 ECMA-262 第 5 版定义),但不支持MSIE(或 JScript)。

回答by user2125726

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

我发现 jasminespyOnProperty可以用于当你想监视对象的 getter 和 setter 时。所以我用这个解决了我的问题:

const cookie: string = 'my-cookie=cookievalue;';    
spyOnProperty(document, 'cookie', 'get').and.returnValue(cookie);

回答by omarjebari

Personally i was unable to hiHyman 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:

在我的测试脚本的顶部,我定义了一个 fakeCookie 对象:

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() 中定义我的 cookie 存根。这基本上会拦截对 jQuery.cookie 的调用,并(相反!)调用我定义的回调函数(见下文):

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!!

每当我获取或设置 cookie 值时,它都会使用我的 fakeCookie 而不是真正的 jQuery.cookie。它通过查看传递的参数数量并推断其是否为 get/set 来做到这一点。我从字面上粘贴了这个,一切都直接起作用了。希望这可以帮助!!

回答by Samuel Elh

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 setTimeoutcall to expire cookies after Xseconds:

我知道这是一个老话题,但在我的情况下,使 cookie 过期是必要的,所以这里有一个解决方案,它结合了上述答案和setTimeoutX几秒钟后调用使 cookie 过期的方法:

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 ]
    }    
}