Проблема IndexedDB в среде Node.js и Jest

IndexedDB — это встроенное хранилище в браузерах, предоставляющее возможность сохранять большие объемы структурированных данных на стороне клиента. Оно работает асинхронно и поддерживает транзакции, что делает его удобным для сложных веб-приложений. Однако при попытке использовать IndexedDB вне браузера, например в Node.js или при тестировании с помощью Jest, возникают серьёзные ограничения и специфические проблемы.

IndexedDB в Node.js

Node.js изначально не поддерживает API браузерного IndexedDB. Любой прямой вызов функций, таких как indexedDB.open(), приведёт к ошибке, так как объект indexedDB не существует в среде сервера. Это ограничение создаёт препятствия для библиотек, построенных на IndexedDB, включая idb-keyval, которая использует IndexedDB для хранения ключ-значение пар.

Чтобы обойти эту проблему, применяются эмуляторы IndexedDB, такие как:

  • fake-indexeddb — реализует интерфейс IndexedDB в Node.js.
  • fake-indexeddb/lib/FDBFactory — предоставляет фабрику для создания экземпляров базы данных.

Пример подключения fake-indexeddb в Node.js:

const FDBFactory = require('fake-indexeddb/lib/FDBFactory');
global.indexedDB = new FDBFactory();

После этой настройки библиотека idb-keyval может работать так, как будто она находится в браузере, используя глобальный объект indexedDB.

Проблемы при использовании Jest

При тестировании с Jest добавляются дополнительные нюансы:

  1. Jest использует jsdom, который частично эмулирует браузерную среду.
  2. Встроенная реализация IndexedDB в jsdom отсутствует, что вызывает ошибки при вызове методов idb-keyval.
  3. Некоторые версии jsdom могут частично поддерживать IndexedDB, но поведение нестабильно, особенно при работе с транзакциями и событиями onsuccess / onerror.

Для стабильной работы рекомендуется:

// jest.setup.js
const FDBFactory = require('fake-indexeddb/lib/FDBFactory');
global.indexedDB = new FDBFactory();

И в jest.config.js указать:

setupFiles: ["<rootDir>/jest.setup.js"]

Это гарантирует, что перед запуском тестов indexedDB будет доступен и idb-keyval сможет корректно сохранять и извлекать данные.

idb-keyval и Node.js

Библиотека idb-keyval построена поверх IndexedDB и предоставляет простой API для операций ключ-значение. Основные функции:

  • set(key, value) — сохраняет значение по ключу.
  • get(key) — извлекает значение по ключу.
  • del(key) — удаляет значение по ключу.
  • clear() — очищает всю базу.
  • keys() — возвращает список всех ключей.

Пример работы с idb-keyval в Node.js с использованием fake-indexeddb:

const { set, get, del, keys } = require('idb-keyval');
const FDBFactory = require('fake-indexeddb/lib/FDBFactory');
global.indexedDB = new FDBFactory();

async function testStorage() {
    await set('name', 'NodeJS');
    const value = await get('name');
    console.log(value); // NodeJS
    await del('name');
    const remainingKeys = await keys();
    console.log(remainingKeys); // []
}

testStorage();

Особенности транзакций и асинхронности

IndexedDB работает с транзакциями, которые асинхронны. В Node.js через fake-indexeddb эти транзакции симулируются, но с некоторыми ограничениями:

  • Вызов get после set в одном блоке может потребовать дополнительного await.
  • Обработка ошибок через события onerror и onsuccess также может отличаться от поведения в браузере.
  • Jest может завершить тест раньше, чем завершатся асинхронные транзакции, если не использовать async/await или done коллбэки.

Рекомендации по тестированию

  • Использовать отдельный файл настройки Jest с эмуляцией IndexedDB.
  • Оборачивать операции idb-keyval в асинхронные функции и корректно await результаты.
  • Для имитации больших наборов данных можно использовать отдельную базу через создание экземпляров FDBFactory для каждого теста, чтобы обеспечить чистую среду.

Итоговая схема работы в Node.js + Jest

  1. Подключение и настройка fake-indexeddb.
  2. Глобальная инициализация indexedDB.
  3. Использование idb-keyval API с async/await.
  4. Очистка базы между тестами для предотвращения конфликтов.

Эта схема позволяет использовать все возможности idb-keyval в среде Node.js и при автоматизированном тестировании с Jest, не сталкиваясь с ограничениями браузерного IndexedDB.