Merge pull request #1376 from PR0M3TH3AN/ai/tests-core-modules-20250226-2648005617024541031

Add unit tests for core modules (cache, sessionActor, r2Service)
This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2026-01-19 09:24:16 -05:00
commit 3376185276
3 files changed
+331

No files matched your search

+120
View File
@@ -0,0 +1,120 @@
import test from "node:test";
import assert from "node:assert";
import {
encryptSessionPrivateKey,
decryptSessionPrivateKey,
persistSessionActor,
readStoredSessionActorEntry,
clearStoredSessionActor,
SESSION_ACTOR_STORAGE_KEY,
__testExports
} from "../../js/nostr/sessionActor.js";
const { generateRandomBytes, isSubtleCryptoAvailable } = __testExports;
// Ensure localStorage is mocked
import "../../tests/test-helpers/setup-localstorage.mjs";
test("js/nostr/sessionActor.js", async (t) => {
if (!isSubtleCryptoAvailable()) {
t.skip("WebCrypto not available in this environment");
return;
}
t.beforeEach(async () => {
localStorage.clear();
await clearStoredSessionActor();
});
await t.test("Encryption and Decryption Roundtrip", async () => {
const privateKey = "nsec1testkey..."; // In reality this would be hex or bech32, but for encryption it is just a string payload
const passphrase = "secure-password";
const encrypted = await encryptSessionPrivateKey(privateKey, passphrase);
assert.ok(encrypted.ciphertext);
assert.ok(encrypted.salt);
assert.ok(encrypted.iv);
assert.strictEqual(encrypted.algorithm, "AES-GCM");
const payload = {
privateKeyEncrypted: encrypted.ciphertext,
encryption: encrypted,
};
const decrypted = await decryptSessionPrivateKey(payload, passphrase);
assert.strictEqual(decrypted, privateKey);
});
await t.test("Decryption fails with wrong passphrase", async () => {
const privateKey = "secret";
const passphrase = "correct";
const wrongPassphrase = "wrong";
const encrypted = await encryptSessionPrivateKey(privateKey, passphrase);
const payload = {
privateKeyEncrypted: encrypted.ciphertext,
encryption: encrypted,
};
await assert.rejects(
async () => {
await decryptSessionPrivateKey(payload, wrongPassphrase);
},
(err) => err.code === "decrypt-failed" || err.message.includes("decrypt-failed")
);
});
await t.test("Persistence and Retrieval", async () => {
const pubkey = "0000000000000000000000000000000000000000000000000000000000000001";
const privateKey = "my-secret-key";
const passphrase = "my-password";
const encrypted = await encryptSessionPrivateKey(privateKey, passphrase);
const actor = {
pubkey,
privateKeyEncrypted: encrypted.ciphertext,
encryption: encrypted,
createdAt: Date.now(),
};
persistSessionActor(actor);
// Verify localStorage
const storedRaw = localStorage.getItem(SESSION_ACTOR_STORAGE_KEY);
assert.ok(storedRaw);
const stored = readStoredSessionActorEntry();
assert.ok(stored);
assert.strictEqual(stored.pubkey, pubkey);
assert.strictEqual(stored.privateKeyEncrypted, encrypted.ciphertext);
// Verify we can decrypt what we retrieved
const decrypted = await decryptSessionPrivateKey(stored, passphrase);
assert.strictEqual(decrypted, privateKey);
});
await t.test("Clear Stored Session Actor", async () => {
const pubkey = "0000000000000000000000000000000000000000000000000000000000000001";
const actor = {
pubkey,
privateKeyEncrypted: "fake-encrypted-data",
encryption: {
salt: "fake-salt",
iv: "fake-iv",
iterations: 1000,
hash: "SHA-256",
algorithm: "AES-GCM",
version: 1
},
createdAt: Date.now(),
};
persistSessionActor(actor);
assert.ok(readStoredSessionActorEntry());
clearStoredSessionActor();
assert.strictEqual(readStoredSessionActorEntry(), null);
});
});
+106
View File
@@ -0,0 +1,106 @@
import test from "node:test";
import assert from "node:assert";
import r2Service from "../../js/services/r2Service.js";
// Ensure localStorage is mocked
import "../../tests/test-helpers/setup-localstorage.mjs";
test("js/services/r2Service.js", async (t) => {
t.beforeEach(async () => {
localStorage.clear();
await r2Service.clearSettings();
});
await t.test("Default Settings", () => {
const settings = r2Service.getSettings();
// The actual default settings might contain more fields than we checked.
// Let's verify the core fields match.
assert.strictEqual(settings.accountId, "");
assert.strictEqual(settings.accessKeyId, "");
assert.strictEqual(settings.secretAccessKey, "");
assert.strictEqual(settings.baseDomain, "");
assert.deepStrictEqual(settings.buckets, {});
});
await t.test("handleCloudflareSettingsSubmit - Valid Input", async () => {
const input = {
accountId: "acc123",
accessKeyId: "key123",
secretAccessKey: "secret123",
baseDomain: "https://pub-xxx.r2.dev",
};
const result = await r2Service.handleCloudflareSettingsSubmit(input);
assert.strictEqual(result, true);
const saved = r2Service.getSettings();
assert.strictEqual(saved.accountId, input.accountId);
assert.strictEqual(saved.accessKeyId, input.accessKeyId);
assert.strictEqual(saved.secretAccessKey, input.secretAccessKey);
assert.strictEqual(saved.baseDomain, input.baseDomain);
});
await t.test("handleCloudflareSettingsSubmit - Invalid S3 URL", async () => {
const input = {
accountId: "acc123",
accessKeyId: "key123",
secretAccessKey: "secret123",
baseDomain: "https://something.r2.cloudflarestorage.com",
};
let status = "";
const cleanup = r2Service.on("settingsStatus", (s) => (status = s.message));
const result = await r2Service.handleCloudflareSettingsSubmit(input);
assert.strictEqual(result, false);
assert.match(status, /entered the S3 API URL/);
cleanup();
});
await t.test("handleCloudflareSettingsSubmit - Missing Fields", async () => {
const input = {
accountId: "acc123",
// missing accessKeyId
secretAccessKey: "secret123",
baseDomain: "https://pub-xxx.r2.dev",
};
const result = await r2Service.handleCloudflareSettingsSubmit(input);
assert.strictEqual(result, false);
});
await t.test("ensureBucketConfigForNpub - Uses Explicit Credentials", async () => {
const npub = "npub1test";
const credentials = {
accountId: "acc123",
accessKeyId: "key123",
secretAccessKey: "secret123",
baseDomain: "https://pub-xxx.r2.dev",
bucket: "custom-bucket",
isLegacy: true,
};
const result = await r2Service.ensureBucketConfigForNpub(npub, { credentials });
assert.strictEqual(result.entry.bucket, "custom-bucket");
assert.strictEqual(result.entry.publicBaseUrl, "https://pub-xxx.r2.dev");
assert.strictEqual(result.customDomainStatus, "manual");
});
await t.test("resolveConnection - Returns Legacy Settings if no StorageService", async () => {
const input = {
accountId: "legacyAcc",
accessKeyId: "legacyKey",
secretAccessKey: "legacySecret",
baseDomain: "https://legacy.com",
};
await r2Service.handleCloudflareSettingsSubmit(input);
const npub = "npub1any";
const resolved = await r2Service.resolveConnection(npub);
assert.ok(resolved);
assert.strictEqual(resolved.accountId, "legacyAcc");
assert.strictEqual(resolved.isLegacy, true);
});
});
+105
View File
@@ -0,0 +1,105 @@
import test from "node:test";
import assert from "node:assert";
import {
loadSavedProfilesFromStorage,
persistSavedProfiles,
setActiveProfilePubkey,
getSavedProfiles,
getActiveProfilePubkey,
setSavedProfiles,
storeUrlHealth,
getCachedUrlHealth,
getModerationSettings,
setModerationSettings,
urlHealthConstants,
} from "../../js/state/cache.js";
// Ensure localStorage is mocked
import "../../tests/test-helpers/setup-localstorage.mjs";
test("js/state/cache.js", async (t) => {
t.beforeEach(() => {
localStorage.clear();
// Reset internal state if possible, or relying on overwrites
setSavedProfiles([]);
setActiveProfilePubkey(null, { persist: false });
});
await t.test("Saved Profiles Persistence", async () => {
const profiles = [
{ pubkey: "0000000000000000000000000000000000000000000000000000000000000001", name: "Alice" },
{ pubkey: "0000000000000000000000000000000000000000000000000000000000000002", name: "Bob" },
];
setSavedProfiles(profiles, { persist: true });
// Simulate reload
const { profiles: loadedProfiles } = loadSavedProfilesFromStorage();
assert.strictEqual(loadedProfiles.length, 2);
assert.strictEqual(loadedProfiles[0].name, "Alice");
assert.strictEqual(loadedProfiles[1].name, "Bob");
});
await t.test("Active Profile Pubkey", async () => {
const pubkey = "0000000000000000000000000000000000000000000000000000000000000001";
// We need to set saved profiles first so the active one is considered valid in some logic paths,
// or just rely on setActiveProfilePubkey which should handle it.
// However, looking at cache.js `loadSavedProfilesFromStorage` implementation:
// It checks if the active candidate exists in `seenPubkeys` (from `savedProfiles`).
// If not, it might not set it or treat it as valid if we are loading from storage.
// Let's add the profile to saved profiles first to be safe for persistence reload check.
setSavedProfiles([{ pubkey, name: "Alice" }]);
setActiveProfilePubkey(pubkey);
assert.strictEqual(getActiveProfilePubkey(), pubkey);
// Verify persistence
const { activePubkey } = loadSavedProfilesFromStorage();
assert.strictEqual(activePubkey, pubkey);
});
await t.test("URL Health Caching", async () => {
const eventId = "event1";
const url = "https://example.com/video.mp4";
const result = { status: "ok", message: "All good" };
storeUrlHealth(eventId, url, result);
const cached = getCachedUrlHealth(eventId, url);
assert.ok(cached);
assert.strictEqual(cached.status, "ok");
assert.strictEqual(cached.url, url);
});
await t.test("URL Health Expiration", async (t) => {
const eventId = "event2";
const url = "https://example.com/expired.mp4";
const result = { status: "checking" };
// Store with very short TTL
storeUrlHealth(eventId, url, result, 1); // 1ms TTL
await new Promise((resolve) => setTimeout(resolve, 10));
const cached = getCachedUrlHealth(eventId, url);
assert.strictEqual(cached, null, "Should return null for expired cache");
});
await t.test("Moderation Settings", async () => {
const defaults = getModerationSettings();
assert.ok(defaults);
const newSettings = {
blurThreshold: 1,
autoplayBlockThreshold: 2,
};
setModerationSettings(newSettings);
const updated = getModerationSettings();
assert.strictEqual(updated.blurThreshold, 1);
assert.strictEqual(updated.autoplayBlockThreshold, 2);
});
});