From ce2c30574c0a7e5918924c27129010691a14f4da Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 11:39:38 +0000 Subject: [PATCH 1/4] test(ai): improve unit test coverage and stability (agent) Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- tests/app-batch-fetch-profiles.test.mjs | 5 ++ tests/utils/lruCache.test.mjs | 86 +++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 tests/utils/lruCache.test.mjs diff --git a/tests/app-batch-fetch-profiles.test.mjs b/tests/app-batch-fetch-profiles.test.mjs index df90a4bc..45148645 100644 --- a/tests/app-batch-fetch-profiles.test.mjs +++ b/tests/app-batch-fetch-profiles.test.mjs @@ -49,6 +49,9 @@ test("batchFetchProfiles handles fast and failing relays", async () => { const originalRelays = Array.isArray(nostrClient.relays) ? [...nostrClient.relays] : []; + const originalReadRelays = Array.isArray(nostrClient.readRelays) + ? [...nostrClient.readRelays] + : nostrClient.readRelays; const originalWriteRelays = Array.isArray(nostrClient.writeRelays) ? [...nostrClient.writeRelays] : nostrClient.writeRelays; @@ -57,6 +60,7 @@ test("batchFetchProfiles handles fast and failing relays", async () => { const poolListCalls = []; nostrClient.relays = [FAST_RELAY, FAIL_RELAY]; + nostrClient.readRelays = [FAST_RELAY, FAIL_RELAY]; nostrClient.writeRelays = [FAST_RELAY, FAIL_RELAY]; nostrClient.pool = { list: (relays, filters) => { @@ -92,6 +96,7 @@ test("batchFetchProfiles handles fast and failing relays", async () => { }); } finally { nostrClient.relays = originalRelays; + nostrClient.readRelays = originalReadRelays; nostrClient.writeRelays = originalWriteRelays; nostrClient.pool = originalPool; } diff --git a/tests/utils/lruCache.test.mjs b/tests/utils/lruCache.test.mjs new file mode 100644 index 00000000..199c50fc --- /dev/null +++ b/tests/utils/lruCache.test.mjs @@ -0,0 +1,86 @@ +import { describe, it, beforeEach } from "node:test"; +import assert from "node:assert/strict"; +import { LRUCache } from "../../js/utils/lruCache.js"; + +describe("LRUCache", () => { + let cache; + + beforeEach(() => { + cache = new LRUCache({ maxSize: 3 }); + }); + + it("should initialize with default options", () => { + const defaultCache = new LRUCache(); + assert.equal(defaultCache.maxSize, 100); + assert.equal(defaultCache.size(), 0); + }); + + it("should store and retrieve values", () => { + cache.set("a", 1); + assert.equal(cache.get("a"), 1); + assert.equal(cache.has("a"), true); + assert.equal(cache.size(), 1); + }); + + it("should evict oldest item when limit is reached", () => { + cache.set("a", 1); + cache.set("b", 2); + cache.set("c", 3); + assert.equal(cache.size(), 3); + + cache.set("d", 4); // Should evict 'a' + assert.equal(cache.size(), 3); + assert.equal(cache.has("a"), false); + assert.equal(cache.get("b"), 2); + assert.equal(cache.get("d"), 4); + }); + + it("should refresh recency on access", () => { + cache.set("a", 1); + cache.set("b", 2); + cache.set("c", 3); + + // Access 'a', making it newest + cache.get("a"); + + cache.set("d", 4); // Should evict 'b' (oldest is now 'b') + + assert.equal(cache.has("b"), false); + assert.equal(cache.has("a"), true); + assert.equal(cache.has("c"), true); + assert.equal(cache.has("d"), true); + }); + + it("should update value and refresh recency on set", () => { + cache.set("a", 1); + cache.set("b", 2); + cache.set("c", 3); + + // Update 'a' + cache.set("a", 10); + + cache.set("d", 4); // Should evict 'b' + + assert.equal(cache.get("a"), 10); + assert.equal(cache.has("b"), false); + }); + + it("should track stats", () => { + cache.set("a", 1); + cache.get("a"); // Hit + cache.get("b"); // Miss + + const stats = cache.getStats(); + assert.equal(stats.hits, 1); + assert.equal(stats.misses, 1); + assert.equal(stats.size, 1); + assert.equal(stats.maxSize, 3); + }); + + it("should clear cache", () => { + cache.set("a", 1); + cache.clear(); + assert.equal(cache.size(), 0); + assert.equal(cache.getStats().hits, 0); + }); +}); From 0ac0b6960d09a14546a92573c83a697ea34c0dd7 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 11:53:04 +0000 Subject: [PATCH 2/4] fix(ci): update test mocks for ProfileModalController Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- tests/profile-modal-controller.test.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/profile-modal-controller.test.mjs b/tests/profile-modal-controller.test.mjs index f14c3730..9d746088 100644 --- a/tests/profile-modal-controller.test.mjs +++ b/tests/profile-modal-controller.test.mjs @@ -275,6 +275,7 @@ function createController(options = {}) { }, publish: async () => ({ ok: true }), on: () => () => {}, + load: async () => {}, }; const hashtagPreferences = { From 113b0a2b72afa4cd05303670ee6a6f9c4d8caab3 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 11:59:18 +0000 Subject: [PATCH 3/4] fix(ci): harden build script and update test mocks Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- scripts/build-dist.mjs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/scripts/build-dist.mjs b/scripts/build-dist.mjs index 0153dd4a..74e19bda 100644 --- a/scripts/build-dist.mjs +++ b/scripts/build-dist.mjs @@ -38,7 +38,11 @@ function copyFile(src, dest) { if (fs.existsSync(src)) { fs.copyFileSync(src, dest); } else { - console.warn(`Warning: Source file ${src} does not exist.`); + const message = `Error: Source file ${src} does not exist.`; + console.error(message); + if (['_headers', '_redirects', 'index.html'].includes(path.basename(src))) { + throw new Error(message); + } } } @@ -74,6 +78,19 @@ function main() { copyFile(file, path.join(DIST, file)); } + // Verify critical CSS generation + const generatedCss = path.join(DIST, 'css', 'tailwind.generated.css'); + if (!fs.existsSync(generatedCss) && !fs.existsSync(path.join('css', 'tailwind.generated.css'))) { + // tailwind might output to dist/css OR css/ then we copy. + // The command is: -o css/tailwind.generated.css + // So it should be in source 'css/', then copied by copyDir('css'...) + // Let's verify it exists in source 'css/' + if (!fs.existsSync(path.join('css', 'tailwind.generated.css'))) { + console.error('Error: css/tailwind.generated.css was not generated.'); + process.exit(1); + } + } + console.log('Copying directories...'); for (const dir of DIRS_TO_COPY) { copyDir(dir, path.join(DIST, dir)); From 044d5629be4a4dcf68b40a8b44b724d182672c9c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 12:04:24 +0000 Subject: [PATCH 4/4] fix(ci): improve build script logging for deployment debugging Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- scripts/build-dist.mjs | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/scripts/build-dist.mjs b/scripts/build-dist.mjs index 74e19bda..02a633f0 100644 --- a/scripts/build-dist.mjs +++ b/scripts/build-dist.mjs @@ -40,6 +40,15 @@ function copyFile(src, dest) { } else { const message = `Error: Source file ${src} does not exist.`; console.error(message); + // Debug: list source directory to check what IS there + try { + console.log(`Source directory listing for context:`); + const dir = path.dirname(src); + console.log(fs.readdirSync(dir || '.')); + } catch (e) { + console.error('Failed to list source directory:', e); + } + if (['_headers', '_redirects', 'index.html'].includes(path.basename(src))) { throw new Error(message); } @@ -79,16 +88,22 @@ function main() { } // Verify critical CSS generation - const generatedCss = path.join(DIST, 'css', 'tailwind.generated.css'); - if (!fs.existsSync(generatedCss) && !fs.existsSync(path.join('css', 'tailwind.generated.css'))) { - // tailwind might output to dist/css OR css/ then we copy. - // The command is: -o css/tailwind.generated.css - // So it should be in source 'css/', then copied by copyDir('css'...) - // Let's verify it exists in source 'css/' - if (!fs.existsSync(path.join('css', 'tailwind.generated.css'))) { - console.error('Error: css/tailwind.generated.css was not generated.'); - process.exit(1); + const generatedCssSource = path.join('css', 'tailwind.generated.css'); + const generatedCssDist = path.join(DIST, 'css', 'tailwind.generated.css'); + + if (!fs.existsSync(generatedCssSource) && !fs.existsSync(generatedCssDist)) { + console.error('Error: css/tailwind.generated.css was not generated.'); + try { + console.log('Listing css/ directory:'); + if (fs.existsSync('css')) { + console.log(fs.readdirSync('css')); + } else { + console.log('css/ directory does not exist.'); + } + } catch (e) { + console.error('Failed to list css directory:', e); } + process.exit(1); } console.log('Copying directories...');