Files
2025-02-25 14:34:49 -08:00

213 lines
5.3 KiB
TypeScript

import {describe, expect, it} from "vitest"
import {defer, makePromise} from "../src/Deferred"
describe("Deferred", () => {
const pubkey = "ee".repeat(32)
const eventId = "ff".repeat(32)
type SuccessResponse = {
eventId: string
pubkey: string
success: true
}
type ErrorResponse = {
code: number
message: string
success: false
}
describe("makePromise", () => {
it("should create a promise that resolves", async () => {
const successData: SuccessResponse = {
eventId: eventId,
pubkey: pubkey,
success: true,
}
const promise = makePromise<SuccessResponse, ErrorResponse>(resolve => {
resolve(successData)
})
const result = await promise
expect(result).toEqual(successData)
})
it("should create a promise that rejects", async () => {
const errorData: ErrorResponse = {
code: 404,
message: "Event not found",
success: false,
}
const promise = makePromise<SuccessResponse, ErrorResponse>((_, reject) => {
reject(errorData)
})
await expect(promise).rejects.toEqual(errorData)
})
it("should handle async operations", async () => {
const successData: SuccessResponse = {
eventId: eventId,
pubkey: pubkey,
success: true,
}
const promise = makePromise<SuccessResponse, ErrorResponse>(resolve => {
setTimeout(() => resolve(successData), 100)
})
const result = await promise
expect(result).toEqual(successData)
})
it("should propagate errors in promise chain", async () => {
const errorData: ErrorResponse = {
code: 500,
message: "Internal error",
success: false,
}
const promise = makePromise<SuccessResponse, ErrorResponse>((_, reject) => {
setTimeout(() => reject(errorData), 100)
})
await expect(promise).rejects.toEqual(errorData)
})
})
describe("defer", () => {
it("should create a deferred promise that can be resolved", async () => {
const deferred = defer<SuccessResponse, ErrorResponse>()
const successData: SuccessResponse = {
eventId: eventId,
pubkey: pubkey,
success: true,
}
// Resolve in next tick to test async behavior
setTimeout(() => {
deferred.resolve(successData)
}, 0)
const result = await deferred
expect(result).toEqual(successData)
})
it("should create a deferred promise that can be rejected", async () => {
const deferred = defer<SuccessResponse, ErrorResponse>()
const errorData: ErrorResponse = {
code: 403,
message: "Unauthorized",
success: false,
}
setTimeout(() => {
deferred.reject(errorData)
}, 0)
await expect(deferred).rejects.toEqual(errorData)
})
it("should handle immediate resolution", async () => {
const deferred = defer<SuccessResponse, ErrorResponse>()
const successData: SuccessResponse = {
eventId: eventId,
pubkey: pubkey,
success: true,
}
deferred.resolve(successData)
const result = await deferred
expect(result).toEqual(successData)
})
it("should handle immediate rejection", async () => {
const deferred = defer<SuccessResponse, ErrorResponse>()
const errorData: ErrorResponse = {
code: 400,
message: "Bad request",
success: false,
}
deferred.reject(errorData)
await expect(deferred).rejects.toEqual(errorData)
})
it("should work with promise chaining", async () => {
const deferred = defer<SuccessResponse, ErrorResponse>()
const successData: SuccessResponse = {
eventId: eventId,
pubkey: pubkey,
success: true,
}
// Create a chain of promises
const chainedPromise = deferred
.then(result => ({
...result,
eventId: result.eventId.toUpperCase(),
}))
.catch(error => {
throw {...error, code: 599}
})
deferred.resolve(successData)
const result = await chainedPromise
expect(result.eventId).toBe(eventId.toUpperCase())
})
it("should handle error propagation in chains", async () => {
const deferred = defer<SuccessResponse, ErrorResponse>()
const errorData: ErrorResponse = {
code: 401,
message: "Unauthorized",
success: false,
}
const chainedPromise = deferred
.then(result => result)
.catch(error => {
throw {...error, code: 599}
})
deferred.reject(errorData)
await expect(chainedPromise).rejects.toEqual({
...errorData,
code: 599,
})
})
it("should maintain type safety with default error type", async () => {
const deferred = defer<string>() // Using default error type
const successData = eventId
const errorData = "Error processing event"
setTimeout(() => {
if (Math.random() > 0.5) {
deferred.resolve(successData)
} else {
deferred.reject(errorData)
}
}, 0)
try {
const result = await deferred
expect(result).toBe(successData)
} catch (error) {
expect(error).toBe(errorData)
}
})
})
})