Skip to content

Commit 893a2d0

Browse files
committed
add tests and docs
1 parent 5cab020 commit 893a2d0

File tree

7 files changed

+505
-15
lines changed

7 files changed

+505
-15
lines changed

packages/gill-extra/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,4 @@ import {
3636

3737
## License
3838

39-
MIT
39+
Copyright (c) 2025 Ian Macalinao. Licensed under the Apache-2.0 License.

packages/gill-extra/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"sideEffects": false,
77
"author": "Ian Macalinao <[email protected]>",
88
"homepage": "https://grill.ianm.com",
9-
"license": "MIT",
9+
"license": "Apache-2.0",
1010
"keywords": [
1111
"solana",
1212
"utilities",
@@ -41,7 +41,7 @@
4141
"clean": "rm -fr dist/ node_modules/ tsconfig.tsbuildinfo",
4242
"typecheck": "tsc --noEmit",
4343
"lint": "eslint . --cache",
44-
"test": "bun test || true"
44+
"test": "bun test src/"
4545
},
4646
"dependencies": {
4747
"@macalinao/dataloader-es": "workspace:*",
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
import { describe, expect, it } from "bun:test";
2+
import { buildGetExplorerLinkFunction } from "./build-get-explorer-link-function.js";
3+
4+
describe("buildGetExplorerLinkFunction", () => {
5+
describe("basic functionality", () => {
6+
it("should create a function that generates explorer links", () => {
7+
const getLink = buildGetExplorerLinkFunction({
8+
baseUrl: "https://explorer.example.com",
9+
});
10+
11+
expect(typeof getLink).toBe("function");
12+
});
13+
14+
it("should use default paths when not specified", () => {
15+
const getLink = buildGetExplorerLinkFunction({
16+
baseUrl: "https://explorer.example.com",
17+
});
18+
19+
const txLink = getLink({ transaction: "abc123" });
20+
expect(txLink).toBe("https://explorer.example.com/tx/abc123");
21+
22+
const addressLink = getLink({ address: "def456" });
23+
expect(addressLink).toBe("https://explorer.example.com/address/def456");
24+
25+
const blockLink = getLink({ block: 789 });
26+
expect(blockLink).toBe("https://explorer.example.com/block/789");
27+
});
28+
29+
it("should use custom paths when specified", () => {
30+
const getLink = buildGetExplorerLinkFunction({
31+
baseUrl: "https://explorer.example.com",
32+
paths: {
33+
transaction: "transaction",
34+
address: "account",
35+
block: "slot",
36+
},
37+
});
38+
39+
const txLink = getLink({ transaction: "abc123" });
40+
expect(txLink).toBe("https://explorer.example.com/transaction/abc123");
41+
42+
const addressLink = getLink({ address: "def456" });
43+
expect(addressLink).toBe("https://explorer.example.com/account/def456");
44+
45+
const blockLink = getLink({ block: 789 });
46+
expect(blockLink).toBe("https://explorer.example.com/slot/789");
47+
});
48+
});
49+
50+
describe("cluster parameters", () => {
51+
it("should add cluster parameter when configured", () => {
52+
const getLink = buildGetExplorerLinkFunction({
53+
baseUrl: "https://explorer.example.com",
54+
clusterParam: {
55+
name: "network",
56+
values: {
57+
devnet: "dev",
58+
testnet: "test",
59+
},
60+
},
61+
});
62+
63+
const devnetLink = getLink({
64+
transaction: "abc123",
65+
cluster: "devnet",
66+
});
67+
expect(devnetLink).toBe(
68+
"https://explorer.example.com/tx/abc123?network=dev",
69+
);
70+
71+
const testnetLink = getLink({
72+
transaction: "abc123",
73+
cluster: "testnet",
74+
});
75+
expect(testnetLink).toBe(
76+
"https://explorer.example.com/tx/abc123?network=test",
77+
);
78+
});
79+
80+
it("should not add cluster parameter when value is not defined", () => {
81+
const getLink = buildGetExplorerLinkFunction({
82+
baseUrl: "https://explorer.example.com",
83+
clusterParam: {
84+
name: "cluster",
85+
values: {
86+
devnet: "devnet",
87+
// mainnet not defined
88+
},
89+
},
90+
});
91+
92+
const mainnetLink = getLink({
93+
transaction: "abc123",
94+
cluster: "mainnet",
95+
});
96+
expect(mainnetLink).toBe("https://explorer.example.com/tx/abc123");
97+
98+
const devnetLink = getLink({
99+
transaction: "abc123",
100+
cluster: "devnet",
101+
});
102+
expect(devnetLink).toBe(
103+
"https://explorer.example.com/tx/abc123?cluster=devnet",
104+
);
105+
});
106+
107+
it("should not add any parameters when clusterParam is not configured", () => {
108+
const getLink = buildGetExplorerLinkFunction({
109+
baseUrl: "https://explorer.example.com",
110+
});
111+
112+
const link = getLink({
113+
transaction: "abc123",
114+
cluster: "devnet",
115+
});
116+
expect(link).toBe("https://explorer.example.com/tx/abc123");
117+
});
118+
});
119+
120+
describe("edge cases", () => {
121+
it("should return base URL when no arguments provided", () => {
122+
const getLink = buildGetExplorerLinkFunction({
123+
baseUrl: "https://explorer.example.com",
124+
});
125+
126+
const link = getLink();
127+
expect(link).toBe("https://explorer.example.com/");
128+
});
129+
130+
it("should return base URL when empty object provided", () => {
131+
const getLink = buildGetExplorerLinkFunction({
132+
baseUrl: "https://explorer.example.com",
133+
});
134+
135+
const link = getLink({});
136+
expect(link).toBe("https://explorer.example.com/");
137+
});
138+
139+
it("should handle baseUrl with trailing slash", () => {
140+
const getLink = buildGetExplorerLinkFunction({
141+
baseUrl: "https://explorer.example.com/",
142+
});
143+
144+
const link = getLink({ transaction: "abc123" });
145+
expect(link).toBe("https://explorer.example.com/tx/abc123");
146+
});
147+
148+
it("should handle block as string or number", () => {
149+
const getLink = buildGetExplorerLinkFunction({
150+
baseUrl: "https://explorer.example.com",
151+
});
152+
153+
const numberLink = getLink({ block: 123456 });
154+
expect(numberLink).toBe("https://explorer.example.com/block/123456");
155+
156+
const stringLink = getLink({ block: "123456" });
157+
expect(stringLink).toBe("https://explorer.example.com/block/123456");
158+
});
159+
});
160+
161+
describe("URL encoding", () => {
162+
it("should properly encode special characters in paths", () => {
163+
const getLink = buildGetExplorerLinkFunction({
164+
baseUrl: "https://explorer.example.com",
165+
});
166+
167+
const link = getLink({ transaction: "abc+123/def" });
168+
// URL constructor handles encoding automatically
169+
expect(link).toBe("https://explorer.example.com/tx/abc+123/def");
170+
});
171+
172+
it("should properly encode cluster parameter values", () => {
173+
const getLink = buildGetExplorerLinkFunction({
174+
baseUrl: "https://explorer.example.com",
175+
clusterParam: {
176+
name: "cluster",
177+
values: {
178+
devnet: "dev net", // space in value
179+
},
180+
},
181+
});
182+
183+
const link = getLink({
184+
transaction: "abc123",
185+
cluster: "devnet",
186+
});
187+
// URLSearchParams should encode the space as +
188+
expect(link).toBe(
189+
"https://explorer.example.com/tx/abc123?cluster=dev+net",
190+
);
191+
});
192+
});
193+
194+
describe("real-world examples", () => {
195+
it("should work for Solscan-like configuration", () => {
196+
const getLink = buildGetExplorerLinkFunction({
197+
baseUrl: "https://solscan.io",
198+
paths: {
199+
transaction: "tx",
200+
address: "account",
201+
block: "block",
202+
},
203+
clusterParam: {
204+
name: "cluster",
205+
values: {
206+
devnet: "devnet",
207+
testnet: "testnet",
208+
},
209+
},
210+
});
211+
212+
const mainnetTx = getLink({ transaction: "sig123" });
213+
expect(mainnetTx).toBe("https://solscan.io/tx/sig123");
214+
215+
const devnetTx = getLink({
216+
transaction: "sig123",
217+
cluster: "devnet",
218+
});
219+
expect(devnetTx).toBe("https://solscan.io/tx/sig123?cluster=devnet");
220+
221+
const address = getLink({ address: "addr456" });
222+
expect(address).toBe("https://solscan.io/account/addr456");
223+
});
224+
225+
it("should work for Solana Explorer-like configuration", () => {
226+
const getLink = buildGetExplorerLinkFunction({
227+
baseUrl: "https://explorer.solana.com",
228+
paths: {
229+
transaction: "tx",
230+
address: "address",
231+
block: "block",
232+
},
233+
clusterParam: {
234+
name: "cluster",
235+
values: {
236+
devnet: "devnet",
237+
testnet: "testnet",
238+
"mainnet-beta": "mainnet-beta",
239+
},
240+
},
241+
});
242+
243+
const mainnetTx = getLink({
244+
transaction: "sig123",
245+
cluster: "mainnet",
246+
});
247+
expect(mainnetTx).toBe("https://explorer.solana.com/tx/sig123");
248+
249+
const betaTx = getLink({
250+
transaction: "sig123",
251+
cluster: "mainnet-beta",
252+
});
253+
expect(betaTx).toBe(
254+
"https://explorer.solana.com/tx/sig123?cluster=mainnet-beta",
255+
);
256+
});
257+
});
258+
});

0 commit comments

Comments
 (0)