Skip to content

Commit

Permalink
Merge pull request #1831 from kleros/fix/sdk-getdispute-answer0
Browse files Browse the repository at this point in the history
Fix: Ensure that SDK getDispute() returns the RTA/Invalid answer
  • Loading branch information
jaybuidl authored Jan 15, 2025
2 parents e65377f + 364cb02 commit 09e3971
Show file tree
Hide file tree
Showing 3 changed files with 229 additions and 1 deletion.
2 changes: 1 addition & 1 deletion kleros-sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kleros/kleros-sdk",
"version": "2.1.10",
"version": "2.1.12",
"description": "SDK for Kleros version 2",
"repository": "[email protected]:kleros/kleros-v2.git",
"homepage": "https://github.com/kleros/kleros-v2/tree/master/kleros-sdk#readme",
Expand Down
11 changes: 11 additions & 0 deletions kleros-sdk/src/utils/getDispute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,16 @@ export const getDispute = async (disputeParameters: GetDisputeParameters): Promi

const populatedTemplate = populateTemplate(templateData, data);

// Filter out any existing answer with id 0 and add our standard Refuse to Arbitrate option
populatedTemplate.answers = [
{
id: "0x0",
title: "Refuse to Arbitrate / Invalid",
description: "Refuse to Arbitrate / Invalid",
reserved: true,
},
...(populatedTemplate.answers?.filter((answer) => answer.id && Number(answer.id) !== 0) || []),
];

return populatedTemplate;
};
217 changes: 217 additions & 0 deletions kleros-sdk/test/getDispute.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { getDispute } from "../src/utils/getDispute";
import fetchDisputeDetails from "../src/requests/fetchDisputeDetails";
import fetchDisputeTemplateFromId from "../src/requests/fetchDisputeTemplateFromId";

// Mock the dependencies
vi.mock("../src/requests/fetchDisputeDetails");
vi.mock("../src/requests/fetchDisputeTemplateFromId");

describe("getDispute", () => {
const mockDisputeId = 123n;
const mockCoreSubgraph = "https://api.thegraph.com/subgraphs/name/kleros/core";
const mockDtrSubgraph = "https://api.thegraph.com/subgraphs/name/kleros/dtr";

const standardRefuseToArbitrateAnswer = {
id: "0x0",
title: "Refuse to Arbitrate / Invalid",
description: "Refuse to Arbitrate / Invalid",
reserved: true,
};

const mockDisputeDetails = {
dispute: {
templateId: 1,
arbitrated: { id: "0x1234" },
arbitrableChainId: 1,
externalDisputeId: 123,
},
};

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

it("should add Refuse to Arbitrate option when answers array is empty", async () => {
const mockTemplate = {
disputeTemplate: {
templateData: JSON.stringify({
title: "Test Dispute",
description: "Test Description",
question: "Test Question",
answers: [],
policyURI: "/ipfs/test",
arbitratorChainID: "1",
arbitratorAddress: "0x1234567890123456789012345678901234567890",
version: "1.0.0",
}),
templateDataMappings: "",
},
};

vi.mocked(fetchDisputeDetails).mockResolvedValue(mockDisputeDetails);
vi.mocked(fetchDisputeTemplateFromId).mockResolvedValue(mockTemplate);

const result = await getDispute({
disputeId: mockDisputeId,
coreSubgraph: mockCoreSubgraph,
dtrSubgraph: mockDtrSubgraph,
});

expect(result?.answers).toHaveLength(1);
expect(result?.answers[0]).toEqual(standardRefuseToArbitrateAnswer);
});

it("should add Refuse to Arbitrate option when it doesn't exist in answers", async () => {
const mockTemplate = {
disputeTemplate: {
templateData: JSON.stringify({
title: "Test Dispute",
description: "Test Description",
question: "Test Question",
answers: [
{
id: "0x1",
title: "Yes",
description: "Yes Description",
},
{
id: "0x2",
title: "No",
description: "No Description",
},
],
policyURI: "/ipfs/test",
arbitratorChainID: "1",
arbitratorAddress: "0x1234567890123456789012345678901234567890",
version: "1.0.0",
}),
templateDataMappings: "",
},
};

vi.mocked(fetchDisputeDetails).mockResolvedValue(mockDisputeDetails);
vi.mocked(fetchDisputeTemplateFromId).mockResolvedValue(mockTemplate);

const result = await getDispute({
disputeId: mockDisputeId,
coreSubgraph: mockCoreSubgraph,
dtrSubgraph: mockDtrSubgraph,
});

expect(result?.answers).toHaveLength(3);
expect(result?.answers[0]).toEqual(standardRefuseToArbitrateAnswer);
expect(result?.answers[1].id).toBe("0x1");
expect(result?.answers[2].id).toBe("0x2");
});

it("should overwrite existing answer with id 0x0 or 0x00", async () => {
// Test with 0x0
const mockTemplate0x0 = {
disputeTemplate: {
templateData: JSON.stringify({
title: "Test Dispute",
description: "Test Description",
question: "Test Question",
answers: [
{
id: "0x0",
title: "Custom Refuse Title",
description: "Custom Refuse Description",
reserved: true,
},
{
id: "0x1",
title: "Yes",
description: "Yes Description",
},
],
policyURI: "/ipfs/test",
arbitratorChainID: "1",
arbitratorAddress: "0x1234567890123456789012345678901234567890",
version: "1.0.0",
}),
templateDataMappings: "",
},
};

vi.mocked(fetchDisputeDetails).mockResolvedValue(mockDisputeDetails);
vi.mocked(fetchDisputeTemplateFromId).mockResolvedValue(mockTemplate0x0);

let result = await getDispute({
disputeId: mockDisputeId,
coreSubgraph: mockCoreSubgraph,
dtrSubgraph: mockDtrSubgraph,
});

expect(result?.answers).toHaveLength(2);
expect(result?.answers[0]).toEqual(standardRefuseToArbitrateAnswer);
expect(result?.answers[1].id).toBe("0x1");

// Test with 0x00
const mockTemplate0x00 = {
disputeTemplate: {
templateData: JSON.stringify({
title: "Test Dispute",
description: "Test Description",
question: "Test Question",
answers: [
{
id: "0x00",
title: "Custom Refuse Title",
description: "Custom Refuse Description",
reserved: true,
},
{
id: "0x1",
title: "Yes",
description: "Yes Description",
},
],
policyURI: "/ipfs/test",
arbitratorChainID: "1",
arbitratorAddress: "0x1234567890123456789012345678901234567890",
version: "1.0.0",
}),
templateDataMappings: "",
},
};

vi.mocked(fetchDisputeTemplateFromId).mockResolvedValue(mockTemplate0x00);

result = await getDispute({
disputeId: mockDisputeId,
coreSubgraph: mockCoreSubgraph,
dtrSubgraph: mockDtrSubgraph,
});

expect(result?.answers).toHaveLength(2);
expect(result?.answers[0]).toEqual(standardRefuseToArbitrateAnswer);
expect(result?.answers[1].id).toBe("0x1");
});

it("should throw NotFoundError when dispute details are not found", async () => {
vi.mocked(fetchDisputeDetails).mockResolvedValue({ dispute: null } as any);

await expect(
getDispute({
disputeId: mockDisputeId,
coreSubgraph: mockCoreSubgraph,
dtrSubgraph: mockDtrSubgraph,
})
).rejects.toThrow("Dispute details not found");
});

it("should throw NotFoundError when template is not found", async () => {
vi.mocked(fetchDisputeDetails).mockResolvedValue(mockDisputeDetails);
vi.mocked(fetchDisputeTemplateFromId).mockResolvedValue(undefined);

await expect(
getDispute({
disputeId: mockDisputeId,
coreSubgraph: mockCoreSubgraph,
dtrSubgraph: mockDtrSubgraph,
})
).rejects.toThrow("Template not found");
});
});

0 comments on commit 09e3971

Please sign in to comment.