Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More test cases #297

Open
wants to merge 16 commits into
base: dev
Choose a base branch
from
6 changes: 3 additions & 3 deletions packages/core-sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@story-protocol/core-sdk",
"version": "1.2.0-rc.0",
"version": "1.2.0-rc.1",
"description": "Story Protocol Core SDK",
"main": "dist/story-protocol-core-sdk.cjs.js",
"module": "dist/story-protocol-core-sdk.esm.js",
Expand All @@ -17,9 +17,9 @@
],
"scripts": {
"build": "pnpm run fix && preconstruct build",
"test": "pnpm run test:unit",
"test": "pnpm run test:integration",
"test:unit": "TS_NODE_PROJECT='./tsconfig.test.json' c8 --all --src ./src mocha -r ts-node/register './test/unit/**/*.test.ts'",
"test:integration": "TS_NODE_PROJECT='./tsconfig.test.json' mocha -r ts-node/register './test/integration/**/*.test.ts' --timeout 240000",
"test:integration": "TS_NODE_PROJECT='./tsconfig.test.json' mocha -r ts-node/register './test/integration/**/*.test.ts' --timeout 960000",
"fix": "pnpm run format:fix && pnpm run lint:fix",
"format": "prettier --check .",
"format:fix": "prettier --write .",
Expand Down
2 changes: 1 addition & 1 deletion packages/core-sdk/src/resources/nftClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class NftClient {
* @param request.isPublicMinting - If true, anyone can mint from the collection. If false, only the addresses with the minter role can mint.
* @param request.mintOpen Whether the collection is open for minting on creation.
* @param request.mintFeeRecipient - The address to receive mint fees.
* @param request.mintFeeRecipient - The contract URI for the collection. Follows ERC-7572 standard. See https://eips.ethereum.org/EIPS/eip-7572
* @param request.contractURI - The contract URI for the collection. Follows ERC-7572 standard. See https://eips.ethereum.org/EIPS/eip-7572
* @param request.baseURI - [Optional] The base URI for the collection. If baseURI is not empty, tokenURI will be either baseURI + token ID (if nftMetadataURI is empty) or baseURI + nftMetadataURI.
* @param request.maxSupply - [Optional] The maximum supply of the collection.
* @param request.mintFee - [Optional] The cost to mint a token.
Expand Down
6 changes: 2 additions & 4 deletions packages/core-sdk/test/integration/ipAsset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,11 @@ describe("IP Asset Functions ", () => {
parentIpIds: [parentIpId!],
licenseTermsIds: [licenseTermsId!],
},
deadline: 1000n,
txOptions: {
waitForTransaction: true,
ipMetadata: {
ipMetadataHash: toHex("test-metadata", { size: 32 }),
},
});
expect(result.txHash).to.be.a("string").and.not.empty;
expect(result.ipId).to.be.a("string").and.not.empty;
});

it("should not throw error when register ip and attach pil terms", async () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/core-sdk/test/integration/utils/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { chainStringToViemChain, waitTx } from "../../../src/utils/utils";
import { http, createPublicClient, createWalletClient, Hex, Address } from "viem";
import { StoryClient, StoryConfig } from "../../../src";
import {
licenseTokenAbi,
licenseTokenAddress,
spgnftBeaconAddress,
licenseTokenAddress,
licenseTokenAbi,
} from "../../../src/abi/generated";
export const RPC = "https://odyssey.storyrpc.io";
export const odyssey = 1516;
Expand Down
10 changes: 0 additions & 10 deletions packages/core-sdk/test/unit/resources/dispute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,5 @@ describe("Test DisputeClient", () => {

expect(result.txHash).equal(txHash);
});

it("should return encodedTxData when call resolveDispute successfully with encodedTxDataOnly", async () => {
const result = await disputeClient.resolveDispute({
disputeId: 1,
data: "0x",
txOptions: { encodedTxDataOnly: true },
});

expect(result.encodedTxData?.data).to.be.a("string").and.not.empty;
});
});
});
100 changes: 97 additions & 3 deletions packages/core-sdk/test/unit/resources/ipAccount.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,21 @@ describe("Test IPAccountClient", () => {
sinon.stub(IpAccountImplClient.prototype, "execute").resolves(txHash);
sinon.stub(IpAccountImplClient.prototype, "executeEncode").returns({ data: "0x", to: "0x" });
sinon.stub(IpAccountImplClient.prototype, "executeWithSig").resolves(txHash);
sinon
.stub(IpAccountImplClient.prototype, "state")
.resolves({ result: "0x73fcb515cee99e4991465ef586cfe2b072ebb512" });

// Make the state stub dynamic, so it can throw errors for specific tests
sinon.stub(IpAccountImplClient.prototype, "state").callsFake(async () => {
if (shouldThrowError) {
throw new Error("Network Error");
}
return { result: "0x73fcb515cee99e4991465ef586cfe2b072ebb512" };
});
});

// A flag to control behavior in tests
let shouldThrowError = false;

afterEach(() => {
sinon.restore();
});

afterEach(() => {
Expand Down Expand Up @@ -89,6 +101,38 @@ describe("Test IPAccountClient", () => {

expect(result.encodedTxData?.data).to.be.a("string").and.not.empty;
});

// Test execute - @boris added test cases
it("should throw error when value is a negative number", async () => {
const request: IPAccountExecuteRequest = {
ipId: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c",
to: zeroAddress,
value: -2, // negative value
data: "0x11111111111111111111111111111",
};
try {
await ipAccountClient.execute(request);
} catch (err) {
expect((err as Error).message).to.include("Failed to execute the IP Account transaction");
}
});

it("should handle partially defined txOptions (encodedTxDataOnly without waitForTransaction)", async () => {
IpAccountImplClient.prototype.executeEncode = sinon.stub().returns("0xencodedTxData");

const result = await ipAccountClient.execute({
ipId: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c",
to: zeroAddress,
value: 2,
data: "0x11111111111111111111111111111",
txOptions: {
encodedTxDataOnly: true,
// waitForTransaction is not defined
},
});

expect(result.encodedTxData).to.equal("0xencodedTxData");
});
});

describe("Test executeWithSig", () => {
Expand Down Expand Up @@ -159,6 +203,30 @@ describe("Test IPAccountClient", () => {

expect(result.encodedTxData?.data).to.be.a("string").and.not.empty;
});

// Test executeWithSig - @boris added test cases

it("should handle network errors in executeWithSig", async () => {
IpAccountImplClient.prototype.executeWithSig = sinon
.stub()
.rejects(new Error("Network Error"));
const request: IPAccountExecuteWithSigRequest = {
ipId: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c",
to: zeroAddress,
value: 2,
data: "0x11111111111111111111111111111",
signer: zeroAddress,
deadline: 20,
signature: zeroAddress,
};
try {
await ipAccountClient.executeWithSig(request);
} catch (err) {
expect((err as Error).message).to.equal(
"Failed to execute with signature for the IP Account transaction: Network Error",
);
}
});
});

describe("Test getIpAccountNonce", () => {
Expand All @@ -177,6 +245,21 @@ describe("Test IPAccountClient", () => {
);
expect(state).to.equal("0x73fcb515cee99e4991465ef586cfe2b072ebb512");
});

// Test getIpAccountNonce - @boris added test cases

it("should handle network errors in getIpAccountNonce", async () => {
shouldThrowError = true; // Cause the error to be thrown
try {
await ipAccountClient.getIpAccountNonce("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c");
} catch (err) {
expect((err as Error).message).to.equal(
"Failed to get the IP Account nonce: Network Error",
);
} finally {
shouldThrowError = false; // Reset the flag for other tests
}
});
});

describe("Test getToken", () => {
Expand All @@ -196,4 +279,15 @@ describe("Test IPAccountClient", () => {
expect(token).to.deep.equal({ chainId: 1513n, tokenContract: zeroAddress, tokenId: 1n });
});
});

// Test getToken - @boris added test cases

it("should handle network errors in getToken", async () => {
sinon.stub(IpAccountImplClient.prototype, "token").rejects(new Error("Network Error"));
try {
await ipAccountClient.getToken("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c");
} catch (err) {
expect((err as Error).message).to.equal("Failed to get the token: Network Error");
}
});
});
118 changes: 118 additions & 0 deletions packages/core-sdk/test/unit/resources/ipAsset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,25 @@ describe("Test IpAssetClient", () => {
expect(metadata).to.have.property("customField1", "Custom Value 1");
expect(metadata).to.have.property("customField2", 42);
});

// generateIpMetadata - @boris added test cases

it("should create an IpMetadata object with default values when optional parameters are missing", function () {
const metadata = ipAssetClient.generateIpMetadata({ title: "Sample Title" });

expect(metadata).to.be.an("object");
expect(metadata).to.have.property("title", "Sample Title");
expect(metadata).to.have.property("description", "");
expect(metadata).to.have.property("ipType", "");
expect(metadata).to.have.property("relationships").that.is.an("array").and.empty;
expect(metadata).to.have.property("createdAt", "");
expect(metadata).to.have.property("watermarkImg", "");
expect(metadata).to.have.property("creators").that.is.an("array").and.empty;
expect(metadata).to.have.property("media").that.is.an("array").and.empty;
expect(metadata).to.have.property("attributes").that.is.an("array").and.empty;
expect(metadata).to.have.property("tags").that.is.an("array").and.empty;
expect(metadata).to.have.property("robotTerms", undefined);
});
});
});

Expand Down Expand Up @@ -688,6 +707,59 @@ describe("Test IpAssetClient", () => {

expect(res.encodedTxData!.data).to.be.a("string").and.not.empty;
});

describe("registerDerivativeWithLicenseTokens", function () {
it("should handle concurrent transactions correctly", async function () {
sinon.stub(ipAssetClient.ipAssetRegistryClient, "isRegistered").resolves(true);
sinon
.stub(ipAssetClient.licenseTokenReadOnlyClient, "ownerOf")
.resolves("0x73fcb515cee99e4991465ef586cfe2b072ebb512");
sinon
.stub(ipAssetClient.licensingModuleClient, "registerDerivativeWithLicenseTokens")
.resolves("0xtesthash");

const response1 = ipAssetClient.registerDerivativeWithLicenseTokens({
childIpId: "0xd142822Dc1674154EaF4DDF38bbF7EF8f0D8ECe4",
licenseTokenIds: ["1"],
});

const response2 = ipAssetClient.registerDerivativeWithLicenseTokens({
childIpId: "0xd142822Dc1674154EaF4DDF38bbF7EF8f0D8ECe4",
licenseTokenIds: ["2"],
});

const [result1, result2] = await Promise.all([response1, response2]);

expect(result1.txHash).to.equal("0xtesthash");
expect(result2.txHash).to.equal("0xtesthash");
});
});

// registerDerivativeWithLicenseTokens - @boris added test cases
it("should handle concurrent transactions correctly", async function () {
sinon.stub(ipAssetClient.ipAssetRegistryClient, "isRegistered").resolves(true);
sinon
.stub(ipAssetClient.licenseTokenReadOnlyClient, "ownerOf")
.resolves("0x73fcb515cee99e4991465ef586cfe2b072ebb512");
sinon
.stub(ipAssetClient.licensingModuleClient, "registerDerivativeWithLicenseTokens")
.resolves("0xtesthash");

const response1 = ipAssetClient.registerDerivativeWithLicenseTokens({
childIpId: "0xd142822Dc1674154EaF4DDF38bbF7EF8f0D8ECe4",
licenseTokenIds: ["1"],
});

const response2 = ipAssetClient.registerDerivativeWithLicenseTokens({
childIpId: "0xd142822Dc1674154EaF4DDF38bbF7EF8f0D8ECe4",
licenseTokenIds: ["2"],
});

const [result1, result2] = await Promise.all([response1, response2]);

expect(result1.txHash).to.equal("0xtesthash");
expect(result2.txHash).to.equal("0xtesthash");
});
});

describe("Test ipAssetClient.createIpAssetWithPilTerms", async () => {
Expand Down Expand Up @@ -806,6 +878,23 @@ describe("Test IpAssetClient", () => {

expect(result.encodedTxData!.data).to.be.a("string").and.not.empty;
});

// Test ipAssetClient.createIpAssetWithPilTerms - @boris added test cases

it("should throw an error when `nftContract` is an invalid address", async function () {
try {
await ipAssetClient.mintAndRegisterIpAssetWithPilTerms({
spgNftContract: "0x",
pilType: PIL_TYPE.COMMERCIAL_USE,
mintingFee: "100",
currency: zeroAddress,
});
} catch (err) {
expect((err as Error).message).to.equal(
"Failed to mint and register IP and attach PIL terms: request.spgNftContract address is invalid: 0x, Address must be a hex value of 20 bytes (40 hex characters) and match its checksum counterpart.",
);
}
});
});

describe("Test ipAssetClient.registerDerivativeIp", async () => {
Expand Down Expand Up @@ -1200,6 +1289,35 @@ describe("Test IpAssetClient", () => {

expect(result.encodedTxData!.data).to.be.a("string").and.not.empty;
});

// registerIpAndAttachPilTerms - @boris added test cases

it("should handle missing optional parameters correctly", async function () {
const stub = sinon.stub(
ipAssetClient.licenseAttachmentWorkflowsClient,
"registerIpAndAttachPilTerms",
);
sinon
.stub(ipAssetClient.ipAssetRegistryClient, "ipId")
.resolves("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c");
sinon.stub(ipAssetClient.ipAssetRegistryClient, "isRegistered").resolves(false);

await ipAssetClient.registerIpAndAttachPilTerms({
nftContract: spgNftContract, // This is assumed to be a valid contract address
tokenId: "3", // Token ID as a string
pilType: PIL_TYPE.COMMERCIAL_USE, // Required type
mintingFee: "0", // Add a valid minting fee (e.g., "0" or "100")
currency: zeroAddress, // Add the zero address or a valid ERC20 address
});

expect(stub.calledOnce).to.be.true;
expect(stub.args[0][0].ipMetadata).to.deep.equal({
ipMetadataURI: "",
ipMetadataHash: zeroHash,
nftMetadataURI: "",
nftMetadataHash: zeroHash,
});
});
});

describe("Test ipAssetClient.mintAndRegisterIpAndMakeDerivative", async () => {
Expand Down
Loading
Loading