Skip to content

Commit

Permalink
Merge pull request #238 from hypercerts-org/feat/parse_uri_testing
Browse files Browse the repository at this point in the history
Parse URI event testing
  • Loading branch information
bitbeckers authored Jan 3, 2025
2 parents 18aef04 + 4cd95a0 commit 04d45e2
Show file tree
Hide file tree
Showing 6 changed files with 321 additions and 4 deletions.
6 changes: 6 additions & 0 deletions src/types/database-generated.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,7 @@ export type Database = {
owner_id: string | null
path_tokens: string[] | null
updated_at: string | null
user_metadata: Json | null
version: string | null
}
Insert: {
Expand All @@ -713,6 +714,7 @@ export type Database = {
owner_id?: string | null
path_tokens?: string[] | null
updated_at?: string | null
user_metadata?: Json | null
version?: string | null
}
Update: {
Expand All @@ -726,6 +728,7 @@ export type Database = {
owner_id?: string | null
path_tokens?: string[] | null
updated_at?: string | null
user_metadata?: Json | null
version?: string | null
}
Relationships: [
Expand All @@ -747,6 +750,7 @@ export type Database = {
key: string
owner_id: string | null
upload_signature: string
user_metadata: Json | null
version: string
}
Insert: {
Expand All @@ -757,6 +761,7 @@ export type Database = {
key: string
owner_id?: string | null
upload_signature: string
user_metadata?: Json | null
version: string
}
Update: {
Expand All @@ -767,6 +772,7 @@ export type Database = {
key?: string
owner_id?: string | null
upload_signature?: string
user_metadata?: Json | null
version?: string
}
Relationships: [
Expand Down
226 changes: 226 additions & 0 deletions test/parsing/parseUriEvent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { parseUriEvent } from "../../src/parsing/parseUriEvent";
import { supabase } from "../../src/clients/supabaseClient";
import { mockMerkleTree } from "../test-utils/mockMerkleTree";
import { mockGeoJson } from "../test-utils/mockGeoJson";

// Mock dependencies
vi.mock("@/clients/supabaseClient", () => ({
supabase: {
rpc: vi.fn(() => ({
throwOnError: () => ({ data: "mock-claim-id" }),
})),
},
}));

describe("parseUriEvent", () => {
const mockBlock = {
timestamp: "1234567890",
blockNumber: 123456,
};

const mockContext = {
getData: vi.fn(),
block: mockBlock,
chain_id: 1,
};

beforeEach(() => {
vi.clearAllMocks();
});

it("should return unparsed result for invalid URIs", async () => {
const mockEvent = {
address: "0x1234567890123456789012345678901234567890",
params: {
value: "ipfs://null",
id: BigInt(1),
},
};

const result = await parseUriEvent({
event: mockEvent,
context: mockContext,
});

expect(result).toEqual([
{
metadata: {
uri: "ipfs://null",
parsed: false,
},
},
]);
});

it("should return unparsed result when getData fails", async () => {
const mockEvent = {
address: "0x1234567890123456789012345678901234567890",
params: {
value: "ipfs://valid",
id: BigInt(1),
},
};

mockContext.getData.mockResolvedValueOnce(null);

const result = await parseUriEvent({
event: mockEvent,
context: mockContext,
});

expect(result).toEqual([
{
metadata: {
uri: "ipfs://valid",
parsed: false,
},
},
]);
});

it("should successfully parse valid metadata without allowlist", async () => {
const mockEvent = {
address: "0x1234567890123456789012345678901234567890",
params: {
value: "ipfs://valid",
id: BigInt(1),
},
};

const mockMetadata = {
name: "Test Hypercert",
description: "Test Description",
image: "ipfs://image",
hypercert: {
contributors: { value: ["contributor1"] },
impact_scope: { value: ["scope1"] },
work_scope: { value: ["work1"] },
impact_timeframe: { value: [1000, 2000] },
work_timeframe: { value: [1000, 2000] },
rights: { value: ["right1"] },
},
};

mockContext.getData.mockResolvedValueOnce(mockMetadata);

const result = await parseUriEvent({
event: mockEvent,
context: mockContext,
});

expect(result[0].metadata).toMatchObject({
name: "Test Hypercert",
description: "Test Description",
image: "ipfs://image",
contributors: ["contributor1"],
parsed: true,
uri: "ipfs://valid",
});
});

it("should handle metadata with allowlist", async () => {
const mockEvent = {
address: "0x1234567890123456789012345678901234567890",
params: {
value: "ipfs://valid",
id: BigInt(1),
},
};

const mockMetadata = {
name: "Test Hypercert",
description: "Test Description",
image: "ipfs://image",
allowList: "ipfs://allowlist",
hypercert: {
contributors: { value: ["contributor1"] },
impact_scope: { value: ["scope1"] },
work_scope: { value: ["work1"] },
impact_timeframe: { value: [1000, 2000] },
work_timeframe: { value: [1000, 2000] },
rights: { value: ["right1"] },
},
};

// Mock allowlist data
const mockAllowlistData = mockMerkleTree;

console.log("mockAllowlistData", mockAllowlistData);

mockContext.getData
.mockResolvedValueOnce(mockMetadata)
.mockResolvedValueOnce(mockAllowlistData);

const result = await parseUriEvent({
event: mockEvent,
context: mockContext,
});

expect(result[0].metadata.allow_list_uri).toBe("ipfs://allowlist");
expect(result[0].allow_list).toBeDefined();
expect(result[0].allow_list?.parsed).toBe(true);
expect(result[0].hypercert_allow_list).toBeDefined();
expect(supabase.rpc).toHaveBeenCalled();
});

it("should throw error for invalid event data", async () => {
const mockEvent = {
address: "invalid-address",
params: {
value: "ipfs://valid",
id: BigInt(1),
},
};

await expect(
parseUriEvent({
event: mockEvent,
context: mockContext,
}),
).rejects.toThrow();
});

describe("should support different trait_types in metadata.properties", () => {
it("should successfully parse valid metadata with GeoJSON", async () => {
const mockEvent = {
address: "0x1234567890123456789012345678901234567890",
params: {
value: "ipfs://valid",
id: BigInt(1),
},
};

const mockMetadata = {
name: "Test Hypercert",
description: "Test Description",
image: "ipfs://image",
hypercert: {
contributors: { value: ["contributor1"] },
impact_scope: { value: ["scope1"] },
work_scope: { value: ["work1"] },
impact_timeframe: { value: [1000, 2000] },
work_timeframe: { value: [1000, 2000] },
rights: { value: ["right1"] },
},
properties: [mockGeoJson],
};

mockContext.getData.mockResolvedValueOnce(mockMetadata);

const result = await parseUriEvent({
event: mockEvent,
context: mockContext,
});

expect(result[0].metadata).toMatchObject({
name: "Test Hypercert",
description: "Test Description",
image: "ipfs://image",
contributors: ["contributor1"],
parsed: true,
uri: "ipfs://valid",
});
});
});
});
5 changes: 5 additions & 0 deletions test/test-utils/mockGeoJson.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const mockGeoJson = {
trait_type: "GeoJSON",
value:
'{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[126.30769314,8.9152762],[126.30784606,8.91580754],[126.30770658,8.91596653],[126.3076288,8.91707414],[126.30783265,8.91750717],[126.30782192,8.91772975],[126.30778168,8.91795763],[126.30752956,8.91827826],[126.30739008,8.91869692],[126.30757515,8.91906789],[126.30747859,8.92022054],[126.30793725,8.92079819],[126.30859439,8.92081144],[126.30859439,8.92103402],[126.30876874,8.92129105],[126.30901282,8.92162227],[126.30935614,8.92204093],[126.31048803,8.92412363],[126.31056911,8.92432947],[126.31051815,8.92449376],[126.31041086,8.92460769],[126.31024724,8.92465539],[126.31013459,8.92465274],[126.30864865,8.92435862],[126.30622125,8.92377038],[126.30609518,8.92371208],[126.30593157,8.92361404],[126.30512422,8.92272108],[126.30507326,8.92263364],[126.30512422,8.92211958],[126.3051135,8.92146244],[126.30499011,8.92077881],[126.30483455,8.92051913],[126.30409157,8.92015611],[126.30428469,8.91981164],[126.30446172,8.91963676],[126.30426055,8.91938503],[126.30393064,8.91922074],[126.30360878,8.91906175],[126.30350417,8.91861394],[126.30345796,8.91852915],[126.30325947,8.91853445],[126.3030288,8.91756993],[126.30308781,8.9173958],[126.30340968,8.91714142],[126.30363498,8.9166936],[126.30769314,8.9152762]]]]},"properties":{"name":"ForestBench - Cagwait"}}]}',
};
8 changes: 8 additions & 0 deletions test/test-utils/mockMerkleTree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const stringContent =
'{"format":"standard-v1","tree":["0xe582f894ed4599f64aed0c4f6ea1ed2d2f7bca47a11c984e63d823a38d4f43b6"],"values":[{"value":["0x59266D85D94666D037C1e32dAa8FaC9E95CdaFEf",100],"treeIndex":0}],"leafEncoding":["address","uint256"]}';

export const mockMerkleTree = stringContent;
export const incorrectMerkleTree = stringContent.replace(
'"leafEncoding":["address","uint256"]',
'"leafEncoding":[null,null]',
);
72 changes: 72 additions & 0 deletions test/test-utils/mockMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const jsonContent = `{
"name": "Example Hypercert",
"description": "This is where the description of the hypercert will go.",
"external_url": "https://hypercerts.xyz",
"image": "ipfs://bafybeifs7abhcooeelyjxmnlrcd5kuupfl5czhtyub2imzxzccrhzz3bem",
"version": "1.0.0",
"properties": [
{
"trait_type": "Example Property 1",
"value": "Some text here"
},
{
"trait_type": "Example Property 2",
"value": "More text here"
}
],
"hypercert": {
"impact_scope": {
"name": "Impact Scope",
"value": [
"all"
],
"display_value": "All"
},
"work_scope": {
"name": "Work Scope",
"value": [
"art design",
"metadata standards"
],
"display_value": "Art Design & Metadata Standards"
},
"work_timeframe": {
"name": "Work Timeframe",
"value": [
1663819200,
1673163072
],
"display_value": "2022-09-22 \u2192 2023-01-08"
},
"impact_timeframe": {
"name": "Impact Timeframe",
"value": [
1673163072,
0
],
"display_value": "2023-01-08 \u2192 Indefinite"
},
"contributors": {
"name": "Contributors",
"value": [
"0x799B774204A348E1182fE01074C51444bA70A149"
],
"display_value": "0x799...149"
},
"rights": {
"name": "Rights",
"value": [
"public display",
"-transfers"
],
"display_value": "Public display"
}
}
}`;

const mockMetadata = JSON.parse(jsonContent);

const incorrectMetadata = JSON.parse(jsonContent);
incorrectMetadata.hypercert = "";

export { mockMetadata, incorrectMetadata };
8 changes: 4 additions & 4 deletions vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ export default defineConfig({
// If you want a coverage reports even if your tests are failing, include the reportOnFailure option
reportOnFailure: true,
thresholds: {
lines: 15,
branches: 35,
functions: 50,
statements: 15,
lines: 20,
branches: 44,
functions: 58,
statements: 21,
},
include: ["src/**/*.ts"],
exclude: [
Expand Down

0 comments on commit 04d45e2

Please sign in to comment.