Skip to content

Commit beca13e

Browse files
committed
core: mock arweave tests
1 parent d3e810f commit beca13e

2 files changed

Lines changed: 2568 additions & 3 deletions

File tree

packages/wallet/core/test/state/arweave/arweave.test.ts

Lines changed: 113 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,30 @@
1+
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
12
import { Address } from 'ox'
2-
import { describe, expect, it } from 'vitest'
3+
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'
34

45
import { Arweave, Reader, Sequence } from '../../../src/state/index'
56

67
const TEST_TIMEOUT_MS = 20_000
8+
const RECORDING_FILE = new URL('./recording', import.meta.url)
9+
10+
type RecordedRequest = {
11+
method: string
12+
url: string
13+
headers: Record<string, string>
14+
body: string
15+
}
16+
17+
type RecordedResponse = {
18+
status: number
19+
statusText: string
20+
headers: Record<string, string>
21+
body: string
22+
}
23+
24+
type RecordingEntry = {
25+
request: RecordedRequest
26+
response: RecordedResponse
27+
}
728

829
const tests: { [method in keyof Reader]: { [description: string]: Parameters<Reader[method]> } } = {
930
getConfiguration: {
@@ -94,9 +115,98 @@ function normalize(value: any): any {
94115
return value
95116
}
96117

118+
function normalizeHeaders(headers: Headers): Record<string, string> {
119+
return Object.fromEntries([...headers.entries()].sort(([left], [right]) => left.localeCompare(right)))
120+
}
121+
122+
async function serializeRequest(input: RequestInfo | URL, init?: RequestInit): Promise<RecordedRequest> {
123+
const request = new Request(input, init)
124+
125+
return {
126+
method: request.method.toUpperCase(),
127+
url: request.url,
128+
headers: normalizeHeaders(request.headers),
129+
body: request.method === 'GET' || request.method === 'HEAD' ? '' : await request.clone().text(),
130+
}
131+
}
132+
133+
function serializeResponse(response: Response, body: string): RecordedResponse {
134+
return {
135+
status: response.status,
136+
statusText: response.statusText,
137+
headers: normalizeHeaders(response.headers),
138+
body,
139+
}
140+
}
141+
142+
function requestKey(request: RecordedRequest): string {
143+
return JSON.stringify(request)
144+
}
145+
97146
describe('Arweave state reader', () => {
98-
const arweave = new Arweave.Reader()
99-
const sequence = new Sequence.Provider()
147+
let arweave: Arweave.Reader
148+
let sequence: Sequence.Provider
149+
let originalFetch: typeof globalThis.fetch | undefined
150+
151+
beforeAll(() => {
152+
originalFetch = globalThis.fetch
153+
if (!originalFetch) {
154+
throw new Error('fetch is not available')
155+
}
156+
157+
if (existsSync(RECORDING_FILE)) {
158+
const entries = JSON.parse(readFileSync(RECORDING_FILE, 'utf8')) as RecordingEntry[]
159+
const responsesByRequest = new Map<string, RecordedResponse[]>()
160+
161+
for (const entry of entries) {
162+
const key = requestKey(entry.request)
163+
const responses = responsesByRequest.get(key)
164+
165+
if (responses) {
166+
responses.push(entry.response)
167+
} else {
168+
responsesByRequest.set(key, [entry.response])
169+
}
170+
}
171+
172+
globalThis.fetch = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
173+
const request = await serializeRequest(input, init)
174+
const response = responsesByRequest.get(requestKey(request))?.shift()
175+
176+
if (!response) {
177+
throw new Error(`no recorded response for request ${JSON.stringify(request, null, 2)}`)
178+
}
179+
180+
return new Response(response.body, {
181+
status: response.status,
182+
statusText: response.statusText,
183+
headers: response.headers,
184+
})
185+
}) as typeof fetch
186+
} else {
187+
const entries: RecordingEntry[] = []
188+
189+
globalThis.fetch = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
190+
const request = await serializeRequest(input, init)
191+
const response = await originalFetch!(input, init)
192+
const body = await response.clone().text()
193+
194+
entries.push({ request, response: serializeResponse(response, body) })
195+
writeFileSync(RECORDING_FILE, JSON.stringify(entries, null, 2))
196+
197+
return response
198+
}) as typeof fetch
199+
}
200+
201+
arweave = new Arweave.Reader()
202+
sequence = new Sequence.Provider()
203+
})
204+
205+
afterAll(() => {
206+
if (originalFetch) {
207+
globalThis.fetch = originalFetch
208+
}
209+
})
100210

101211
const methods = Object.entries(tests).filter(([, methodTests]) => Object.keys(methodTests).length > 0)
102212
if (methods.length === 0) {

0 commit comments

Comments
 (0)