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, }, );