@keyv/test-suite
Version:
Test suite for Keyv API compliancy
496 lines (487 loc) • 19.4 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
default: () => index_default,
delay: () => delay,
keyvApiTests: () => api_default,
keyvCompresstionTests: () => compression_default,
keyvIteratorTests: () => iterator_default,
keyvNamespaceTest: () => namespace_default,
keyvValueTests: () => values_default
});
module.exports = __toCommonJS(index_exports);
// src/api.ts
var import_timekeeper = __toESM(require("timekeeper"), 1);
var keyvApiTests = (test, Keyv2, store) => {
test.beforeEach(async () => {
const keyv = new Keyv2({ store: store() });
await keyv.clear();
});
test.it(".set(key, value) returns a Promise", (t) => {
const keyv = new Keyv2({ store: store() });
t.expect(keyv.set("foo", "bar") instanceof Promise).toBeTruthy();
});
test.it(".set(key, value) resolves to true", async (t) => {
const keyv = new Keyv2({ store: store() });
t.expect(await keyv.set("foo", "bar")).toBeTruthy();
});
test.it(".set(key, value) sets a value", async (t) => {
const keyv = new Keyv2({ store: store() });
await keyv.set("foo", "bar");
t.expect(await keyv.get("foo")).toBe("bar");
});
test.it(".set(key, value, ttl) sets a value that expires", async (t) => {
const ttl = 1e3;
const keyv = new Keyv2({ store: store() });
await keyv.set("foo", "bar", ttl);
t.expect(await keyv.get("foo")).toBe("bar");
import_timekeeper.default.freeze(Date.now() + ttl + 1);
t.expect(await keyv.get("foo")).toBeUndefined();
import_timekeeper.default.reset();
});
test.it(".get(key) returns a Promise", (t) => {
const keyv = new Keyv2({ store: store() });
t.expect(keyv.get("foo") instanceof Promise).toBeTruthy();
});
test.it(".get(key) resolves to value", async (t) => {
const keyv = new Keyv2({ store: store() });
await keyv.set("foo", "bar");
t.expect(await keyv.get("foo")).toBe("bar");
});
test.it(".get(key) with nonexistent key resolves to undefined", async (t) => {
const keyv = new Keyv2({ store: store() });
t.expect(await keyv.get("foo")).toBeUndefined();
});
test.it(".get([keys]) should return array values", async (t) => {
const keyv = new Keyv2({ store: store() });
const ttl = 3e3;
await keyv.set("foo", "bar", ttl);
await keyv.set("foo1", "bar1", ttl);
await keyv.set("foo2", "bar2", ttl);
const values = await keyv.get(["foo", "foo1", "foo2"]);
t.expect(Array.isArray(values)).toBeTruthy();
t.expect(values[0]).toBe("bar");
t.expect(values[1]).toBe("bar1");
t.expect(values[2]).toBe("bar2");
});
test.it(".get([keys]) should return array value undefined when expires", async (t) => {
const keyv = new Keyv2();
await keyv.set("foo", "bar");
await keyv.set("foo1", "bar1", 1);
await keyv.set("foo2", "bar2");
await new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 30);
});
const values = await keyv.get(["foo", "foo1", "foo2"]);
t.expect(Array.isArray(values)).toBeTruthy();
t.expect(values[0]).toBe("bar");
t.expect(values[1]).toBeUndefined();
t.expect(values[2]).toBe("bar2");
});
test.it(".get([keys]) should return array values with undefined", async (t) => {
const keyv = new Keyv2({ store: store() });
const ttl = 3e3;
await keyv.set("foo", "bar", ttl);
await keyv.set("foo2", "bar2", ttl);
const values = await keyv.get(["foo", "foo1", "foo2"]);
t.expect(Array.isArray(values)).toBeTruthy();
t.expect(values[0]).toBe("bar");
t.expect(values[1]).toBeUndefined();
t.expect(values[2]).toBe("bar2");
});
test.it(".get([keys]) should return undefined array for all no existent keys", async (t) => {
const keyv = new Keyv2({ store: store() });
const values = await keyv.get(["foo", "foo1", "foo2"]);
t.expect(Array.isArray(values)).toBeTruthy();
t.expect(values).toEqual([void 0, void 0, void 0]);
});
test.it(".delete(key) returns a Promise", (t) => {
const keyv = new Keyv2({ store: store() });
t.expect(keyv.delete("foo") instanceof Promise).toBeTruthy();
});
test.it(".delete([key]) returns a Promise", (t) => {
const keyv = new Keyv2({ store: store() });
t.expect(keyv.delete(["foo"]) instanceof Promise).toBeTruthy();
});
test.it(".delete(key) resolves to true", async (t) => {
const keyv = new Keyv2({ store: store() });
await keyv.set("foo", "bar");
t.expect(await keyv.delete("foo")).toBeTruthy();
});
test.it(".delete(key) with nonexistent key resolves to false", async (t) => {
const keyv = new Keyv2({ store: store() });
t.expect(await keyv.delete("foo")).toBeFalsy();
});
test.it(".delete(key) deletes a key", async (t) => {
const keyv = new Keyv2({ store: store() });
await keyv.set("foo", "bar");
t.expect(await keyv.delete("foo")).toBeTruthy();
t.expect(await keyv.get("foo")).toBeUndefined();
});
test.it(".deleteMany([keys]) should delete multiple key", async (t) => {
const keyv = new Keyv2({ store: store() });
await keyv.set("foo", "bar");
await keyv.set("foo1", "bar1");
await keyv.set("foo2", "bar2");
t.expect(await keyv.delete(["foo", "foo1", "foo2"])).toBeTruthy();
t.expect(await keyv.get("foo")).toBeUndefined();
t.expect(await keyv.get("foo1")).toBeUndefined();
t.expect(await keyv.get("foo2")).toBeUndefined();
});
test.it(".deleteMany([keys]) with nonexistent keys resolves to false", async (t) => {
const keyv = new Keyv2({ store: store() });
t.expect(await keyv.delete(["foo", "foo1", "foo2"])).toBeFalsy();
});
test.it(".clear() returns a Promise", async (t) => {
const keyv = new Keyv2({ store: store() });
const returnValue = keyv.clear();
t.expect(returnValue instanceof Promise).toBeTruthy();
await returnValue;
});
test.it(".clear() resolves to undefined", async (t) => {
const keyv = new Keyv2({ store: store() });
t.expect(await keyv.clear()).toBeUndefined();
await keyv.set("foo", "bar");
t.expect(await keyv.clear()).toBeUndefined();
});
test.it(".clear() deletes all key/value pairs", async (t) => {
const keyv = new Keyv2({ store: store() });
await keyv.set("foo", "bar");
await keyv.set("fizz", "buzz");
await keyv.clear();
t.expect(await keyv.get("foo")).toBeUndefined();
t.expect(await keyv.get("fizz")).toBeUndefined();
});
test.it(".has(key) where key is the key we are looking for", async (t) => {
const keyv = new Keyv2({ store: store() });
await keyv.set("foo", "bar");
t.expect(await keyv.has("foo")).toBeTruthy();
t.expect(await keyv.has("fizz")).toBeFalsy();
});
};
var api_default = keyvApiTests;
// src/values.ts
var import_buffer = require("buffer");
var import_json_bigint = __toESM(require("json-bigint"), 1);
var import_bignumber = __toESM(require("bignumber.js"), 1);
var keyvValueTests = (test, Keyv2, store) => {
test.beforeEach(async () => {
const keyv = new Keyv2({ store: store() });
await keyv.clear();
});
test.it("value can be false", async (t) => {
const keyv = new Keyv2({ store: store() });
await keyv.set("foo", false);
t.expect(await keyv.get("foo")).toBeFalsy();
});
test.it("value can be null", async (t) => {
const keyv = new Keyv2({ store: store() });
await keyv.set("foo", null);
t.expect(await keyv.get("foo")).toBeNull();
});
test.it("value can be undefined", async (t) => {
const keyv = new Keyv2({ store: store() });
await keyv.set("foo", void 0);
t.expect(await keyv.get("foo")).toBeUndefined();
});
test.it("value can be a number", async (t) => {
const keyv = new Keyv2({ store: store() });
await keyv.set("foo", 0);
t.expect(await keyv.get("foo")).toBe(0);
});
test.it("value can be an object", async (t) => {
const keyv = new Keyv2({ store: store() });
const value = { fizz: "buzz" };
await keyv.set("foo", value);
t.expect(await keyv.get("foo")).toEqual(value);
});
test.it("value can be a buffer", async (t) => {
const keyv = new Keyv2({ store: store() });
const buf = import_buffer.Buffer.from("bar");
await keyv.set("foo", buf);
t.expect(buf.equals(await keyv.get("foo"))).toBeTruthy();
});
test.it("value can be an object containing a buffer", async (t) => {
const keyv = new Keyv2({ store: store() });
const value = { buff: import_buffer.Buffer.from("buzz") };
await keyv.set("foo", value);
t.expect(await keyv.get("foo")).toEqual(value);
});
test.it("value can contain quotes", async (t) => {
const keyv = new Keyv2({ store: store() });
const value = '"';
await keyv.set("foo", value);
t.expect(await keyv.get("foo")).toEqual(value);
});
test.it("value can be a string", async (t) => {
const keyv = new Keyv2({ store: store() });
await keyv.set("foo", "bar");
t.expect(await keyv.get("foo")).toBe("bar");
});
test.it("value can not be symbol", async (t) => {
const keyv = new Keyv2({ store: store() });
const value = Symbol("value");
let errorObject;
try {
await keyv.set("foo", value);
} catch (error) {
errorObject = error;
t.expect(error.message).toBe("symbol cannot be serialized");
}
t.expect(errorObject.message).toBe("symbol cannot be serialized");
});
test.it("value can be BigInt using other serializer/deserializer", async (t) => {
store().opts.deserialize = import_json_bigint.default.parse;
const keyv = new Keyv2({
store: store(),
serialize: import_json_bigint.default.stringify,
deserialize: import_json_bigint.default.parse
});
const value = BigInt("9223372036854775807");
await keyv.set("foo", value);
const storedValue = await keyv.get("foo");
t.expect(import_json_bigint.default.stringify(storedValue)).toBe((0, import_bignumber.default)(value).toString());
});
test.it("single quotes value should be saved", async (t) => {
const keyv = new Keyv2({ store: store() });
let value = "'";
await keyv.set("key", value);
t.expect(await keyv.get("key")).toBe(value);
value = "''";
await keyv.set("key1", value);
t.expect(await keyv.get("key1")).toBe(value);
value = '"';
await keyv.set("key2", value);
t.expect(await keyv.get("key2")).toBe(value);
});
test.it("single quotes key should be saved", async (t) => {
const keyv = new Keyv2({ store: store() });
const value = "'";
const key = "'";
await keyv.set(key, value);
t.expect(await keyv.get(key)).toBe(value);
});
};
var values_default = keyvValueTests;
// src/namespace.ts
var keyvNamespaceTests = (test, Keyv2, store) => {
test.beforeEach(async () => {
const keyv1 = new Keyv2({ store: store(), namespace: "keyv1" });
const keyv2 = new Keyv2({ store: store(), namespace: "keyv2" });
await keyv1.clear();
await keyv2.clear();
});
test.it("namespaced set/get don't collide", async (t) => {
const keyv1 = new Keyv2({ store: store(), namespace: "keyv1" });
const keyv2 = new Keyv2({ store: store(), namespace: "keyv2" });
await keyv1.set("foo", "keyv1");
await keyv2.set("foo", "keyv2");
t.expect(await keyv1.get("foo")).toBe("keyv1");
t.expect(await keyv2.get("foo")).toBe("keyv2");
});
test.it("namespaced delete only deletes from current namespace", async (t) => {
const keyv1 = new Keyv2({ store: store(), namespace: "keyv1" });
const keyv2 = new Keyv2({ store: store(), namespace: "keyv2" });
await keyv1.set("foo", "keyv1");
await keyv2.set("foo", "keyv2");
t.expect(await keyv1.delete("foo")).toBe(true);
t.expect(await keyv1.get("foo")).toBeUndefined();
t.expect(await keyv2.get("foo")).toBe("keyv2");
});
test.it("namespaced clear only clears current namespace", async (t) => {
const keyv1 = new Keyv2({ store: store(), namespace: "keyv1" });
const keyv2 = new Keyv2({ store: store(), namespace: "keyv2" });
await keyv1.set("foo", "keyv1");
await keyv1.set("bar", "keyv1");
await keyv2.set("foo", "keyv2");
await keyv2.set("bar", "keyv2");
await keyv1.clear();
t.expect(await keyv1.get("foo")).toBeUndefined();
t.expect(await keyv1.get("bar")).toBeUndefined();
t.expect(await keyv2.get("foo")).toBe("keyv2");
t.expect(await keyv2.get("bar")).toBe("keyv2");
});
test.afterEach(async () => {
const keyv1 = new Keyv2({ store: store(), namespace: "keyv1" });
const keyv2 = new Keyv2({ store: store(), namespace: "keyv2" });
await keyv1.clear();
await keyv2.clear();
});
};
var namespace_default = keyvNamespaceTests;
// src/helper.ts
async function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// src/iterator.ts
var keyvIteratorTests = (test, Keyv2, store) => {
test.beforeEach(async () => {
const keyv = new Keyv2({ store: store() });
await keyv.clear();
});
test.it(".iterator() returns an asyncIterator", (t) => {
const keyv = new Keyv2({ store: store() });
t.expect(typeof keyv.iterator()[Symbol.asyncIterator]).toBe("function");
});
test.it("iterator() iterates over all values", async (t) => {
const keyv = new Keyv2({ store: store() });
const map = new Map(Array.from({ length: 5 }).fill(0).map((_x, i) => [String(i), String(i + 10)]));
const toResolve = [];
for (const [key, value] of map) {
toResolve.push(keyv.set(key, value));
}
await Promise.all(toResolve);
t.expect.assertions(map.size);
for await (const [key, value] of keyv.iterator()) {
const doesKeyExist = map.has(key);
const isValueSame = map.get(key) === value;
t.expect(doesKeyExist && isValueSame).toBeTruthy();
}
});
test.it(
"iterator() doesn't yield values from other namespaces",
async (t) => {
const keyvStore = store();
const keyv1 = new Keyv2({ store: keyvStore, namespace: "keyv1" });
const map1 = new Map(Array.from({ length: 5 }).fill(0).map((_x, i) => [String(i), String(i + 10)]));
const toResolve = [];
for (const [key, value] of map1) {
toResolve.push(keyv1.set(key, value));
}
await Promise.all(toResolve);
const keyv2 = new Keyv2({ store: keyvStore, namespace: "keyv2" });
const map2 = new Map(Array.from({ length: 5 }).fill(0).map((_x, i) => [String(i), String(i + 11)]));
toResolve.length = 0;
for (const [key, value] of map2) {
toResolve.push(keyv2.set(key, value));
}
await Promise.all(toResolve);
t.expect.assertions(map2.size);
for await (const [key, value] of keyv2.iterator()) {
const doesKeyExist = map2.has(key);
const isValueSame = map2.get(key) === value;
t.expect(doesKeyExist && isValueSame).toBeTruthy();
}
}
);
test.it(
"iterator() doesn't yield expired values, and deletes them",
async (t) => {
const keyv = new Keyv2({ store: store() });
const map = new Map(Array.from({ length: 5 }).fill(0).map((_x, i) => [String(i), String(i + 10)]));
const toResolve = [];
for (const [key, value] of map) {
toResolve.push(keyv.set(key, value, 200));
}
toResolve.push(keyv.set("foo", "bar"));
await Promise.all(toResolve);
await delay(250);
const iterator = keyv.iterator();
let entry = await iterator.next();
const [k, v] = entry.value;
t.expect(k).toBe("foo");
t.expect(v).toBe("bar");
entry = await iterator.next();
t.expect(entry.value).toBeUndefined();
}
);
};
var iterator_default = keyvIteratorTests;
// src/compression.ts
var import_keyv = __toESM(require("keyv"), 1);
var keyvCompressionTests = (test, compression) => {
let keyv;
test.beforeEach(async () => {
keyv = new import_keyv.default({
store: /* @__PURE__ */ new Map(),
compression
});
await keyv.clear();
});
test.it("number array compression/decompression", async (t) => {
const array = JSON.stringify([4, 5, 6, 7]);
const compressed = await compression.compress(array);
const decompressed = JSON.parse(await compression.decompress(compressed));
t.expect(decompressed).toEqual([4, 5, 6, 7]);
});
test.it("compression/decompression using default options", async (t) => {
const compressed = await compression.compress("whatever");
t.expect(compressed).not.toBe("whatever");
const decompressed = await compression.decompress(compressed);
t.expect(decompressed).toBe("whatever");
});
test.it("compression/decompression with number", async (t) => {
const number_ = JSON.stringify(5);
const compressed = await compression.compress(number_);
t.expect(compressed).not.toBe(5);
const decompressed = JSON.parse(await compression.decompress(compressed));
t.expect(decompressed).toBe(5);
});
test.it("serialize compression", async (t) => {
const json = await compression.serialize({
value: "whatever",
expires: void 0
});
t.expect(JSON.parse(json).value).not.toBe("whatever");
});
test.it("deserialize compression", async (t) => {
const json = await compression.serialize({
value: "whatever",
expires: void 0
});
const djson = await compression.deserialize(json);
t.expect(djson).toEqual({ expires: void 0, value: "whatever" });
});
test.it("compress/decompress with main keyv", async (t) => {
const keyv2 = new import_keyv.default({ compression });
await keyv2.set("foo", "bar");
t.expect(await keyv2.get("foo")).toBe("bar");
});
};
var compression_default = keyvCompressionTests;
// src/index.ts
var keyvTestSuite = (test, Keyv2, store) => {
api_default(test, Keyv2, store);
values_default(test, Keyv2, store);
namespace_default(test, Keyv2, store);
};
var index_default = keyvTestSuite;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
delay,
keyvApiTests,
keyvCompresstionTests,
keyvIteratorTests,
keyvNamespaceTest,
keyvValueTests
});