Files
welshman/packages/app/__tests__/commands.test.ts
T
2025-02-28 15:06:05 -08:00

276 lines
7.1 KiB
TypeScript

import {ctx} from "@welshman/lib"
import {FOLLOWS, MUTES, PINS} from "@welshman/util"
import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"
import {follow, mute, pin, unfollow, unmute, unpin} from "../src/commands"
import * as thunkModule from "../src/thunk"
import {thunkWorker} from "../src/thunk"
import {repository} from "../src/core"
vi.mock(import("@welshman/lib"), async importOriginal => ({
...(await importOriginal()),
ctx: {
app: {
router: {
FromUser: vi.fn().mockReturnValue({
getUrls: vi.fn().mockReturnValue(["relay1", "relay2"]),
}),
},
},
net: {
getExecutor: vi.fn(),
optimizeSubscriptions: vi.fn().mockReturnValue([]),
},
},
}))
vi.mock(import("../src/session"), async importOriginal => ({
...(await importOriginal()),
nip44EncryptToSelf: vi.fn().mockImplementation(text => `encrypted:${text}`),
pubkey: {
get: () => "ee".repeat(32),
subscribe: run => {
run("ee".repeat(32))
return () => null
},
},
}))
describe("commands", () => {
const pubkey1 = "aa".repeat(32)
const pubkey2 = "bb".repeat(32)
const event1 = "ee".repeat(32)
const event2 = "ff".repeat(32)
beforeEach(async () => {
vi.useFakeTimers()
vi.setSystemTime(new Date())
// Reset any module state
vi.resetModules()
// Clear any cached data
vi.clearAllMocks()
repository.load([])
})
afterEach(() => {
vi.clearAllTimers()
vi.useRealTimers()
thunkWorker.clear()
thunkWorker.pause()
thunkWorker.resume()
// vi.resetAllMocks()
})
describe("follow commands", () => {
it("should create new follows list if none exists", async () => {
const publishThunkSpy = vi.spyOn(thunkModule, "publishThunk")
await follow(["p", pubkey1])
await vi.runAllTimersAsync()
expect(publishThunkSpy).toHaveBeenCalledWith(
expect.objectContaining({
event: expect.objectContaining({
kind: FOLLOWS,
tags: expect.arrayContaining([["p", pubkey1]]),
}),
relays: ["relay1", "relay2"],
}),
)
})
it("should use existing follows list if available", async () => {
const publishThunkSpy = vi.spyOn(thunkModule, "publishThunk")
await follow(["p", pubkey1])
await vi.runAllTimersAsync()
await follow(["p", pubkey2])
await vi.runAllTimersAsync()
expect(publishThunkSpy).toHaveBeenCalledWith(
expect.objectContaining({
event: expect.objectContaining({
kind: FOLLOWS,
tags: expect.arrayContaining([
["p", pubkey1],
["p", pubkey2],
]),
}),
relays: ["relay1", "relay2"],
}),
)
})
it("should handle unfollow command", async () => {
const publishThunkSpy = vi.spyOn(thunkModule, "publishThunk")
await follow(["p", pubkey1])
await vi.runAllTimersAsync()
await unfollow(pubkey1)
expect(publishThunkSpy).toHaveBeenCalledWith(
expect.objectContaining({
event: expect.objectContaining({
kind: FOLLOWS,
tags: expect.arrayContaining([]),
}),
relays: ["relay1", "relay2"],
}),
)
})
})
describe("mute commands", () => {
it("should create new mutes list if none exists", async () => {
const publishThunkSpy = vi.spyOn(thunkModule, "publishThunk")
await mute(["p", pubkey1])
await vi.runAllTimersAsync()
expect(publishThunkSpy).toHaveBeenCalledWith({
event: expect.objectContaining({
kind: MUTES,
tags: expect.arrayContaining([["p", pubkey1]]),
}),
relays: ["relay1", "relay2"],
})
})
it("should use existing mutes list if available", async () => {
const publishThunkSpy = vi.spyOn(thunkModule, "publishThunk")
await mute(["p", pubkey1])
await vi.runAllTimersAsync()
await mute(["p", pubkey2])
await vi.runAllTimersAsync()
expect(publishThunkSpy).toHaveBeenCalledWith(
expect.objectContaining({
event: expect.objectContaining({
kind: MUTES,
tags: expect.arrayContaining([
["p", pubkey1],
["p", pubkey2],
]),
}),
relays: ["relay1", "relay2"],
}),
)
})
it("should handle unmute command", async () => {
const publishThunkSpy = vi.spyOn(thunkModule, "publishThunk")
await mute(["p", pubkey1])
await vi.runAllTimersAsync()
await unmute("pubkey1")
expect(publishThunkSpy).toHaveBeenCalledWith(
expect.objectContaining({
event: expect.objectContaining({
kind: MUTES,
tags: expect.arrayContaining([]),
}),
relays: ["relay1", "relay2"],
}),
)
})
})
describe("pin commands", () => {
it("should create new pins list if none exists", async () => {
const publishThunkSpy = vi.spyOn(thunkModule, "publishThunk")
await pin(["e", event1])
await vi.runAllTimersAsync()
expect(publishThunkSpy).toHaveBeenCalledWith(
expect.objectContaining({
event: expect.objectContaining({
kind: PINS,
tags: expect.arrayContaining([["e", event1]]),
}),
relays: ["relay1", "relay2"],
}),
)
})
it("should use existing pins list if available", async () => {
const publishThunkSpy = vi.spyOn(thunkModule, "publishThunk")
await pin(["e", event1])
await vi.runAllTimersAsync()
await pin(["e", event2])
await vi.runAllTimersAsync()
expect(publishThunkSpy).toHaveBeenCalledWith(
expect.objectContaining({
event: expect.objectContaining({
kind: PINS,
tags: expect.arrayContaining([
["e", event1],
["e", event2],
]),
}),
relays: ["relay1", "relay2"],
}),
)
})
it("should handle unpin command", async () => {
const publishThunkSpy = vi.spyOn(thunkModule, "publishThunk")
await pin(["e", event1])
await vi.runAllTimersAsync()
await unpin("event1")
expect(publishThunkSpy).toHaveBeenCalledWith(
expect.objectContaining({
event: expect.objectContaining({
kind: PINS,
tags: expect.arrayContaining([]),
}),
relays: ["relay1", "relay2"],
}),
)
})
})
describe("relay selection", () => {
it("should use correct relays from router", async () => {
const publishThunkSpy = vi.spyOn(thunkModule, "publishThunk")
const mockGetUrls = vi.fn().mockReturnValue(["relay3", "relay4"])
vi.mocked(ctx.app.router.FromUser).mockReturnValue({
getUrls: mockGetUrls,
})
await follow(["p", pubkey1])
expect(ctx.app.router.FromUser).toHaveBeenCalled()
expect(mockGetUrls).toHaveBeenCalled()
expect(publishThunkSpy).toHaveBeenCalledWith(
expect.objectContaining({
relays: ["relay3", "relay4"],
}),
)
})
})
})