簡體   English   中英

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

[英]Is it possible to mock document.cookie in JavaScript?

document.cookie就像一個字符串,但又不是字符串。 引用Mozilla 文檔中的示例:

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,可以嗎? 如何?

您可以使用cookie setter和getter創建一個對象。 這是一個非常簡單的實現:

var mock = {
    value_: '', 

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

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

可能不適用於所有瀏覽器(特別是IE)。 更新:它僅適用於支持ECMAScript 5的瀏覽器!

更多關於吸氣劑和二傳手的信息

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

DEMO

此實現允許覆蓋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);

@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)。

以下是我最終在 Jest 中的做法:

添加Secure屬性后,我的 cookie 不再添加到document.cookie (因為document.location是不安全的http://localhost )。

所以經過大量的試驗和錯誤(試圖攔截document.cookie的 setter 並刪除它的;Secure從它,但是然后再次調用document.cookie =新值觸發了一個無限循環,因為它再次進入 setter ... ) ,我最終得到了這個非常簡單的解決方案:

beforeEach(function() {
  let cookieJar = document.cookie;
  jest.spyOn(document, 'cookie', 'set').mockImplementation(cookie => {
    cookieJar += cookie;
  });
  jest.spyOn(document, 'cookie', 'get').mockImplementation(() => cookieJar);
})

我個人無法劫持文檔對象。 一個似乎對我有用的簡單解決方案如下......

在我的測試腳本的頂部,我定義了一個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來完成此操作。 我直接粘貼了這個,它都直接蝙蝠。 希望這可以幫助!!

我知道這是一個古老的話題,但在我的情況下,過期的cookie是必要的,所以這里的解決方案結合了上述答案和一個setTimeout調用,在X秒后過期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 ]
    }    
}

我發現茉莉有spyOnProperty ,當你想窺探對象的getter和setter時可以使用它。 所以我解決了我的問題:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM