import {type TestContext, setup} from "@holllo/test"; import {type Value} from "@holllo/webextension-storage"; import browser from "webextension-polyfill"; import {type Item, createItem, nextItem, nextItemId, storage} from "./item.js"; const testText = "Test Item"; const testUrl = "https://example.org/"; /** * Check all properties of an {@link Item}. * * @param item The {@link Item} to assert. * @param test The {@link TestContext} for the assertions. */ function assertItem(item: Value, test: TestContext): void { // Assert that itemKeyPrefix is used. test.true(/^item-\d+$/.test(item.key), "item key regex"); // Assert that deserialization instantiates any classes. test.true(item.value.dateAdded instanceof Date, "dateAdded is a Date"); // Assert that the expected values are indeed present. test.true(item.value.id > 0, "id is set"); test.equals(item.value.text, testText, "text is set"); test.equals(item.value.url, testUrl, "url is set"); } await setup( "Item", async (group) => { group.beforeAll(async () => { // If we're in production and testing, clear item storage. if (!$dev && $test) { await storage.clear(); } }); group.test("create & nextItem", async (test) => { const testItem = await createItem(testText, testUrl); assertItem(testItem, test); await testItem.save(); // Make sure `nextItem()` returns an item. let storedNext = await nextItem(); if (storedNext === undefined) { throw new Error("Expected an item"); } // Assert that our first test item and the stored one are identical. test.equals(storedNext.key, testItem.key, "id check"); assertItem(storedNext, test); // Store all test items we create so we can remove them later on. const items = [testItem]; // Create a bunch of test items and assert them all. for (let index = 1; index < 10; index++) { const next = await createItem(testText, testUrl); test.equals(testItem.value.id + index, next.value.id, "id check"); assertItem(next, test); items.push(next); await next.save(); } // Remove all test items. await Promise.all(items.map(async (item) => item.remove())); // After all items have been removed test that `nextItem` returns nothing. // This test will fail if an item is left from development, to clear // storage automatically run in production and have test enabled. // ie. `NODE_ENV=production TEST=true makers dev` // TODO: Temporarily store existing storage and run the tests, and then // restore it again. storedNext = await nextItem(); test.equals(storedNext, undefined, "next item is undefined"); }); group.test("nextItemId", async (test) => { const testItem = await createItem(testText, testUrl); assertItem(testItem, test); await testItem.save(); const id = await nextItemId(); test.equals(typeof id, "number", "id is a number"); test.false(Number.isNaN(id), "id is not NaN"); test.true(id > 0, "id larger than 0"); test.equals(await nextItemId(), testItem.value.id + 1, "id check"); await testItem.remove(); }); }, { // Run tests in series since we're using WebExtension storage to test stuff // and don't want the ID checks to interfere with one another. parallel: false, }, );