diff --git a/src/social/SocialAPI.ts b/src/social/SocialAPI.ts index 935b87e..6453ab0 100644 --- a/src/social/SocialAPI.ts +++ b/src/social/SocialAPI.ts @@ -9,10 +9,10 @@ import { createThreadRequestBody, incrementLikeCounterRequestBody, IncrementLikeCounterRequestBody, - queryThreadRepliesParams, - QueryThreadRepliesParams, - queryThreadsParams, - QueryThreadsParams, + QueryThreadsReplyRequestParams, + queryThreadsReplyRequestParamsSchema, + QueryThreadsRequestParams, + queryThreadsRequestParamsSchema, ThreadRepliesResult, ThreadsResult, } from "./schemas"; @@ -20,15 +20,17 @@ import { export class SocialAPI { constructor(private url = BE_URL) {} - getThreads(params: QueryThreadsParams): Promise { - const queryParams = new URLSearchParams(queryThreadsParams.parse(params) as Record); + getThreads(params: QueryThreadsRequestParams): Promise { + const queryParams = new URLSearchParams(queryThreadsRequestParamsSchema.parse(params) as Record); return jsonFetch(`${this.url}/threads?${queryParams}`, { method: "GET", }); } - getThreadReplies(params: QueryThreadRepliesParams): Promise { - const queryParams = new URLSearchParams(queryThreadRepliesParams.parse(params) as Record); + getThreadReplies(params: QueryThreadsReplyRequestParams): Promise { + const queryParams = new URLSearchParams( + queryThreadsReplyRequestParamsSchema.parse(params) as Record, + ); return jsonFetch(`${this.url}/replies?${queryParams}`, { method: "GET", }); diff --git a/src/social/schemas.ts b/src/social/schemas.ts index 88f0821..62ea002 100644 --- a/src/social/schemas.ts +++ b/src/social/schemas.ts @@ -1,32 +1,17 @@ -import { z, ZodRawShape } from "zod"; +import { z } from "zod"; +import { paginatedResultSchema } from "../coin/schemas/coin-schemas"; export const createThreadRequestBody = z.object({ message: z.string(), coinType: z.string(), }); -export const paginatedResultSchema = (result: z.ZodObject) => - z.object({ - paginationToken: z.string().nullish(), - result: z.array(result), - }); - export const createThreadReplyRequestBody = z.object({ message: z.string(), coinType: z.string(), threadId: z.string(), }); -export const queryThreadsParams = z.object({ - coinType: z.string(), - paginationToken: z.string().nullish(), -}); - -export const queryThreadRepliesParams = z.object({ - threadId: z.string(), - paginationToken: z.string().nullish(), -}); - export const incrementLikeCounterRequestBody = z.object({ coinType: z.string(), threadId: z.string(), @@ -51,15 +36,32 @@ export const threadReplyMessageSchema = baseMessageSchema.extend({ type: z.literal("REPLY"), }); +export const threadsSortableColumns = z.literal("creationTime").or(z.literal("replyCount")).or(z.literal("likeCount")); +export const threadsReplySortableColumns = z.literal("creationTime").or(z.literal("likeCount")); + const threadsResult = paginatedResultSchema(threadMessageSchema); const threadRepliesResult = paginatedResultSchema(threadReplyMessageSchema); +export const queryThreadsRequestParamsSchema = z.object({ + sortBy: threadsSortableColumns, + coinType: z.string(), + direction: z.literal("asc").or(z.literal("desc")), + paginationToken: z.string().nullish(), +}); + +export const queryThreadsReplyRequestParamsSchema = z.object({ + sortBy: threadsReplySortableColumns, + threadId: z.string(), + direction: z.literal("asc").or(z.literal("desc")), + paginationToken: z.string().nullish(), +}); + +export type ThreadsResult = z.infer; +export type ThreadRepliesResult = z.infer; +export type QueryThreadsRequestParams = z.infer; +export type QueryThreadsReplyRequestParams = z.infer; export type ThreadReplyMessage = z.infer; export type ThreadMessage = z.infer; export type CreateThreadRequestBody = z.infer; export type CreateThreadReplyBody = z.infer; export type IncrementLikeCounterRequestBody = z.infer; -export type ThreadsResult = z.infer; -export type ThreadRepliesResult = z.infer; -export type QueryThreadsParams = z.infer; -export type QueryThreadRepliesParams = z.infer; diff --git a/tests/e2e/LivePool.test.ts b/tests/e2e/LivePool.test.ts index dce82f9..dcdb976 100644 --- a/tests/e2e/LivePool.test.ts +++ b/tests/e2e/LivePool.test.ts @@ -6,7 +6,7 @@ describe("Live pool", () => { const livePools = await LivePool.fromRegistry({ provider: new SuiClient({ url: getFullnodeUrl("mainnet") }), }); - + console.log("live pools", livePools); livePools.forEach((pool) => expect(pool.data).toEqual({ address: expect.any(String), diff --git a/tests/e2e/SocialAPI.test.ts b/tests/e2e/SocialAPI.test.ts index 7d0edc3..439ac09 100644 --- a/tests/e2e/SocialAPI.test.ts +++ b/tests/e2e/SocialAPI.test.ts @@ -2,16 +2,18 @@ import { Ed25519Keypair } from "@mysten/sui.js/keypairs/ed25519"; import { Auth, CoinAPI } from "../../src"; import { SocialAPI } from "../../src/social/SocialAPI"; import { Coin } from "../../src/coin/schemas/coin-schemas"; +import { isSorted } from "./helpers"; const BE_URL = "https://14r6b4r6kf.execute-api.us-east-1.amazonaws.com/prod"; -describe("Social APIs", () => { - let keypair: Ed25519Keypair; - let coin: Coin; +const socialAPI = new SocialAPI(BE_URL); + +describe("Threads fetching", () => { + let coin: Coin | undefined; + const keypair = new Ed25519Keypair(); + let threadId: string | undefined; beforeAll(async () => { - keypair = new Ed25519Keypair(); - console.log("Testing with wallet", keypair.getPublicKey().toSuiAddress()); const authService = new Auth(BE_URL); const messageToSign = await authService.requestMessageToSign(keypair.getPublicKey().toSuiAddress()); const { signature } = await keypair.signPersonalMessage(Buffer.from(messageToSign)); @@ -19,27 +21,144 @@ describe("Social APIs", () => { walletAddress: keypair.getPublicKey().toSuiAddress(), signedMessage: signature, }); - console.log("Wallet authenticated"); - const coinApi = new CoinAPI(BE_URL); - const { coin: createdCoin } = await coinApi.createCoin({ + const coinApi = new CoinAPI(); + const { coin: coinFetched } = await coinApi.createCoin({ txDigest: "Bdkcg4Z2HuUTRkvG5mrCZRya8fxqwPzbHnY3cfD1tTYQ", socialLinks: { twitter: "mytwitter", discord: "mydiscord", }, }); - console.log("Created coin"); - coin = createdCoin; + coin = coinFetched; + for (let i = 0; i < 10; i++) { + await socialAPI.createThread({ + message: `Test message ${i}`, + coinType: coin.type, + }); + const { result } = await socialAPI.getThreads({ + sortBy: "creationTime", + direction: "desc", + coinType: coin!.type, + }); + const nLikes = Math.floor(Math.random() * (5 - 0 + 1)) + 0; + for (let j = 0; j < nLikes; j++) { + await socialAPI.like({ + coinType: coin.type, + threadId: result[0].id, + }); + } + const nReplies = Math.floor(Math.random() * (5 - 0 + 1)) + 0; + for (let j = 0; j < nReplies; j++) { + await socialAPI.createThreadReply({ + coinType: coin.type, + threadId: result[0].id, + message: `Reply ${j}`, + }); + const reply = await socialAPI.getThreadReplies({ + sortBy: "creationTime", + direction: "desc", + threadId: result[0].id, + }); + const nLikes = Math.floor(Math.random() * (5 - 0 + 1)) + 0; + for (let l = 0; l < nLikes; l++) { + await socialAPI.like({ + coinType: coin.type, + threadId: result[0].id, + replyId: reply.result[0].id, + }); + } + } + } + }); + + test("check queryThreads retrieve successfully all threads, sorted by creationTime asc", async () => { + const { result } = await socialAPI.getThreads({ + sortBy: "creationTime", + direction: "asc", + coinType: coin!.type, + }); + expect(isSorted(result, "creationDate", "asc")).toBe(true); + }); + + test("check queryThreads retrieve successfully all threads, sorted by likeCount asc", async () => { + const { result } = await socialAPI.getThreads({ + sortBy: "likeCount", + direction: "asc", + coinType: coin!.type, + }); + expect(isSorted(result, "likeCounter", "asc")).toBe(true); + }); + + test("check queryThreads retrieve successfully all threads, sorted by replyCounter asc", async () => { + const { result } = await socialAPI.getThreads({ + sortBy: "replyCount", + direction: "asc", + coinType: coin!.type, + }); + expect(isSorted(result, "replyCounter", "asc")).toBe(true); + }); + + test("check queryThreads retrieve successfully all threads, sorted by creationTime desc", async () => { + const { result } = await socialAPI.getThreads({ + sortBy: "creationTime", + direction: "desc", + coinType: coin!.type, + }); + expect(isSorted(result, "creationDate", "desc")).toBe(true); + }); + + test("check queryThreads retrieve successfully all threads, sorted by likeCount desc", async () => { + const { result } = await socialAPI.getThreads({ + sortBy: "likeCount", + direction: "desc", + coinType: coin!.type, + }); + expect(isSorted(result, "likeCounter", "desc")).toBe(true); + }); + + test("check queryThreads retrieve successfully all threads, sorted by replyCounter desc", async () => { + const { result } = await socialAPI.getThreads({ + sortBy: "replyCount", + direction: "desc", + coinType: coin!.type, + }); + threadId = result[0].id; + expect(isSorted(result, "replyCounter", "desc")).toBe(true); + }); + + test("check queryThreadsReplies retrieve successfully all threads, sorted by creationTime desc", async () => { + const { result } = await socialAPI.getThreadReplies({ + sortBy: "creationTime", + direction: "desc", + threadId: threadId!, + }); + expect(isSorted(result, "creationDate", "desc")).toBe(true); + }); + + test("check queryThreadReplies retrieve successfully all threads, sorted by likeCount desc", async () => { + const { result } = await socialAPI.getThreadReplies({ + sortBy: "likeCount", + direction: "desc", + threadId: threadId!, + }); + expect(isSorted(result, "likeCounter", "desc")).toBe(true); + }); + + test("check queryThreadsReplies retrieve successfully all threads replies, sorted by creationTime asc", async () => { + const { result } = await socialAPI.getThreadReplies({ + sortBy: "creationTime", + direction: "asc", + threadId: threadId!, + }); + expect(isSorted(result, "creationDate", "asc")).toBe(true); }); - test("Social APIs flow", async () => { - const socialAPI = new SocialAPI(BE_URL); - await socialAPI.createThread({ - message: "Test message", - coinType: coin.type, + test("check queryThreadReplies retrieve successfully all threads replies, sorted by likeCount asc", async () => { + const { result } = await socialAPI.getThreadReplies({ + sortBy: "likeCount", + direction: "asc", + threadId: threadId!, }); - const { result } = await socialAPI.getThreads({ coinType: coin.type }); - const thread = result.find((r) => r.creator === keypair.getPublicKey().toSuiAddress()); - expect(thread).toBeTruthy(); + expect(isSorted(result, "likeCounter", "asc")).toBe(true); }); }); diff --git a/tests/e2e/StakingPool.test.ts b/tests/e2e/StakingPool.test.ts index ce7813e..417e85a 100644 --- a/tests/e2e/StakingPool.test.ts +++ b/tests/e2e/StakingPool.test.ts @@ -1,5 +1,5 @@ import { getFullnodeUrl, SuiClient } from "@mysten/sui.js/client"; -import { PoolAPI, StakingPool } from "../../src"; +import { StakingPool } from "../../src"; import { FeeState } from "../../src/staking-pool/FeeState"; import { VestingConfig } from "../../src/staking-pool/VestingConfig"; diff --git a/vitest.config.ts b/vitest.config.ts index 1bedbb4..7499941 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -4,6 +4,8 @@ export default defineConfig({ test: { globals: true, environment: "node", + hookTimeout: Infinity, + testTimeout: Infinity, }, resolve: { alias: {},