При работе с криптографическими операциями особенно важна проверка корректности реализации. Ошибка в тестах или их отсутствие может привести к уязвимостям, которые трудно обнаружить на этапе эксплуатации. Для JavaScript-экосистемы широко применяются три инструмента: Jest, Mocha и встроенный модуль assert. Каждый из них позволяет тестировать операции хеширования, шифрования и дешифрования, реализованные с помощью Crypto-JS.
Хеш-функции в Crypto-JS (например, SHA-256, MD5) должны возвращать строго определённый результат для одного и того же входа.
Пример теста на корректность SHA-256:
const CryptoJS = require("crypto-js");
test("SHA-256 hashing", () => {
const hash = CryptoJS.SHA256("hello").toString();
expect(hash).toBe("2cf24dba5fb0a..."); // укорочено
});
Ключевые моменты:
.toString()Jest — инструмент с «из коробки» встроенными assertions и механизмами мокирования.
npm install --save-dev jest
const CryptoJS = require("crypto-js");
describe("CryptoJS AES", () => {
test("Encryption and decryption", () => {
const text = "Secret message";
const key = "password";
const encrypted = CryptoJS.AES.encrypt(text, key).toString();
const decrypted = CryptoJS.AES.decrypt(encrypted, key).toString(CryptoJS.enc.Utf8);
expect(decrypted).toBe(text);
});
});
test("Decryption with wrong key fails", () => {
const text = "data";
const encrypted = CryptoJS.AES.encrypt(text, "key1").toString();
const decrypted = CryptoJS.AES.decrypt(encrypted, "key2").toString(CryptoJS.enc.Utf8);
expect(decrypted).not.toBe(text);
});
Mocha — гибкий тестовый фреймворк, который обычно используется вместе с библиотекой утверждений Chai.
npm install --save-dev mocha chai
const CryptoJS = require("crypto-js");
const { expect } = require("chai");
describe("CryptoJS Hashing", function () {
it("should hash correctly using MD5", function () {
const hash = CryptoJS.MD5("hello").toString();
expect(hash).to.equal("5d41402abc4b2a76b9719d911017c592");
});
});
describe("AES encryption", function () {
it("should encrypt and decrypt correctly", function () {
const message = "hello";
const key = "secret";
const encrypted = CryptoJS.AES.encrypt(message, key).toString();
const decrypted = CryptoJS.AES.decrypt(encrypted, key)
.toString(CryptoJS.enc.Utf8);
expect(decrypted).to.equal(message);
});
});
Node.js предоставляет минималистичный модуль assert, который подходит для простых проверок.
const assert = require("assert");
const CryptoJS = require("crypto-js");
const hash = CryptoJS.SHA1("test").toString();
assert.strictEqual(
hash,
"a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"
);
const message = "data";
const key = "pass";
const encrypted = CryptoJS.AES.encrypt(message, key).toString();
const decrypted = CryptoJS.AES.decrypt(encrypted, key)
.toString(CryptoJS.enc.Utf8);
assert.strictEqual(decrypted, message);
Crypto-JS активно использует кодировки, что требует отдельной проверки.
test("UTF-8 encoding", () => {
const wordArray = CryptoJS.enc.Utf8.parse("hello");
const result = CryptoJS.enc.Utf8.stringify(wordArray);
expect(result).toBe("hello");
});
Ошибки в кодировке часто приводят к:
Хеш-функции обязаны быть детерминированными:
test("Hash is deterministic", () => {
const input = "same input";
const hash1 = CryptoJS.SHA256(input).toString();
const hash2 = CryptoJS.SHA256(input).toString();
expect(hash1).toBe(hash2);
});
Шифрование с использованием случайных параметров должно давать разные результаты:
test("Encryption produces different outputs", () => {
const text = "secret";
const encrypted1 = CryptoJS.AES.encrypt(text, "key").toString();
const encrypted2 = CryptoJS.AES.encrypt(text, "key").toString();
expect(encrypted1).not.toBe(encrypted2);
});
При этом дешифровка должна оставаться корректной.
Хотя это не основная задача unit-тестов, иногда проверяется время выполнения:
test("Hash performance", () => {
const start = Date.now();
for (let i = 0; i < 1000; i++) {
CryptoJS.SHA256("data");
}
const duration = Date.now() - start;
expect(duration).toBeLessThan(500);
});
При использовании Jest можно изолировать зависимости:
jest.mock("crypto-js", () => ({
SHA256: jest.fn(() => ({
toString: () => "mocked_hash"
}))
}));
Это позволяет:
Рекомендуемая организация:
/tests
hashing.test.js
encryption.test.js
encoding.test.js
Каждый файл покрывает отдельный аспект:
| Характеристика | Jest | Mocha | assert |
|---|---|---|---|
| Встроенные assertions | Да | Нет | Да |
| Простота настройки | Высокая | Средняя | Максимальная |
| Мокирование | Да | Через библиотеки | Нет |
| Подходит для крупных проектов | Да | Да | Ограниченно |
Иногда требуется удостовериться, что результат совпадает с другими реализациями:
test("Cross-platform hash", () => {
const hash = CryptoJS.SHA256("hello").toString();
expect(hash).toBe("2cf24dba5fb0a...");
});
Такие тесты особенно важны при интеграции с backend-системами.
test("HMAC SHA256", () => {
const result = CryptoJS.HmacSHA256("message", "key").toString();
expect(result).toBeDefined();
});
test("Base64 encoding", () => {
const encoded = CryptoJS.enc.Base64.stringify(
CryptoJS.enc.Utf8.parse("hello")
);
const decoded = CryptoJS.enc.Base64.parse(encoded)
.toString(CryptoJS.enc.Utf8);
expect(decoded).toBe("hello");
});
Высокий уровень покрытия особенно важен для криптографии:
Пример:
test("Empty string hash", () => {
const hash = CryptoJS.SHA256("").toString();
expect(hash).toBeDefined();
});
Интеграция с CI:
npm test
или для Mocha:
npx mocha
Автоматический запуск тестов позволяет: