Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"test": "jest --runInBand",
"test:watch": "jest --watch --runInBand",
"test:coverage": "jest --coverage --runInBand",
"tsup": "tsup src/index.ts --dts --format cjs,esm --out-dir dist"
},
"author": "",
Expand Down
285 changes: 285 additions & 0 deletions test/integration/acpClient.integration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
import { Address } from "viem";
import AcpClient from "../../src/acpClient";
import AcpContractClientV2 from "../../src/contractClients/acpContractClientV2";
import {
AcpAgentSort,
AcpGraduationStatus,
AcpOnlineStatus,
} from "../../src/interfaces";
import AcpJobOffering from "../../src/acpJobOffering";
import AcpJob from "../../src/acpJob";
import {
WHITELISTED_WALLET_PRIVATE_KEY,
BUYER_ENTITY_ID,
BUYER_AGENT_WALLET_ADDRESS,
} from "../env";
import { testBaseAcpConfigV2 } from "../testConfigs";

describe("AcpClient Integration Testing", () => {
let acpClient: AcpClient;
let contractClient: AcpContractClientV2;

beforeAll(async () => {
contractClient = await AcpContractClientV2.build(
WHITELISTED_WALLET_PRIVATE_KEY as Address,
BUYER_ENTITY_ID,
BUYER_AGENT_WALLET_ADDRESS as Address,
testBaseAcpConfigV2,
);

acpClient = new AcpClient({ acpContractClient: contractClient });
}, 45000);

describe("Initialization (init)", () => {
it("should initialize client successfully", () => {
expect(acpClient).toBeDefined();
expect(acpClient).toBeInstanceOf(AcpClient);
});

it("should have correct wallet address", () => {
expect(acpClient.walletAddress).toBe(BUYER_AGENT_WALLET_ADDRESS);
});

it("should have valid acpUrl", () => {
expect(acpClient.acpUrl).toBeDefined();
expect(acpClient.acpUrl).toBe("https://acpx.virtuals.io");
});

it("should have contract client initialized", () => {
expect(acpClient.acpContractClient).toBeDefined();
expect(acpClient.acpContractClient).toBe(contractClient);
});

it("should establish socket connection on initialization", (done) => {
// The socket connection is established in the constructor via init()
// If we reach this point without errors, the connection was successful
expect(acpClient).toBeDefined();

// Give socket time to connect
setTimeout(() => {
// If no connection errors thrown, test passes
done();
}, 2000);
}, 10000);

it("should handle onNewTask callback when provided", (done) => {
const onNewTaskMock = jest.fn((job: AcpJob) => {
expect(job).toBeInstanceOf(AcpJob);
done();
});

// Create a new client with callback
const clientWithCallback = new AcpClient({
acpContractClient: contractClient,
onNewTask: onNewTaskMock,
});

expect(clientWithCallback).toBeDefined();

// Note: This test will pass even if event doesn't fire
// Real socket event testing would require triggering an actual job
setTimeout(() => {
if (onNewTaskMock.mock.calls.length === 0) {
// No event fired, but that's expected in test environment
done();
}
}, 5000);
}, 10000);

it("should handle onEvaluate callback when provided", (done) => {
const onEvaluateMock = jest.fn((job: AcpJob) => {
expect(job).toBeInstanceOf(AcpJob);
done();
});

const clientWithCallback = new AcpClient({
acpContractClient: contractClient,
onEvaluate: onEvaluateMock,
});

expect(clientWithCallback).toBeDefined();

setTimeout(() => {
if (onEvaluateMock.mock.calls.length === 0) {
done();
}
}, 5000);
}, 10000);
});

describe("Agent Browsing (browseAgents)", () => {
it("should browse agents with keyword", async () => {
const keyword = "trading";
const options = {
top_k: 5,
};

const result = await acpClient.browseAgents(keyword, options);

expect(Array.isArray(result)).toBe(true);

console.log(`Found ${result.length} agents for keyword: ${keyword}`);
}, 30000);

it("should return agents with correct structure", async () => {
const keyword = "agent";
const options = {
top_k: 3,
};

const result = await acpClient.browseAgents(keyword, options);

if (result.length > 0) {
const firstAgent = result[0];

expect(firstAgent).toHaveProperty("id");
expect(firstAgent).toHaveProperty("name");
expect(firstAgent).toHaveProperty("description");
expect(firstAgent).toHaveProperty("walletAddress");
expect(firstAgent).toHaveProperty("contractAddress");
expect(firstAgent).toHaveProperty("jobOfferings");
expect(firstAgent).toHaveProperty("twitterHandle");

expect(typeof firstAgent.id).toBe("number");
expect(typeof firstAgent.name).toBe("string");
expect(typeof firstAgent.walletAddress).toBe("string");
expect(Array.isArray(firstAgent.jobOfferings)).toBe(true);

console.log("First agent:", {
id: firstAgent.id,
name: firstAgent.name,
jobCount: firstAgent.jobOfferings.length,
});
}
}, 30000);

it("should return job offerings as AcpJobOffering instances", async () => {
const keyword = "agent";
const options = {
top_k: 5,
};

const result = await acpClient.browseAgents(keyword, options);

const agentWithJobs = result.find(
(agent) => agent.jobOfferings.length > 0,
);

if (agentWithJobs) {
const jobOffering = agentWithJobs.jobOfferings[0];

expect(jobOffering).toBeInstanceOf(AcpJobOffering);
expect(typeof jobOffering.initiateJob).toBe("function");

console.log("Job offering:", {
name: jobOffering.name,
price: jobOffering.price,
});
} else {
console.log("No agents with job offerings found");
}
}, 30000);

it("should filter out own wallet address", async () => {
const keyword = "agent";
const options = {
top_k: 10,
};

const result = await acpClient.browseAgents(keyword, options);

// Verify own wallet is not in results
const ownWalletInResults = result.some(
(agent) =>
agent.walletAddress.toLowerCase() ===
BUYER_AGENT_WALLET_ADDRESS.toLowerCase(),
);

expect(ownWalletInResults).toBe(false);
}, 30000);

it("should filter by contract address", async () => {
const keyword = "agent";
const options = {
top_k: 10,
};

const result = await acpClient.browseAgents(keyword, options);

if (result.length > 0) {
// All returned agents should have matching contract address
const allHaveMatchingContract = result.every(
(agent) =>
agent.contractAddress.toLowerCase() ===
contractClient.contractAddress.toLowerCase(),
);

expect(allHaveMatchingContract).toBe(true);
}
}, 30000);

it("should respect top_k parameter", async () => {
const keyword = "agent";
const topK = 2;
const options = {
top_k: topK,
};

const result = await acpClient.browseAgents(keyword, options);

expect(result.length).toBeLessThanOrEqual(topK);
}, 30000);

it("should handle search with sort options", async () => {
const keyword = "trading";
const options = {
top_k: 5,
sort_by: [AcpAgentSort.SUCCESSFUL_JOB_COUNT],
};

const result = await acpClient.browseAgents(keyword, options);

expect(Array.isArray(result)).toBe(true);
console.log(`Found ${result.length} agents sorted by successfulJobCount`);
}, 30000);

it("should handle search with graduation status filter", async () => {
const keyword = "agent";
const options = {
top_k: 5,
graduationStatus: AcpGraduationStatus.GRADUATED,
};

const result = await acpClient.browseAgents(keyword, options);

expect(Array.isArray(result)).toBe(true);
console.log(`Found ${result.length} graduated agents`);
}, 30000);

it("should handle search with online status filter", async () => {
const keyword = "agent";
const options = {
top_k: 5,
onlineStatus: AcpOnlineStatus.ONLINE,
};

const result = await acpClient.browseAgents(keyword, options);

expect(Array.isArray(result)).toBe(true);
console.log(`Found ${result.length} online agents`);
}, 30000);

it("should return empty or minimal results for non-existent keyword", async () => {
const keyword = "thiskeywordisnotakeyworddonotreturnanyagents";
const options = {
top_k: 5,
};

const result = await acpClient.browseAgents(keyword, options);

expect(Array.isArray(result)).toBe(true);
// May or may not be empty depending on API behavior
console.log(`Found ${result.length} agents for non-existent keyword`);
}, 30000);
});
});
5 changes: 4 additions & 1 deletion test/integration/acpContractClientV2.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import {
SELLER_ENTITY_ID,
SELLER_AGENT_WALLET_ADDRESS,
} from "../env";
import { testBaseAcpConfigV2 } from "../testConfigs";

describe("AcpContractClientV2 Integration Testing", () => {
jest.setTimeout(10000);
jest.setTimeout(60000); // 60 seconds for network operations

let contractClient: AcpContractClientV2;

Expand All @@ -20,6 +21,7 @@ describe("AcpContractClientV2 Integration Testing", () => {
WHITELISTED_WALLET_PRIVATE_KEY as Address,
SELLER_ENTITY_ID,
SELLER_AGENT_WALLET_ADDRESS as Address,
testBaseAcpConfigV2,
);

expect(contractClient).toBeDefined();
Expand All @@ -38,6 +40,7 @@ describe("AcpContractClientV2 Integration Testing", () => {
WHITELISTED_WALLET_PRIVATE_KEY as Address,
SELLER_ENTITY_ID,
SELLER_AGENT_WALLET_ADDRESS as Address,
testBaseAcpConfigV2,
);

await contractClient.init(
Expand Down
Loading