mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
209 lines
7.3 KiB
JavaScript
209 lines
7.3 KiB
JavaScript
import "./test-helpers/setup-localstorage.mjs";
|
|
import { test, describe, beforeEach, afterEach, mock } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import AuthService from "../js/services/authService.js";
|
|
import {
|
|
getPubkey,
|
|
setPubkey,
|
|
getCurrentUserNpub,
|
|
setCurrentUserNpub,
|
|
} from "../js/state/appState.js";
|
|
import {
|
|
getSavedProfiles,
|
|
mutateSavedProfiles,
|
|
getActiveProfilePubkey,
|
|
setActiveProfilePubkey,
|
|
} from "../js/state/cache.js";
|
|
|
|
// Mock dependencies
|
|
const mockNostrClient = {
|
|
pubkey: null,
|
|
logout: mock.fn(),
|
|
pool: { list: mock.fn(async () => []) },
|
|
relays: [],
|
|
handleEvent: mock.fn(),
|
|
};
|
|
|
|
const mockUserBlocks = {
|
|
loadBlocks: mock.fn(async () => true),
|
|
reset: mock.fn(),
|
|
};
|
|
|
|
const mockRelayManager = {
|
|
loadRelayList: mock.fn(async () => true),
|
|
reset: mock.fn(),
|
|
};
|
|
|
|
const mockAccessControl = {
|
|
isLockdownActive: mock.fn(() => false),
|
|
isAdminEditor: mock.fn(() => false),
|
|
canAccess: mock.fn(() => true),
|
|
isBlacklisted: mock.fn(() => false),
|
|
};
|
|
|
|
const mockLogger = mock.fn();
|
|
|
|
const mockAuthProvider = {
|
|
login: mock.fn(async () => ({ pubkey: "0000000000000000000000000000000000000000000000000000000000000001", authType: "nip07" })),
|
|
};
|
|
|
|
const mockGetAuthProvider = mock.fn((id) => mockAuthProvider);
|
|
|
|
describe("AuthService Coverage", () => {
|
|
let authService;
|
|
|
|
beforeEach(() => {
|
|
// Reset global state
|
|
setPubkey(null);
|
|
setCurrentUserNpub(null);
|
|
setActiveProfilePubkey(null, { persist: false });
|
|
mutateSavedProfiles(() => [], { persist: false, persistActive: false });
|
|
|
|
// Reset mocks
|
|
mockNostrClient.logout.mock.resetCalls();
|
|
mockUserBlocks.loadBlocks.mock.resetCalls();
|
|
mockUserBlocks.reset.mock.resetCalls();
|
|
mockRelayManager.loadRelayList.mock.resetCalls();
|
|
mockRelayManager.reset.mock.resetCalls();
|
|
mockAccessControl.isLockdownActive.mock.resetCalls();
|
|
mockAuthProvider.login.mock.resetCalls();
|
|
|
|
authService = new AuthService({
|
|
nostrClient: mockNostrClient,
|
|
userBlocks: mockUserBlocks,
|
|
relayManager: mockRelayManager,
|
|
logger: mockLogger,
|
|
accessControl: mockAccessControl,
|
|
getAuthProvider: mockGetAuthProvider,
|
|
});
|
|
});
|
|
|
|
describe("login", () => {
|
|
test("successfully logs in with valid pubkey", async () => {
|
|
const pubkey = "0000000000000000000000000000000000000000000000000000000000000001";
|
|
const result = await authService.login(pubkey);
|
|
|
|
assert.equal(getPubkey(), pubkey);
|
|
assert.equal(getActiveProfilePubkey(), pubkey);
|
|
assert.equal(result.pubkey, pubkey);
|
|
|
|
const saved = getSavedProfiles();
|
|
assert.equal(saved.length, 1);
|
|
assert.equal(saved[0].pubkey, pubkey);
|
|
});
|
|
|
|
test("updates global state and calls post-login hooks", async () => {
|
|
const pubkey = "0000000000000000000000000000000000000000000000000000000000000002";
|
|
await authService.login(pubkey);
|
|
|
|
assert.strictEqual(mockRelayManager.loadRelayList.mock.callCount(), 1);
|
|
// Blocks are deferred by default in login flow, so loadBlocks should not be called immediately
|
|
assert.strictEqual(mockUserBlocks.loadBlocks.mock.callCount(), 0);
|
|
});
|
|
|
|
test("throws if lockdown is active and user is not admin", async () => {
|
|
mockAccessControl.isLockdownActive.mock.mockImplementation(() => true);
|
|
mockAccessControl.isAdminEditor.mock.mockImplementation(() => false);
|
|
|
|
await assert.rejects(
|
|
async () => await authService.login("0000000000000000000000000000000000000000000000000000000000000003"),
|
|
{ code: "site-lockdown" }
|
|
);
|
|
});
|
|
|
|
test("allows login if lockdown is active but user is admin", async () => {
|
|
mockAccessControl.isLockdownActive.mock.mockImplementation(() => true);
|
|
mockAccessControl.isAdminEditor.mock.mockImplementation(() => true);
|
|
|
|
const pubkey = "0000000000000000000000000000000000000000000000000000000000000004";
|
|
await authService.login(pubkey);
|
|
assert.equal(getPubkey(), pubkey);
|
|
});
|
|
});
|
|
|
|
describe("logout", () => {
|
|
test("clears state and calls reset on dependencies", async () => {
|
|
// Setup initial state
|
|
const pubkey = "0000000000000000000000000000000000000000000000000000000000000005";
|
|
await authService.login(pubkey);
|
|
|
|
await authService.logout();
|
|
|
|
assert.equal(getPubkey(), null);
|
|
assert.equal(getActiveProfilePubkey(), null);
|
|
|
|
assert.strictEqual(mockNostrClient.logout.mock.callCount(), 1);
|
|
assert.strictEqual(mockUserBlocks.reset.mock.callCount(), 1);
|
|
assert.strictEqual(mockRelayManager.reset.mock.callCount(), 1);
|
|
});
|
|
});
|
|
|
|
describe("requestLogin", () => {
|
|
test("uses provider to login", async () => {
|
|
const pubkey = "0000000000000000000000000000000000000000000000000000000000000001";
|
|
mockAuthProvider.login.mock.mockImplementation(async () => ({ pubkey, authType: "nip07" }));
|
|
|
|
const result = await authService.requestLogin({ providerId: "nip07" });
|
|
|
|
assert.equal(result.pubkey, pubkey);
|
|
assert.strictEqual(mockAuthProvider.login.mock.callCount(), 1);
|
|
// requestLogin calls login() internally if autoApply is true (default)
|
|
assert.equal(getPubkey(), pubkey);
|
|
});
|
|
|
|
test("does not call login if autoApply is false", async () => {
|
|
const pubkey = "0000000000000000000000000000000000000000000000000000000000000001";
|
|
mockAuthProvider.login.mock.mockImplementation(async () => ({ pubkey, authType: "nip07" }));
|
|
|
|
await authService.requestLogin({ providerId: "nip07", autoApply: false });
|
|
|
|
assert.equal(getPubkey(), null);
|
|
});
|
|
});
|
|
|
|
describe("switchProfile", () => {
|
|
test("switches to an existing profile", async () => {
|
|
const pubkey1 = "0000000000000000000000000000000000000000000000000000000000000001";
|
|
const pubkey2 = "0000000000000000000000000000000000000000000000000000000000000002";
|
|
|
|
await authService.login(pubkey1);
|
|
// Reset mocks to clear login calls
|
|
mockRelayManager.loadRelayList.mock.resetCalls();
|
|
|
|
// Mock login for switch
|
|
mockAuthProvider.login.mock.mockImplementation(async () => ({ pubkey: pubkey2, authType: "nip07" }));
|
|
|
|
await authService.switchProfile(pubkey2, { providerId: "nip07" });
|
|
|
|
assert.equal(getPubkey(), pubkey2);
|
|
assert.equal(getActiveProfilePubkey(), pubkey2);
|
|
});
|
|
|
|
test("reorders saved profiles on switch", async () => {
|
|
const pubkey1 = "0000000000000000000000000000000000000000000000000000000000000001";
|
|
const pubkey2 = "0000000000000000000000000000000000000000000000000000000000000002";
|
|
|
|
await authService.login(pubkey1);
|
|
await authService.login(pubkey2);
|
|
|
|
// At this point pubkey2 is active and likely last or first in savedProfiles depending on implementation.
|
|
// mutateSavedProfiles pushes to end if new.
|
|
// So [pubkey1, pubkey2].
|
|
|
|
let saved = getSavedProfiles();
|
|
assert.equal(saved.length, 2);
|
|
assert.equal(saved[1].pubkey, pubkey2);
|
|
|
|
// Switch back to pubkey1
|
|
mockAuthProvider.login.mock.mockImplementation(async () => ({ pubkey: pubkey1, authType: "nip07" }));
|
|
await authService.switchProfile(pubkey1);
|
|
|
|
saved = getSavedProfiles();
|
|
// Should be moved to front?
|
|
// Code says: if (index > 0) { const [moved] = draft.splice(index, 1); draft.unshift(moved); }
|
|
// So yes, moved to front.
|
|
assert.equal(saved[0].pubkey, pubkey1);
|
|
});
|
|
});
|
|
});
|