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

时间:2011-06-23 15:16:45

标签: javascript unit-testing

document.cookie就像一个字符串,但它不是一个字符串。引用Mozilla doc

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

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

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

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

6 个答案:

答案 0 :(得分:15)

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

var mock = {
    value_: '', 

    get cookie() {
        return this.value_;
    },

    set cookie(value) {
        this.value_ += value + ';';
    }
};

可能不适用于所有浏览器(尤其是IE)。 更新:仅适用于支持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

答案 1 :(得分:9)

此实现允许覆盖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);

答案 2 :(得分:8)

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

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

答案 3 :(得分:0)

我个人无法劫持文档对象。 一个似乎对我有用的简单解决方案如下......

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

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

然后在我的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]);
        }
    });
});

任何时候我获得或设置cookie值它使用我的fakeCookie而不是真正的jQuery.cookie。它通过查看传递的参数数量并推断它是否为get / set来完成此操作。我直接粘贴了这个,它都直接蝙蝠。 希望这会有所帮助!!

答案 4 :(得分:0)

我知道这是一个古老的主题,但在我的情况下,过期的Cookie是必要的,所以这里的解决方案结合了上述答案和Sub ConditionalFormat() Dim LR As Long, i As Long Dim ws As Worksheet Set ws = Sheets("Overall Stats") With ws LR = .Range("G" & .Rows.Count).End(xlUp).Row 'Line 8 here 'removed the `3` from `G3` For i = 1 To LR With .Range("G" & i) If .Value = "ISO2" Then Range(ws.Range("L3"), ws.Range("L3").End(xlDown)).FormatConditions.AddColorScale ColorScaleType:=3 'End With 'This line is extraneous and should be removed. It WILL throw an error, if uncommented. End If End With Next i End With End Sub 调用,以便在setTimeout秒后过期Cookie:

X

答案 5 :(得分:0)

我发现茉莉花有spyOnProperty,当您想监视对象的吸气剂和吸气剂时,可以使用它。所以我用这个解决了我的问题:

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