Можно ли высмеять document.cookie в JavaScript?

document.cookie - это как строка, но это не строка. Чтобы привести пример из документа Mozilla:

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

Если вы попытались сделать mock cookie с использованием только строки, вы не получите одинаковых результатов:

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

Итак, если вы хотите unit test модуль, который работает в cookie, и если вы хотите использовать mock cookie для этих тестов, не могли бы вы? Как?

Ответ 1

Вы можете создать объект с помощью setter и getter cookie. Вот очень простая реализация:

var mock = {
    value_: '', 

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

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

Возможно, не работает во всех браузерах (особенно IE). Обновление: Он работает только в браузерах, поддерживающих ECMAScript 5!

Подробнее о getter и сеттерах.

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

DEMO

Ответ 2

@Felix King отвечает правильно, я просто хотел указать, что существует альтернативный синтаксис для определения сеттеров и геттеров в 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"

И снова большинство браузеров поддерживают ECMAScript 5 (определенный ECMA-262 5th Edition), но не MSIE (или JScript).

Ответ 3

Эта реализация позволяет перезаписывать файлы 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);

Ответ 4

Лично я не смог захватить объект документа. Простое решение, которое, кажется, работает для меня, было следующим...

В верхней части моего теста script я определяю объект 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. Я буквально вставлял это, и все это работало прямо с места в карьер. Надеюсь, это поможет!