mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Refactor post-login state loading and add tests
This commit is contained in:
1 parent
c092e10188
commit
599c40c3cc
2 files changed
+243
-36
No files matched your search
+66
-36
@@ -395,43 +395,73 @@ export default class AuthService {
|
||||
|
||||
async applyPostLoginState() {
|
||||
const activePubkey = this.normalizeHexPubkey(getPubkey()) || getPubkey();
|
||||
if (!activePubkey) {
|
||||
return { pubkey: null };
|
||||
}
|
||||
|
||||
let blocksLoaded = false;
|
||||
if (this.userBlocks && typeof this.userBlocks.loadBlocks === "function") {
|
||||
try {
|
||||
await this.userBlocks.loadBlocks(activePubkey);
|
||||
blocksLoaded = true;
|
||||
} catch (error) {
|
||||
this.log("[AuthService] Failed to load block list", error);
|
||||
}
|
||||
}
|
||||
|
||||
let relaysLoaded = false;
|
||||
if (this.relayManager && typeof this.relayManager.loadRelayList === "function") {
|
||||
try {
|
||||
await this.relayManager.loadRelayList(activePubkey);
|
||||
relaysLoaded = true;
|
||||
} catch (error) {
|
||||
this.log("[AuthService] Failed to load relay list", error);
|
||||
}
|
||||
}
|
||||
|
||||
let profile = null;
|
||||
try {
|
||||
profile = await this.loadOwnProfile(activePubkey);
|
||||
} catch (error) {
|
||||
this.log("[AuthService] Failed to load own profile", error);
|
||||
}
|
||||
|
||||
return {
|
||||
pubkey: activePubkey,
|
||||
blocksLoaded,
|
||||
relaysLoaded,
|
||||
profile,
|
||||
const detail = {
|
||||
pubkey: activePubkey || null,
|
||||
blocksLoaded: false,
|
||||
relaysLoaded: false,
|
||||
profile: null,
|
||||
};
|
||||
|
||||
if (!activePubkey) {
|
||||
return detail;
|
||||
}
|
||||
|
||||
const schedule = (callback) => Promise.resolve().then(() => callback());
|
||||
|
||||
const operations = [];
|
||||
|
||||
if (this.userBlocks && typeof this.userBlocks.loadBlocks === "function") {
|
||||
operations.push({
|
||||
name: "blocksLoaded",
|
||||
promise: schedule(() => this.userBlocks.loadBlocks(activePubkey)),
|
||||
onFulfilled: () => true,
|
||||
onRejected: (error) => {
|
||||
this.log("[AuthService] Failed to load block list", error);
|
||||
return false;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (this.relayManager && typeof this.relayManager.loadRelayList === "function") {
|
||||
operations.push({
|
||||
name: "relaysLoaded",
|
||||
promise: schedule(() => this.relayManager.loadRelayList(activePubkey)),
|
||||
onFulfilled: () => true,
|
||||
onRejected: (error) => {
|
||||
this.log("[AuthService] Failed to load relay list", error);
|
||||
return false;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
operations.push({
|
||||
name: "profile",
|
||||
promise: schedule(() => this.loadOwnProfile(activePubkey)),
|
||||
onFulfilled: (value) => value,
|
||||
onRejected: (error) => {
|
||||
this.log("[AuthService] Failed to load own profile", error);
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
const settled = await Promise.allSettled(
|
||||
operations.map((operation) => operation.promise)
|
||||
);
|
||||
|
||||
settled.forEach((result, index) => {
|
||||
const operation = operations[index];
|
||||
if (!operation) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.status === "fulfilled") {
|
||||
detail[operation.name] = operation.onFulfilled(result.value);
|
||||
} else {
|
||||
detail[operation.name] = operation.onRejected(result.reason);
|
||||
}
|
||||
});
|
||||
|
||||
return detail;
|
||||
}
|
||||
|
||||
async logout() {
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
// Run with: node tests/auth-service.test.mjs
|
||||
|
||||
import "./test-helpers/setup-localstorage.mjs";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import AuthService from "../js/services/authService.js";
|
||||
import {
|
||||
setPubkey,
|
||||
setCurrentUserNpub,
|
||||
} from "../js/state/appState.js";
|
||||
import {
|
||||
mutateSavedProfiles,
|
||||
setActiveProfilePubkey,
|
||||
getProfileCacheMap,
|
||||
} from "../js/state/cache.js";
|
||||
|
||||
if (typeof globalThis.window === "undefined") {
|
||||
globalThis.window = {};
|
||||
}
|
||||
|
||||
if (!globalThis.window.NostrTools) {
|
||||
globalThis.window.NostrTools = {};
|
||||
}
|
||||
|
||||
if (!globalThis.window.NostrTools.nip19) {
|
||||
globalThis.window.NostrTools.nip19 = {
|
||||
decode(value) {
|
||||
if (typeof value !== "string") {
|
||||
throw new Error("invalid value");
|
||||
}
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) {
|
||||
throw new Error("empty value");
|
||||
}
|
||||
if (trimmed.startsWith("npub1")) {
|
||||
return { type: "npub", data: trimmed.slice(5) || "" };
|
||||
}
|
||||
return { type: "hex", data: trimmed };
|
||||
},
|
||||
npubEncode(hex) {
|
||||
if (typeof hex !== "string") {
|
||||
throw new Error("invalid hex");
|
||||
}
|
||||
const trimmed = hex.trim();
|
||||
if (!trimmed) {
|
||||
throw new Error("empty hex");
|
||||
}
|
||||
return `npub1${trimmed}`;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const SAMPLE_PUBKEY = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
|
||||
|
||||
function resetState() {
|
||||
setPubkey(null);
|
||||
setCurrentUserNpub(null);
|
||||
setActiveProfilePubkey(null, { persist: false });
|
||||
mutateSavedProfiles(() => [], { persist: false, persistActive: false });
|
||||
const cache = getProfileCacheMap();
|
||||
if (cache && typeof cache.clear === "function") {
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
await (async () => {
|
||||
resetState();
|
||||
setPubkey(SAMPLE_PUBKEY);
|
||||
|
||||
const calls = [];
|
||||
let resolveBlocks;
|
||||
|
||||
const service = new AuthService({
|
||||
userBlocks: {
|
||||
loadBlocks: () => {
|
||||
calls.push("blocks:start");
|
||||
return new Promise((resolve) => {
|
||||
resolveBlocks = resolve;
|
||||
});
|
||||
},
|
||||
},
|
||||
relayManager: {
|
||||
loadRelayList: () => {
|
||||
calls.push("relays:start");
|
||||
return Promise.resolve("relays");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
service.loadOwnProfile = () => {
|
||||
calls.push("profile:start");
|
||||
return Promise.resolve({ name: "Test User" });
|
||||
};
|
||||
|
||||
const promise = service.applyPostLoginState();
|
||||
|
||||
await Promise.resolve();
|
||||
|
||||
assert.deepEqual(calls, ["blocks:start", "relays:start", "profile:start"]);
|
||||
|
||||
resolveBlocks();
|
||||
|
||||
const detail = await promise;
|
||||
|
||||
assert.equal(detail.pubkey, SAMPLE_PUBKEY);
|
||||
assert.equal(detail.blocksLoaded, true);
|
||||
assert.equal(detail.relaysLoaded, true);
|
||||
assert.deepEqual(detail.profile, { name: "Test User" });
|
||||
})();
|
||||
|
||||
await (async () => {
|
||||
resetState();
|
||||
setPubkey(SAMPLE_PUBKEY);
|
||||
|
||||
const logs = [];
|
||||
const service = new AuthService({
|
||||
userBlocks: {
|
||||
loadBlocks: () => {
|
||||
throw new Error("blocks failed synchronously");
|
||||
},
|
||||
},
|
||||
relayManager: {
|
||||
loadRelayList: () => Promise.reject(new Error("relays failed")),
|
||||
},
|
||||
});
|
||||
|
||||
service.log = (message, error) => {
|
||||
logs.push({ message, error });
|
||||
};
|
||||
|
||||
service.loadOwnProfile = () => Promise.reject(new Error("profile failed"));
|
||||
|
||||
const detail = await service.applyPostLoginState();
|
||||
|
||||
assert.equal(detail.pubkey, SAMPLE_PUBKEY);
|
||||
assert.equal(detail.blocksLoaded, false);
|
||||
assert.equal(detail.relaysLoaded, false);
|
||||
assert.equal(detail.profile, null);
|
||||
|
||||
assert.equal(logs.length, 3);
|
||||
assert(logs.some(({ message }) => message.includes("block list")));
|
||||
assert(logs.some(({ message }) => message.includes("relay list")));
|
||||
assert(logs.some(({ message }) => message.includes("own profile")));
|
||||
})();
|
||||
|
||||
await (async () => {
|
||||
resetState();
|
||||
|
||||
const service = new AuthService();
|
||||
const detail = await service.applyPostLoginState();
|
||||
|
||||
assert.deepEqual(detail, {
|
||||
pubkey: null,
|
||||
blocksLoaded: false,
|
||||
relaysLoaded: false,
|
||||
profile: null,
|
||||
});
|
||||
})();
|
||||
|
||||
await (async () => {
|
||||
resetState();
|
||||
|
||||
const service = new AuthService();
|
||||
const postLogin = {
|
||||
pubkey: SAMPLE_PUBKEY,
|
||||
blocksLoaded: true,
|
||||
relaysLoaded: false,
|
||||
profile: { name: "Stub" },
|
||||
};
|
||||
|
||||
service.applyPostLoginState = async () => postLogin;
|
||||
|
||||
const detail = await service.login(SAMPLE_PUBKEY);
|
||||
|
||||
assert.equal(detail.postLogin, postLogin);
|
||||
assert.deepEqual(detail.postLogin, postLogin);
|
||||
})();
|
||||
Reference in new issue
Block a user