Skip to content

Commit 586336d

Browse files
macmac
authored andcommitted
test(koios): add schema tests for voting_procedures and proposal_procedures
1 parent 5294b01 commit 586336d

1 file changed

Lines changed: 268 additions & 0 deletions

File tree

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
import { Schema } from "effect"
2+
import { describe, expect, it } from "vitest"
3+
4+
import { TxInfoSchema } from "../src/sdk/provider/internal/Koios.js"
5+
6+
// Minimal valid TxInfoSchema payload — only fields needed to exercise the new structs
7+
const baseTxInfo = {
8+
tx_hash: "d10133964da9e443b303917fd0b7644ae3d01c133deff85b4f59416c2d00f530",
9+
block_hash: "f144a8264acf4bdfe2e1241170969c930d64ab6b0996a4a45237b623f1dd670e",
10+
block_height: 5385757,
11+
epoch_no: 250,
12+
epoch_slot: 142,
13+
absolute_slot: 22636942,
14+
tx_timestamp: 1614203233,
15+
tx_block_index: 0,
16+
tx_size: 512,
17+
total_output: "157832856",
18+
fee: "172101",
19+
treasury_donation: "0",
20+
deposit: "0",
21+
invalid_before: null,
22+
invalid_after: null,
23+
collateral_inputs: null,
24+
collateral_output: null,
25+
reference_inputs: null,
26+
inputs: [],
27+
outputs: [],
28+
withdrawals: null,
29+
assets_minted: null,
30+
metadata: null,
31+
certificates: null,
32+
native_scripts: null,
33+
plutus_contracts: null,
34+
voting_procedures: null,
35+
proposal_procedures: null
36+
}
37+
38+
describe("Koios TxInfoSchema — voting_procedures & proposal_procedures", () => {
39+
describe("voting_procedures", () => {
40+
it("accepts null", () => {
41+
const result = Schema.decodeUnknownSync(TxInfoSchema)({ ...baseTxInfo, voting_procedures: null })
42+
expect(result.voting_procedures).toBeNull()
43+
})
44+
45+
it("accepts a valid voting procedure array", () => {
46+
const votingProcedures = [
47+
{
48+
proposal_tx_hash: "d10133964da9e443b303917fd0b7644ae3d01c133deff85b4f59416c2d00f530",
49+
proposal_index: 0,
50+
voter_role: "DRep" as const,
51+
voter: "drep1yfhyq6tztjksqqpd5lglc3zr2tn8vylgjh9xzz7n2p4l4lgk3qam3",
52+
voter_hex: "6e4069625cad00002da7d1fc444352e67613e895ca610bd3506bfafd",
53+
vote: "Yes" as const
54+
}
55+
]
56+
const result = Schema.decodeUnknownSync(TxInfoSchema)({ ...baseTxInfo, voting_procedures: votingProcedures })
57+
expect(result.voting_procedures).toHaveLength(1)
58+
expect(result.voting_procedures![0].voter_role).toBe("DRep")
59+
expect(result.voting_procedures![0].vote).toBe("Yes")
60+
})
61+
62+
it("accepts all valid voter_role values", () => {
63+
const roles = ["DRep", "SPO", "ConstitutionalCommittee"] as const
64+
for (const voter_role of roles) {
65+
const result = Schema.decodeUnknownSync(TxInfoSchema)({
66+
...baseTxInfo,
67+
voting_procedures: [
68+
{
69+
proposal_tx_hash: "abc123",
70+
proposal_index: 0,
71+
voter_role,
72+
voter: "voter",
73+
voter_hex: "abcd",
74+
vote: "No"
75+
}
76+
]
77+
})
78+
expect(result.voting_procedures![0].voter_role).toBe(voter_role)
79+
}
80+
})
81+
82+
it("accepts all valid vote values", () => {
83+
const votes = ["Yes", "No", "Abstain"] as const
84+
for (const vote of votes) {
85+
const result = Schema.decodeUnknownSync(TxInfoSchema)({
86+
...baseTxInfo,
87+
voting_procedures: [
88+
{
89+
proposal_tx_hash: "abc",
90+
proposal_index: 0,
91+
voter_role: "SPO",
92+
voter: "v",
93+
voter_hex: "ff",
94+
vote
95+
}
96+
]
97+
})
98+
expect(result.voting_procedures![0].vote).toBe(vote)
99+
}
100+
})
101+
102+
it("rejects an unknown voter_role", () => {
103+
expect(() =>
104+
Schema.decodeUnknownSync(TxInfoSchema)({
105+
...baseTxInfo,
106+
voting_procedures: [
107+
{
108+
proposal_tx_hash: "abc",
109+
proposal_index: 0,
110+
voter_role: "InvalidRole", // not in the literal union
111+
voter: "v",
112+
voter_hex: "ff",
113+
vote: "Yes"
114+
}
115+
]
116+
})
117+
).toThrow()
118+
})
119+
120+
it("rejects an unknown vote value", () => {
121+
expect(() =>
122+
Schema.decodeUnknownSync(TxInfoSchema)({
123+
...baseTxInfo,
124+
voting_procedures: [
125+
{
126+
proposal_tx_hash: "abc",
127+
proposal_index: 0,
128+
voter_role: "DRep",
129+
voter: "v",
130+
voter_hex: "ff",
131+
vote: "Maybe" // not Yes/No/Abstain
132+
}
133+
]
134+
})
135+
).toThrow()
136+
})
137+
})
138+
139+
describe("proposal_procedures", () => {
140+
it("accepts null", () => {
141+
const result = Schema.decodeUnknownSync(TxInfoSchema)({ ...baseTxInfo, proposal_procedures: null })
142+
expect(result.proposal_procedures).toBeNull()
143+
})
144+
145+
it("accepts a valid InfoAction proposal", () => {
146+
const proposals = [
147+
{
148+
index: 0,
149+
type: "InfoAction" as const,
150+
description: { tag: "InfoAction" },
151+
deposit: "100000000000",
152+
return_address: "stake1uy6yzwsxxc28lfms0qmpxvyz9a7y770rtcqx9y96m42cttqwvp4m5",
153+
expiration: 680,
154+
meta_url: "https://example.com/meta.json",
155+
meta_hash: "dc208474e195442d07a5b6d42af19bb2db02229427dfb53ab23122e6b0e2487d",
156+
withdrawal: null,
157+
param_proposal: null
158+
}
159+
]
160+
const result = Schema.decodeUnknownSync(TxInfoSchema)({ ...baseTxInfo, proposal_procedures: proposals })
161+
expect(result.proposal_procedures).toHaveLength(1)
162+
expect(result.proposal_procedures![0].type).toBe("InfoAction")
163+
expect(result.proposal_procedures![0].expiration).toBe(680)
164+
})
165+
166+
it("accepts a TreasuryWithdrawals proposal with withdrawal array", () => {
167+
const proposals = [
168+
{
169+
index: 0,
170+
type: "TreasuryWithdrawals" as const,
171+
description: { tag: "TreasuryWithdrawals" },
172+
deposit: "100000000000",
173+
return_address: "stake1uy6yzwsxxc28lfms0qmpxvyz9a7y770rtcqx9y96m42cttqwvp4m5",
174+
expiration: null,
175+
meta_url: null,
176+
meta_hash: null,
177+
withdrawal: [
178+
{
179+
stake_address: "stake1uy6yzwsxxc28lfms0qmpxvyz9a7y770rtcqx9y96m42cttqwvp4m5",
180+
amount: "31235800000"
181+
}
182+
],
183+
param_proposal: null
184+
}
185+
]
186+
const result = Schema.decodeUnknownSync(TxInfoSchema)({ ...baseTxInfo, proposal_procedures: proposals })
187+
expect(result.proposal_procedures![0].withdrawal).toHaveLength(1)
188+
expect(result.proposal_procedures![0].withdrawal![0].amount).toBe("31235800000")
189+
})
190+
191+
it("accepts all valid proposal types", () => {
192+
const types = [
193+
"ParameterChange",
194+
"HardForkInitiation",
195+
"TreasuryWithdrawals",
196+
"NoConfidence",
197+
"NewCommittee",
198+
"NewConstitution",
199+
"InfoAction"
200+
] as const
201+
202+
for (const type of types) {
203+
const result = Schema.decodeUnknownSync(TxInfoSchema)({
204+
...baseTxInfo,
205+
proposal_procedures: [
206+
{
207+
index: 0,
208+
type,
209+
description: {},
210+
deposit: "100000000000",
211+
return_address: "stake1abc",
212+
expiration: null,
213+
meta_url: null,
214+
meta_hash: null,
215+
withdrawal: null,
216+
param_proposal: null
217+
}
218+
]
219+
})
220+
expect(result.proposal_procedures![0].type).toBe(type)
221+
}
222+
})
223+
224+
it("rejects an unknown proposal type", () => {
225+
expect(() =>
226+
Schema.decodeUnknownSync(TxInfoSchema)({
227+
...baseTxInfo,
228+
proposal_procedures: [
229+
{
230+
index: 0,
231+
type: "UnknownProposalType", // not in the literal union
232+
description: {},
233+
deposit: "100000000000",
234+
return_address: "stake1abc",
235+
expiration: null,
236+
meta_url: null,
237+
meta_hash: null,
238+
withdrawal: null,
239+
param_proposal: null
240+
}
241+
]
242+
})
243+
).toThrow()
244+
})
245+
246+
it("rejects missing required field (deposit)", () => {
247+
expect(() =>
248+
Schema.decodeUnknownSync(TxInfoSchema)({
249+
...baseTxInfo,
250+
proposal_procedures: [
251+
{
252+
index: 0,
253+
type: "InfoAction",
254+
description: {},
255+
// deposit is missing
256+
return_address: "stake1abc",
257+
expiration: null,
258+
meta_url: null,
259+
meta_hash: null,
260+
withdrawal: null,
261+
param_proposal: null
262+
}
263+
]
264+
})
265+
).toThrow()
266+
})
267+
})
268+
})

0 commit comments

Comments
 (0)