fake-indexeddb

repository·master·Indexed 20 days ago

https://github.com/dumbmatter/fakeindexeddb

A pure JavaScript in-memory implementation of the IndexedDB API, designed for environments where a real IndexedDB is unavailable, such as Node.js or testing environments (e.g., Jest). It provides a way to populate the global scope with IndexedDB variables via the `fake-indexeddb/auto` entrypoint or through explicit imports. Version 6.2.5.

Tokens
8.6K
Snippets
27
Records
38
Agent score
71%

What's inside fake-indexeddb

  1. Understand the purpose of the lib directory

    master

    The lib directory exists solely for backwards compatibility with fake-indexeddb version 3 and earlier. It provides .js and .d.ts files for environments that do not support the package.json exports field.

    Use the files in lib if you are using:

    • Jest 27 and earlier: These versions do not understand the package.json exports field and require the .js files from lib.
    • TypeScript 4.6 and earlier: These versions do not support specifying types within the exports field and require the .d.ts files from lib to resolve types correctly.
  2. Use fake-indexeddb via global scope (auto mode)

    master

    The easiest way to use the library is to import fake-indexeddb/auto. This automatically populates the global scope with all IndexedDB variables (like indexedDB, IDBKeyRange, etc.), making it behave exactly like a browser environment.

    import "fake-indexeddb/auto";
    
    // Now you can use standard IndexedDB APIs
    var request = indexedDB.open("test", 3);
    // ... rest of your IndexedDB code
    import "fake-indexeddb/auto";
    
    var request = indexedDB.open("test", 3);
    request.onupgradeneeded = function () {
        var db = request.result;
        var store = db.createObjectStore("books", {keyPath: "isbn"});
        store.createIndex("by_title", "title", {unique: true});
    
        store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
        store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
        store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});
    }
    request.onsuccess = function (event) {
        var db = event.target.result;
    
        var tx = db.transaction("books");
    
        tx.objectStore("books").index("by_title").get("Quarry Memories").addEventListener("success", function (event) {
            console.log("From index:", event.target.result);
        });
        tx.objectStore("books").openCursor(IDBKeyRange.lowerBound(200000)).onsuccess = function (event) {
            var cursor = event.target.result;
            if (cursor) {
                console.log("From cursor:", cursor.value);
                cursor.continue();
            }
        };
        tx.oncomplete = function () {
            console.log("All done!");
        };
    };
  3. Integrate fake-indexeddb with Dexie or other wrappers

    master

    Using with global scope

    If you import fake-indexeddb/auto before importing dexie, it should work automatically:

    import "fake-indexeddb/auto";
    import Dexie from "dexie";
    
    const db = new Dexie("MyDatabase");

    Using without global scope

    If you prefer not to modify the global scope, pass the fake objects explicitly to the wrapper's constructor:

    import Dexie from "dexie";
    import { indexedDB, IDBKeyRange } from "fake-indexeddb";
    
    const db = new Dexie("MyDatabase", { indexedDB: indexedDB, IDBKeyRange: IDBKeyRange });
  4. Configure fake-indexeddb for Jest

    master

    Single test file

    Require fake-indexeddb/auto at the very beginning of your test file.

    Global Jest configuration

    To apply fake-indexeddb to all tests automatically, add the auto setup script to the setupFiles array in your jest.config.js:

    {
        "setupFiles": [
            "fake-indexeddb/auto"
        ]
    }
  5. Populate global scope with IndexedDB variables using auto/index.mjs

    master

    The auto/index.mjs module is a side-effect import designed to automatically populate the global scope (window, self, or global) with fake-indexeddb implementations of the IndexedDB API.

    By importing this file, the following global variables are defined and made writable, allowing libraries that expect a native IndexedDB environment (like Dexie.js or other IndexedDB wrappers) to function in environments where IndexedDB is missing (e.g., Node.js or certain test runners):

    • indexedDB (mapped to fakeIndexedDB)
    • IDBCursor (mapped to FDBCursor)
    • IDBCursorWithValue (mapped to FDBCursorWithValue)
    • IDBDatabase (mapped to FDBDatabase)
    • IDBFactory (mapped to FDBFactory)
    • IDBIndex (mapped to FDBIndex)
    • IDBKeyRange (mapped to FDBKeyRange)
    • IDBObjectStore (mapped to FDBObjectStore)
    • IDBOpenDBRequest (mapped to FDBOpenDBRequest)
    • IDBRecord (mapped to FDBRecord)
    • IDBRequest (mapped to FDBRequest)
    • IDBTransaction (mapped to FDBTransaction)
    • IDBVersionChangeEvent (mapped to FDBVersionChangeEvent)

    This approach works in browsers, Web Workers, and Node.js.

    import './path/to/auto/index.mjs';
    
    // After this import, global variables like indexedDB are available
    // and can be used by libraries expecting a native IndexedDB environment.
  6. Populate the global scope with IndexedDB variables using `auto`

    master

    The auto entrypoint is a side-effect import designed to automatically populate the global scope (window, self, or global) with fake-indexeddb implementations of the IndexedDB API. This is useful in environments like Node.js or testing frameworks (e.g., Jest with jsdom) where the native indexedDB global is missing.

    By importing this module, the following globals are made available and writable:

    • indexedDB (mapped to fakeIndexedDB)
    • IDBCursor (mapped to FDBCursor)
    • IDBCursorWithValue (mapped to FDBCursorWithValue)
    • IDBDatabase (mapped to FDBDatabase)
    • IDBFactory (mapped to FDBFactory)
    • IDBIndex (mapped to FDBIndex)
    • IDBKeyRange (mapped to FDBKeyRange)
    • IDBObjectStore (mapped to FDBObjectStore)
    • IDBOpenDBRequest (mapped to FDBOpenDBRequest)
    • IDBRecord (mapped to FDBRecord)
    • IDBRequest (mapped to FDBRequest)
    • IDBTransaction (mapped to FDBTransaction)
    • IDBVersionChangeEvent (mapped to FDBVersionChangeEvent)
    require('fake-indexeddb/auto');
  7. Fix structuredClone issues in jsdom/Jest

    master

    Since version 5, fake-indexeddb does not include a structuredClone polyfill. This can cause issues in jsdom environments (commonly used with Jest).

    Option 1: Use core-js polyfill

    Install core-js and import the polyfill before fake-indexeddb/auto:

    import "core-js/stable/structured-clone";
    import "fake-indexeddb/auto";

    Option 2: Manually inject Node.js structuredClone into JSDOM

    Create a custom Jest environment to attach the Node.js structuredClone to the global object:

    // FixJSDOMEnvironment.ts
    import JSDOMEnvironment from 'jest-environment-jsdom';
    
    export default class FixJSDOMEnvironment extends JSDOMEnvironment {
      constructor(...args: ConstructorParameters<typeof JSDOMEnvironment>) {
        super(...args);
        this.global.structuredClone = structuredClone;
      }
    }

    Then update your jest.config.js:

    /** @type {import('jest').Config} */
    const config = {
      testEnvironment: './FixJSDOMEnvironment.ts',
    };
    
    module.exports = config;
  8. Reset IndexedDB state for fresh tests

    master

    To ensure test isolation, you can reset the mocked IndexedDB state by creating a new instance of IDBFactory and assigning it to the global indexedDB variable.

    import "fake-indexeddb/auto";
    import { IDBFactory } from "fake-indexeddb";
    
    // Resetting the state
    indexedDB = new IDBFactory();
    import "fake-indexeddb/auto";
    import { IDBFactory } from "fake-indexeddb";
    
    // Whenever you want a fresh indexedDB
    indexedDB = new IDBFactory();
  9. Use fake-indexeddb with explicit imports

    master

    If you do not want to modify the global scope, you can import specific IndexedDB variables directly from fake-indexeddb. You can also rename them to avoid conflicts with existing variables.

    import {
        indexedDB,
        IDBKeyRange,
        // ... other types/objects
    } from "fake-indexeddb";
    
    // Or rename to avoid conflicts
    import { indexedDB as fakeIndexedDB } from "fake-indexeddb";
    import {
        indexedDB,
        IDBCursor,
        IDBCursorWithValue,
        IDBDatabase,
        IDBFactory,
        IDBIndex,
        IDBKeyRange,
        IDBObjectStore,
        IDBOpenDBRequest,
        IDBRequest,
        IDBTransaction,
        IDBVersionChangeEvent,
    } from "fake-indexeddb";