PersistentCache.test.js (4290B)
1 import { GlobalOverrider } from "test/unit/utils"; 2 import { PersistentCache } from "lib/PersistentCache.sys.mjs"; 3 4 describe("PersistentCache", () => { 5 let fakeIOUtils; 6 let fakePathUtils; 7 let cache; 8 let filename = "cache.json"; 9 let consoleErrorStub; 10 let globals; 11 let sandbox; 12 13 beforeEach(() => { 14 globals = new GlobalOverrider(); 15 sandbox = sinon.createSandbox(); 16 fakeIOUtils = { 17 writeJSON: sinon.stub().resolves(0), 18 readJSON: sinon.stub().resolves({}), 19 }; 20 fakePathUtils = { 21 join: sinon.stub().returns(filename), 22 localProfileDir: "/", 23 }; 24 consoleErrorStub = sandbox.stub(); 25 globals.set("console", { error: consoleErrorStub }); 26 globals.set("IOUtils", fakeIOUtils); 27 globals.set("PathUtils", fakePathUtils); 28 29 cache = new PersistentCache(filename); 30 }); 31 afterEach(() => { 32 globals.restore(); 33 sandbox.restore(); 34 }); 35 36 describe("#get", () => { 37 it("tries to read the file", async () => { 38 await cache.get("foo"); 39 assert.calledOnce(fakeIOUtils.readJSON); 40 }); 41 it("doesnt try to read the file if it was already loaded", async () => { 42 await cache._load(); 43 fakeIOUtils.readJSON.resetHistory(); 44 await cache.get("foo"); 45 assert.notCalled(fakeIOUtils.readJSON); 46 }); 47 it("should catch and report errors", async () => { 48 fakeIOUtils.readJSON.rejects(new SyntaxError("Failed to parse JSON")); 49 await cache._load(); 50 assert.calledOnce(consoleErrorStub); 51 52 cache._cache = undefined; 53 consoleErrorStub.resetHistory(); 54 55 fakeIOUtils.readJSON.rejects( 56 new DOMException("IOUtils shutting down", "AbortError") 57 ); 58 await cache._load(); 59 assert.calledOnce(consoleErrorStub); 60 61 cache._cache = undefined; 62 consoleErrorStub.resetHistory(); 63 64 fakeIOUtils.readJSON.rejects( 65 new DOMException("File not found", "NotFoundError") 66 ); 67 await cache._load(); 68 assert.notCalled(consoleErrorStub); 69 }); 70 it("returns data for a given cache key", async () => { 71 fakeIOUtils.readJSON.resolves({ foo: "bar" }); 72 let value = await cache.get("foo"); 73 assert.equal(value, "bar"); 74 }); 75 it("returns undefined for a cache key that doesn't exist", async () => { 76 let value = await cache.get("baz"); 77 assert.equal(value, undefined); 78 }); 79 it("returns all the data if no cache key is specified", async () => { 80 fakeIOUtils.readJSON.resolves({ foo: "bar" }); 81 let value = await cache.get(); 82 assert.deepEqual(value, { foo: "bar" }); 83 }); 84 }); 85 86 describe("#set", () => { 87 it("tries to read the file on the first set", async () => { 88 await cache.set("foo", { x: 42 }); 89 assert.calledOnce(fakeIOUtils.readJSON); 90 }); 91 it("doesnt try to read the file if it was already loaded", async () => { 92 cache = new PersistentCache(filename, true); 93 await cache._load(); 94 fakeIOUtils.readJSON.resetHistory(); 95 await cache.set("foo", { x: 42 }); 96 assert.notCalled(fakeIOUtils.readJSON); 97 }); 98 it("sets a string value", async () => { 99 const key = "testkey"; 100 const value = "testvalue"; 101 await cache.set(key, value); 102 const cachedValue = await cache.get(key); 103 assert.equal(cachedValue, value); 104 }); 105 it("sets an object value", async () => { 106 const key = "testkey"; 107 const value = { x: 1, y: 2, z: 3 }; 108 await cache.set(key, value); 109 const cachedValue = await cache.get(key); 110 assert.deepEqual(cachedValue, value); 111 }); 112 it("writes the data to file", async () => { 113 const key = "testkey"; 114 const value = { x: 1, y: 2, z: 3 }; 115 116 await cache.set(key, value); 117 assert.calledOnce(fakeIOUtils.writeJSON); 118 assert.calledWith( 119 fakeIOUtils.writeJSON, 120 filename, 121 { [[key]]: value }, 122 { tmpPath: `${filename}.tmp` } 123 ); 124 }); 125 it("throws when failing to get file path", async () => { 126 Object.defineProperty(fakePathUtils, "localProfileDir", { 127 get() { 128 throw new Error(); 129 }, 130 }); 131 132 let rejected = false; 133 try { 134 await cache.set("key", "val"); 135 } catch (error) { 136 rejected = true; 137 } 138 139 assert(rejected); 140 }); 141 }); 142 });