From e4fc2f56e15792aaa7d4752fe0b58823fa48d969 Mon Sep 17 00:00:00 2001 From: Ry Racherbaumer Date: Fri, 1 Nov 2024 13:41:00 -0500 Subject: [PATCH] Update browser SDK tests --- sdks/browser-sdk/test/Client.test.ts | 193 ++++++++++++++++++-- sdks/browser-sdk/test/Conversation.test.ts | 39 +++- sdks/browser-sdk/test/Conversations.test.ts | 83 ++++++++- sdks/browser-sdk/test/Utils.test.ts | 2 +- sdks/browser-sdk/test/helpers.ts | 4 +- 5 files changed, 302 insertions(+), 19 deletions(-) diff --git a/sdks/browser-sdk/test/Client.test.ts b/sdks/browser-sdk/test/Client.test.ts index 404a0a5d9..d5683ccfa 100644 --- a/sdks/browser-sdk/test/Client.test.ts +++ b/sdks/browser-sdk/test/Client.test.ts @@ -1,11 +1,19 @@ +import { + WasmConsentEntityType, + WasmConsentState, + WasmSignatureRequestType, +} from "@xmtp/wasm-bindings"; +import { v4 } from "uuid"; +import { toBytes } from "viem"; import { describe, expect, it } from "vitest"; +import { Conversation } from "@/Conversation"; import { createClient, createRegisteredClient, createUser, } from "@test/helpers"; -describe("Client", () => { +describe.concurrent("Client", () => { it("should create a client", async () => { const user = createUser(); const client = await createClient(user); @@ -22,9 +30,13 @@ describe("Client", () => { const client2 = await createRegisteredClient(user); expect(await client2.isRegistered()).toBe(true); expect(await client2.getCreateInboxSignatureText()).toBeUndefined(); - expect( - Object.fromEntries(await client2.canMessage([user.account.address])), - ).toEqual({ + }); + + it("should be able to message registered identity", async () => { + const user = createUser(); + const client = await createRegisteredClient(user); + const canMessage = await client.canMessage([user.account.address]); + expect(Object.fromEntries(canMessage)).toEqual({ [user.account.address.toLowerCase()]: true, }); }); @@ -48,19 +60,178 @@ describe("Client", () => { user.account.address.toLowerCase(), ]); expect(inboxState.recoveryAddress).toBe(user.account.address.toLowerCase()); + + const user2 = createUser(); + const client2 = await createClient(user2); + const inboxState2 = await client2.getLatestInboxState(client.inboxId!); + expect(inboxState2.inboxId).toBe(client.inboxId); + expect(inboxState.installations.length).toBe(1); + expect(inboxState.installations[0].id).toBe(client.installationId); + expect(inboxState2.accountAddresses).toEqual([ + user.account.address.toLowerCase(), + ]); + expect(inboxState2.recoveryAddress).toBe( + user.account.address.toLowerCase(), + ); }); - it("should get latest inbox state from inbox ID", async () => { + it("should add a wallet association to the client", async () => { const user = createUser(); + const user2 = createUser(); const client = await createRegisteredClient(user); - const inboxState = await client.getLatestInboxState(client.inboxId!); - expect(inboxState.inboxId).toBe(client.inboxId); - expect(inboxState.installations.map((install) => install.id)).toEqual([ - client.installationId, - ]); + const signatureText = await client.getAddWalletSignatureText( + user2.account.address, + ); + expect(signatureText).toBeDefined(); + + // sign message + const signature = await user.wallet.signMessage({ + message: signatureText!, + }); + const signature2 = await user2.wallet.signMessage({ + message: signatureText!, + }); + + await client.addSignature( + WasmSignatureRequestType.AddWallet, + toBytes(signature), + ); + await client.addSignature( + WasmSignatureRequestType.AddWallet, + toBytes(signature2), + ); + await client.applySignatures(); + + const inboxState = await client.inboxState(); + expect(inboxState.accountAddresses.length).toEqual(2); + expect(inboxState.accountAddresses).toContain( + user.account.address.toLowerCase(), + ); + expect(inboxState.accountAddresses).toContain( + user2.account.address.toLowerCase(), + ); + }); + + it("should revoke a wallet association from the client", async () => { + const user = createUser(); + const user2 = createUser(); + const client = await createRegisteredClient(user); + const signatureText = await client.getAddWalletSignatureText( + user2.account.address, + ); + expect(signatureText).toBeDefined(); + + // sign message + const signature = await user.wallet.signMessage({ + message: signatureText!, + }); + const signature2 = await user2.wallet.signMessage({ + message: signatureText!, + }); + + await client.addSignature( + WasmSignatureRequestType.AddWallet, + toBytes(signature), + ); + await client.addSignature( + WasmSignatureRequestType.AddWallet, + toBytes(signature2), + ); + await client.applySignatures(); + + const signatureText2 = await client.getRevokeWalletSignatureText( + user2.account.address, + ); + expect(signatureText2).toBeDefined(); + + // sign message + const signature3 = await user.wallet.signMessage({ + message: signatureText2!, + }); + + await client.addSignature( + WasmSignatureRequestType.RevokeWallet, + toBytes(signature3), + ); + await client.applySignatures(); + const inboxState = await client.inboxState(); expect(inboxState.accountAddresses).toEqual([ user.account.address.toLowerCase(), ]); - expect(inboxState.recoveryAddress).toBe(user.account.address.toLowerCase()); + }); + + it("should revoke all installations", async () => { + const user = createUser(); + + const client = await createRegisteredClient(user); + user.uuid = v4(); + const client2 = await createRegisteredClient(user); + user.uuid = v4(); + const client3 = await createRegisteredClient(user); + + const inboxState = await client3.inboxState(true); + expect(inboxState.installations.length).toBe(3); + + const installationIds = inboxState.installations.map((i) => i.id); + expect(installationIds).toContain(client.installationId); + expect(installationIds).toContain(client2.installationId); + expect(installationIds).toContain(client3.installationId); + + const signatureText = await client3.getRevokeInstallationsSignatureText(); + expect(signatureText).toBeDefined(); + + // sign message + const signature = await user.wallet.signMessage({ + message: signatureText!, + }); + + await client3.addSignature( + WasmSignatureRequestType.RevokeInstallations, + toBytes(signature), + ); + await client3.applySignatures(); + const inboxState2 = await client3.inboxState(true); + + expect(inboxState2.installations.length).toBe(1); + expect(inboxState2.installations[0].id).toBe(client3.installationId); + }); + + it("should manage consent states", async () => { + const user1 = createUser(); + const user2 = createUser(); + const client1 = await createRegisteredClient(user1); + const client2 = await createRegisteredClient(user2); + const group = await client1.conversations.newGroup([user2.account.address]); + + await client2.conversations.sync(); + const group2 = await client2.conversations.getConversationById(group.id); + + expect(group2).not.toBeNull(); + + expect( + await client2.getConsentState(WasmConsentEntityType.GroupId, group2!.id), + ).toBe(WasmConsentState.Unknown); + + await client2.setConsentStates([ + { + entityType: WasmConsentEntityType.GroupId, + entity: group2!.id, + state: WasmConsentState.Allowed, + }, + ]); + + expect( + await client2.getConsentState(WasmConsentEntityType.GroupId, group2!.id), + ).toBe(WasmConsentState.Allowed); + + const convo = new Conversation(client2, group2!.id, group2); + + expect(await convo.consentState()).toBe(WasmConsentState.Allowed); + + await convo.updateConsentState(WasmConsentState.Denied); + + expect( + await client2.getConsentState(WasmConsentEntityType.GroupId, group2!.id), + ).toBe(WasmConsentState.Denied); }); }); diff --git a/sdks/browser-sdk/test/Conversation.test.ts b/sdks/browser-sdk/test/Conversation.test.ts index 1bcd1cc6d..696df11bf 100644 --- a/sdks/browser-sdk/test/Conversation.test.ts +++ b/sdks/browser-sdk/test/Conversation.test.ts @@ -1,4 +1,6 @@ +import { WasmConsentState } from "@xmtp/wasm-bindings"; import { describe, expect, it } from "vitest"; +import { Conversation } from "@/Conversation"; import { ContentTypeTest, createRegisteredClient, @@ -6,7 +8,7 @@ import { TestCodec, } from "@test/helpers"; -describe("Conversation", () => { +describe.concurrent("Conversation", () => { it("should update conversation name", async () => { const user1 = createUser(); const user2 = createUser(); @@ -372,4 +374,39 @@ describe("Conversation", () => { expect(superAdmins3.length).toBe(1); expect(superAdmins3).toContain(client1.inboxId); }); + + it("should manage group consent state", async () => { + const user1 = createUser(); + const user2 = createUser(); + const user3 = createUser(); + const client1 = await createRegisteredClient(user1); + const client2 = await createRegisteredClient(user2); + const client3 = await createRegisteredClient(user3); + const group = await client1.conversations.newGroup([user2.account.address]); + expect(group).toBeDefined(); + const dmGroup = await client1.conversations.newDm(user3.account.address); + expect(dmGroup).toBeDefined(); + + await client2.conversations.sync(); + const group2 = await client2.conversations.getConversationById(group.id); + expect(group2).toBeDefined(); + + const groupConvo = new Conversation(client2, group2!.id, group2); + + expect(await groupConvo.consentState()).toBe(WasmConsentState.Unknown); + await groupConvo.send("gm!"); + expect(await groupConvo.consentState()).toBe(WasmConsentState.Allowed); + + await client3.conversations.sync(); + const dmGroup2 = await client3.conversations.getConversationById( + dmGroup.id, + ); + expect(dmGroup2).toBeDefined(); + + const dmConvo = new Conversation(client3, dmGroup2!.id, dmGroup2); + + expect(await dmConvo.consentState()).toBe(WasmConsentState.Unknown); + await dmConvo.send("gm!"); + expect(await dmConvo.consentState()).toBe(WasmConsentState.Allowed); + }); }); diff --git a/sdks/browser-sdk/test/Conversations.test.ts b/sdks/browser-sdk/test/Conversations.test.ts index b0d5ee7a5..bdd2b58f8 100644 --- a/sdks/browser-sdk/test/Conversations.test.ts +++ b/sdks/browser-sdk/test/Conversations.test.ts @@ -1,13 +1,18 @@ -import { WasmGroupPermissionsOptions } from "@xmtp/wasm-bindings"; +import { + WasmConsentState, + WasmGroupPermissionsOptions, +} from "@xmtp/wasm-bindings"; import { describe, expect, it } from "vitest"; import { createRegisteredClient, createUser } from "@test/helpers"; -describe("Conversations", () => { +describe.concurrent("Conversations", () => { it("should not have initial conversations", async () => { const user = createUser(); const client = await createRegisteredClient(user); - const conversations = await client.conversations.list(); - expect(conversations.length).toBe(0); + + expect((await client.conversations.list()).length).toBe(0); + expect((await client.conversations.listDms()).length).toBe(0); + expect((await client.conversations.listGroups()).length).toBe(0); }); it("should create a new conversation", async () => { @@ -19,7 +24,6 @@ describe("Conversations", () => { user2.account.address, ]); expect(conversation).toBeDefined(); - expect( (await client1.conversations.getConversationById(conversation.id))?.id, ).toBe(conversation.id); @@ -65,6 +69,75 @@ describe("Conversations", () => { const conversations2 = await client2.conversations.list(); expect(conversations2.length).toBe(1); expect(conversations2[0].id).toBe(conversation.id); + + expect((await client2.conversations.listDms()).length).toBe(0); + expect((await client2.conversations.listGroups()).length).toBe(1); + }); + + it("should create a dm group", async () => { + const user1 = createUser(); + const user2 = createUser(); + const client1 = await createRegisteredClient(user1); + const client2 = await createRegisteredClient(user2); + const group = await client1.conversations.newDm(user2.account.address); + expect(group).toBeDefined(); + expect(group.id).toBeDefined(); + expect(group.createdAtNs).toBeDefined(); + expect(group.createdAt).toBeDefined(); + expect(group.isActive).toBe(true); + expect(group.name).toBe(""); + expect(group.permissions?.policyType).toBe( + WasmGroupPermissionsOptions.CustomPolicy, + ); + expect(group.permissions?.policySet).toEqual({ + addAdminPolicy: 1, + addMemberPolicy: 1, + removeAdminPolicy: 1, + removeMemberPolicy: 1, + updateGroupDescriptionPolicy: 0, + updateGroupImageUrlSquarePolicy: 0, + updateGroupNamePolicy: 0, + updateGroupPinnedFrameUrlPolicy: 0, + }); + expect(group.addedByInboxId).toBe(client1.inboxId); + expect((await group.messages()).length).toBe(1); + const members = await group.members(); + expect(members.length).toBe(2); + const memberInboxIds = members.map((member) => member.inboxId); + expect(memberInboxIds).toContain(client1.inboxId); + expect(memberInboxIds).toContain(client2.inboxId); + expect(group.metadata?.conversationType).toBe("dm"); + expect(group.metadata?.creatorInboxId).toBe(client1.inboxId); + + expect(await group.consentState()).toBe(WasmConsentState.Allowed); + + const group1 = await client1.conversations.list(); + expect(group1.length).toBe(1); + expect(group1[0].id).toBe(group.id); + expect(await group1[0].dmPeerInboxId()).toBe(client2.inboxId); + + expect((await client1.conversations.listDms()).length).toBe(1); + expect((await client1.conversations.listGroups()).length).toBe(0); + + expect((await client2.conversations.list()).length).toBe(0); + + await client2.conversations.sync(); + + const group2 = await client2.conversations.list(); + expect(group2.length).toBe(1); + expect(group2[0].id).toBe(group.id); + expect(await group2[0].dmPeerInboxId()).toBe(client1.inboxId); + + expect((await client2.conversations.listDms()).length).toBe(1); + expect((await client2.conversations.listGroups()).length).toBe(0); + + const dm1 = await client1.conversations.getDmByInboxId(client2.inboxId!); + expect(dm1).toBeDefined(); + expect(dm1!.id).toBe(group.id); + + const dm2 = await client2.conversations.getDmByInboxId(client1.inboxId!); + expect(dm2).toBeDefined(); + expect(dm2!.id).toBe(group.id); }); it("should get a group by ID", async () => { diff --git a/sdks/browser-sdk/test/Utils.test.ts b/sdks/browser-sdk/test/Utils.test.ts index b7b7692f0..18b453596 100644 --- a/sdks/browser-sdk/test/Utils.test.ts +++ b/sdks/browser-sdk/test/Utils.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest"; import { Utils } from "@/Utils"; import { createRegisteredClient, createUser } from "@test/helpers"; -describe("Utils", () => { +describe.concurrent("Utils", () => { it("should generate inbox id", async () => { const utils = new Utils(); const inboxId = await utils.generateInboxId("0x1234"); diff --git a/sdks/browser-sdk/test/helpers.ts b/sdks/browser-sdk/test/helpers.ts index cbeeaa4cc..563d1dedc 100644 --- a/sdks/browser-sdk/test/helpers.ts +++ b/sdks/browser-sdk/test/helpers.ts @@ -4,6 +4,7 @@ import { type EncodedContent, } from "@xmtp/content-type-primitives"; import { WasmSignatureRequestType } from "@xmtp/wasm-bindings"; +import { v4 } from "uuid"; import { createWalletClient, http, toBytes } from "viem"; import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; import { sepolia } from "viem/chains"; @@ -21,6 +22,7 @@ export const createUser = () => { chain: sepolia, transport: http(), }), + uuid: v4(), }; }; @@ -44,7 +46,7 @@ export const createClient = async (user: User, options?: ClientOptions) => { }; return Client.create(user.account.address, { ...opts, - dbPath: `./test-${user.account.address}.db3`, + dbPath: `./test-${user.uuid}.db3`, }); };