From 3fbb9bf9cbc8ec540100a1283bf90d50dd48cf58 Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Tue, 31 Oct 2023 16:34:37 -0600 Subject: [PATCH 01/22] upgrade debs + github action --- .github/workflows/test.yml | 2 +- flake.lock | 32 ++++++++++++++++---------------- flake.nix | 2 +- package-lock.json | 18 +++++++++--------- tests/package.json | 4 ++-- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index acdc185b..5be01931 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install nix uses: cachix/install-nix-action@v22 diff --git a/flake.lock b/flake.lock index 85ae5f5c..1cb027f9 100644 --- a/flake.lock +++ b/flake.lock @@ -175,16 +175,16 @@ "holochain": { "flake": false, "locked": { - "lastModified": 1694632043, - "narHash": "sha256-5QWUpWnwuzUi3hROrOZyQNla8iGdr+oGCH2nniRePBE=", + "lastModified": 1696074490, + "narHash": "sha256-195lUl9x6zLhfrDXMh6WEFa/tEFilhJT/zLJchywnQw=", "owner": "holochain", "repo": "holochain", - "rev": "1f59d33623031eefe76b5f3573970c9c33f21877", + "rev": "da0ca3dc2521ee69c9f9e50dd318ab34d60199d4", "type": "github" }, "original": { "owner": "holochain", - "ref": "holochain-0.2.2", + "ref": "holochain-0.2.3-beta-rc.1", "repo": "holochain", "type": "github" } @@ -238,11 +238,11 @@ ] }, "locked": { - "lastModified": 1696966770, - "narHash": "sha256-vs+gg7LLj8BZTsxfvzWl49lCGI4iST1Hc5+nAtKCSrY=", + "lastModified": 1698761834, + "narHash": "sha256-0NgQ8b3/WsGZN188wCkxYuDa6ykFflClOm7O1jUf+Rs=", "owner": "holochain", "repo": "holochain", - "rev": "25aee0d63126db6abe9b039ddc2f54c53641beec", + "rev": "a9275d8b2790031a20b4d1e712cc5c399eec6029", "type": "github" }, "original": { @@ -302,11 +302,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1696604326, - "narHash": "sha256-YXUNI0kLEcI5g8lqGMb0nh67fY9f2YoJsILafh6zlMo=", + "lastModified": 1698611440, + "narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "87828a0e03d1418e848d3dd3f3014a632e4a4f64", + "rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735", "type": "github" }, "original": { @@ -407,11 +407,11 @@ ] }, "locked": { - "lastModified": 1696817516, - "narHash": "sha256-Xt9OY4Wnk9/vuUfA0OHFtmSlaen5GyiS9msgwOz3okI=", + "lastModified": 1698726852, + "narHash": "sha256-V1S4TTzg++GzPc96i/yy4jib+7/xU0LXHcggm9MllMM=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "c0df7f2a856b5ff27a3ce314f6d7aacf5fda546f", + "rev": "ec19bd20af08f3b004089cc12ab54c823ed899b7", "type": "github" }, "original": { @@ -461,11 +461,11 @@ }, "locked": { "dir": "versions/0_2", - "lastModified": 1696966770, - "narHash": "sha256-vs+gg7LLj8BZTsxfvzWl49lCGI4iST1Hc5+nAtKCSrY=", + "lastModified": 1698761834, + "narHash": "sha256-0NgQ8b3/WsGZN188wCkxYuDa6ykFflClOm7O1jUf+Rs=", "owner": "holochain", "repo": "holochain", - "rev": "25aee0d63126db6abe9b039ddc2f54c53641beec", + "rev": "a9275d8b2790031a20b4d1e712cc5c399eec6029", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 7234f13c..792fa222 100644 --- a/flake.nix +++ b/flake.nix @@ -5,7 +5,7 @@ versions.url = "github:holochain/holochain?dir=versions/0_2"; holonix.url = "github:holochain/holochain"; holonix.inputs.versions.follows = "versions"; - holonix.inputs.holochain.url = "github:holochain/holochain/holochain-0.2.2"; + holonix.inputs.holochain.url = "github:holochain/holochain/holochain-0.2.3-beta-rc.1"; }; outputs = inputs@{ holonix, ... }: diff --git a/package-lock.json b/package-lock.json index 15fca372..913c14b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -840,9 +840,9 @@ "integrity": "sha512-DJx4V2KXHVLciyOGjOYKTM/JLBpBEZ3RsPIRCgf7qmwhQdxXvhi2p+oFFRD51yUT5uC1/MzIVeJCl/R60PwFbw==" }, "node_modules/@holochain/tryorama": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@holochain/tryorama/-/tryorama-0.15.0.tgz", - "integrity": "sha512-GWsiheb6AFkPkT1ho+dJeFRB2jVboIm/Gp+7v1LshKbDZrgY7oDEopyQPWmy4SkQQYItuscGaIdaOUJIQJuGKQ==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@holochain/tryorama/-/tryorama-0.15.1.tgz", + "integrity": "sha512-MjDaJ1arv9dafVQ6AGifZdOrIQ6uLqE3qq6XdLpCTbedduKBH014m/dHR2njzLO+ogfXOqrWthX50/tSq3rtig==", "dependencies": { "@holochain/client": "^0.16.0", "get-port": "^6.1.2", @@ -7407,17 +7407,17 @@ }, "tests": { "dependencies": { - "@holochain/client": "^0.16.1", - "@holochain/tryorama": "0.15.0", + "@holochain/client": "^0.16.3", + "@holochain/tryorama": "0.15.1", "@msgpack/msgpack": "^2.8.0", "typescript": "^4.9.4", "vitest": "^0.28.5" } }, "tests/node_modules/@holochain/client": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@holochain/client/-/client-0.16.2.tgz", - "integrity": "sha512-1Msw6tSdCDI3f2UIdSAYtiAqxxdHt6ufmQSw+GEbvDaIjVXPQWi39IQe5Zzep4VPJoproyurrBRNG1l+/3YrjA==", + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@holochain/client/-/client-0.16.3.tgz", + "integrity": "sha512-bj/yWg3HJCQ1YcVX2yeZX5EiF2X8xv6jIC3q0g7GvdCAlwUqk4fieRQBf8ieYmd9WXmmfs55PVllYw2ofeR9ug==", "dependencies": { "@holochain/serialization": "^0.1.0-beta-rc.3", "@msgpack/msgpack": "^2.8.0", @@ -7430,7 +7430,7 @@ "ws": "^8.14.2" }, "engines": { - "node": ">=16.0.0 || >=18.0.0" + "node": ">=18.0.0 || >=20.0.0" } }, "tests/node_modules/typescript": { diff --git a/tests/package.json b/tests/package.json index 702503d4..473ccf7a 100644 --- a/tests/package.json +++ b/tests/package.json @@ -5,8 +5,8 @@ "test": "vitest run" }, "dependencies": { - "@holochain/client": "^0.16.1", - "@holochain/tryorama": "0.15.0", + "@holochain/client": "^0.16.3", + "@holochain/tryorama": "0.15.1", "@msgpack/msgpack": "^2.8.0", "typescript": "^4.9.4", "vitest": "^0.28.5" From f3f94f03b5256cb32a262753e301df965955badf Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Tue, 31 Oct 2023 17:19:27 -0600 Subject: [PATCH 02/22] test: fix data.data tests --- .../follows/follower-to-creators.test.ts | 15 +--- .../mewsfeed/likes/liker-to-hashes.test.ts | 10 +-- .../mews/followed-creators-mews.test.ts | 6 ++ .../mewsfeed/mews/mew-to-responses.test.ts | 7 +- tests/src/stress-test-local.spec.ts | 77 +++++++++++++++++++ ui/src/stores/toasts.ts | 2 - 6 files changed, 90 insertions(+), 27 deletions(-) create mode 100644 tests/src/stress-test-local.spec.ts diff --git a/tests/src/mewsfeed/follows/follower-to-creators.test.ts b/tests/src/mewsfeed/follows/follower-to-creators.test.ts index b5326afb..e569a562 100644 --- a/tests/src/mewsfeed/follows/follower-to-creators.test.ts +++ b/tests/src/mewsfeed/follows/follower-to-creators.test.ts @@ -121,10 +121,7 @@ test("Agent cannot follow themselves", async () => { fn_name: "follow", payload: alice.agentPubKey, }); - await expect(response).rejects.toHaveProperty( - "data.data", - expect.stringContaining("InvalidCommit") - ); + await expect(response).rejects.toThrowError(/InvalidCommit/); }, true, { timeout: 500000 } @@ -169,10 +166,7 @@ test("Agent can only change their own follows", async () => { target_creator: targetAddress, }, }); - await expect(response).rejects.toHaveProperty( - "data.data", - expect.stringContaining("InvalidCommit") - ); + await expect(response).rejects.toThrowError(/InvalidCommit/); // Alice removes her own follow await alice.cells[0].callZome({ @@ -192,10 +186,7 @@ test("Agent can only change their own follows", async () => { target_creator: targetAddress, }, }); - await expect(response2).rejects.toHaveProperty( - "data.data", - expect.stringContaining("InvalidCommit") - ); + await expect(response2).rejects.toThrowError(/InvalidCommit/); }, true, { timeout: 500000 } diff --git a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts index 6cea47fb..0138d4f1 100644 --- a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts +++ b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts @@ -128,10 +128,7 @@ test("Agent can only change their own likes", async () => { target_hash: targetAddress, }, }); - await expect(response).rejects.toHaveProperty( - "data.data", - expect.stringContaining("InvalidCommit") - ); + await expect(response).rejects.toThrowError(/InvalidCommit/); // Alice removes her own like await alice.cells[0].callZome({ @@ -151,10 +148,7 @@ test("Agent can only change their own likes", async () => { target_hash: targetAddress, }, }); - await expect(response2).rejects.toHaveProperty( - "data.data", - expect.stringContaining("InvalidCommit") - ); + await expect(response2).rejects.toThrowError(/InvalidCommit/); }, true, { timeout: 500000 } diff --git a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts index 073e25ad..e0537196 100644 --- a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts +++ b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts @@ -13,21 +13,27 @@ test("create a Mew and get followed creators mews", async () => { // Add 2 players with the test app to the Scenario. The returned players // can be destructured. + console.log("adding"); const [alice, bob] = await scenario.addPlayersWithApps([ appSource, appSource, ]); + console.log("added"); // Shortcut peer discovery through gossip and register all agents in every // conductor of the scenario. + console.log("sharing all agents"); await scenario.shareAllAgents(); + console.log("shared"); // Bob follows alice + console.log("calling zome follow"); await bob.cells[0].callZome({ zome_name: "follows", fn_name: "follow", payload: alice.agentPubKey, }); + console.log("called"); // Bob gets followed creators mews let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ diff --git a/tests/src/mewsfeed/mews/mew-to-responses.test.ts b/tests/src/mewsfeed/mews/mew-to-responses.test.ts index 219b7a03..06447128 100644 --- a/tests/src/mewsfeed/mews/mew-to-responses.test.ts +++ b/tests/src/mewsfeed/mews/mew-to-responses.test.ts @@ -137,7 +137,7 @@ test("Agent can mewmew a mew, only once", async () => { assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); assert.isTrue( originalMew.is_mewmewed, - "original mew's mewmew is alice's mewmew" + "original mew's mewmew is alice's mewmew" ); // Mewmew the same mew again @@ -146,10 +146,7 @@ test("Agent can mewmew a mew, only once", async () => { fn_name: "create_mew", payload: aliceMewmewInput, }); - await expect(response).rejects.toHaveProperty( - "data.data", - expect.stringContaining("InvalidCommit") - ); + await expect(response).rejects.toThrowError(/InvalidCommit/); }, true, { timeout: 500000 } diff --git a/tests/src/stress-test-local.spec.ts b/tests/src/stress-test-local.spec.ts new file mode 100644 index 00000000..88f6bae0 --- /dev/null +++ b/tests/src/stress-test-local.spec.ts @@ -0,0 +1,77 @@ +import { TryCpScenario } from "@holochain/tryorama"; +import { Mew } from "../../ui/src/types/types"; +import { test } from "vitest"; +import { ActionHash, encodeHashToBase64, AppBundle } from "@holochain/client"; + +const ZOME_NAME = "mews"; + +const TRYCP_SERVER_PORT = 9000; + +// 172.26.211.71 +// 172.26.206.61 +// 172.26.212.148 + +const holoportIps = ["172.26.211.71"]; +// const holoportIps = ["172.26.212.148", "172.26.211.71"]; +// const holoportIps = ["172.26.212.148", "172.26.206.61", "172.26.211.71"]; +const holoportUrls = holoportIps.map( + (ip) => new URL(`ws://${ip}:${TRYCP_SERVER_PORT}`) +); + +const app: { bundle: AppBundle } = { + bundle: { + manifest: { + manifest_version: "1", + name: "holofuel", + roles: [ + { + dna: { + url: "https://github.com/jost-s/hc-utils/releases/download/0.2.1-beta-rc.0/holofuel.dna", + modifiers: { + network_seed: Date.now().toString(), + }, + }, + name: "role", + }, + ], + }, + resources: {}, + }, +}; + +console.log(`Distributed test across ${holoportIps.length} HoloPorts`); +console.log(); + +test("stress test local", async (t) => { + const scenario = new TryCpScenario(); + const numberOfAgentsPerConductor = 10; + + try { + const clientsPlayers = await scenario.addClientsPlayers(holoportUrls, { + app, + numberOfAgentsPerConductor, + }); + + const mew: Mew = { + text: "01234567890", + links: [], + mew_type: { Original: null }, + }; + await Promise.all( + clientsPlayers[0].players.map((player, index) => { + return player.cells[0] + .callZome({ + zome_name: ZOME_NAME, + fn_name: "create_mew", + payload: mew, + }) + .then((actionHash: ActionHash) => { + console.log(index, "response", encodeHashToBase64(actionHash)); + t.expect(actionHash).not.toBeNull(); + }); + }) + ); + } catch (error) { + console.log("ererere", error); + } +}); diff --git a/ui/src/stores/toasts.ts b/ui/src/stores/toasts.ts index e398c3a2..d1456def 100644 --- a/ui/src/stores/toasts.ts +++ b/ui/src/stores/toasts.ts @@ -14,8 +14,6 @@ export const useToasts = defineStore("toasts", () => { let text; if (error instanceof Error) { text = error.message; - } else if (error.type === "error" && "data" in error) { - text = error.data.data; } else { text = JSON.stringify(error, null, 4); } From 22338f8b31e3a34ac2e7989e1775b5c3cfe95e60 Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Tue, 31 Oct 2023 17:32:52 -0600 Subject: [PATCH 03/22] nix: only pull in holochain binaries --- flake.lock | 12 ++++++------ flake.nix | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 1cb027f9..ce81441a 100644 --- a/flake.lock +++ b/flake.lock @@ -238,11 +238,11 @@ ] }, "locked": { - "lastModified": 1698761834, - "narHash": "sha256-0NgQ8b3/WsGZN188wCkxYuDa6ykFflClOm7O1jUf+Rs=", + "lastModified": 1698790077, + "narHash": "sha256-hZhq6mpQaGy5DA4oXt9vWY+9mSxQYmUALCXHQsWQh3E=", "owner": "holochain", "repo": "holochain", - "rev": "a9275d8b2790031a20b4d1e712cc5c399eec6029", + "rev": "88100b526371b6c36eedf4bbf9ec0ceda3174c00", "type": "github" }, "original": { @@ -461,11 +461,11 @@ }, "locked": { "dir": "versions/0_2", - "lastModified": 1698761834, - "narHash": "sha256-0NgQ8b3/WsGZN188wCkxYuDa6ykFflClOm7O1jUf+Rs=", + "lastModified": 1698790077, + "narHash": "sha256-hZhq6mpQaGy5DA4oXt9vWY+9mSxQYmUALCXHQsWQh3E=", "owner": "holochain", "repo": "holochain", - "rev": "a9275d8b2790031a20b4d1e712cc5c399eec6029", + "rev": "88100b526371b6c36eedf4bbf9ec0ceda3174c00", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 792fa222..4489c95e 100644 --- a/flake.nix +++ b/flake.nix @@ -16,7 +16,7 @@ perSystem = { config, system, pkgs, ... }: { devShells.default = pkgs.mkShell { - inputsFrom = [ holonix.devShells.${system}.holonix ]; + inputsFrom = [ holonix.devShells.${system}.holochainBinaries ]; packages = with pkgs; [ # add further packages from nixpkgs nodejs From 0aa2031881644437dbdd0b5e30f932e4a7638eba Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Tue, 31 Oct 2023 20:29:33 -0600 Subject: [PATCH 04/22] refactor: remove explicit timeout in tests --- .../agent_pins/pinner-to-hashes.test.ts | 166 +- .../follows/follower-to-creators.test.ts | 832 +++++----- .../mewsfeed/likes/liker-to-hashes.test.ts | 284 ++-- tests/src/mewsfeed/mews/agent-mews.test.ts | 462 +++--- .../mews/agent-to-notifications.test.ts | 1420 ++++++++--------- .../src/mewsfeed/mews/dna-properties.test.ts | 302 ++-- .../mews/followed-creators-mews.test.ts | 1159 +++++++------- .../src/mewsfeed/mews/mention-to-mews.test.ts | 434 +++-- .../mewsfeed/mews/mew-to-responses.test.ts | 402 +++-- .../mewsfeed/mews/mew-with-context.test.ts | 1 - .../src/mewsfeed/mews/pinner-to-mews.test.ts | 110 +- tests/src/mewsfeed/mews/tags-to-mews.test.ts | 1099 +++++++------ 12 files changed, 3243 insertions(+), 3428 deletions(-) diff --git a/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts b/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts index 843a4246..a0599574 100644 --- a/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts +++ b/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts @@ -4,89 +4,85 @@ import { runScenario, dhtSync } from "@holochain/tryorama"; import { AgentPubKey, HoloHash, fakeActionHash } from "@holochain/client"; test("link a Pinner to a Hash", async () => { - await runScenario( - async (scenario) => { - // Construct proper paths for your app. - // This assumes app bundle created by the `hc app pack` command. - const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; - - // Set up the app to be installed - const appSource = { appBundleSource: { path: testAppPath } }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetHash = await fakeActionHash(); - - // Bob gets the links, should be empty - let linksOutput: HoloHash[] = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Pinner to Hash - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: targetHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - const pinnersOutput: AgentPubKey[] = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_pinners_for_hash", - payload: targetHash, - }); - assert.equal(pinnersOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: targetHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_pinners_for_hash", - payload: targetHash, - }); - - assert.equal(linksOutput.length, 0); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Construct proper paths for your app. + // This assumes app bundle created by the `hc app pack` command. + const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; + + // Set up the app to be installed + const appSource = { appBundleSource: { path: testAppPath } }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetHash = await fakeActionHash(); + + // Bob gets the links, should be empty + let linksOutput: HoloHash[] = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Pinner to Hash + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: targetHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + const pinnersOutput: AgentPubKey[] = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_pinners_for_hash", + payload: targetHash, + }); + assert.equal(pinnersOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: targetHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_pinners_for_hash", + payload: targetHash, + }); + + assert.equal(linksOutput.length, 0); + }, true); }); diff --git a/tests/src/mewsfeed/follows/follower-to-creators.test.ts b/tests/src/mewsfeed/follows/follower-to-creators.test.ts index e569a562..f66bb1dc 100644 --- a/tests/src/mewsfeed/follows/follower-to-creators.test.ts +++ b/tests/src/mewsfeed/follows/follower-to-creators.test.ts @@ -4,454 +4,426 @@ import { AgentPubKey, Record } from "@holochain/client"; import { mewsfeedAppBundleSource } from "../../common"; test("link a Follower to a Creator", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = bob.agentPubKey; - - // Bob gets the links, should be empty - let linksOutput: Record[] = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Follower to Creator - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = bob.agentPubKey; + + // Bob gets the links, should be empty + let linksOutput: Record[] = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Follower to Creator + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: targetAddress, - }, - }); - assert.equal(linksOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: targetAddress, + }, + }); + assert.equal(linksOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: targetAddress, - }, - }); - assert.equal(linksOutput.length, 0); - }, - true, - { timeout: 500000 } - ); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: targetAddress, + }, + }); + assert.equal(linksOutput.length, 0); + }, true); }); test("Agent cannot follow themselves", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice tries to follow herself - const response = alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice tries to follow herself + const response = alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + }, true); }); test("Agent can only change their own follows", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = bob.agentPubKey; + + // Alice follows bob + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to remove alices' follow + const response = bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + + // Alice removes her own follow + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "unfollow", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to add a follow for allice + const response2 = bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); + await expect(response2).rejects.toThrowError(/InvalidCommit/); + }, true); +}); + +test("Creators list are hash-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol, john, steve, mary] = + await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + appSource, appSource, appSource, ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = bob.agentPubKey; - - // Alice follows bob - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to remove alices' follow - const response = bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a link from Follower to Creator + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: bob.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: carol.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: john.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: steve.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: mary.agentPubKey, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const page1: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + limit: 2, }, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - - // Alice removes her own follow - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "unfollow", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to add a follow for allice - const response2 = bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, + }, + }); + + assert.deepEqual(page1[0], mary.agentPubKey); + assert.deepEqual(page1[1], steve.agentPubKey); + + const page2: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page1[1], + limit: 2, }, - }); - await expect(response2).rejects.toThrowError(/InvalidCommit/); - }, - true, - { timeout: 500000 } - ); + }, + }); + assert.deepEqual(page2[0], john.agentPubKey); + assert.deepEqual(page2[1], carol.agentPubKey); + + const page3: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page2[1], + limit: 2, + }, + }, + }); + assert.lengthOf(page3, 1); + assert.deepEqual(page3[0], bob.agentPubKey); + + const page5: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page3[0], + limit: 2, + }, + }, + }); + assert.lengthOf(page5, 0); + }, true); }); -test( - "Creators list are hash-paginated", - async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol, john, steve, mary] = - await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a link from Follower to Creator - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: bob.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: carol.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: john.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: steve.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: mary.agentPubKey, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const page1: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - limit: 2, - }, - }, - }); - - assert.deepEqual(page1[0], mary.agentPubKey); - assert.deepEqual(page1[1], steve.agentPubKey); - - const page2: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - after_agentpubkey: page1[1], - limit: 2, - }, - }, - }); - assert.deepEqual(page2[0], john.agentPubKey); - assert.deepEqual(page2[1], carol.agentPubKey); - - const page3: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - after_agentpubkey: page2[1], - limit: 2, - }, - }, - }); - assert.lengthOf(page3, 1); - assert.deepEqual(page3[0], bob.agentPubKey); - - const page5: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - after_agentpubkey: page3[0], - limit: 2, - }, - }, - }); - assert.lengthOf(page5, 0); +test("Followers list are hash-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol, john, steve, mary] = + await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a link from Follower to Creator + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, }, - true, - { timeout: 500000 } - ); - }, - { timeout: 500000 } -); - -test( - "Followers list are hash-paginated", - async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol, john, steve, mary] = - await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a link from Follower to Creator - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await carol.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: carol.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await john.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: john.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await steve.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: steve.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await mary.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: mary.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - await dhtSync( - [alice, bob, carol, john, steve, mary], - alice.cells[0].cell_id[0] - ); - - const page1: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - limit: 2, - }, - }, - }); - - assert.deepEqual(page1[0], mary.agentPubKey); - assert.deepEqual(page1[1], steve.agentPubKey); - - const page2: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page1[1], - limit: 2, - }, - }, - }); - assert.deepEqual(page2[0], john.agentPubKey); - assert.deepEqual(page2[1], carol.agentPubKey); - - const page3: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page2[1], - limit: 2, - }, - }, - }); - assert.lengthOf(page3, 1); - assert.deepEqual(page3[0], bob.agentPubKey); - - const page5: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page3[0], - limit: 2, - }, - }, - }); - assert.lengthOf(page5, 0); + }); + await carol.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: carol.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + await john.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: john.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + await steve.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: steve.agentPubKey, + target_creator: alice.agentPubKey, }, - true, - { timeout: 500000 } + }); + await mary.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: mary.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + await dhtSync( + [alice, bob, carol, john, steve, mary], + alice.cells[0].cell_id[0] ); - }, - { timeout: 500000 } -); + + const page1: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + limit: 2, + }, + }, + }); + + assert.deepEqual(page1[0], mary.agentPubKey); + assert.deepEqual(page1[1], steve.agentPubKey); + + const page2: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + after_agentpubkey: page1[1], + limit: 2, + }, + }, + }); + assert.deepEqual(page2[0], john.agentPubKey); + assert.deepEqual(page2[1], carol.agentPubKey); + + const page3: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + after_agentpubkey: page2[1], + limit: 2, + }, + }, + }); + assert.lengthOf(page3, 1); + assert.deepEqual(page3[0], bob.agentPubKey); + + const page5: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + after_agentpubkey: page3[0], + limit: 2, + }, + }, + }); + assert.lengthOf(page5, 0); + }, true); +}); diff --git a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts index 0138d4f1..8f58310e 100644 --- a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts +++ b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts @@ -4,153 +4,145 @@ import { Record, fakeActionHash } from "@holochain/client"; import { mewsfeedAppBundleSource } from "../../common"; test("link a Liker to a Hash", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = await fakeActionHash(); - - // Bob gets the links, should be empty - let linksOutput: Record[] = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Liker to Hash - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: baseAddress, - target_hash: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_likers_for_hash", - payload: targetAddress, - }); - assert.equal(linksOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: baseAddress, - target_hash: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_likers_for_hash", - payload: targetAddress, - }); - assert.equal(linksOutput.length, 0); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = await fakeActionHash(); + + // Bob gets the links, should be empty + let linksOutput: Record[] = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Liker to Hash + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: baseAddress, + target_hash: targetAddress, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_likers_for_hash", + payload: targetAddress, + }); + assert.equal(linksOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: baseAddress, + target_hash: targetAddress, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_likers_for_hash", + payload: targetAddress, + }); + assert.equal(linksOutput.length, 0); + }, true); }); test("Agent can only change their own likes", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const targetAddress = await fakeActionHash(); - - // Alice likes hash - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "like", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to remove alices' like - const response = bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: alice.agentPubKey, - target_hash: targetAddress, - }, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - - // Alice removes her own like - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "unlike", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to add a like for allice - const response2 = bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: alice.agentPubKey, - target_hash: targetAddress, - }, - }); - await expect(response2).rejects.toThrowError(/InvalidCommit/); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const targetAddress = await fakeActionHash(); + + // Alice likes hash + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "like", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to remove alices' like + const response = bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: alice.agentPubKey, + target_hash: targetAddress, + }, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + + // Alice removes her own like + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "unlike", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to add a like for allice + const response2 = bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: alice.agentPubKey, + target_hash: targetAddress, + }, + }); + await expect(response2).rejects.toThrowError(/InvalidCommit/); + }, true); }); diff --git a/tests/src/mewsfeed/mews/agent-mews.test.ts b/tests/src/mewsfeed/mews/agent-mews.test.ts index e09914cb..54b97b64 100644 --- a/tests/src/mewsfeed/mews/agent-mews.test.ts +++ b/tests/src/mewsfeed/mews/agent-mews.test.ts @@ -6,247 +6,239 @@ import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; test("create a Mew and get agent mews", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Bob gets agent mews - let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - }, - }); - assert.equal(collectionOutput.length, 0); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets agent mews again - collectionOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - }, - }); - assert.equal(collectionOutput.length, 1); - assert.deepEqual(actionHash, collectionOutput[0].action_hash); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Bob gets agent mews + let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + }, + }); + assert.equal(collectionOutput.length, 0); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets agent mews again + collectionOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + }, + }); + assert.equal(collectionOutput.length, 1); + assert.deepEqual(actionHash, collectionOutput[0].action_hash); + }, true); }); -test("Agent mews list are time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - limit: 2, - }, +test("Agent mews lists are time-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + limit: 2, }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, + }, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - }, + }, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - }, + }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - }, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); + assert.lengthOf(page5, 0); + }, true); }); diff --git a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts index 99104133..c1aaf61b 100644 --- a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts +++ b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts @@ -12,744 +12,720 @@ import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; test("notifications include my agent follows & unfollows", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Bob follows Alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - // Bob unfollows Alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyAgentUnfollowed]: null }, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyAgentFollowed]: null }, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Bob follows Alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + // Bob unfollows Alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyAgentUnfollowed]: null }, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyAgentFollowed]: null }, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, true); }); test("notifications include my mews' likes & unlikes", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - const feedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob likes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - // Bob unlikes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewUnlicked]: null }, - feed_mew: feedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewLicked]: null }, - feed_mew: feedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + const feedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob likes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + // Bob unlikes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewUnlicked]: null }, + feed_mew: feedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewLicked]: null }, + feed_mew: feedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, true); }); test("notifications include my mews' pins & unpins", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - const feedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob likes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "add_hash_for_pinner", - payload: { - base_pinner: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - // Bob unlikes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "remove_hash_for_pinner", - payload: { - base_pinner: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewUnpinned]: null }, - feed_mew: feedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewPinned]: null }, - feed_mew: feedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + const feedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob likes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "add_hash_for_pinner", + payload: { + base_pinner: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + // Bob unlikes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "remove_hash_for_pinner", + payload: { + base_pinner: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewUnpinned]: null }, + feed_mew: feedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewPinned]: null }, + feed_mew: feedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, true); }); test("notifications include my mews' replies, quotes, mewmews", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies to Alice's mew - const replyInput: Mew = { - text: "test reply 12345", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, - }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, - }); - - // Bob mewmews Alice's mew - const mewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }; - const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewmewInput, - }); - const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmewActionHash, - }); - - // Bob quotes Alice's mew - const quoteInput: Mew = { - text: "a response to a quoted mew", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }; - const quoteActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: quoteInput, - }); - const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quoteActionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: quoteFeedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: mewmewFeedMew, - }); - expect(notifications[2]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(3); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies to Alice's mew + const replyInput: Mew = { + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob mewmews Alice's mew + const mewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }; + const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewmewInput, + }); + const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmewActionHash, + }); + + // Bob quotes Alice's mew + const quoteInput: Mew = { + text: "a response to a quoted mew", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }; + const quoteActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: quoteInput, + }); + const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quoteActionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: quoteFeedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: mewmewFeedMew, + }); + expect(notifications[2]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(3); + }, true); }); test("notifications include replies, quotes, mewmews to mews that I also responded to", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Carol creates a Mew - const actionHash: ActionHash = await createMew(carol.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice reply's to Carol's mew - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "test reply 12345", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }, - }); - - // Bob replies to Carol's mew - const replyInput: Mew = { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Carol creates a Mew + const actionHash: ActionHash = await createMew(carol.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice reply's to Carol's mew + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { text: "test reply 12345", links: [], mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, - }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, - }); - - // Bob mewmews Carol's mew - const mewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }; - const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewmewInput, - }); - const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmewActionHash, - }); - - // Bob quotes Carol's mew - const quoteInput: Mew = { - text: "a response to a quoted mew", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }; - const quoteActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: quoteInput, - }); - const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quoteActionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: quoteFeedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: mewmewFeedMew, - }); - expect(notifications[2]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: replyFeedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(3); - }, - true, - { timeout: 500000 } - ); + }, + }); + + // Bob replies to Carol's mew + const replyInput: Mew = { + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob mewmews Carol's mew + const mewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }; + const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewmewInput, + }); + const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmewActionHash, + }); + + // Bob quotes Carol's mew + const quoteInput: Mew = { + text: "a response to a quoted mew", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }; + const quoteActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: quoteInput, + }); + const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quoteActionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: quoteFeedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: mewmewFeedMew, + }); + expect(notifications[2]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: replyFeedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(3); + }, true); }); test("notifications list is time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies to Alice's mew - const replyInput: Mew = { - text: "xyxyxyxy test reply 1", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, - }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, - }); - - // Bob replies to Alice's mew - const replyInput2: Mew = { - text: "xyxyxyxy test reply 2", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash2: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput2, - }); - const replyFeedMew2: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash2, - }); - - // Bob replies to Alice's mew - const replyInput3: Mew = { - text: "xyxyxyxy test reply 3", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash3: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput3, - }); - const replyFeedMew3: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash3, - }); - - // Bob replies to Alice's mew - const replyInput4: Mew = { - text: "xyxyxyxy test reply 4", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash4: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput4, - }); - const replyFeedMew4: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash4, - }); - - // Bob replies to Alice's mew - const replyInput5: Mew = { - text: "xyxyxyxy test reply 5", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash5: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput5, - }); - const replyFeedMew5: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash5, - }); - - // Bob replies to Alice's mew - const replyInput6: Mew = { - text: "xyxyxyxy test reply 6", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash6: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput6, - }); - const replyFeedMew6: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash6, - }); - - // Bob replies to Alice's mew - const replyInput7: Mew = { - text: "xyxyxyxy test reply 7", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash7: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput7, - }); - const replyFeedMew7: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash7, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const page1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page1[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew7, - }); - expect(page1[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew6, - }); - - expect(page1[0].timestamp).greaterThanOrEqual(page1[1].timestamp); - - // Alice gets notifications - const page2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page1[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page2[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew5, - }); - expect(page2[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew4, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp); - - // Alice gets notifications - const page3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page2[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page3[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew3, - }); - expect(page3[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew2, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp) - .greaterThanOrEqual(page3[0].timestamp) - .greaterThanOrEqual(page3[1].timestamp); - - // Alice gets notifications - const page4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page3[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - assert.lengthOf(page4, 1); - expect(page4[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp) - .greaterThanOrEqual(page3[0].timestamp) - .greaterThanOrEqual(page3[1].timestamp) - .greaterThanOrEqual(page4[0].timestamp); - - const page5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page4[0].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies to Alice's mew + const replyInput: Mew = { + text: "xyxyxyxy test reply 1", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob replies to Alice's mew + const replyInput2: Mew = { + text: "xyxyxyxy test reply 2", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash2: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput2, + }); + const replyFeedMew2: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash2, + }); + + // Bob replies to Alice's mew + const replyInput3: Mew = { + text: "xyxyxyxy test reply 3", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash3: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput3, + }); + const replyFeedMew3: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash3, + }); + + // Bob replies to Alice's mew + const replyInput4: Mew = { + text: "xyxyxyxy test reply 4", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash4: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput4, + }); + const replyFeedMew4: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash4, + }); + + // Bob replies to Alice's mew + const replyInput5: Mew = { + text: "xyxyxyxy test reply 5", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash5: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput5, + }); + const replyFeedMew5: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash5, + }); + + // Bob replies to Alice's mew + const replyInput6: Mew = { + text: "xyxyxyxy test reply 6", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash6: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput6, + }); + const replyFeedMew6: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash6, + }); + + // Bob replies to Alice's mew + const replyInput7: Mew = { + text: "xyxyxyxy test reply 7", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash7: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput7, + }); + const replyFeedMew7: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash7, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const page1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(page1[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew7, + }); + expect(page1[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew6, + }); + + expect(page1[0].timestamp).greaterThanOrEqual(page1[1].timestamp); + + // Alice gets notifications + const page2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page1[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(page2[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew5, + }); + expect(page2[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew4, + }); + + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp); + + // Alice gets notifications + const page3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page2[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(page3[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew3, + }); + expect(page3[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew2, + }); + + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp) + .greaterThanOrEqual(page3[0].timestamp) + .greaterThanOrEqual(page3[1].timestamp); + + // Alice gets notifications + const page4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page3[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + assert.lengthOf(page4, 1); + expect(page4[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew, + }); + + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp) + .greaterThanOrEqual(page3[0].timestamp) + .greaterThanOrEqual(page3[1].timestamp) + .greaterThanOrEqual(page4[0].timestamp); + + const page5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page4[0].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + assert.lengthOf(page5, 0); + }, true); }); diff --git a/tests/src/mewsfeed/mews/dna-properties.test.ts b/tests/src/mewsfeed/mews/dna-properties.test.ts index ffcc9369..2a87e2ab 100644 --- a/tests/src/mewsfeed/mews/dna-properties.test.ts +++ b/tests/src/mewsfeed/mews/dna-properties.test.ts @@ -8,183 +8,161 @@ import { } from "../../common.js"; test("Mew must not be longer than DNA property mew_characters_max chars", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const createMewInput: Mew = { - text: new Array(200).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const createMewInput: Mew = { + text: new Array(200).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length" + ); + + createMewInput.text = new Array(201).fill("a").join(""); + try { + await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", payload: createMewInput, }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length" - ); - - createMewInput.text = new Array(201).fill("a").join(""); - try { - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.fail("mew content longer than mew_characters_max is valid"); - } catch (error) { - assert.ok( - true, - "mew content longer than mew_characters_max is invalid" - ); - } - }, - true, - { timeout: 500000 } - ); + assert.fail("mew content longer than mew_characters_max is valid"); + } catch (error) { + assert.ok(true, "mew content longer than mew_characters_max is invalid"); + } + }, true); }); test("Mew must not be shorter than DNA property mew_characters_min chars", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const createMewInput: Mew = { - text: new Array(10).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const createMewInput: Mew = { + text: new Array(10).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length" + ); + + createMewInput.text = new Array(2).fill("a").join(""); + try { + await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", payload: createMewInput, }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length" - ); - - createMewInput.text = new Array(2).fill("a").join(""); - try { - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.fail("mew content shorter than mew_characters_min is valid"); - } catch (error) { - assert.ok( - true, - "mew content shorter than mew_characters_min is invalid" - ); - } - }, - true, - { timeout: 500000 } - ); + assert.fail("mew content shorter than mew_characters_min is valid"); + } catch (error) { + assert.ok(true, "mew content shorter than mew_characters_min is invalid"); + } + }, true); }); test("Mew can be any length if DNA property mew_characters_min and mew_characters_max not set", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { - appBundleSource: mewsfeedAppBundleSourceNoLengthLimits, - }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // 0 charactres - const createMewInput2: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash2: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - assert.deepEqual( - action_hash2.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length 0" - ); - - // 1000 charactres - const createMewInput3: Mew = { - text: new Array(1000).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash3: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - assert.deepEqual( - action_hash3.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length 1000" - ); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { + appBundleSource: mewsfeedAppBundleSourceNoLengthLimits, + }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // 0 charactres + const createMewInput2: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash2: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + assert.deepEqual( + action_hash2.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length 0" + ); + + // 1000 charactres + const createMewInput3: Mew = { + text: new Array(1000).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash3: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + assert.deepEqual( + action_hash3.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length 1000" + ); + }, true); }); test("Can get deserialized DNA Properties", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const properties = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_dna_properties", - payload: null, - }); - expect(properties).toHaveProperty("mew_characters_min", 5); - expect(properties).toHaveProperty("mew_characters_max", 200); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const properties = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_dna_properties", + payload: null, + }); + expect(properties).toHaveProperty("mew_characters_min", 5); + expect(properties).toHaveProperty("mew_characters_max", 200); + }, true); }); diff --git a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts index e0537196..6e6109ec 100644 --- a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts +++ b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts @@ -6,619 +6,584 @@ import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; test("create a Mew and get followed creators mews", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - console.log("adding"); - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - console.log("added"); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - console.log("sharing all agents"); - await scenario.shareAllAgents(); - console.log("shared"); - - // Bob follows alice - console.log("calling zome follow"); - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - console.log("called"); - - // Bob gets followed creators mews - let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.equal(collectionOutput.length, 0); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets followed creators mews again - collectionOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - - assert.equal(collectionOutput.length, 1); - assert.deepEqual(actionHash, collectionOutput[0].action_hash); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + console.log("adding"); + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + console.log("added"); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + console.log("sharing all agents"); + await scenario.shareAllAgents(); + console.log("shared"); + + // Bob follows alice + console.log("calling zome follow"); + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + console.log("called"); + + // Bob gets followed creators mews + let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.equal(collectionOutput.length, 0); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets followed creators mews again + collectionOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + + assert.equal(collectionOutput.length, 1); + assert.deepEqual(actionHash, collectionOutput[0].action_hash); + }, true); }); test("Followed creators mews should include mews of followed creator", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = "test-mew"; - const mewInput: Mew = { - text: mewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewInput, - }); - - const bobMewsFeedInitial: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - bobMewsFeedInitial.length === 0, - "bob's mews feed is initially empty" - ); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); - assert.equal( - bobMewsFeed[0].mew.text, - mewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = "test-mew"; + const mewInput: Mew = { + text: mewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewInput, + }); + + const bobMewsFeedInitial: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + bobMewsFeedInitial.length === 0, + "bob's mews feed is initially empty" + ); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal( + bobMewsFeed[0].mew.text, + mewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + }, true); }); test("Followed creators mews should include own mews", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewsFeedInitial: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - aliceMewsFeedInitial.length === 0, - "alice's mews feed is initially empty" - ); - - const mewContent = "test-mew"; - const mewInput: Mew = { - text: mewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewInput, - }); - - const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - aliceMewsFeed.length === 1, - "alice's mews feed includes her mew" - ); - assert.equal( - aliceMewsFeed[0].mew.text, - mewContent, - "mew content matches" - ); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewsFeedInitial: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeedInitial.length === 0, + "alice's mews feed is initially empty" + ); + + const mewContent = "test-mew"; + const mewInput: Mew = { + text: mewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewInput, + }); + + const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(aliceMewsFeed.length === 1, "alice's mews feed includes her mew"); + assert.equal(aliceMewsFeed[0].mew.text, mewContent, "mew content matches"); + }, true); }); test("Followed creators mews should not include mews of non-followed creator", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const carolMewContent = "carol-test-mew"; - const carolMewInput: Mew = { - text: carolMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await carol.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: carolMewInput, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); - assert.equal( - bobMewsFeed[0].mew.text, - aliceMewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const carolMewContent = "carol-test-mew"; + const carolMewInput: Mew = { + text: carolMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await carol.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: carolMewInput, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal( + bobMewsFeed[0].mew.text, + aliceMewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + }, true); }); test("Unfollowing should exclude creators mews from feed", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const bobMewsFeedWhenFollowing: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - bobMewsFeedWhenFollowing.length === 1, - "bob's mews feed includes 1 mew" - ); - assert.equal( - bobMewsFeedWhenFollowing[0].mew.text, - aliceMewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "unfollow", - payload: alice.agentPubKey, - }); - - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 0, "bob's mews feed is empty"); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const bobMewsFeedWhenFollowing: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + bobMewsFeedWhenFollowing.length === 1, + "bob's mews feed includes 1 mew" + ); + assert.equal( + bobMewsFeedWhenFollowing[0].mew.text, + aliceMewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "unfollow", + payload: alice.agentPubKey, + }); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 0, "bob's mews feed is empty"); + }, true); }); test("Followed creators mews should be ordered by timestamp in descending order", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const firstMewContent = "first-test-mew"; - const firstMewInput: Mew = { - text: firstMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: firstMewInput, - }); - - const secondMewContent = "second-test-mew"; - const secondMewInput: Mew = { - text: secondMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: secondMewInput, - }); - - const thirdMewContent = "third-test-mew"; - const thirdMewInput: Mew = { - text: thirdMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await carol.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: thirdMewInput, - }); - - const fourthMewContent = "fourth-test-mew"; - const fourthMewInput: Mew = { - text: fourthMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: fourthMewInput, - }); - // alice starts following bob and carol - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: bob.agentPubKey, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: carol.agentPubKey, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - aliceMewsFeed.length === 4, - "alice's mews feed includes all 4 mews" - ); - assert.equal( - aliceMewsFeed[0].mew.text, - fourthMewContent, - "mew 1 in feed is fourth mew" - ); - assert.equal( - aliceMewsFeed[1].mew.text, - thirdMewContent, - "mew 2 in feed is third mew" - ); - assert.equal( - aliceMewsFeed[2].mew.text, - secondMewContent, - "mew 3 in feed is second mew" - ); - assert.equal( - aliceMewsFeed[3].mew.text, - firstMewContent, - "mew 4 in feed is first mew" - ); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const firstMewContent = "first-test-mew"; + const firstMewInput: Mew = { + text: firstMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: firstMewInput, + }); + + const secondMewContent = "second-test-mew"; + const secondMewInput: Mew = { + text: secondMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: secondMewInput, + }); + + const thirdMewContent = "third-test-mew"; + const thirdMewInput: Mew = { + text: thirdMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await carol.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: thirdMewInput, + }); + + const fourthMewContent = "fourth-test-mew"; + const fourthMewInput: Mew = { + text: fourthMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: fourthMewInput, + }); + // alice starts following bob and carol + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: bob.agentPubKey, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: carol.agentPubKey, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeed.length === 4, + "alice's mews feed includes all 4 mews" + ); + assert.equal( + aliceMewsFeed[0].mew.text, + fourthMewContent, + "mew 1 in feed is fourth mew" + ); + assert.equal( + aliceMewsFeed[1].mew.text, + thirdMewContent, + "mew 2 in feed is third mew" + ); + assert.equal( + aliceMewsFeed[2].mew.text, + secondMewContent, + "mew 3 in feed is second mew" + ); + assert.equal( + aliceMewsFeed[3].mew.text, + firstMewContent, + "mew 4 in feed is first mew" + ); + }, true); }); test("Followed creators mews list are time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const page1: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - limit: 2, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - }, - }); - - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const page1: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + limit: 2, + }, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, + }); + + assert.lengthOf(page5, 0); + }, true); }); diff --git a/tests/src/mewsfeed/mews/mention-to-mews.test.ts b/tests/src/mewsfeed/mews/mention-to-mews.test.ts index 79eba740..f12c62e3 100644 --- a/tests/src/mewsfeed/mews/mention-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/mention-to-mews.test.ts @@ -11,260 +11,252 @@ import { createMew } from "./common.js"; import { ActionHash } from "@holochain/client"; test("mention in mews", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - await createMew(alice.cells[0], { - text: "this is for @bob", - links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], - mew_type: { Original: null }, - }); + await createMew(alice.cells[0], { + text: "this is for @bob", + links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], + mew_type: { Original: null }, + }); - const actionHash2: ActionHash = await createMew(bob.cells[0], { - text: "this is for @bob 2", - links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], - mew_type: { Original: null }, - }); + const actionHash2: ActionHash = await createMew(bob.cells[0], { + text: "this is for @bob 2", + links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], + mew_type: { Original: null }, + }); - const actionHash3: ActionHash = await createMew(alice.cells[0], { - text: "this is for @alice", - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { Original: null }, - }); + const actionHash3: ActionHash = await createMew(alice.cells[0], { + text: "this is for @alice", + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { Original: null }, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - const mentionedMewsBob: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: bob.agentPubKey, - }, - }); - assert.ok(mentionedMewsBob.length === 2, "one mew with mention"); - assert.deepEqual(mentionedMewsBob[0].action_hash, actionHash2); + const mentionedMewsBob: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: bob.agentPubKey, + }, + }); + assert.ok(mentionedMewsBob.length === 2, "one mew with mention"); + assert.deepEqual(mentionedMewsBob[0].action_hash, actionHash2); - const mentionedMewsAlice: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - }, - }); - assert.ok(mentionedMewsAlice.length === 1, "one mew with mention"); - assert.deepEqual(mentionedMewsAlice[0].action_hash, actionHash3); - }, - true, - { timeout: 500000 } - ); + const mentionedMewsAlice: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + }, + }); + assert.ok(mentionedMewsAlice.length === 1, "one mew with mention"); + assert.deepEqual(mentionedMewsAlice[0].action_hash, actionHash3); + }, true); }); test("Mentions list are time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - const mewContent1 = "My Mew with @mention 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); + const mewContent1 = "My Mew with @mention 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); - const mewContent2 = "My Mew with @mention 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); + const mewContent2 = "My Mew with @mention 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); - const mewContent3 = "My Mew with @mention 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); + const mewContent3 = "My Mew with @mention 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); - const mewContent4 = "My Mew with @mention 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); + const mewContent4 = "My Mew with @mention 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); - const mewContent5 = "My Mew with @mention 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); + const mewContent5 = "My Mew with @mention 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); - const mewContent6 = "My Mew with @mention 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); + const mewContent6 = "My Mew with @mention 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); - const mewContent7 = "My Mew with @mention 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); + const mewContent7 = "My Mew with @mention 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - start_time: null, - limit: 2, - }, + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + start_time: null, + limit: 2, }, - }); + }, + }); - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - }, + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - }, + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - }, + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); + assert.lengthOf(page5, 0); + }, true); }); diff --git a/tests/src/mewsfeed/mews/mew-to-responses.test.ts b/tests/src/mewsfeed/mews/mew-to-responses.test.ts index 06447128..513a9c1e 100644 --- a/tests/src/mewsfeed/mews/mew-to-responses.test.ts +++ b/tests/src/mewsfeed/mews/mew-to-responses.test.ts @@ -5,219 +5,203 @@ import { mewsfeedAppBundleSource } from "../../common.js"; import { ActionHash } from "@holochain/client"; test("Agent can reply to a mew", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const aliceReplyContent = "alice-test-reply"; - const aliceReplyInput: Mew = { - text: aliceReplyContent, - links: [], - mew_type: { [MewTypeName.Reply]: action_hash }, - }; - const reply_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceReplyInput, - }); - - const replyMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: reply_action_hash, - }); - assert.ok(MewTypeName.Reply in replyMew.mew.mew_type, "mew is a reply"); - assert.equal( - replyMew.mew.text, - aliceReplyContent, - "reply is alice's reply" - ); - - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.replies_count === 1, "original mew has 1 reply"); - assert.isTrue( - originalMew.is_replied, - "original mew's reply is alice's reply" - ); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const aliceReplyContent = "alice-test-reply"; + const aliceReplyInput: Mew = { + text: aliceReplyContent, + links: [], + mew_type: { [MewTypeName.Reply]: action_hash }, + }; + const reply_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceReplyInput, + }); + + const replyMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: reply_action_hash, + }); + assert.ok(MewTypeName.Reply in replyMew.mew.mew_type, "mew is a reply"); + assert.equal( + replyMew.mew.text, + aliceReplyContent, + "reply is alice's reply" + ); + + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); + assert.ok(originalMew.replies_count === 1, "original mew has 1 reply"); + assert.isTrue( + originalMew.is_replied, + "original mew's reply is alice's reply" + ); + }, true); }); test("Agent can mewmew a mew, only once", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const aliceMewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: action_hash }, - }; - const mewmew_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewmewInput, - }); - - const mewmew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmew_action_hash, - }); - assert.ok(MewTypeName.Mewmew in mewmew.mew.mew_type, "mew is a mewmew"); - assert.deepEqual( - mewmew.mew, - aliceMewmewInput, - "mewmew is alice's mewmew" - ); - - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); - assert.isTrue( - originalMew.is_mewmewed, - "original mew's mewmew is alice's mewmew" - ); - - // Mewmew the same mew again - const response = alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewmewInput, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const aliceMewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: action_hash }, + }; + const mewmew_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewmewInput, + }); + + const mewmew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmew_action_hash, + }); + assert.ok(MewTypeName.Mewmew in mewmew.mew.mew_type, "mew is a mewmew"); + assert.deepEqual(mewmew.mew, aliceMewmewInput, "mewmew is alice's mewmew"); + + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); + assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); + assert.isTrue( + originalMew.is_mewmewed, + "original mew's mewmew is alice's mewmew" + ); + + // Mewmew the same mew again + const response = alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewmewInput, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + }, true); }); test("Agent can quote a mew", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const aliceQuoteText = "alice-test-quote"; - const aliceQuoteInput: Mew = { - text: aliceQuoteText, - links: [], - mew_type: { - [MewTypeName.Quote]: action_hash, - }, - }; - const quote_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceQuoteInput, - }); - - const quote: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quote_action_hash, - }); - assert.ok(MewTypeName.Quote in quote.mew.mew_type, "mew is a quote"); - assert.equal(quote.mew.text, aliceQuoteText, "quote is alice's quote"); - - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.quotes_count === 1, "original mew has 1 quote"); - assert.isTrue( - originalMew.is_quoted, - "original mew's quote is alice's quote" - ); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const aliceQuoteText = "alice-test-quote"; + const aliceQuoteInput: Mew = { + text: aliceQuoteText, + links: [], + mew_type: { + [MewTypeName.Quote]: action_hash, + }, + }; + const quote_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceQuoteInput, + }); + + const quote: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quote_action_hash, + }); + assert.ok(MewTypeName.Quote in quote.mew.mew_type, "mew is a quote"); + assert.equal(quote.mew.text, aliceQuoteText, "quote is alice's quote"); + + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); + assert.ok(originalMew.quotes_count === 1, "original mew has 1 quote"); + assert.isTrue( + originalMew.is_quoted, + "original mew's quote is alice's quote" + ); + }, true); }); diff --git a/tests/src/mewsfeed/mews/mew-with-context.test.ts b/tests/src/mewsfeed/mews/mew-with-context.test.ts index b99e9b9b..38ce0161 100644 --- a/tests/src/mewsfeed/mews/mew-with-context.test.ts +++ b/tests/src/mewsfeed/mews/mew-with-context.test.ts @@ -5,7 +5,6 @@ import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; - test("Mew with context contains licks count and is_licked", async () => { await runScenario( async (scenario) => { diff --git a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts index c784031c..4f6cc49e 100644 --- a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts @@ -5,72 +5,68 @@ import { FeedMew } from "../../../../ui/src/types/types.js"; import { createMew } from "./common.js"; test("link a Pinner to a Mew", async () => { - await runScenario( - async (scenario) => { - // Construct proper paths for your app. - // This assumes app bundle created by the `hc app pack` command. - const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; + await runScenario(async (scenario) => { + // Construct proper paths for your app. + // This assumes app bundle created by the `hc app pack` command. + const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; - // Set up the app to be installed - const appSource = { appBundleSource: { path: testAppPath } }; + // Set up the app to be installed + const appSource = { appBundleSource: { path: testAppPath } }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - const baseAddress = alice.agentPubKey; - const targetActionHash: ActionHash = await createMew(alice.cells[0]); + const baseAddress = alice.agentPubKey; + const targetActionHash: ActionHash = await createMew(alice.cells[0]); - // Bob gets the links, should be empty - let linksOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); + // Bob gets the links, should be empty + let linksOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); - // Alice creates a link from Pinner to Mew - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: targetActionHash, - }); + // Alice creates a link from Pinner to Mew + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: targetActionHash, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 1); - assert.deepEqual(targetActionHash, linksOutput[0].action_hash); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 1); + assert.deepEqual(targetActionHash, linksOutput[0].action_hash); - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: targetActionHash, - }); + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: targetActionHash, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - }, - true, - { timeout: 500000 } - ); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + }, true); }); diff --git a/tests/src/mewsfeed/mews/tags-to-mews.test.ts b/tests/src/mewsfeed/mews/tags-to-mews.test.ts index 7d4e2133..92ff5510 100644 --- a/tests/src/mewsfeed/mews/tags-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/tags-to-mews.test.ts @@ -11,588 +11,561 @@ import { import { mewsfeedAppBundleSource } from "../../common.js"; test("Hashtag, cashtag and mention", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = - "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; - const createMewInput: Mew = { - text: mewContent, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a valid mew" - ); - - const hashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - }, - }); - assert.ok(hashtaggedMews.length === 1, "one mew with hashtag"); - assert.equal( - hashtaggedMews[0].mew.text, - mewContent, - "mew content matches" - ); - - const arabicHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#سعيدة", - }, - }); - assert.ok( - arabicHashtaggedMews.length === 1, - "one mew with arabic hashtag" - ); - assert.equal( - arabicHashtaggedMews[0].mew.text, - mewContent, - "mew content matches" - ); - - // get hashtag containing emojis -- invalid hashtag! - const emojiHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#😃😃😃", - }, - }); - assert.ok(emojiHashtaggedMews.length === 0, "no mew with emoji hashtag"); - - const cashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - }, - }); - assert.ok(cashtaggedMews.length === 1, "one mew with cashtag"); - - const mentionedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - }, - }); - assert.ok(mentionedMews.length === 1, "one mew with mention"); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = + "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; + const createMewInput: Mew = { + text: mewContent, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a valid mew" + ); + + const hashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + }, + }); + assert.ok(hashtaggedMews.length === 1, "one mew with hashtag"); + assert.equal(hashtaggedMews[0].mew.text, mewContent, "mew content matches"); + + const arabicHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#سعيدة", + }, + }); + assert.ok(arabicHashtaggedMews.length === 1, "one mew with arabic hashtag"); + assert.equal( + arabicHashtaggedMews[0].mew.text, + mewContent, + "mew content matches" + ); + + // get hashtag containing emojis -- invalid hashtag! + const emojiHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#😃😃😃", + }, + }); + assert.ok(emojiHashtaggedMews.length === 0, "no mew with emoji hashtag"); + + const cashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + }, + }); + assert.ok(cashtaggedMews.length === 1, "one mew with cashtag"); + + const mentionedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + }, + }); + assert.ok(mentionedMews.length === 1, "one mew with mention"); + }, true); }); test("Prefix index should return hashtags and cashtags", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = - "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; - const createMewInput: Mew = { - text: mewContent, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a valid mew" - ); - - const hashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "has", - limit: 10, - }, - }); - assert.ok(hashtags.length === 1, "one hashtag"); - assert.equal(hashtags[0], "#hashtag", "hashtag search result matches"); - - const arabicHashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "سعيدة", - limit: 10, - }, - }); - assert.ok(arabicHashtags.length === 1, "one arabic hashtag"); - assert.equal( - arabicHashtags[0], - "#سعيدة", - "hashtag search result matches" - ); - - // get hashtag containing emojis -- invalid hashtag! - const emojiHashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "😃😃😃", - limit: 10, - }, - }); - assert.ok(emojiHashtags.length === 0, "no emoji hashtags"); - - const cashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "cas", - limit: 10, - }, - }); - assert.ok(cashtags.length === 1, "one cashtag"); - assert.equal(cashtags[0], "$cashtag", "hashtag search result matches"); - }, - true, - { timeout: 500000 } - ); + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = + "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; + const createMewInput: Mew = { + text: mewContent, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a valid mew" + ); + + const hashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "has", + limit: 10, + }, + }); + assert.ok(hashtags.length === 1, "one hashtag"); + assert.equal(hashtags[0], "#hashtag", "hashtag search result matches"); + + const arabicHashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "سعيدة", + limit: 10, + }, + }); + assert.ok(arabicHashtags.length === 1, "one arabic hashtag"); + assert.equal(arabicHashtags[0], "#سعيدة", "hashtag search result matches"); + + // get hashtag containing emojis -- invalid hashtag! + const emojiHashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "😃😃😃", + limit: 10, + }, + }); + assert.ok(emojiHashtags.length === 0, "no emoji hashtags"); + + const cashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "cas", + limit: 10, + }, + }); + assert.ok(cashtags.length === 1, "one cashtag"); + assert.equal(cashtags[0], "$cashtag", "hashtag search result matches"); + }, true); }); test("Hashtags list are time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - limit: 2, - }, + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + limit: 2, }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, + }, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page2[page1.length - 1].action_hash, - limit: 2, - }, + }, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page2[page1.length - 1].action_hash, + limit: 2, }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page3[page1.length - 1].action_hash, - limit: 2, - }, + }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page3[page1.length - 1].action_hash, + limit: 2, }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - }, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); + assert.lengthOf(page5, 0); + }, true); }); test("Cashtags list are time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with $cashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with $cashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with $cashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with $cashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with $cashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with $cashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with $cashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - start_time: null, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with $cashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with $cashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with $cashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with $cashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with $cashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with $cashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with $cashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + start_time: null, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, + }, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, + }, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, + }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, - }); + }, + }); - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); + assert.lengthOf(page5, 0); + }, true); }); From 5f1d803a034dd9d615035e9f405b7008cf431900 Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Tue, 31 Oct 2023 20:47:35 -0600 Subject: [PATCH 05/22] tests: run in parallel --- .../agent_pins/pinner-to-hashes.test.ts | 172 +- .../follows/follower-to-creators.test.ts | 814 +++++----- .../mewsfeed/likes/liker-to-hashes.test.ts | 290 ++-- tests/src/mewsfeed/mews/agent-mews.test.ts | 462 +++--- .../mews/agent-to-notifications.test.ts | 1432 +++++++++-------- .../src/mewsfeed/mews/dna-properties.test.ts | 310 ++-- .../mews/followed-creators-mews.test.ts | 1171 +++++++------- .../src/mewsfeed/mews/mention-to-mews.test.ts | 438 ++--- .../mewsfeed/mews/mew-to-responses.test.ts | 410 ++--- .../mewsfeed/mews/mew-with-context.test.ts | 684 ++++---- .../src/mewsfeed/mews/pinner-to-mews.test.ts | 112 +- tests/src/mewsfeed/mews/tags-to-mews.test.ts | 1111 ++++++------- 12 files changed, 3726 insertions(+), 3680 deletions(-) diff --git a/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts b/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts index a0599574..b2bd12a2 100644 --- a/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts +++ b/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts @@ -1,88 +1,90 @@ -import { assert, test } from "vitest"; +import { assert, describe, it } from "vitest"; -import { runScenario, dhtSync } from "@holochain/tryorama"; import { AgentPubKey, HoloHash, fakeActionHash } from "@holochain/client"; - -test("link a Pinner to a Hash", async () => { - await runScenario(async (scenario) => { - // Construct proper paths for your app. - // This assumes app bundle created by the `hc app pack` command. - const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; - - // Set up the app to be installed - const appSource = { appBundleSource: { path: testAppPath } }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetHash = await fakeActionHash(); - - // Bob gets the links, should be empty - let linksOutput: HoloHash[] = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Pinner to Hash - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: targetHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - const pinnersOutput: AgentPubKey[] = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_pinners_for_hash", - payload: targetHash, - }); - assert.equal(pinnersOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: targetHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_pinners_for_hash", - payload: targetHash, - }); - - assert.equal(linksOutput.length, 0); - }, true); +import { dhtSync, runScenario } from "@holochain/tryorama"; + +describe.concurrent("pinner-to-hashes", () => { + it("link a Pinner to a Hash", async () => { + await runScenario(async (scenario) => { + // Construct proper paths for your app. + // This assumes app bundle created by the `hc app pack` command. + const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; + + // Set up the app to be installed + const appSource = { appBundleSource: { path: testAppPath } }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetHash = await fakeActionHash(); + + // Bob gets the links, should be empty + let linksOutput: HoloHash[] = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Pinner to Hash + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: targetHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + const pinnersOutput: AgentPubKey[] = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_pinners_for_hash", + payload: targetHash, + }); + assert.equal(pinnersOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: targetHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_pinners_for_hash", + payload: targetHash, + }); + + assert.equal(linksOutput.length, 0); + }, true); + }); }); diff --git a/tests/src/mewsfeed/follows/follower-to-creators.test.ts b/tests/src/mewsfeed/follows/follower-to-creators.test.ts index f66bb1dc..d877793d 100644 --- a/tests/src/mewsfeed/follows/follower-to-creators.test.ts +++ b/tests/src/mewsfeed/follows/follower-to-creators.test.ts @@ -1,429 +1,431 @@ -import { assert, test, expect } from "vitest"; -import { runScenario, dhtSync } from "@holochain/tryorama"; import { AgentPubKey, Record } from "@holochain/client"; +import { dhtSync, runScenario } from "@holochain/tryorama"; +import { assert, describe, expect, it } from "vitest"; import { mewsfeedAppBundleSource } from "../../common"; -test("link a Follower to a Creator", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = bob.agentPubKey; - - // Bob gets the links, should be empty - let linksOutput: Record[] = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Follower to Creator - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: targetAddress, - }, - }); - assert.equal(linksOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: targetAddress, - }, - }); - assert.equal(linksOutput.length, 0); - }, true); -}); - -test("Agent cannot follow themselves", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice tries to follow herself - const response = alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - }, true); -}); - -test("Agent can only change their own follows", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = bob.agentPubKey; - - // Alice follows bob - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to remove alices' follow - const response = bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - - // Alice removes her own follow - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "unfollow", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to add a follow for allice - const response2 = bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); - await expect(response2).rejects.toThrowError(/InvalidCommit/); - }, true); -}); +describe.concurrent("follower-to-creators", () => { + it("link a Follower to a Creator", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; -test("Creators list are hash-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol, john, steve, mary] = - await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - appSource, + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ appSource, appSource, ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a link from Follower to Creator - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: bob.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: carol.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: john.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: steve.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: mary.agentPubKey, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const page1: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - limit: 2, + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = bob.agentPubKey; + + // Bob gets the links, should be empty + let linksOutput: Record[] = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, }, - }, - }); - - assert.deepEqual(page1[0], mary.agentPubKey); - assert.deepEqual(page1[1], steve.agentPubKey); - - const page2: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - after_agentpubkey: page1[1], - limit: 2, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Follower to Creator + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, }, - }, - }); - assert.deepEqual(page2[0], john.agentPubKey); - assert.deepEqual(page2[1], carol.agentPubKey); - - const page3: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - after_agentpubkey: page2[1], - limit: 2, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, }, - }, - }); - assert.lengthOf(page3, 1); - assert.deepEqual(page3[0], bob.agentPubKey); - - const page5: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - after_agentpubkey: page3[0], - limit: 2, + }); + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: targetAddress, }, - }, - }); - assert.lengthOf(page5, 0); - }, true); -}); + }); + assert.equal(linksOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); -test("Followers list are hash-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol, john, steve, mary] = - await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - appSource, + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: targetAddress, + }, + }); + assert.equal(linksOutput.length, 0); + }, true); + }); + + it("Agent cannot follow themselves", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice tries to follow herself + const response = alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + }, true); + }); + + it("Agent can only change their own follows", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ appSource, appSource, ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a link from Follower to Creator - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await carol.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: carol.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await john.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: john.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await steve.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: steve.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await mary.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: mary.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - await dhtSync( - [alice, bob, carol, john, steve, mary], - alice.cells[0].cell_id[0] - ); - - const page1: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - limit: 2, + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = bob.agentPubKey; + + // Alice follows bob + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to remove alices' follow + const response = bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + + // Alice removes her own follow + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "unfollow", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to add a follow for allice + const response2 = bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); + await expect(response2).rejects.toThrowError(/InvalidCommit/); + }, true); + }); + + it("Creators list are hash-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol, john, steve, mary] = + await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a link from Follower to Creator + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: bob.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: carol.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: john.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: steve.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: mary.agentPubKey, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const page1: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + limit: 2, + }, + }, + }); + + assert.deepEqual(page1[0], mary.agentPubKey); + assert.deepEqual(page1[1], steve.agentPubKey); + + const page2: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page1[1], + limit: 2, + }, + }, + }); + assert.deepEqual(page2[0], john.agentPubKey); + assert.deepEqual(page2[1], carol.agentPubKey); + + const page3: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page2[1], + limit: 2, + }, + }, + }); + assert.lengthOf(page3, 1); + assert.deepEqual(page3[0], bob.agentPubKey); + + const page5: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page3[0], + limit: 2, + }, + }, + }); + assert.lengthOf(page5, 0); + }, true); + }); + + it("Followers list are hash-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol, john, steve, mary] = + await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a link from Follower to Creator + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + await carol.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: carol.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + await john.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: john.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + await steve.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: steve.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + await mary.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: mary.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + await dhtSync( + [alice, bob, carol, john, steve, mary], + alice.cells[0].cell_id[0] + ); + + const page1: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + limit: 2, + }, }, - }, - }); - - assert.deepEqual(page1[0], mary.agentPubKey); - assert.deepEqual(page1[1], steve.agentPubKey); - - const page2: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page1[1], - limit: 2, + }); + + assert.deepEqual(page1[0], mary.agentPubKey); + assert.deepEqual(page1[1], steve.agentPubKey); + + const page2: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + after_agentpubkey: page1[1], + limit: 2, + }, }, - }, - }); - assert.deepEqual(page2[0], john.agentPubKey); - assert.deepEqual(page2[1], carol.agentPubKey); - - const page3: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page2[1], - limit: 2, + }); + assert.deepEqual(page2[0], john.agentPubKey); + assert.deepEqual(page2[1], carol.agentPubKey); + + const page3: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + after_agentpubkey: page2[1], + limit: 2, + }, }, - }, - }); - assert.lengthOf(page3, 1); - assert.deepEqual(page3[0], bob.agentPubKey); - - const page5: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page3[0], - limit: 2, + }); + assert.lengthOf(page3, 1); + assert.deepEqual(page3[0], bob.agentPubKey); + + const page5: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + after_agentpubkey: page3[0], + limit: 2, + }, }, - }, - }); - assert.lengthOf(page5, 0); - }, true); + }); + assert.lengthOf(page5, 0); + }, true); + }); }); diff --git a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts index 8f58310e..498a8e73 100644 --- a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts +++ b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts @@ -1,148 +1,150 @@ -import { assert, expect, test } from "vitest"; -import { runScenario, dhtSync } from "@holochain/tryorama"; import { Record, fakeActionHash } from "@holochain/client"; +import { dhtSync, runScenario } from "@holochain/tryorama"; +import { assert, describe, expect, it } from "vitest"; import { mewsfeedAppBundleSource } from "../../common"; -test("link a Liker to a Hash", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = await fakeActionHash(); - - // Bob gets the links, should be empty - let linksOutput: Record[] = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Liker to Hash - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: baseAddress, - target_hash: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_likers_for_hash", - payload: targetAddress, - }); - assert.equal(linksOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: baseAddress, - target_hash: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_likers_for_hash", - payload: targetAddress, - }); - assert.equal(linksOutput.length, 0); - }, true); -}); - -test("Agent can only change their own likes", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const targetAddress = await fakeActionHash(); - - // Alice likes hash - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "like", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to remove alices' like - const response = bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: alice.agentPubKey, - target_hash: targetAddress, - }, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - - // Alice removes her own like - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "unlike", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to add a like for allice - const response2 = bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: alice.agentPubKey, - target_hash: targetAddress, - }, - }); - await expect(response2).rejects.toThrowError(/InvalidCommit/); - }, true); +describe.concurrent("liker-to-hashes", () => { + it("link a Liker to a Hash", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = await fakeActionHash(); + + // Bob gets the links, should be empty + let linksOutput: Record[] = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Liker to Hash + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: baseAddress, + target_hash: targetAddress, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_likers_for_hash", + payload: targetAddress, + }); + assert.equal(linksOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: baseAddress, + target_hash: targetAddress, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_likers_for_hash", + payload: targetAddress, + }); + assert.equal(linksOutput.length, 0); + }, true); + }); + + it("Agent can only change their own likes", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const targetAddress = await fakeActionHash(); + + // Alice likes hash + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "like", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to remove alices' like + const response = bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: alice.agentPubKey, + target_hash: targetAddress, + }, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + + // Alice removes her own like + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "unlike", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to add a like for allice + const response2 = bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: alice.agentPubKey, + target_hash: targetAddress, + }, + }); + await expect(response2).rejects.toThrowError(/InvalidCommit/); + }, true); + }); }); diff --git a/tests/src/mewsfeed/mews/agent-mews.test.ts b/tests/src/mewsfeed/mews/agent-mews.test.ts index 54b97b64..a0856d10 100644 --- a/tests/src/mewsfeed/mews/agent-mews.test.ts +++ b/tests/src/mewsfeed/mews/agent-mews.test.ts @@ -1,244 +1,246 @@ import { ActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -import { assert, expect, test } from "vitest"; +import { assert, describe, expect, it } from "vitest"; import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -test("create a Mew and get agent mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Bob gets agent mews - let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - }, - }); - assert.equal(collectionOutput.length, 0); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets agent mews again - collectionOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - }, - }); - assert.equal(collectionOutput.length, 1); - assert.deepEqual(actionHash, collectionOutput[0].action_hash); - }, true); -}); +describe.concurrent("agent-mews", () => { + it("create a Mew and get agent mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Bob gets agent mews + let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + }, + }); + assert.equal(collectionOutput.length, 0); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); -test("Agent mews lists are time-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - limit: 2, + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets agent mews again + collectionOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + }, + }); + assert.equal(collectionOutput.length, 1); + assert.deepEqual(actionHash, collectionOutput[0].action_hash); + }, true); + }); + + it("Agent mews lists are time-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + limit: 2, + }, }, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, }, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, }, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + }, }, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); - assert.lengthOf(page5, 0); - }, true); + assert.lengthOf(page5, 0); + }, true); + }); }); diff --git a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts index c1aaf61b..fafdab72 100644 --- a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts +++ b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts @@ -1,6 +1,6 @@ import { ActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -import { assert, expect, test } from "vitest"; +import { assert, describe, expect, it, test } from "vitest"; import { FeedMew, Mew, @@ -11,721 +11,723 @@ import { import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -test("notifications include my agent follows & unfollows", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Bob follows Alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - // Bob unfollows Alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyAgentUnfollowed]: null }, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyAgentFollowed]: null }, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, true); -}); - -test("notifications include my mews' likes & unlikes", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - const feedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob likes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - // Bob unlikes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewUnlicked]: null }, - feed_mew: feedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewLicked]: null }, - feed_mew: feedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, true); -}); - -test("notifications include my mews' pins & unpins", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - const feedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob likes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "add_hash_for_pinner", - payload: { - base_pinner: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - // Bob unlikes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "remove_hash_for_pinner", - payload: { - base_pinner: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewUnpinned]: null }, - feed_mew: feedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewPinned]: null }, - feed_mew: feedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, true); -}); - -test("notifications include my mews' replies, quotes, mewmews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies to Alice's mew - const replyInput: Mew = { - text: "test reply 12345", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, - }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, - }); - - // Bob mewmews Alice's mew - const mewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }; - const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewmewInput, - }); - const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmewActionHash, - }); - - // Bob quotes Alice's mew - const quoteInput: Mew = { - text: "a response to a quoted mew", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }; - const quoteActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: quoteInput, - }); - const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quoteActionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: quoteFeedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: mewmewFeedMew, - }); - expect(notifications[2]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(3); - }, true); -}); - -test("notifications include replies, quotes, mewmews to mews that I also responded to", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Carol creates a Mew - const actionHash: ActionHash = await createMew(carol.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice reply's to Carol's mew - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { +describe.concurrent("agent-to-notifications", () => { + it("notifications include my agent follows & unfollows", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Bob follows Alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + // Bob unfollows Alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyAgentUnfollowed]: null }, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyAgentFollowed]: null }, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, true); + }); + + it("notifications include my mews' likes & unlikes", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + const feedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob likes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + // Bob unlikes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewUnlicked]: null }, + feed_mew: feedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewLicked]: null }, + feed_mew: feedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, true); + }); + + it("notifications include my mews' pins & unpins", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + const feedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob likes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "add_hash_for_pinner", + payload: { + base_pinner: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + // Bob unlikes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "remove_hash_for_pinner", + payload: { + base_pinner: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewUnpinned]: null }, + feed_mew: feedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewPinned]: null }, + feed_mew: feedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, true); + }); + + it("notifications include my mews' replies, quotes, mewmews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies to Alice's mew + const replyInput: Mew = { text: "test reply 12345", links: [], mew_type: { [MewTypeName.Reply]: actionHash }, - }, - }); - - // Bob replies to Carol's mew - const replyInput: Mew = { - text: "test reply 12345", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, - }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, - }); - - // Bob mewmews Carol's mew - const mewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }; - const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewmewInput, - }); - const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmewActionHash, - }); - - // Bob quotes Carol's mew - const quoteInput: Mew = { - text: "a response to a quoted mew", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }; - const quoteActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: quoteInput, - }); - const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quoteActionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: quoteFeedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: mewmewFeedMew, - }); - expect(notifications[2]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: replyFeedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(3); - }, true); -}); - -test("notifications list is time-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies to Alice's mew - const replyInput: Mew = { - text: "xyxyxyxy test reply 1", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, - }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, - }); - - // Bob replies to Alice's mew - const replyInput2: Mew = { - text: "xyxyxyxy test reply 2", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash2: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput2, - }); - const replyFeedMew2: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash2, - }); - - // Bob replies to Alice's mew - const replyInput3: Mew = { - text: "xyxyxyxy test reply 3", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash3: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput3, - }); - const replyFeedMew3: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash3, - }); - - // Bob replies to Alice's mew - const replyInput4: Mew = { - text: "xyxyxyxy test reply 4", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash4: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput4, - }); - const replyFeedMew4: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash4, - }); - - // Bob replies to Alice's mew - const replyInput5: Mew = { - text: "xyxyxyxy test reply 5", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash5: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput5, - }); - const replyFeedMew5: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash5, - }); - - // Bob replies to Alice's mew - const replyInput6: Mew = { - text: "xyxyxyxy test reply 6", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash6: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput6, - }); - const replyFeedMew6: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash6, - }); - - // Bob replies to Alice's mew - const replyInput7: Mew = { - text: "xyxyxyxy test reply 7", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash7: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput7, - }); - const replyFeedMew7: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash7, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const page1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page1[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew7, - }); - expect(page1[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew6, - }); - - expect(page1[0].timestamp).greaterThanOrEqual(page1[1].timestamp); - - // Alice gets notifications - const page2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page1[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page2[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew5, - }); - expect(page2[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew4, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp); - - // Alice gets notifications - const page3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page2[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page3[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew3, - }); - expect(page3[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew2, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp) - .greaterThanOrEqual(page3[0].timestamp) - .greaterThanOrEqual(page3[1].timestamp); - - // Alice gets notifications - const page4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page3[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - assert.lengthOf(page4, 1); - expect(page4[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp) - .greaterThanOrEqual(page3[0].timestamp) - .greaterThanOrEqual(page3[1].timestamp) - .greaterThanOrEqual(page4[0].timestamp); - - const page5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page4[0].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - assert.lengthOf(page5, 0); - }, true); + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob mewmews Alice's mew + const mewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }; + const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewmewInput, + }); + const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmewActionHash, + }); + + // Bob quotes Alice's mew + const quoteInput: Mew = { + text: "a response to a quoted mew", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }; + const quoteActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: quoteInput, + }); + const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quoteActionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: quoteFeedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: mewmewFeedMew, + }); + expect(notifications[2]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(3); + }, true); + }); + + it("notifications include replies, quotes, mewmews to mews that I also responded to", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Carol creates a Mew + const actionHash: ActionHash = await createMew(carol.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice reply's to Carol's mew + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }, + }); + + // Bob replies to Carol's mew + const replyInput: Mew = { + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob mewmews Carol's mew + const mewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }; + const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewmewInput, + }); + const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmewActionHash, + }); + + // Bob quotes Carol's mew + const quoteInput: Mew = { + text: "a response to a quoted mew", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }; + const quoteActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: quoteInput, + }); + const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quoteActionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: quoteFeedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: mewmewFeedMew, + }); + expect(notifications[2]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: replyFeedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(3); + }, true); + }); + + it("notifications list is time-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies to Alice's mew + const replyInput: Mew = { + text: "xyxyxyxy test reply 1", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob replies to Alice's mew + const replyInput2: Mew = { + text: "xyxyxyxy test reply 2", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash2: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput2, + }); + const replyFeedMew2: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash2, + }); + + // Bob replies to Alice's mew + const replyInput3: Mew = { + text: "xyxyxyxy test reply 3", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash3: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput3, + }); + const replyFeedMew3: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash3, + }); + + // Bob replies to Alice's mew + const replyInput4: Mew = { + text: "xyxyxyxy test reply 4", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash4: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput4, + }); + const replyFeedMew4: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash4, + }); + + // Bob replies to Alice's mew + const replyInput5: Mew = { + text: "xyxyxyxy test reply 5", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash5: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput5, + }); + const replyFeedMew5: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash5, + }); + + // Bob replies to Alice's mew + const replyInput6: Mew = { + text: "xyxyxyxy test reply 6", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash6: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput6, + }); + const replyFeedMew6: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash6, + }); + + // Bob replies to Alice's mew + const replyInput7: Mew = { + text: "xyxyxyxy test reply 7", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash7: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput7, + }); + const replyFeedMew7: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash7, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const page1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(page1[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew7, + }); + expect(page1[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew6, + }); + + expect(page1[0].timestamp).greaterThanOrEqual(page1[1].timestamp); + + // Alice gets notifications + const page2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page1[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(page2[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew5, + }); + expect(page2[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew4, + }); + + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp); + + // Alice gets notifications + const page3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page2[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(page3[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew3, + }); + expect(page3[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew2, + }); + + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp) + .greaterThanOrEqual(page3[0].timestamp) + .greaterThanOrEqual(page3[1].timestamp); + + // Alice gets notifications + const page4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page3[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + assert.lengthOf(page4, 1); + expect(page4[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew, + }); + + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp) + .greaterThanOrEqual(page3[0].timestamp) + .greaterThanOrEqual(page3[1].timestamp) + .greaterThanOrEqual(page4[0].timestamp); + + const page5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page4[0].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + assert.lengthOf(page5, 0); + }, true); + }); }); diff --git a/tests/src/mewsfeed/mews/dna-properties.test.ts b/tests/src/mewsfeed/mews/dna-properties.test.ts index 2a87e2ab..0e2d1234 100644 --- a/tests/src/mewsfeed/mews/dna-properties.test.ts +++ b/tests/src/mewsfeed/mews/dna-properties.test.ts @@ -1,168 +1,176 @@ import { ActionHash } from "@holochain/client"; import { runScenario } from "@holochain/tryorama"; -import { assert, expect, test } from "vitest"; +import { assert, describe, expect, it } from "vitest"; import { Mew, MewTypeName } from "../../../../ui/src/types/types.js"; import { mewsfeedAppBundleSource, mewsfeedAppBundleSourceNoLengthLimits, } from "../../common.js"; -test("Mew must not be longer than DNA property mew_characters_max chars", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const createMewInput: Mew = { - text: new Array(200).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length" - ); - - createMewInput.text = new Array(201).fill("a").join(""); - try { - await alice.cells[0].callZome({ +describe.concurrent("dna-properties", () => { + it("Mew must not be longer than DNA property mew_characters_max chars", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const createMewInput: Mew = { + text: new Array(200).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", payload: createMewInput, }); - assert.fail("mew content longer than mew_characters_max is valid"); - } catch (error) { - assert.ok(true, "mew content longer than mew_characters_max is invalid"); - } - }, true); -}); - -test("Mew must not be shorter than DNA property mew_characters_min chars", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const createMewInput: Mew = { - text: new Array(10).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length" - ); - - createMewInput.text = new Array(2).fill("a").join(""); - try { - await alice.cells[0].callZome({ + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length" + ); + + createMewInput.text = new Array(201).fill("a").join(""); + try { + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.fail("mew content longer than mew_characters_max is valid"); + } catch (error) { + assert.ok( + true, + "mew content longer than mew_characters_max is invalid" + ); + } + }, true); + }); + + it("Mew must not be shorter than DNA property mew_characters_min chars", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const createMewInput: Mew = { + text: new Array(10).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", payload: createMewInput, }); - assert.fail("mew content shorter than mew_characters_min is valid"); - } catch (error) { - assert.ok(true, "mew content shorter than mew_characters_min is invalid"); - } - }, true); -}); - -test("Mew can be any length if DNA property mew_characters_min and mew_characters_max not set", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { - appBundleSource: mewsfeedAppBundleSourceNoLengthLimits, - }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // 0 charactres - const createMewInput2: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash2: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - assert.deepEqual( - action_hash2.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length 0" - ); - - // 1000 charactres - const createMewInput3: Mew = { - text: new Array(1000).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash3: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - assert.deepEqual( - action_hash3.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length 1000" - ); - }, true); -}); - -test("Can get deserialized DNA Properties", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const properties = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_dna_properties", - payload: null, - }); - expect(properties).toHaveProperty("mew_characters_min", 5); - expect(properties).toHaveProperty("mew_characters_max", 200); - }, true); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length" + ); + + createMewInput.text = new Array(2).fill("a").join(""); + try { + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.fail("mew content shorter than mew_characters_min is valid"); + } catch (error) { + assert.ok( + true, + "mew content shorter than mew_characters_min is invalid" + ); + } + }, true); + }); + + it("Mew can be any length if DNA property mew_characters_min and mew_characters_max not set", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { + appBundleSource: mewsfeedAppBundleSourceNoLengthLimits, + }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // 0 charactres + const createMewInput2: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash2: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + assert.deepEqual( + action_hash2.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length 0" + ); + + // 1000 charactres + const createMewInput3: Mew = { + text: new Array(1000).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash3: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + assert.deepEqual( + action_hash3.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length 1000" + ); + }, true); + }); + + it("Can get deserialized DNA Properties", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const properties = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_dna_properties", + payload: null, + }); + expect(properties).toHaveProperty("mew_characters_min", 5); + expect(properties).toHaveProperty("mew_characters_max", 200); + }, true); + }); }); diff --git a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts index 6e6109ec..491ae94e 100644 --- a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts +++ b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts @@ -1,589 +1,592 @@ -import { assert, expect, test } from "vitest"; -import { runScenario, dhtSync } from "@holochain/tryorama"; import { ActionHash } from "@holochain/client"; -import { createMew } from "./common"; +import { dhtSync, runScenario } from "@holochain/tryorama"; +import { assert, describe, expect, it } from "vitest"; import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; +import { createMew } from "./common"; -test("create a Mew and get followed creators mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - console.log("adding"); - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - console.log("added"); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - console.log("sharing all agents"); - await scenario.shareAllAgents(); - console.log("shared"); - - // Bob follows alice - console.log("calling zome follow"); - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - console.log("called"); - - // Bob gets followed creators mews - let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.equal(collectionOutput.length, 0); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets followed creators mews again - collectionOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - - assert.equal(collectionOutput.length, 1); - assert.deepEqual(actionHash, collectionOutput[0].action_hash); - }, true); -}); - -test("Followed creators mews should include mews of followed creator", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = "test-mew"; - const mewInput: Mew = { - text: mewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewInput, - }); - - const bobMewsFeedInitial: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - bobMewsFeedInitial.length === 0, - "bob's mews feed is initially empty" - ); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); - assert.equal( - bobMewsFeed[0].mew.text, - mewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - }, true); -}); - -test("Followed creators mews should include own mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewsFeedInitial: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - aliceMewsFeedInitial.length === 0, - "alice's mews feed is initially empty" - ); - - const mewContent = "test-mew"; - const mewInput: Mew = { - text: mewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewInput, - }); - - const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(aliceMewsFeed.length === 1, "alice's mews feed includes her mew"); - assert.equal(aliceMewsFeed[0].mew.text, mewContent, "mew content matches"); - }, true); -}); - -test("Followed creators mews should not include mews of non-followed creator", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const carolMewContent = "carol-test-mew"; - const carolMewInput: Mew = { - text: carolMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await carol.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: carolMewInput, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); - assert.equal( - bobMewsFeed[0].mew.text, - aliceMewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - }, true); -}); - -test("Unfollowing should exclude creators mews from feed", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const bobMewsFeedWhenFollowing: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - bobMewsFeedWhenFollowing.length === 1, - "bob's mews feed includes 1 mew" - ); - assert.equal( - bobMewsFeedWhenFollowing[0].mew.text, - aliceMewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "unfollow", - payload: alice.agentPubKey, - }); - - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 0, "bob's mews feed is empty"); - }, true); -}); - -test("Followed creators mews should be ordered by timestamp in descending order", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const firstMewContent = "first-test-mew"; - const firstMewInput: Mew = { - text: firstMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: firstMewInput, - }); - - const secondMewContent = "second-test-mew"; - const secondMewInput: Mew = { - text: secondMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: secondMewInput, - }); - - const thirdMewContent = "third-test-mew"; - const thirdMewInput: Mew = { - text: thirdMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await carol.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: thirdMewInput, - }); - - const fourthMewContent = "fourth-test-mew"; - const fourthMewInput: Mew = { - text: fourthMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: fourthMewInput, - }); - // alice starts following bob and carol - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: bob.agentPubKey, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: carol.agentPubKey, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - aliceMewsFeed.length === 4, - "alice's mews feed includes all 4 mews" - ); - assert.equal( - aliceMewsFeed[0].mew.text, - fourthMewContent, - "mew 1 in feed is fourth mew" - ); - assert.equal( - aliceMewsFeed[1].mew.text, - thirdMewContent, - "mew 2 in feed is third mew" - ); - assert.equal( - aliceMewsFeed[2].mew.text, - secondMewContent, - "mew 3 in feed is second mew" - ); - assert.equal( - aliceMewsFeed[3].mew.text, - firstMewContent, - "mew 4 in feed is first mew" - ); - }, true); -}); - -test("Followed creators mews list are time-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const page1: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - limit: 2, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - }, - }); - - assert.lengthOf(page5, 0); - }, true); +describe.concurrent("followed-creators-mews", () => { + it("create a Mew and get followed creators mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Bob follows alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + // Bob gets followed creators mews + let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.equal(collectionOutput.length, 0); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets followed creators mews again + collectionOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + + assert.equal(collectionOutput.length, 1); + assert.deepEqual(actionHash, collectionOutput[0].action_hash); + }, true); + }); + + it("Followed creators mews should include mews of followed creator", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = "test-mew"; + const mewInput: Mew = { + text: mewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewInput, + }); + + const bobMewsFeedInitial: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + bobMewsFeedInitial.length === 0, + "bob's mews feed is initially empty" + ); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal( + bobMewsFeed[0].mew.text, + mewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + }, true); + }); + + it("Followed creators mews should include own mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewsFeedInitial: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeedInitial.length === 0, + "alice's mews feed is initially empty" + ); + + const mewContent = "test-mew"; + const mewInput: Mew = { + text: mewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewInput, + }); + + const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeed.length === 1, + "alice's mews feed includes her mew" + ); + assert.equal( + aliceMewsFeed[0].mew.text, + mewContent, + "mew content matches" + ); + }, true); + }); + + it("Followed creators mews should not include mews of non-followed creator", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const carolMewContent = "carol-test-mew"; + const carolMewInput: Mew = { + text: carolMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await carol.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: carolMewInput, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal( + bobMewsFeed[0].mew.text, + aliceMewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + }, true); + }); + + it("Unfollowing should exclude creators mews from feed", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const bobMewsFeedWhenFollowing: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + bobMewsFeedWhenFollowing.length === 1, + "bob's mews feed includes 1 mew" + ); + assert.equal( + bobMewsFeedWhenFollowing[0].mew.text, + aliceMewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "unfollow", + payload: alice.agentPubKey, + }); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 0, "bob's mews feed is empty"); + }, true); + }); + + it("Followed creators mews should be ordered by timestamp in descending order", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const firstMewContent = "first-test-mew"; + const firstMewInput: Mew = { + text: firstMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: firstMewInput, + }); + + const secondMewContent = "second-test-mew"; + const secondMewInput: Mew = { + text: secondMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: secondMewInput, + }); + + const thirdMewContent = "third-test-mew"; + const thirdMewInput: Mew = { + text: thirdMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await carol.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: thirdMewInput, + }); + + const fourthMewContent = "fourth-test-mew"; + const fourthMewInput: Mew = { + text: fourthMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: fourthMewInput, + }); + // alice starts following bob and carol + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: bob.agentPubKey, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: carol.agentPubKey, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeed.length === 4, + "alice's mews feed includes all 4 mews" + ); + assert.equal( + aliceMewsFeed[0].mew.text, + fourthMewContent, + "mew 1 in feed is fourth mew" + ); + assert.equal( + aliceMewsFeed[1].mew.text, + thirdMewContent, + "mew 2 in feed is third mew" + ); + assert.equal( + aliceMewsFeed[2].mew.text, + secondMewContent, + "mew 3 in feed is second mew" + ); + assert.equal( + aliceMewsFeed[3].mew.text, + firstMewContent, + "mew 4 in feed is first mew" + ); + }, true); + }); + + it("Followed creators mews list are time-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const page1: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + limit: 2, + }, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, + }); + + assert.lengthOf(page5, 0); + }, true); + }); }); diff --git a/tests/src/mewsfeed/mews/mention-to-mews.test.ts b/tests/src/mewsfeed/mews/mention-to-mews.test.ts index f12c62e3..d80f8d84 100644 --- a/tests/src/mewsfeed/mews/mention-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/mention-to-mews.test.ts @@ -1,5 +1,6 @@ +import { ActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -import { assert, expect, test } from "vitest"; +import { assert, describe, expect, it } from "vitest"; import { FeedMew, LinkTargetName, @@ -8,255 +9,256 @@ import { } from "../../../../ui/src/types/types.js"; import { mewsfeedAppBundleSource } from "../../common.js"; import { createMew } from "./common.js"; -import { ActionHash } from "@holochain/client"; -test("mention in mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; +describe.concurrent("mention-to-mews", () => { + it("mention in mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - await createMew(alice.cells[0], { - text: "this is for @bob", - links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], - mew_type: { Original: null }, - }); + await createMew(alice.cells[0], { + text: "this is for @bob", + links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], + mew_type: { Original: null }, + }); - const actionHash2: ActionHash = await createMew(bob.cells[0], { - text: "this is for @bob 2", - links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], - mew_type: { Original: null }, - }); + const actionHash2: ActionHash = await createMew(bob.cells[0], { + text: "this is for @bob 2", + links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], + mew_type: { Original: null }, + }); - const actionHash3: ActionHash = await createMew(alice.cells[0], { - text: "this is for @alice", - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { Original: null }, - }); + const actionHash3: ActionHash = await createMew(alice.cells[0], { + text: "this is for @alice", + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { Original: null }, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - const mentionedMewsBob: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: bob.agentPubKey, - }, - }); - assert.ok(mentionedMewsBob.length === 2, "one mew with mention"); - assert.deepEqual(mentionedMewsBob[0].action_hash, actionHash2); + const mentionedMewsBob: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: bob.agentPubKey, + }, + }); + assert.ok(mentionedMewsBob.length === 2, "one mew with mention"); + assert.deepEqual(mentionedMewsBob[0].action_hash, actionHash2); - const mentionedMewsAlice: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - }, - }); - assert.ok(mentionedMewsAlice.length === 1, "one mew with mention"); - assert.deepEqual(mentionedMewsAlice[0].action_hash, actionHash3); - }, true); -}); + const mentionedMewsAlice: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + }, + }); + assert.ok(mentionedMewsAlice.length === 1, "one mew with mention"); + assert.deepEqual(mentionedMewsAlice[0].action_hash, actionHash3); + }, true); + }); -test("Mentions list are time-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + it("Mentions list are time-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - const mewContent1 = "My Mew with @mention 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); + const mewContent1 = "My Mew with @mention 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); - const mewContent2 = "My Mew with @mention 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); + const mewContent2 = "My Mew with @mention 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); - const mewContent3 = "My Mew with @mention 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); + const mewContent3 = "My Mew with @mention 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); - const mewContent4 = "My Mew with @mention 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); + const mewContent4 = "My Mew with @mention 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); - const mewContent5 = "My Mew with @mention 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); + const mewContent5 = "My Mew with @mention 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); - const mewContent6 = "My Mew with @mention 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); + const mewContent6 = "My Mew with @mention 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); - const mewContent7 = "My Mew with @mention 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); + const mewContent7 = "My Mew with @mention 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - start_time: null, - limit: 2, + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + start_time: null, + limit: 2, + }, }, - }, - }); + }); - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); - assert.lengthOf(page5, 0); - }, true); + assert.lengthOf(page5, 0); + }, true); + }); }); diff --git a/tests/src/mewsfeed/mews/mew-to-responses.test.ts b/tests/src/mewsfeed/mews/mew-to-responses.test.ts index 513a9c1e..03e9da73 100644 --- a/tests/src/mewsfeed/mews/mew-to-responses.test.ts +++ b/tests/src/mewsfeed/mews/mew-to-responses.test.ts @@ -1,207 +1,213 @@ +import { ActionHash } from "@holochain/client"; import { runScenario } from "@holochain/tryorama"; -import { assert, expect, test } from "vitest"; +import { assert, describe, expect, it } from "vitest"; import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types.js"; import { mewsfeedAppBundleSource } from "../../common.js"; -import { ActionHash } from "@holochain/client"; - -test("Agent can reply to a mew", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const aliceReplyContent = "alice-test-reply"; - const aliceReplyInput: Mew = { - text: aliceReplyContent, - links: [], - mew_type: { [MewTypeName.Reply]: action_hash }, - }; - const reply_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceReplyInput, - }); - - const replyMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: reply_action_hash, - }); - assert.ok(MewTypeName.Reply in replyMew.mew.mew_type, "mew is a reply"); - assert.equal( - replyMew.mew.text, - aliceReplyContent, - "reply is alice's reply" - ); - - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.replies_count === 1, "original mew has 1 reply"); - assert.isTrue( - originalMew.is_replied, - "original mew's reply is alice's reply" - ); - }, true); -}); - -test("Agent can mewmew a mew, only once", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const aliceMewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: action_hash }, - }; - const mewmew_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewmewInput, - }); - - const mewmew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmew_action_hash, - }); - assert.ok(MewTypeName.Mewmew in mewmew.mew.mew_type, "mew is a mewmew"); - assert.deepEqual(mewmew.mew, aliceMewmewInput, "mewmew is alice's mewmew"); - - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); - assert.isTrue( - originalMew.is_mewmewed, - "original mew's mewmew is alice's mewmew" - ); - - // Mewmew the same mew again - const response = alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewmewInput, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - }, true); -}); -test("Agent can quote a mew", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const aliceQuoteText = "alice-test-quote"; - const aliceQuoteInput: Mew = { - text: aliceQuoteText, - links: [], - mew_type: { - [MewTypeName.Quote]: action_hash, - }, - }; - const quote_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceQuoteInput, - }); - - const quote: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quote_action_hash, - }); - assert.ok(MewTypeName.Quote in quote.mew.mew_type, "mew is a quote"); - assert.equal(quote.mew.text, aliceQuoteText, "quote is alice's quote"); - - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.quotes_count === 1, "original mew has 1 quote"); - assert.isTrue( - originalMew.is_quoted, - "original mew's quote is alice's quote" - ); - }, true); +describe.concurrent("mew-to-responses", () => { + it("Agent can reply to a mew", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const aliceReplyContent = "alice-test-reply"; + const aliceReplyInput: Mew = { + text: aliceReplyContent, + links: [], + mew_type: { [MewTypeName.Reply]: action_hash }, + }; + const reply_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceReplyInput, + }); + + const replyMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: reply_action_hash, + }); + assert.ok(MewTypeName.Reply in replyMew.mew.mew_type, "mew is a reply"); + assert.equal( + replyMew.mew.text, + aliceReplyContent, + "reply is alice's reply" + ); + + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); + assert.ok(originalMew.replies_count === 1, "original mew has 1 reply"); + assert.isTrue( + originalMew.is_replied, + "original mew's reply is alice's reply" + ); + }, true); + }); + + it("Agent can mewmew a mew, only once", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const aliceMewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: action_hash }, + }; + const mewmew_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewmewInput, + }); + + const mewmew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmew_action_hash, + }); + assert.ok(MewTypeName.Mewmew in mewmew.mew.mew_type, "mew is a mewmew"); + assert.deepEqual( + mewmew.mew, + aliceMewmewInput, + "mewmew is alice's mewmew" + ); + + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); + assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); + assert.isTrue( + originalMew.is_mewmewed, + "original mew's mewmew is alice's mewmew" + ); + + // Mewmew the same mew again + const response = alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewmewInput, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + }, true); + }); + + it("Agent can quote a mew", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const aliceQuoteText = "alice-test-quote"; + const aliceQuoteInput: Mew = { + text: aliceQuoteText, + links: [], + mew_type: { + [MewTypeName.Quote]: action_hash, + }, + }; + const quote_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceQuoteInput, + }); + + const quote: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quote_action_hash, + }); + assert.ok(MewTypeName.Quote in quote.mew.mew_type, "mew is a quote"); + assert.equal(quote.mew.text, aliceQuoteText, "quote is alice's quote"); + + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); + assert.ok(originalMew.quotes_count === 1, "original mew has 1 quote"); + assert.isTrue( + originalMew.is_quoted, + "original mew's quote is alice's quote" + ); + }, true); + }); }); diff --git a/tests/src/mewsfeed/mews/mew-with-context.test.ts b/tests/src/mewsfeed/mews/mew-with-context.test.ts index 38ce0161..ef105377 100644 --- a/tests/src/mewsfeed/mews/mew-with-context.test.ts +++ b/tests/src/mewsfeed/mews/mew-with-context.test.ts @@ -1,346 +1,348 @@ import { ActionHash } from "@holochain/client"; -import { dhtSync, pause, runScenario } from "@holochain/tryorama"; -import { assert, expect, test } from "vitest"; -import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types"; +import { dhtSync, runScenario } from "@holochain/tryorama"; +import { assert, describe, expect, it } from "vitest"; +import { FeedMew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -test("Mew with context contains licks count and is_licked", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob licks the mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "like", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - let feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.licks_count).toEqual(1); - expect(feedMew.is_licked).true; - - // Alice gets the mew with context - let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.licks_count).toEqual(1); - expect(aliceFeedMew.is_licked).false; - - // Bob unlicks the mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "unlike", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - feedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.licks_count).toEqual(0); - expect(feedMew.is_licked).false; - - // Alice gets the mew with context - aliceFeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.licks_count).toEqual(0); - expect(aliceFeedMew.is_licked).false; - }, - true, - { timeout: 100000 } - ); -}); - -test("Mew with context contains replies count and is_replied", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies the mew - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "my reply blah blah", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - const feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.replies_count).toEqual(1); - expect(feedMew.is_replied).true; - - // Alice gets the mew with context - const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.replies_count).toEqual(1); - expect(aliceFeedMew.is_replied).false; - }, - true, - { timeout: 100000 } - ); -}); - -test("Mew with context contains quotes count and is_quoted", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies the mew - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "this is a quote blah blah", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - const feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.quotes_count).toEqual(1); - expect(feedMew.is_quoted).true; - - // Alice gets the mew with context - const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.quotes_count).toEqual(1); - expect(aliceFeedMew.is_quoted).false; - }, - true, - { timeout: 100000 } - ); -}); - -test("Mew with context contains mewmews count and is_mewmewed", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob mewmews the mew - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - const feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.mewmews_count).toEqual(1); - expect(feedMew.is_mewmewed).true; - console.warn("bob got mew"); - - // Alice gets the mew with context - const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - console.warn("alice got mew"); - - expect(aliceFeedMew.mewmews_count).toEqual(1); - expect(aliceFeedMew.is_mewmewed).false; - }, - true, - { timeout: 100000 } - ); -}); - -test("Mew with context contains is_pinned", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob pins the mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - let feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.is_pinned).true; - - // Alice gets the mew with context - let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.is_pinned).false; - - // Bob unpins the mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - feedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.is_pinned).false; - - // Alice gets the mew with context - aliceFeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.is_pinned).false; - }, - true, - { timeout: 100000 } - ); +describe.concurrent("mew-with-context", () => { + it("Mew with context contains licks count and is_licked", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob licks the mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "like", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + let feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.licks_count).toEqual(1); + expect(feedMew.is_licked).true; + + // Alice gets the mew with context + let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.licks_count).toEqual(1); + expect(aliceFeedMew.is_licked).false; + + // Bob unlicks the mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "unlike", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + feedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.licks_count).toEqual(0); + expect(feedMew.is_licked).false; + + // Alice gets the mew with context + aliceFeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.licks_count).toEqual(0); + expect(aliceFeedMew.is_licked).false; + }, + true, + { timeout: 100000 } + ); + }); + + it("Mew with context contains replies count and is_replied", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies the mew + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "my reply blah blah", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + const feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.replies_count).toEqual(1); + expect(feedMew.is_replied).true; + + // Alice gets the mew with context + const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.replies_count).toEqual(1); + expect(aliceFeedMew.is_replied).false; + }, + true, + { timeout: 100000 } + ); + }); + + it("Mew with context contains quotes count and is_quoted", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies the mew + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "this is a quote blah blah", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + const feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.quotes_count).toEqual(1); + expect(feedMew.is_quoted).true; + + // Alice gets the mew with context + const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.quotes_count).toEqual(1); + expect(aliceFeedMew.is_quoted).false; + }, + true, + { timeout: 100000 } + ); + }); + + it("Mew with context contains mewmews count and is_mewmewed", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob mewmews the mew + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + const feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.mewmews_count).toEqual(1); + expect(feedMew.is_mewmewed).true; + console.warn("bob got mew"); + + // Alice gets the mew with context + const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + console.warn("alice got mew"); + + expect(aliceFeedMew.mewmews_count).toEqual(1); + expect(aliceFeedMew.is_mewmewed).false; + }, + true, + { timeout: 100000 } + ); + }); + + it("Mew with context contains is_pinned", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob pins the mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + let feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.is_pinned).true; + + // Alice gets the mew with context + let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.is_pinned).false; + + // Bob unpins the mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + feedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.is_pinned).false; + + // Alice gets the mew with context + aliceFeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.is_pinned).false; + }, + true, + { timeout: 100000 } + ); + }); }); diff --git a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts index 4f6cc49e..ef681684 100644 --- a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts @@ -1,72 +1,74 @@ import { ActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -import { assert, test } from "vitest"; +import { assert, describe, it } from "vitest"; import { FeedMew } from "../../../../ui/src/types/types.js"; import { createMew } from "./common.js"; -test("link a Pinner to a Mew", async () => { - await runScenario(async (scenario) => { - // Construct proper paths for your app. - // This assumes app bundle created by the `hc app pack` command. - const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; +describe.concurrent("pinner-to-mews", () => { + it("link a Pinner to a Mew", async () => { + await runScenario(async (scenario) => { + // Construct proper paths for your app. + // This assumes app bundle created by the `hc app pack` command. + const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; - // Set up the app to be installed - const appSource = { appBundleSource: { path: testAppPath } }; + // Set up the app to be installed + const appSource = { appBundleSource: { path: testAppPath } }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - const baseAddress = alice.agentPubKey; - const targetActionHash: ActionHash = await createMew(alice.cells[0]); + const baseAddress = alice.agentPubKey; + const targetActionHash: ActionHash = await createMew(alice.cells[0]); - // Bob gets the links, should be empty - let linksOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); + // Bob gets the links, should be empty + let linksOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); - // Alice creates a link from Pinner to Mew - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: targetActionHash, - }); + // Alice creates a link from Pinner to Mew + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: targetActionHash, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 1); - assert.deepEqual(targetActionHash, linksOutput[0].action_hash); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 1); + assert.deepEqual(targetActionHash, linksOutput[0].action_hash); - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: targetActionHash, - }); + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: targetActionHash, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - }, true); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + }, true); + }); }); diff --git a/tests/src/mewsfeed/mews/tags-to-mews.test.ts b/tests/src/mewsfeed/mews/tags-to-mews.test.ts index 92ff5510..f01c963f 100644 --- a/tests/src/mewsfeed/mews/tags-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/tags-to-mews.test.ts @@ -1,6 +1,6 @@ import { ActionHash } from "@holochain/client"; -import { pause, runScenario } from "@holochain/tryorama"; -import { assert, expect, test } from "vitest"; +import { runScenario } from "@holochain/tryorama"; +import { assert, describe, expect, it } from "vitest"; import { FeedMew, LinkTargetName, @@ -10,562 +10,575 @@ import { } from "../../../../ui/src/types/types.js"; import { mewsfeedAppBundleSource } from "../../common.js"; -test("Hashtag, cashtag and mention", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = - "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; - const createMewInput: Mew = { - text: mewContent, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a valid mew" - ); - - const hashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - }, - }); - assert.ok(hashtaggedMews.length === 1, "one mew with hashtag"); - assert.equal(hashtaggedMews[0].mew.text, mewContent, "mew content matches"); - - const arabicHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#سعيدة", - }, - }); - assert.ok(arabicHashtaggedMews.length === 1, "one mew with arabic hashtag"); - assert.equal( - arabicHashtaggedMews[0].mew.text, - mewContent, - "mew content matches" - ); - - // get hashtag containing emojis -- invalid hashtag! - const emojiHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#😃😃😃", - }, - }); - assert.ok(emojiHashtaggedMews.length === 0, "no mew with emoji hashtag"); - - const cashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - }, - }); - assert.ok(cashtaggedMews.length === 1, "one mew with cashtag"); - - const mentionedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - }, - }); - assert.ok(mentionedMews.length === 1, "one mew with mention"); - }, true); -}); - -test("Prefix index should return hashtags and cashtags", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = - "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; - const createMewInput: Mew = { - text: mewContent, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a valid mew" - ); - - const hashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "has", - limit: 10, - }, - }); - assert.ok(hashtags.length === 1, "one hashtag"); - assert.equal(hashtags[0], "#hashtag", "hashtag search result matches"); - - const arabicHashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "سعيدة", - limit: 10, - }, - }); - assert.ok(arabicHashtags.length === 1, "one arabic hashtag"); - assert.equal(arabicHashtags[0], "#سعيدة", "hashtag search result matches"); - - // get hashtag containing emojis -- invalid hashtag! - const emojiHashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "😃😃😃", - limit: 10, - }, - }); - assert.ok(emojiHashtags.length === 0, "no emoji hashtags"); - - const cashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "cas", - limit: 10, - }, - }); - assert.ok(cashtags.length === 1, "one cashtag"); - assert.equal(cashtags[0], "$cashtag", "hashtag search result matches"); - }, true); -}); - -test("Hashtags list are time-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - limit: 2, +describe.concurrent("tags-to-mews", () => { + it("Hashtag, cashtag and mention", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = + "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; + const createMewInput: Mew = { + text: mewContent, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a valid mew" + ); + + const hashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", }, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, + }); + assert.ok(hashtaggedMews.length === 1, "one mew with hashtag"); + assert.equal( + hashtaggedMews[0].mew.text, + mewContent, + "mew content matches" + ); + + const arabicHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#سعيدة", }, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page2[page1.length - 1].action_hash, - limit: 2, + }); + assert.ok( + arabicHashtaggedMews.length === 1, + "one mew with arabic hashtag" + ); + assert.equal( + arabicHashtaggedMews[0].mew.text, + mewContent, + "mew content matches" + ); + + // get hashtag containing emojis -- invalid hashtag! + const emojiHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#😃😃😃", }, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page3[page1.length - 1].action_hash, - limit: 2, + }); + assert.ok(emojiHashtaggedMews.length === 0, "no mew with emoji hashtag"); + + const cashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", }, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, + }); + assert.ok(cashtaggedMews.length === 1, "one mew with cashtag"); + + const mentionedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, }, - }, - }); - - assert.lengthOf(page5, 0); - }, true); -}); - -test("Cashtags list are time-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with $cashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with $cashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with $cashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with $cashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with $cashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with $cashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with $cashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - start_time: null, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, + }); + assert.ok(mentionedMews.length === 1, "one mew with mention"); + }, true); + }); + + it("Prefix index should return hashtags and cashtags", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = + "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; + const createMewInput: Mew = { + text: mewContent, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a valid mew" + ); + + const hashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "has", + limit: 10, + }, + }); + assert.ok(hashtags.length === 1, "one hashtag"); + assert.equal(hashtags[0], "#hashtag", "hashtag search result matches"); + + const arabicHashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "سعيدة", + limit: 10, + }, + }); + assert.ok(arabicHashtags.length === 1, "one arabic hashtag"); + assert.equal( + arabicHashtags[0], + "#سعيدة", + "hashtag search result matches" + ); + + // get hashtag containing emojis -- invalid hashtag! + const emojiHashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "😃😃😃", + limit: 10, + }, + }); + assert.ok(emojiHashtags.length === 0, "no emoji hashtags"); + + const cashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "cas", + limit: 10, + }, + }); + assert.ok(cashtags.length === 1, "one cashtag"); + assert.equal(cashtags[0], "$cashtag", "hashtag search result matches"); + }, true); + }); + + it("Hashtags list are time-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + limit: 2, + }, + }, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, + }, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page2[page1.length - 1].action_hash, + limit: 2, + }, + }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page3[page1.length - 1].action_hash, + limit: 2, + }, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, + }, + }); + + assert.lengthOf(page5, 0); + }, true); + }); + + it("Cashtags list are time-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with $cashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with $cashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with $cashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with $cashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with $cashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with $cashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with $cashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + start_time: null, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, }, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, }, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, }, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, }, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, }, - }, - }); + }); - assert.lengthOf(page5, 0); - }, true); + assert.lengthOf(page5, 0); + }, true); + }); }); From f5c9a6495ae3c52425f03f3ac642d958bb91d932 Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Wed, 1 Nov 2023 05:54:35 -0600 Subject: [PATCH 06/22] nix: roll back to v0.2.2 --- flake.lock | 42 ++++++++++++++---------------------------- flake.nix | 1 - 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/flake.lock b/flake.lock index ce81441a..cb107df3 100644 --- a/flake.lock +++ b/flake.lock @@ -173,23 +173,6 @@ } }, "holochain": { - "flake": false, - "locked": { - "lastModified": 1696074490, - "narHash": "sha256-195lUl9x6zLhfrDXMh6WEFa/tEFilhJT/zLJchywnQw=", - "owner": "holochain", - "repo": "holochain", - "rev": "da0ca3dc2521ee69c9f9e50dd318ab34d60199d4", - "type": "github" - }, - "original": { - "owner": "holochain", - "ref": "holochain-0.2.3-beta-rc.1", - "repo": "holochain", - "type": "github" - } - }, - "holochain_2": { "flake": false, "locked": { "lastModified": 1694632043, @@ -215,7 +198,10 @@ "empty": "empty", "flake-compat": "flake-compat_2", "flake-parts": "flake-parts", - "holochain": "holochain", + "holochain": [ + "holonix", + "empty" + ], "lair": [ "holonix", "empty" @@ -238,11 +224,11 @@ ] }, "locked": { - "lastModified": 1698790077, - "narHash": "sha256-hZhq6mpQaGy5DA4oXt9vWY+9mSxQYmUALCXHQsWQh3E=", + "lastModified": 1698820331, + "narHash": "sha256-NTSZ1hdnrsDI7yBTK9COVXZf4lXfM6t2RXa0Q2bmtNg=", "owner": "holochain", "repo": "holochain", - "rev": "88100b526371b6c36eedf4bbf9ec0ceda3174c00", + "rev": "8521cee803aadb6e51fa967d57006eadf7861630", "type": "github" }, "original": { @@ -407,11 +393,11 @@ ] }, "locked": { - "lastModified": 1698726852, - "narHash": "sha256-V1S4TTzg++GzPc96i/yy4jib+7/xU0LXHcggm9MllMM=", + "lastModified": 1698804896, + "narHash": "sha256-vSms7A9bWHC00343qyXuNVm65LZDagDkukpkpwC2VxY=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "ec19bd20af08f3b004089cc12ab54c823ed899b7", + "rev": "c5f8326c668b78275eccce90839861a3c8e1d3b2", "type": "github" }, "original": { @@ -454,18 +440,18 @@ }, "versions": { "inputs": { - "holochain": "holochain_2", + "holochain": "holochain", "lair": "lair", "launcher": "launcher", "scaffolding": "scaffolding" }, "locked": { "dir": "versions/0_2", - "lastModified": 1698790077, - "narHash": "sha256-hZhq6mpQaGy5DA4oXt9vWY+9mSxQYmUALCXHQsWQh3E=", + "lastModified": 1698820331, + "narHash": "sha256-NTSZ1hdnrsDI7yBTK9COVXZf4lXfM6t2RXa0Q2bmtNg=", "owner": "holochain", "repo": "holochain", - "rev": "88100b526371b6c36eedf4bbf9ec0ceda3174c00", + "rev": "8521cee803aadb6e51fa967d57006eadf7861630", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 4489c95e..416cc192 100644 --- a/flake.nix +++ b/flake.nix @@ -5,7 +5,6 @@ versions.url = "github:holochain/holochain?dir=versions/0_2"; holonix.url = "github:holochain/holochain"; holonix.inputs.versions.follows = "versions"; - holonix.inputs.holochain.url = "github:holochain/holochain/holochain-0.2.3-beta-rc.1"; }; outputs = inputs@{ holonix, ... }: From c510be84af4ff7f1adad7540ff61aa5f2d16ee01 Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Wed, 1 Nov 2023 06:22:53 -0600 Subject: [PATCH 07/22] build: update tryorama --- package-lock.json | 8 ++++---- tests/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 913c14b2..e795c47b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -840,9 +840,9 @@ "integrity": "sha512-DJx4V2KXHVLciyOGjOYKTM/JLBpBEZ3RsPIRCgf7qmwhQdxXvhi2p+oFFRD51yUT5uC1/MzIVeJCl/R60PwFbw==" }, "node_modules/@holochain/tryorama": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@holochain/tryorama/-/tryorama-0.15.1.tgz", - "integrity": "sha512-MjDaJ1arv9dafVQ6AGifZdOrIQ6uLqE3qq6XdLpCTbedduKBH014m/dHR2njzLO+ogfXOqrWthX50/tSq3rtig==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@holochain/tryorama/-/tryorama-0.15.2.tgz", + "integrity": "sha512-Hgec9/KiQRxqZm/1LPN3EQ0GWOqusyhu+dC+XA5nJfARTDVM178mMmnQ08Uqk1s7FwA50Lq+/YAGpr4kIz7kBg==", "dependencies": { "@holochain/client": "^0.16.0", "get-port": "^6.1.2", @@ -7408,7 +7408,7 @@ "tests": { "dependencies": { "@holochain/client": "^0.16.3", - "@holochain/tryorama": "0.15.1", + "@holochain/tryorama": "0.15.2", "@msgpack/msgpack": "^2.8.0", "typescript": "^4.9.4", "vitest": "^0.28.5" diff --git a/tests/package.json b/tests/package.json index 473ccf7a..cbc07860 100644 --- a/tests/package.json +++ b/tests/package.json @@ -6,7 +6,7 @@ }, "dependencies": { "@holochain/client": "^0.16.3", - "@holochain/tryorama": "0.15.1", + "@holochain/tryorama": "0.15.2", "@msgpack/msgpack": "^2.8.0", "typescript": "^4.9.4", "vitest": "^0.28.5" From 409a5327d1863e9361dcf549adb04c88fe38356d Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Wed, 1 Nov 2023 06:41:28 -0600 Subject: [PATCH 08/22] revert: remove timeouts --- .../agent_pins/pinner-to-hashes.test.ts | 166 +++--- .../follows/follower-to-creators.test.ts | 240 ++++---- .../mewsfeed/likes/liker-to-hashes.test.ts | 118 ++-- tests/src/mewsfeed/mews/agent-mews.test.ts | 372 ++++++------ .../mews/agent-to-notifications.test.ts | 532 +++++++++--------- .../src/mewsfeed/mews/dna-properties.test.ts | 38 +- .../mews/followed-creators-mews.test.ts | 374 ++++++------ .../src/mewsfeed/mews/mention-to-mews.test.ts | 336 +++++------ .../mewsfeed/mews/mew-to-responses.test.ts | 132 +++-- .../mewsfeed/mews/mew-with-context.test.ts | 2 +- .../src/mewsfeed/mews/pinner-to-mews.test.ts | 110 ++-- tests/src/mewsfeed/mews/tags-to-mews.test.ts | 388 ++++++------- 12 files changed, 1428 insertions(+), 1380 deletions(-) diff --git a/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts b/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts index b2bd12a2..921edb96 100644 --- a/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts +++ b/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts @@ -5,86 +5,90 @@ import { dhtSync, runScenario } from "@holochain/tryorama"; describe.concurrent("pinner-to-hashes", () => { it("link a Pinner to a Hash", async () => { - await runScenario(async (scenario) => { - // Construct proper paths for your app. - // This assumes app bundle created by the `hc app pack` command. - const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; - - // Set up the app to be installed - const appSource = { appBundleSource: { path: testAppPath } }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetHash = await fakeActionHash(); - - // Bob gets the links, should be empty - let linksOutput: HoloHash[] = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Pinner to Hash - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: targetHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - const pinnersOutput: AgentPubKey[] = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_pinners_for_hash", - payload: targetHash, - }); - assert.equal(pinnersOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: targetHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_pinners_for_hash", - payload: targetHash, - }); - - assert.equal(linksOutput.length, 0); - }, true); + await runScenario( + async (scenario) => { + // Construct proper paths for your app. + // This assumes app bundle created by the `hc app pack` command. + const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; + + // Set up the app to be installed + const appSource = { appBundleSource: { path: testAppPath } }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetHash = await fakeActionHash(); + + // Bob gets the links, should be empty + let linksOutput: HoloHash[] = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Pinner to Hash + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: targetHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + const pinnersOutput: AgentPubKey[] = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_pinners_for_hash", + payload: targetHash, + }); + assert.equal(pinnersOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: targetHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_pinners_for_hash", + payload: targetHash, + }); + + assert.equal(linksOutput.length, 0); + }, + true, + { timeout: 500000 } + ); }); }); diff --git a/tests/src/mewsfeed/follows/follower-to-creators.test.ts b/tests/src/mewsfeed/follows/follower-to-creators.test.ts index d877793d..9623fa22 100644 --- a/tests/src/mewsfeed/follows/follower-to-creators.test.ts +++ b/tests/src/mewsfeed/follows/follower-to-creators.test.ts @@ -305,127 +305,131 @@ describe.concurrent("follower-to-creators", () => { }); it("Followers list are hash-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol, john, steve, mary] = - await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a link from Follower to Creator - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await carol.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: carol.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await john.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: john.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await steve.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: steve.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await mary.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: mary.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - await dhtSync( - [alice, bob, carol, john, steve, mary], - alice.cells[0].cell_id[0] - ); - - const page1: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - limit: 2, + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol, john, steve, mary] = + await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a link from Follower to Creator + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, }, - }, - }); - - assert.deepEqual(page1[0], mary.agentPubKey); - assert.deepEqual(page1[1], steve.agentPubKey); - - const page2: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page1[1], - limit: 2, + }); + await carol.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: carol.agentPubKey, + target_creator: alice.agentPubKey, }, - }, - }); - assert.deepEqual(page2[0], john.agentPubKey); - assert.deepEqual(page2[1], carol.agentPubKey); - - const page3: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page2[1], - limit: 2, + }); + await john.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: john.agentPubKey, + target_creator: alice.agentPubKey, }, - }, - }); - assert.lengthOf(page3, 1); - assert.deepEqual(page3[0], bob.agentPubKey); - - const page5: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page3[0], - limit: 2, + }); + await steve.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: steve.agentPubKey, + target_creator: alice.agentPubKey, }, - }, - }); - assert.lengthOf(page5, 0); - }, true); + }); + await mary.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: mary.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + await dhtSync( + [alice, bob, carol, john, steve, mary], + alice.cells[0].cell_id[0] + ); + + const page1: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + limit: 2, + }, + }, + }); + + assert.deepEqual(page1[0], mary.agentPubKey); + assert.deepEqual(page1[1], steve.agentPubKey); + + const page2: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + after_agentpubkey: page1[1], + limit: 2, + }, + }, + }); + assert.deepEqual(page2[0], john.agentPubKey); + assert.deepEqual(page2[1], carol.agentPubKey); + + const page3: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + after_agentpubkey: page2[1], + limit: 2, + }, + }, + }); + assert.lengthOf(page3, 1); + assert.deepEqual(page3[0], bob.agentPubKey); + + const page5: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + after_agentpubkey: page3[0], + limit: 2, + }, + }, + }); + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); }); diff --git a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts index 498a8e73..b2c697a5 100644 --- a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts +++ b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts @@ -89,62 +89,66 @@ describe.concurrent("liker-to-hashes", () => { }); it("Agent can only change their own likes", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const targetAddress = await fakeActionHash(); - - // Alice likes hash - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "like", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to remove alices' like - const response = bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: alice.agentPubKey, - target_hash: targetAddress, - }, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - - // Alice removes her own like - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "unlike", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to add a like for allice - const response2 = bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: alice.agentPubKey, - target_hash: targetAddress, - }, - }); - await expect(response2).rejects.toThrowError(/InvalidCommit/); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const targetAddress = await fakeActionHash(); + + // Alice likes hash + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "like", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to remove alices' like + const response = bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: alice.agentPubKey, + target_hash: targetAddress, + }, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + + // Alice removes her own like + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "unlike", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to add a like for allice + const response2 = bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: alice.agentPubKey, + target_hash: targetAddress, + }, + }); + await expect(response2).rejects.toThrowError(/InvalidCommit/); + }, + true, + { timeout: 500000 } + ); }); }); diff --git a/tests/src/mewsfeed/mews/agent-mews.test.ts b/tests/src/mewsfeed/mews/agent-mews.test.ts index a0856d10..b0621a7d 100644 --- a/tests/src/mewsfeed/mews/agent-mews.test.ts +++ b/tests/src/mewsfeed/mews/agent-mews.test.ts @@ -52,195 +52,199 @@ describe.concurrent("agent-mews", () => { }); it("Agent mews lists are time-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - limit: 2, + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + limit: 2, + }, }, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, }, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, }, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + }, }, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); - assert.lengthOf(page5, 0); - }, true); + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); }); diff --git a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts index fafdab72..ab4bca57 100644 --- a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts +++ b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts @@ -1,6 +1,6 @@ import { ActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -import { assert, describe, expect, it, test } from "vitest"; +import { assert, describe, expect, it } from "vitest"; import { FeedMew, Mew, @@ -466,268 +466,272 @@ describe.concurrent("agent-to-notifications", () => { }); it("notifications list is time-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies to Alice's mew - const replyInput: Mew = { - text: "xyxyxyxy test reply 1", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, - }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, - }); - - // Bob replies to Alice's mew - const replyInput2: Mew = { - text: "xyxyxyxy test reply 2", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash2: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput2, - }); - const replyFeedMew2: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash2, - }); - - // Bob replies to Alice's mew - const replyInput3: Mew = { - text: "xyxyxyxy test reply 3", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash3: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput3, - }); - const replyFeedMew3: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash3, - }); - - // Bob replies to Alice's mew - const replyInput4: Mew = { - text: "xyxyxyxy test reply 4", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash4: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput4, - }); - const replyFeedMew4: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash4, - }); - - // Bob replies to Alice's mew - const replyInput5: Mew = { - text: "xyxyxyxy test reply 5", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash5: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput5, - }); - const replyFeedMew5: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash5, - }); - - // Bob replies to Alice's mew - const replyInput6: Mew = { - text: "xyxyxyxy test reply 6", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash6: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput6, - }); - const replyFeedMew6: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash6, - }); - - // Bob replies to Alice's mew - const replyInput7: Mew = { - text: "xyxyxyxy test reply 7", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash7: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput7, - }); - const replyFeedMew7: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash7, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const page1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page1[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew7, - }); - expect(page1[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew6, - }); - - expect(page1[0].timestamp).greaterThanOrEqual(page1[1].timestamp); - - // Alice gets notifications - const page2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page1[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page2[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew5, - }); - expect(page2[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew4, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp); - - // Alice gets notifications - const page3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page2[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page3[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew3, - }); - expect(page3[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew2, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp) - .greaterThanOrEqual(page3[0].timestamp) - .greaterThanOrEqual(page3[1].timestamp); - - // Alice gets notifications - const page4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page3[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - assert.lengthOf(page4, 1); - expect(page4[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp) - .greaterThanOrEqual(page3[0].timestamp) - .greaterThanOrEqual(page3[1].timestamp) - .greaterThanOrEqual(page4[0].timestamp); - - const page5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page4[0].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - assert.lengthOf(page5, 0); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies to Alice's mew + const replyInput: Mew = { + text: "xyxyxyxy test reply 1", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob replies to Alice's mew + const replyInput2: Mew = { + text: "xyxyxyxy test reply 2", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash2: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput2, + }); + const replyFeedMew2: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash2, + }); + + // Bob replies to Alice's mew + const replyInput3: Mew = { + text: "xyxyxyxy test reply 3", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash3: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput3, + }); + const replyFeedMew3: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash3, + }); + + // Bob replies to Alice's mew + const replyInput4: Mew = { + text: "xyxyxyxy test reply 4", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash4: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput4, + }); + const replyFeedMew4: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash4, + }); + + // Bob replies to Alice's mew + const replyInput5: Mew = { + text: "xyxyxyxy test reply 5", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash5: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput5, + }); + const replyFeedMew5: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash5, + }); + + // Bob replies to Alice's mew + const replyInput6: Mew = { + text: "xyxyxyxy test reply 6", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash6: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput6, + }); + const replyFeedMew6: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash6, + }); + + // Bob replies to Alice's mew + const replyInput7: Mew = { + text: "xyxyxyxy test reply 7", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash7: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput7, + }); + const replyFeedMew7: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash7, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const page1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(page1[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew7, + }); + expect(page1[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew6, + }); + + expect(page1[0].timestamp).greaterThanOrEqual(page1[1].timestamp); + + // Alice gets notifications + const page2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page1[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(page2[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew5, + }); + expect(page2[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew4, + }); + + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp); + + // Alice gets notifications + const page3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page2[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(page3[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew3, + }); + expect(page3[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew2, + }); + + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp) + .greaterThanOrEqual(page3[0].timestamp) + .greaterThanOrEqual(page3[1].timestamp); + + // Alice gets notifications + const page4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page3[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + assert.lengthOf(page4, 1); + expect(page4[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew, + }); + + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp) + .greaterThanOrEqual(page3[0].timestamp) + .greaterThanOrEqual(page3[1].timestamp) + .greaterThanOrEqual(page4[0].timestamp); + + const page5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page4[0].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); }); diff --git a/tests/src/mewsfeed/mews/dna-properties.test.ts b/tests/src/mewsfeed/mews/dna-properties.test.ts index 0e2d1234..e0379043 100644 --- a/tests/src/mewsfeed/mews/dna-properties.test.ts +++ b/tests/src/mewsfeed/mews/dna-properties.test.ts @@ -152,25 +152,29 @@ describe.concurrent("dna-properties", () => { }); it("Can get deserialized DNA Properties", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - const properties = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_dna_properties", - payload: null, - }); - expect(properties).toHaveProperty("mew_characters_min", 5); - expect(properties).toHaveProperty("mew_characters_max", 200); - }, true); + const properties = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_dna_properties", + payload: null, + }); + expect(properties).toHaveProperty("mew_characters_min", 5); + expect(properties).toHaveProperty("mew_characters_max", 200); + }, + true, + { timeout: 500000 } + ); }); }); diff --git a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts index 491ae94e..ab46d6bb 100644 --- a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts +++ b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts @@ -403,190 +403,194 @@ describe.concurrent("followed-creators-mews", () => { }); it("Followed creators mews list are time-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const page1: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - limit: 2, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - }, - }); - - assert.lengthOf(page5, 0); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const page1: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + limit: 2, + }, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, + }); + + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); }); diff --git a/tests/src/mewsfeed/mews/mention-to-mews.test.ts b/tests/src/mewsfeed/mews/mention-to-mews.test.ts index d80f8d84..8f439987 100644 --- a/tests/src/mewsfeed/mews/mention-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/mention-to-mews.test.ts @@ -70,195 +70,199 @@ describe.concurrent("mention-to-mews", () => { }); it("Mentions list are time-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - const mewContent1 = "My Mew with @mention 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); + const mewContent1 = "My Mew with @mention 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); - const mewContent2 = "My Mew with @mention 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); + const mewContent2 = "My Mew with @mention 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); - const mewContent3 = "My Mew with @mention 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); + const mewContent3 = "My Mew with @mention 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); - const mewContent4 = "My Mew with @mention 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); + const mewContent4 = "My Mew with @mention 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); - const mewContent5 = "My Mew with @mention 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); + const mewContent5 = "My Mew with @mention 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); - const mewContent6 = "My Mew with @mention 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); + const mewContent6 = "My Mew with @mention 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); - const mewContent7 = "My Mew with @mention 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); + const mewContent7 = "My Mew with @mention 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - start_time: null, - limit: 2, + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + start_time: null, + limit: 2, + }, }, - }, - }); + }); - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); - assert.lengthOf(page5, 0); - }, true); + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); }); diff --git a/tests/src/mewsfeed/mews/mew-to-responses.test.ts b/tests/src/mewsfeed/mews/mew-to-responses.test.ts index 03e9da73..ea01b686 100644 --- a/tests/src/mewsfeed/mews/mew-to-responses.test.ts +++ b/tests/src/mewsfeed/mews/mew-to-responses.test.ts @@ -147,67 +147,75 @@ describe.concurrent("mew-to-responses", () => { }); it("Agent can quote a mew", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const aliceQuoteText = "alice-test-quote"; - const aliceQuoteInput: Mew = { - text: aliceQuoteText, - links: [], - mew_type: { - [MewTypeName.Quote]: action_hash, - }, - }; - const quote_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceQuoteInput, - }); - - const quote: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quote_action_hash, - }); - assert.ok(MewTypeName.Quote in quote.mew.mew_type, "mew is a quote"); - assert.equal(quote.mew.text, aliceQuoteText, "quote is alice's quote"); - - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.quotes_count === 1, "original mew has 1 quote"); - assert.isTrue( - originalMew.is_quoted, - "original mew's quote is alice's quote" - ); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const aliceQuoteText = "alice-test-quote"; + const aliceQuoteInput: Mew = { + text: aliceQuoteText, + links: [], + mew_type: { + [MewTypeName.Quote]: action_hash, + }, + }; + const quote_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceQuoteInput, + }); + + const quote: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quote_action_hash, + }); + assert.ok(MewTypeName.Quote in quote.mew.mew_type, "mew is a quote"); + assert.equal(quote.mew.text, aliceQuoteText, "quote is alice's quote"); + + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal( + originalMew.mew.text, + aliceMewContent, + "mew is alice's mew" + ); + assert.ok(originalMew.quotes_count === 1, "original mew has 1 quote"); + assert.isTrue( + originalMew.is_quoted, + "original mew's quote is alice's quote" + ); + }, + true, + { timeout: 500000 } + ); }); }); diff --git a/tests/src/mewsfeed/mews/mew-with-context.test.ts b/tests/src/mewsfeed/mews/mew-with-context.test.ts index ef105377..4cf985c5 100644 --- a/tests/src/mewsfeed/mews/mew-with-context.test.ts +++ b/tests/src/mewsfeed/mews/mew-with-context.test.ts @@ -342,7 +342,7 @@ describe.concurrent("mew-with-context", () => { expect(aliceFeedMew.is_pinned).false; }, true, - { timeout: 100000 } + { timeout: 500000 } ); }); }); diff --git a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts index ef681684..49e48992 100644 --- a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts @@ -6,69 +6,73 @@ import { createMew } from "./common.js"; describe.concurrent("pinner-to-mews", () => { it("link a Pinner to a Mew", async () => { - await runScenario(async (scenario) => { - // Construct proper paths for your app. - // This assumes app bundle created by the `hc app pack` command. - const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; + await runScenario( + async (scenario) => { + // Construct proper paths for your app. + // This assumes app bundle created by the `hc app pack` command. + const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; - // Set up the app to be installed - const appSource = { appBundleSource: { path: testAppPath } }; + // Set up the app to be installed + const appSource = { appBundleSource: { path: testAppPath } }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - const baseAddress = alice.agentPubKey; - const targetActionHash: ActionHash = await createMew(alice.cells[0]); + const baseAddress = alice.agentPubKey; + const targetActionHash: ActionHash = await createMew(alice.cells[0]); - // Bob gets the links, should be empty - let linksOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); + // Bob gets the links, should be empty + let linksOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); - // Alice creates a link from Pinner to Mew - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: targetActionHash, - }); + // Alice creates a link from Pinner to Mew + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: targetActionHash, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 1); - assert.deepEqual(targetActionHash, linksOutput[0].action_hash); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 1); + assert.deepEqual(targetActionHash, linksOutput[0].action_hash); - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: targetActionHash, - }); + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: targetActionHash, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - }, true); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + }, + true, + { timeout: 500000 } + ); }); }); diff --git a/tests/src/mewsfeed/mews/tags-to-mews.test.ts b/tests/src/mewsfeed/mews/tags-to-mews.test.ts index f01c963f..01a1deff 100644 --- a/tests/src/mewsfeed/mews/tags-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/tags-to-mews.test.ts @@ -382,203 +382,207 @@ describe.concurrent("tags-to-mews", () => { }); it("Cashtags list are time-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with $cashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with $cashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with $cashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with $cashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with $cashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with $cashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with $cashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - start_time: null, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with $cashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with $cashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with $cashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with $cashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with $cashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with $cashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with $cashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + start_time: null, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, }, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, }, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, }, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, }, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, }, - }, - }); + }); - assert.lengthOf(page5, 0); - }, true); + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); }); From 2cb73776bf88384c599514c2e8b21b488187aa4a Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Wed, 1 Nov 2023 09:37:46 -0600 Subject: [PATCH 09/22] timeout not being effective --- .../agent_pins/pinner-to-hashes.test.ts | 176 +-- .../follows/follower-to-creators.test.ts | 638 ++++----- .../mewsfeed/likes/liker-to-hashes.test.ts | 228 +-- tests/src/mewsfeed/mews/agent-mews.test.ts | 428 +++--- .../mews/agent-to-notifications.test.ts | 1220 ++++++++--------- .../src/mewsfeed/mews/dna-properties.test.ts | 288 ++-- .../mews/followed-creators-mews.test.ts | 987 +++++++------ .../src/mewsfeed/mews/mention-to-mews.test.ts | 430 +++--- .../mewsfeed/mews/mew-to-responses.test.ts | 322 +++-- .../mewsfeed/mews/mew-with-context.test.ts | 680 ++++----- .../src/mewsfeed/mews/pinner-to-mews.test.ts | 120 +- tests/src/mewsfeed/mews/tags-to-mews.test.ts | 769 +++++------ 12 files changed, 3127 insertions(+), 3159 deletions(-) diff --git a/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts b/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts index 921edb96..87d943fe 100644 --- a/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts +++ b/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts @@ -3,92 +3,92 @@ import { assert, describe, it } from "vitest"; import { AgentPubKey, HoloHash, fakeActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -describe.concurrent("pinner-to-hashes", () => { - it("link a Pinner to a Hash", async () => { - await runScenario( - async (scenario) => { - // Construct proper paths for your app. - // This assumes app bundle created by the `hc app pack` command. - const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; - - // Set up the app to be installed - const appSource = { appBundleSource: { path: testAppPath } }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetHash = await fakeActionHash(); - - // Bob gets the links, should be empty - let linksOutput: HoloHash[] = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Pinner to Hash - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: targetHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - const pinnersOutput: AgentPubKey[] = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_pinners_for_hash", - payload: targetHash, - }); - assert.equal(pinnersOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: targetHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_pinners_for_hash", - payload: targetHash, - }); - - assert.equal(linksOutput.length, 0); - }, - true, - { timeout: 500000 } - ); - }); +// describe.concurrent("pinner-to-hashes", () => { +it("link a Pinner to a Hash", async () => { + await runScenario( + async (scenario) => { + // Construct proper paths for your app. + // This assumes app bundle created by the `hc app pack` command. + const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; + + // Set up the app to be installed + const appSource = { appBundleSource: { path: testAppPath } }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetHash = await fakeActionHash(); + + // Bob gets the links, should be empty + let linksOutput: HoloHash[] = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Pinner to Hash + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: targetHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + const pinnersOutput: AgentPubKey[] = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_pinners_for_hash", + payload: targetHash, + }); + assert.equal(pinnersOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: targetHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_pinners_for_hash", + payload: targetHash, + }); + + assert.equal(linksOutput.length, 0); + }, + true, + { timeout: 500000 } + ); }); +// }); diff --git a/tests/src/mewsfeed/follows/follower-to-creators.test.ts b/tests/src/mewsfeed/follows/follower-to-creators.test.ts index 9623fa22..de459980 100644 --- a/tests/src/mewsfeed/follows/follower-to-creators.test.ts +++ b/tests/src/mewsfeed/follows/follower-to-creators.test.ts @@ -3,187 +3,310 @@ import { dhtSync, runScenario } from "@holochain/tryorama"; import { assert, describe, expect, it } from "vitest"; import { mewsfeedAppBundleSource } from "../../common"; -describe.concurrent("follower-to-creators", () => { - it("link a Follower to a Creator", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = bob.agentPubKey; - - // Bob gets the links, should be empty - let linksOutput: Record[] = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Follower to Creator - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: targetAddress, - }, - }); - assert.equal(linksOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); +// describe.concurrent("follower-to-creators", () => { +it("link a Follower to a Creator", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = bob.agentPubKey; + + // Bob gets the links, should be empty + let linksOutput: Record[] = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Follower to Creator + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: targetAddress, - }, - }); - assert.equal(linksOutput.length, 0); - }, true); - }); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: targetAddress, + }, + }); + assert.equal(linksOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); - it("Agent cannot follow themselves", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: targetAddress, + }, + }); + assert.equal(linksOutput.length, 0); + }, true); +}); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); +it("Agent cannot follow themselves", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice tries to follow herself + const response = alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + }, true); +}); - // Alice tries to follow herself - const response = alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - }, true); - }); +it("Agent can only change their own follows", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = bob.agentPubKey; + + // Alice follows bob + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to remove alices' follow + const response = bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + + // Alice removes her own follow + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "unfollow", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to add a follow for allice + const response2 = bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); + await expect(response2).rejects.toThrowError(/InvalidCommit/); + }, true); +}); - it("Agent can only change their own follows", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; +it("Creators list are hash-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol, john, steve, mary] = + await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + appSource, appSource, appSource, ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = bob.agentPubKey; - - // Alice follows bob - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: targetAddress, - }); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a link from Follower to Creator + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: bob.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: carol.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: john.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: steve.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: mary.agentPubKey, + }, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob tries to remove alices' follow - const response = bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, + const page1: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + limit: 2, }, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - - // Alice removes her own follow - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "unfollow", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to add a follow for allice - const response2 = bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, + }, + }); + + assert.deepEqual(page1[0], mary.agentPubKey); + assert.deepEqual(page1[1], steve.agentPubKey); + + const page2: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page1[1], + limit: 2, }, - }); - await expect(response2).rejects.toThrowError(/InvalidCommit/); - }, true); - }); + }, + }); + assert.deepEqual(page2[0], john.agentPubKey); + assert.deepEqual(page2[1], carol.agentPubKey); + + const page3: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page2[1], + limit: 2, + }, + }, + }); + assert.lengthOf(page3, 1); + assert.deepEqual(page3[0], bob.agentPubKey); + + const page5: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page3[0], + limit: 2, + }, + }, + }); + assert.lengthOf(page5, 0); + }, true); +}); - it("Creators list are hash-paginated", async () => { - await runScenario(async (scenario) => { +it("Followers list are hash-paginated", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -204,54 +327,57 @@ describe.concurrent("follower-to-creators", () => { await scenario.shareAllAgents(); // Alice creates a link from Follower to Creator - await alice.cells[0].callZome({ + await bob.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: alice.agentPubKey, - target_creator: bob.agentPubKey, + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, }, }); - await alice.cells[0].callZome({ + await carol.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: alice.agentPubKey, - target_creator: carol.agentPubKey, + base_follower: carol.agentPubKey, + target_creator: alice.agentPubKey, }, }); - await alice.cells[0].callZome({ + await john.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: alice.agentPubKey, - target_creator: john.agentPubKey, + base_follower: john.agentPubKey, + target_creator: alice.agentPubKey, }, }); - await alice.cells[0].callZome({ + await steve.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: alice.agentPubKey, - target_creator: steve.agentPubKey, + base_follower: steve.agentPubKey, + target_creator: alice.agentPubKey, }, }); - await alice.cells[0].callZome({ + await mary.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: alice.agentPubKey, - target_creator: mary.agentPubKey, + base_follower: mary.agentPubKey, + target_creator: alice.agentPubKey, }, }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync( + [alice, bob, carol, john, steve, mary], + alice.cells[0].cell_id[0] + ); const page1: AgentPubKey[] = await alice.cells[0].callZome({ zome_name: "follows", - fn_name: "get_creators_for_follower", + fn_name: "get_followers_for_creator", payload: { - follower: alice.agentPubKey, + creator: alice.agentPubKey, page: { limit: 2, }, @@ -263,9 +389,9 @@ describe.concurrent("follower-to-creators", () => { const page2: AgentPubKey[] = await alice.cells[0].callZome({ zome_name: "follows", - fn_name: "get_creators_for_follower", + fn_name: "get_followers_for_creator", payload: { - follower: alice.agentPubKey, + creator: alice.agentPubKey, page: { after_agentpubkey: page1[1], limit: 2, @@ -277,9 +403,9 @@ describe.concurrent("follower-to-creators", () => { const page3: AgentPubKey[] = await alice.cells[0].callZome({ zome_name: "follows", - fn_name: "get_creators_for_follower", + fn_name: "get_followers_for_creator", payload: { - follower: alice.agentPubKey, + creator: alice.agentPubKey, page: { after_agentpubkey: page2[1], limit: 2, @@ -291,9 +417,9 @@ describe.concurrent("follower-to-creators", () => { const page5: AgentPubKey[] = await alice.cells[0].callZome({ zome_name: "follows", - fn_name: "get_creators_for_follower", + fn_name: "get_followers_for_creator", payload: { - follower: alice.agentPubKey, + creator: alice.agentPubKey, page: { after_agentpubkey: page3[0], limit: 2, @@ -301,135 +427,9 @@ describe.concurrent("follower-to-creators", () => { }, }); assert.lengthOf(page5, 0); - }, true); - }); - - it("Followers list are hash-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol, john, steve, mary] = - await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a link from Follower to Creator - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await carol.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: carol.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await john.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: john.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await steve.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: steve.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await mary.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: mary.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - await dhtSync( - [alice, bob, carol, john, steve, mary], - alice.cells[0].cell_id[0] - ); - - const page1: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - limit: 2, - }, - }, - }); - - assert.deepEqual(page1[0], mary.agentPubKey); - assert.deepEqual(page1[1], steve.agentPubKey); - - const page2: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page1[1], - limit: 2, - }, - }, - }); - assert.deepEqual(page2[0], john.agentPubKey); - assert.deepEqual(page2[1], carol.agentPubKey); - - const page3: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page2[1], - limit: 2, - }, - }, - }); - assert.lengthOf(page3, 1); - assert.deepEqual(page3[0], bob.agentPubKey); - - const page5: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page3[0], - limit: 2, - }, - }, - }); - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); - }); + }, + true, + { timeout: 500000 } + ); }); +// }); diff --git a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts index b2c697a5..34418b34 100644 --- a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts +++ b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts @@ -3,9 +3,94 @@ import { dhtSync, runScenario } from "@holochain/tryorama"; import { assert, describe, expect, it } from "vitest"; import { mewsfeedAppBundleSource } from "../../common"; -describe.concurrent("liker-to-hashes", () => { - it("link a Liker to a Hash", async () => { - await runScenario(async (scenario) => { +// describe.concurrent("liker-to-hashes", () => { +it("link a Liker to a Hash", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = await fakeActionHash(); + + // Bob gets the links, should be empty + let linksOutput: Record[] = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Liker to Hash + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: baseAddress, + target_hash: targetAddress, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_likers_for_hash", + payload: targetAddress, + }); + assert.equal(linksOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: baseAddress, + target_hash: targetAddress, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_likers_for_hash", + payload: targetAddress, + }); + assert.equal(linksOutput.length, 0); + }, true); +}); + +it("Agent can only change their own likes", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -20,135 +105,50 @@ describe.concurrent("liker-to-hashes", () => { // conductor of the scenario. await scenario.shareAllAgents(); - const baseAddress = alice.agentPubKey; const targetAddress = await fakeActionHash(); - // Bob gets the links, should be empty - let linksOutput: Record[] = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Liker to Hash + // Alice likes hash await alice.cells[0].callZome({ zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: baseAddress, - target_hash: targetAddress, - }, + fn_name: "like", + payload: targetAddress, }); await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_likers_for_hash", - payload: targetAddress, - }); - assert.equal(linksOutput.length, 1); - - await alice.cells[0].callZome({ + // Bob tries to remove alices' like + const response = bob.cells[0].callZome({ zome_name: "likes", fn_name: "remove_hash_for_liker", payload: { - base_liker: baseAddress, + base_liker: alice.agentPubKey, target_hash: targetAddress, }, }); + await expect(response).rejects.toThrowError(/InvalidCommit/); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ + // Alice removes her own like + await alice.cells[0].callZome({ zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, + fn_name: "unlike", + payload: targetAddress, }); - assert.equal(linksOutput.length, 0); - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to add a like for allice + const response2 = bob.cells[0].callZome({ zome_name: "likes", - fn_name: "get_likers_for_hash", - payload: targetAddress, + fn_name: "add_hash_for_liker", + payload: { + base_liker: alice.agentPubKey, + target_hash: targetAddress, + }, }); - assert.equal(linksOutput.length, 0); - }, true); - }); - - it("Agent can only change their own likes", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const targetAddress = await fakeActionHash(); - - // Alice likes hash - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "like", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to remove alices' like - const response = bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: alice.agentPubKey, - target_hash: targetAddress, - }, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - - // Alice removes her own like - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "unlike", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to add a like for allice - const response2 = bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: alice.agentPubKey, - target_hash: targetAddress, - }, - }); - await expect(response2).rejects.toThrowError(/InvalidCommit/); - }, - true, - { timeout: 500000 } - ); - }); + await expect(response2).rejects.toThrowError(/InvalidCommit/); + }, + true, + { timeout: 500000 } + ); }); +// }); diff --git a/tests/src/mewsfeed/mews/agent-mews.test.ts b/tests/src/mewsfeed/mews/agent-mews.test.ts index b0621a7d..34bef6dc 100644 --- a/tests/src/mewsfeed/mews/agent-mews.test.ts +++ b/tests/src/mewsfeed/mews/agent-mews.test.ts @@ -5,246 +5,246 @@ import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -describe.concurrent("agent-mews", () => { - it("create a Mew and get agent mews", async () => { - await runScenario(async (scenario) => { +// describe.concurrent("agent-mews", () => { +it("create a Mew and get agent mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Bob gets agent mews + let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + }, + }); + assert.equal(collectionOutput.length, 0); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets agent mews again + collectionOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + }, + }); + assert.equal(collectionOutput.length, 1); + assert.deepEqual(actionHash, collectionOutput[0].action_hash); + }, true); +}); + +it("Agent mews lists are time-paginated", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; // Add 2 players with the test app to the Scenario. The returned players // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); + const [alice] = await scenario.addPlayersWithApps([appSource]); // Shortcut peer discovery through gossip and register all agents in every // conductor of the scenario. await scenario.shareAllAgents(); - // Bob gets agent mews - let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + limit: 2, + }, + }, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_agent_mews_with_context", payload: { agent: alice.agentPubKey, + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, }, }); - assert.equal(collectionOutput.length, 0); - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); - // Bob gets agent mews again - collectionOutput = await bob.cells[0].callZome({ + const page3: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_agent_mews_with_context", payload: { agent: alice.agentPubKey, + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, }, }); - assert.equal(collectionOutput.length, 1); - assert.deepEqual(actionHash, collectionOutput[0].action_hash); - }, true); - }); - - it("Agent mews lists are time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - limit: 2, - }, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - }, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - }, + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - }, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); - }); + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); +// }); diff --git a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts index ab4bca57..d8417014 100644 --- a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts +++ b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts @@ -11,74 +11,463 @@ import { import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -describe.concurrent("agent-to-notifications", () => { - it("notifications include my agent follows & unfollows", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Bob follows Alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - // Bob unfollows Alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); +// describe.concurrent("agent-to-notifications", () => { +it("notifications include my agent follows & unfollows", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Bob follows Alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + // Bob unfollows Alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyAgentUnfollowed]: null }, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyAgentFollowed]: null }, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, true); +}); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); +it("notifications include my mews' likes & unlikes", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + const feedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob likes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + // Bob unlikes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewUnlicked]: null }, + feed_mew: feedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewLicked]: null }, + feed_mew: feedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, true); +}); - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); +it("notifications include my mews' pins & unpins", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + const feedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob likes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "add_hash_for_pinner", + payload: { + base_pinner: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + // Bob unlikes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "remove_hash_for_pinner", + payload: { + base_pinner: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewUnpinned]: null }, + feed_mew: feedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewPinned]: null }, + feed_mew: feedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, true); +}); - // Notifications should be orderded by action time descending (newest first) - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyAgentUnfollowed]: null }, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyAgentFollowed]: null }, - }); +it("notifications include my mews' replies, quotes, mewmews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies to Alice's mew + const replyInput: Mew = { + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob mewmews Alice's mew + const mewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }; + const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewmewInput, + }); + const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmewActionHash, + }); + + // Bob quotes Alice's mew + const quoteInput: Mew = { + text: "a response to a quoted mew", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }; + const quoteActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: quoteInput, + }); + const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quoteActionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: quoteFeedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: mewmewFeedMew, + }); + expect(notifications[2]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(3); + }, true); +}); - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, true); - }); +it("notifications include replies, quotes, mewmews to mews that I also responded to", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Carol creates a Mew + const actionHash: ActionHash = await createMew(carol.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice reply's to Carol's mew + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }, + }); + + // Bob replies to Carol's mew + const replyInput: Mew = { + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob mewmews Carol's mew + const mewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }; + const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewmewInput, + }); + const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmewActionHash, + }); + + // Bob quotes Carol's mew + const quoteInput: Mew = { + text: "a response to a quoted mew", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }; + const quoteActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: quoteInput, + }); + const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quoteActionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: quoteFeedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: mewmewFeedMew, + }); + expect(notifications[2]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: replyFeedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(3); + }, true); +}); - it("notifications include my mews' likes & unlikes", async () => { - await runScenario(async (scenario) => { +it("notifications list is time-paginated", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -96,642 +485,253 @@ describe.concurrent("agent-to-notifications", () => { // Alice creates a Mew const actionHash: ActionHash = await createMew(alice.cells[0]); assert.ok(actionHash); - const feedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob likes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - // Bob unlikes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: bob.agentPubKey, - target_hash: actionHash, - }, - }); await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ + // Bob replies to Alice's mew + const replyInput: Mew = { + text: "xyxyxyxy test reply 1", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewUnlicked]: null }, - feed_mew: feedMew, + fn_name: "create_mew", + payload: replyInput, }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewLicked]: null }, - feed_mew: feedMew, + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, }); - // Alice gets notifications count - const count = await alice.cells[0].callZome({ + // Bob replies to Alice's mew + const replyInput2: Mew = { + text: "xyxyxyxy test reply 2", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash2: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, + fn_name: "create_mew", + payload: replyInput2, }); - expect(count).toEqual(2); - }, true); - }); - - it("notifications include my mews' pins & unpins", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - const feedMew: FeedMew = await alice.cells[0].callZome({ + const replyFeedMew2: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob likes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "add_hash_for_pinner", - payload: { - base_pinner: bob.agentPubKey, - target_hash: actionHash, - }, + payload: replyActionHash2, }); - // Bob unlikes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "remove_hash_for_pinner", - payload: { - base_pinner: bob.agentPubKey, - target_hash: actionHash, - }, + // Bob replies to Alice's mew + const replyInput3: Mew = { + text: "xyxyxyxy test reply 3", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash3: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput3, }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ + const replyFeedMew3: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, + fn_name: "get_mew_with_context", + payload: replyActionHash3, }); - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewUnpinned]: null }, - feed_mew: feedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewPinned]: null }, - feed_mew: feedMew, + // Bob replies to Alice's mew + const replyInput4: Mew = { + text: "xyxyxyxy test reply 4", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash4: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput4, }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ + const replyFeedMew4: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, + fn_name: "get_mew_with_context", + payload: replyActionHash4, }); - expect(count).toEqual(2); - }, true); - }); - - it("notifications include my mews' replies, quotes, mewmews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); // Bob replies to Alice's mew - const replyInput: Mew = { - text: "test reply 12345", + const replyInput5: Mew = { + text: "xyxyxyxy test reply 5", links: [], mew_type: { [MewTypeName.Reply]: actionHash }, }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ + const replyActionHash5: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: replyInput, + payload: replyInput5, }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + const replyFeedMew5: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: replyActionHash, + payload: replyActionHash5, }); - // Bob mewmews Alice's mew - const mewmewInput: Mew = { - text: "", + // Bob replies to Alice's mew + const replyInput6: Mew = { + text: "xyxyxyxy test reply 6", links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, + mew_type: { [MewTypeName.Reply]: actionHash }, }; - const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ + const replyActionHash6: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: mewmewInput, + payload: replyInput6, }); - const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + const replyFeedMew6: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: mewmewActionHash, + payload: replyActionHash6, }); - // Bob quotes Alice's mew - const quoteInput: Mew = { - text: "a response to a quoted mew", + // Bob replies to Alice's mew + const replyInput7: Mew = { + text: "xyxyxyxy test reply 7", links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, + mew_type: { [MewTypeName.Reply]: actionHash }, }; - const quoteActionHash: ActionHash = await bob.cells[0].callZome({ + const replyActionHash7: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: quoteInput, + payload: replyInput7, }); - const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ + const replyFeedMew7: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: quoteActionHash, + payload: replyActionHash7, }); await dhtSync([alice, bob], alice.cells[0].cell_id[0]); // Alice gets notifications - const notifications = await alice.cells[0].callZome({ + const page1 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_notifications", - payload: null, + payload: { + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, }); - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: quoteFeedMew, - }); - expect(notifications[1]).toMatchObject({ + // Notifications should be orderded by action time descending (newest first) + expect(page1[0]).toMatchObject({ agent: bob.agentPubKey, notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: mewmewFeedMew, + feed_mew: replyFeedMew7, }); - expect(notifications[2]).toMatchObject({ + expect(page1[1]).toMatchObject({ agent: bob.agentPubKey, notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, + feed_mew: replyFeedMew6, }); - expect(count).toEqual(3); - }, true); - }); - - it("notifications include replies, quotes, mewmews to mews that I also responded to", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - // Carol creates a Mew - const actionHash: ActionHash = await createMew(carol.cells[0]); - assert.ok(actionHash); + expect(page1[0].timestamp).greaterThanOrEqual(page1[1].timestamp); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice reply's to Carol's mew - await alice.cells[0].callZome({ + // Alice gets notifications + const page2 = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "create_mew", + fn_name: "get_my_notifications", payload: { - text: "test reply 12345", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, + after_timestamp: page1[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, }, }); - // Bob replies to Carol's mew - const replyInput: Mew = { - text: "test reply 12345", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, + // Notifications should be orderded by action time descending (newest first) + expect(page2[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew5, }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, + expect(page2[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew4, }); - // Bob mewmews Carol's mew - const mewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }; - const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewmewInput, - }); - const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp); + + // Alice gets notifications + const page3 = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmewActionHash, + fn_name: "get_my_notifications", + payload: { + after_timestamp: page2[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, }); - // Bob quotes Carol's mew - const quoteInput: Mew = { - text: "a response to a quoted mew", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }; - const quoteActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: quoteInput, + // Notifications should be orderded by action time descending (newest first) + expect(page3[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew3, }); - const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quoteActionHash, + expect(page3[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew2, }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp) + .greaterThanOrEqual(page3[0].timestamp) + .greaterThanOrEqual(page3[1].timestamp); // Alice gets notifications - const notifications = await alice.cells[0].callZome({ + const page4 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: quoteFeedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, + payload: { + after_timestamp: page3[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, }, - feed_mew: mewmewFeedMew, }); - expect(notifications[2]).toMatchObject({ + + // Notifications should be orderded by action time descending (newest first) + assert.lengthOf(page4, 1); + expect(page4[0]).toMatchObject({ agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, feed_mew: replyFeedMew, }); - // Alice gets notifications count - const count = await alice.cells[0].callZome({ + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp) + .greaterThanOrEqual(page3[0].timestamp) + .greaterThanOrEqual(page3[1].timestamp) + .greaterThanOrEqual(page4[0].timestamp); + + const page5 = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, + fn_name: "get_my_notifications", + payload: { + after_timestamp: page4[0].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, }); - expect(count).toEqual(3); - }, true); - }); - - it("notifications list is time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies to Alice's mew - const replyInput: Mew = { - text: "xyxyxyxy test reply 1", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, - }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, - }); - - // Bob replies to Alice's mew - const replyInput2: Mew = { - text: "xyxyxyxy test reply 2", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash2: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput2, - }); - const replyFeedMew2: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash2, - }); - - // Bob replies to Alice's mew - const replyInput3: Mew = { - text: "xyxyxyxy test reply 3", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash3: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput3, - }); - const replyFeedMew3: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash3, - }); - - // Bob replies to Alice's mew - const replyInput4: Mew = { - text: "xyxyxyxy test reply 4", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash4: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput4, - }); - const replyFeedMew4: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash4, - }); - - // Bob replies to Alice's mew - const replyInput5: Mew = { - text: "xyxyxyxy test reply 5", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash5: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput5, - }); - const replyFeedMew5: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash5, - }); - - // Bob replies to Alice's mew - const replyInput6: Mew = { - text: "xyxyxyxy test reply 6", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash6: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput6, - }); - const replyFeedMew6: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash6, - }); - - // Bob replies to Alice's mew - const replyInput7: Mew = { - text: "xyxyxyxy test reply 7", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash7: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput7, - }); - const replyFeedMew7: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash7, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const page1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page1[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew7, - }); - expect(page1[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew6, - }); - - expect(page1[0].timestamp).greaterThanOrEqual(page1[1].timestamp); - - // Alice gets notifications - const page2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page1[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page2[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew5, - }); - expect(page2[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew4, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp); - - // Alice gets notifications - const page3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page2[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page3[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew3, - }); - expect(page3[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew2, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp) - .greaterThanOrEqual(page3[0].timestamp) - .greaterThanOrEqual(page3[1].timestamp); - - // Alice gets notifications - const page4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page3[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - assert.lengthOf(page4, 1); - expect(page4[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp) - .greaterThanOrEqual(page3[0].timestamp) - .greaterThanOrEqual(page3[1].timestamp) - .greaterThanOrEqual(page4[0].timestamp); - - const page5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page4[0].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); - }); + + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); +// }); diff --git a/tests/src/mewsfeed/mews/dna-properties.test.ts b/tests/src/mewsfeed/mews/dna-properties.test.ts index e0379043..6879ee20 100644 --- a/tests/src/mewsfeed/mews/dna-properties.test.ts +++ b/tests/src/mewsfeed/mews/dna-properties.test.ts @@ -7,105 +7,149 @@ import { mewsfeedAppBundleSourceNoLengthLimits, } from "../../common.js"; -describe.concurrent("dna-properties", () => { - it("Mew must not be longer than DNA property mew_characters_max chars", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); +// describe.concurrent("dna-properties", () => { +it("Mew must not be longer than DNA property mew_characters_max chars", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const createMewInput: Mew = { + text: new Array(200).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length" + ); - const createMewInput: Mew = { - text: new Array(200).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ + createMewInput.text = new Array(201).fill("a").join(""); + try { + await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", payload: createMewInput, }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length" - ); - - createMewInput.text = new Array(201).fill("a").join(""); - try { - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.fail("mew content longer than mew_characters_max is valid"); - } catch (error) { - assert.ok( - true, - "mew content longer than mew_characters_max is invalid" - ); - } - }, true); - }); - - it("Mew must not be shorter than DNA property mew_characters_min chars", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); + assert.fail("mew content longer than mew_characters_max is valid"); + } catch (error) { + assert.ok(true, "mew content longer than mew_characters_max is invalid"); + } + }, true); +}); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); +it("Mew must not be shorter than DNA property mew_characters_min chars", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const createMewInput: Mew = { + text: new Array(10).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length" + ); - const createMewInput: Mew = { - text: new Array(10).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ + createMewInput.text = new Array(2).fill("a").join(""); + try { + await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", payload: createMewInput, }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length" - ); - - createMewInput.text = new Array(2).fill("a").join(""); - try { - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.fail("mew content shorter than mew_characters_min is valid"); - } catch (error) { - assert.ok( - true, - "mew content shorter than mew_characters_min is invalid" - ); - } - }, true); - }); - - it("Mew can be any length if DNA property mew_characters_min and mew_characters_max not set", async () => { - await runScenario(async (scenario) => { + assert.fail("mew content shorter than mew_characters_min is valid"); + } catch (error) { + assert.ok(true, "mew content shorter than mew_characters_min is invalid"); + } + }, true); +}); + +it("Mew can be any length if DNA property mew_characters_min and mew_characters_max not set", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { + appBundleSource: mewsfeedAppBundleSourceNoLengthLimits, + }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // 0 charactres + const createMewInput2: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash2: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + assert.deepEqual( + action_hash2.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length 0" + ); + + // 1000 charactres + const createMewInput3: Mew = { + text: new Array(1000).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash3: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + assert.deepEqual( + action_hash3.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length 1000" + ); + }, true); +}); + +it("Can get deserialized DNA Properties", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed - const appSource = { - appBundleSource: mewsfeedAppBundleSourceNoLengthLimits, - }; + const appSource = { appBundleSource: mewsfeedAppBundleSource }; // Add 2 players with the test app to the Scenario. The returned players // can be destructured. @@ -115,66 +159,16 @@ describe.concurrent("dna-properties", () => { // conductor of the scenario. await scenario.shareAllAgents(); - // 0 charactres - const createMewInput2: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash2: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - assert.deepEqual( - action_hash2.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length 0" - ); - - // 1000 charactres - const createMewInput3: Mew = { - text: new Array(1000).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash3: ActionHash = await alice.cells[0].callZome({ + const properties = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, + fn_name: "get_dna_properties", + payload: null, }); - assert.deepEqual( - action_hash3.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length 1000" - ); - }, true); - }); - - it("Can get deserialized DNA Properties", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const properties = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_dna_properties", - payload: null, - }); - expect(properties).toHaveProperty("mew_characters_min", 5); - expect(properties).toHaveProperty("mew_characters_max", 200); - }, - true, - { timeout: 500000 } - ); - }); + expect(properties).toHaveProperty("mew_characters_min", 5); + expect(properties).toHaveProperty("mew_characters_max", 200); + }, + true, + { timeout: 500000 } + ); }); +// }); diff --git a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts index ab46d6bb..4c3dea25 100644 --- a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts +++ b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts @@ -5,58 +5,399 @@ import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -describe.concurrent("followed-creators-mews", () => { - it("create a Mew and get followed creators mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; +// describe.concurrent("followed-creators-mews", () => { +it("create a Mew and get followed creators mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Bob follows alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + // Bob gets followed creators mews + let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.equal(collectionOutput.length, 0); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets followed creators mews again + collectionOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + + assert.equal(collectionOutput.length, 1); + assert.deepEqual(actionHash, collectionOutput[0].action_hash); + }, true); +}); - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); +it("Followed creators mews should include mews of followed creator", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = "test-mew"; + const mewInput: Mew = { + text: mewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewInput, + }); + + const bobMewsFeedInitial: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + bobMewsFeedInitial.length === 0, + "bob's mews feed is initially empty" + ); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal( + bobMewsFeed[0].mew.text, + mewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + }, true); +}); - // Bob follows alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); +it("Followed creators mews should include own mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewsFeedInitial: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeedInitial.length === 0, + "alice's mews feed is initially empty" + ); - // Bob gets followed creators mews - let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.equal(collectionOutput.length, 0); + const mewContent = "test-mew"; + const mewInput: Mew = { + text: mewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewInput, + }); + + const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(aliceMewsFeed.length === 1, "alice's mews feed includes her mew"); + assert.equal(aliceMewsFeed[0].mew.text, mewContent, "mew content matches"); + }, true); +}); - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); +it("Followed creators mews should not include mews of non-followed creator", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const carolMewContent = "carol-test-mew"; + const carolMewInput: Mew = { + text: carolMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await carol.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: carolMewInput, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal( + bobMewsFeed[0].mew.text, + aliceMewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + }, true); +}); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); +it("Unfollowing should exclude creators mews from feed", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const bobMewsFeedWhenFollowing: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + bobMewsFeedWhenFollowing.length === 1, + "bob's mews feed includes 1 mew" + ); + assert.equal( + bobMewsFeedWhenFollowing[0].mew.text, + aliceMewContent, + "mew content in bob's mews feed matches alice's mew content" + ); - // Bob gets followed creators mews again - collectionOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "unfollow", + payload: alice.agentPubKey, + }); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 0, "bob's mews feed is empty"); + }, true); +}); - assert.equal(collectionOutput.length, 1); - assert.deepEqual(actionHash, collectionOutput[0].action_hash); - }, true); - }); +it("Followed creators mews should be ordered by timestamp in descending order", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const firstMewContent = "first-test-mew"; + const firstMewInput: Mew = { + text: firstMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: firstMewInput, + }); + + const secondMewContent = "second-test-mew"; + const secondMewInput: Mew = { + text: secondMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: secondMewInput, + }); + + const thirdMewContent = "third-test-mew"; + const thirdMewInput: Mew = { + text: thirdMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await carol.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: thirdMewInput, + }); + + const fourthMewContent = "fourth-test-mew"; + const fourthMewInput: Mew = { + text: fourthMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: fourthMewInput, + }); + // alice starts following bob and carol + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: bob.agentPubKey, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: carol.agentPubKey, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeed.length === 4, + "alice's mews feed includes all 4 mews" + ); + assert.equal( + aliceMewsFeed[0].mew.text, + fourthMewContent, + "mew 1 in feed is fourth mew" + ); + assert.equal( + aliceMewsFeed[1].mew.text, + thirdMewContent, + "mew 2 in feed is third mew" + ); + assert.equal( + aliceMewsFeed[2].mew.text, + secondMewContent, + "mew 3 in feed is second mew" + ); + assert.equal( + aliceMewsFeed[3].mew.text, + firstMewContent, + "mew 4 in feed is first mew" + ); + }, true); +}); - it("Followed creators mews should include mews of followed creator", async () => { - await runScenario(async (scenario) => { +it("Followed creators mews list are time-paginated", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -71,188 +412,88 @@ describe.concurrent("followed-creators-mews", () => { // conductor of the scenario. await scenario.shareAllAgents(); - const mewContent = "test-mew"; - const mewInput: Mew = { - text: mewContent, + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, links: [], mew_type: { [MewTypeName.Original]: null }, }; - await alice.cells[0].callZome({ + const mewActionHash1 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: mewInput, - }); - - const bobMewsFeedInitial: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - bobMewsFeedInitial.length === 0, - "bob's mews feed is initially empty" - ); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, + payload: createMewInput1, }); - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); - assert.equal( - bobMewsFeed[0].mew.text, - mewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - }, true); - }); - - it("Followed creators mews should include own mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewsFeedInitial: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - aliceMewsFeedInitial.length === 0, - "alice's mews feed is initially empty" - ); - - const mewContent = "test-mew"; - const mewInput: Mew = { - text: mewContent, + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, links: [], mew_type: { [MewTypeName.Original]: null }, }; - await alice.cells[0].callZome({ + const mewActionHash2 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: mewInput, + payload: createMewInput2, }); - const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, + fn_name: "create_mew", + payload: createMewInput3, }); - assert.ok( - aliceMewsFeed.length === 1, - "alice's mews feed includes her mew" - ); - assert.equal( - aliceMewsFeed[0].mew.text, - mewContent, - "mew content matches" - ); - }, true); - }); - - it("Followed creators mews should not include mews of non-followed creator", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, links: [], mew_type: { [MewTypeName.Original]: null }, }; - await alice.cells[0].callZome({ + const mewActionHash4 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: aliceMewInput, + payload: createMewInput4, }); - const carolMewContent = "carol-test-mew"; - const carolMewInput: Mew = { - text: carolMewContent, + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, links: [], mew_type: { [MewTypeName.Original]: null }, }; - await carol.cells[0].callZome({ + const mewActionHash5 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: carolMewInput, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, + payload: createMewInput5, }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, + fn_name: "create_mew", + payload: createMewInput6, }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); - assert.equal( - bobMewsFeed[0].mew.text, - aliceMewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - }, true); - }); - - it("Unfollowing should exclude creators mews from feed", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, links: [], mew_type: { [MewTypeName.Original]: null }, }; - await alice.cells[0].callZome({ + const mewActionHash7 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: aliceMewInput, + payload: createMewInput7, }); await bob.cells[0].callZome({ @@ -260,337 +501,89 @@ describe.concurrent("followed-creators-mews", () => { fn_name: "follow", payload: alice.agentPubKey, }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - const bobMewsFeedWhenFollowing: FeedMew[] = await bob.cells[0].callZome({ + const page1: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_followed_creators_mews_with_context", - payload: null, + payload: { + limit: 2, + }, }); - assert.ok( - bobMewsFeedWhenFollowing.length === 1, - "bob's mews feed includes 1 mew" - ); - assert.equal( - bobMewsFeedWhenFollowing[0].mew.text, - aliceMewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "unfollow", - payload: alice.agentPubKey, - }); + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + const page2: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_followed_creators_mews_with_context", - payload: null, + payload: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, }); - assert.ok(bobMewsFeed.length === 0, "bob's mews feed is empty"); - }, true); - }); - it("Followed creators mews should be ordered by timestamp in descending order", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const firstMewContent = "first-test-mew"; - const firstMewInput: Mew = { - text: firstMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: firstMewInput, - }); - - const secondMewContent = "second-test-mew"; - const secondMewInput: Mew = { - text: secondMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await bob.cells[0].callZome({ + const page3: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "create_mew", - payload: secondMewInput, + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, }); - const thirdMewContent = "third-test-mew"; - const thirdMewInput: Mew = { - text: thirdMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await carol.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: thirdMewInput, - }); + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); - const fourthMewContent = "fourth-test-mew"; - const fourthMewInput: Mew = { - text: fourthMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ + const page4: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "create_mew", - payload: fourthMewInput, - }); - // alice starts following bob and carol - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: bob.agentPubKey, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: carol.agentPubKey, + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + }, }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_followed_creators_mews_with_context", - payload: null, + payload: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, }); - assert.ok( - aliceMewsFeed.length === 4, - "alice's mews feed includes all 4 mews" - ); - assert.equal( - aliceMewsFeed[0].mew.text, - fourthMewContent, - "mew 1 in feed is fourth mew" - ); - assert.equal( - aliceMewsFeed[1].mew.text, - thirdMewContent, - "mew 2 in feed is third mew" - ); - assert.equal( - aliceMewsFeed[2].mew.text, - secondMewContent, - "mew 3 in feed is second mew" - ); - assert.equal( - aliceMewsFeed[3].mew.text, - firstMewContent, - "mew 4 in feed is first mew" - ); - }, true); - }); - - it("Followed creators mews list are time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const page1: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - limit: 2, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - }, - }); - - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); - }); + + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); +// }); diff --git a/tests/src/mewsfeed/mews/mention-to-mews.test.ts b/tests/src/mewsfeed/mews/mention-to-mews.test.ts index 8f439987..7166bed8 100644 --- a/tests/src/mewsfeed/mews/mention-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/mention-to-mews.test.ts @@ -10,259 +10,259 @@ import { import { mewsfeedAppBundleSource } from "../../common.js"; import { createMew } from "./common.js"; -describe.concurrent("mention-to-mews", () => { - it("mention in mews", async () => { - await runScenario(async (scenario) => { +// describe.concurrent("mention-to-mews", () => { +it("mention in mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + await createMew(alice.cells[0], { + text: "this is for @bob", + links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], + mew_type: { Original: null }, + }); + + const actionHash2: ActionHash = await createMew(bob.cells[0], { + text: "this is for @bob 2", + links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], + mew_type: { Original: null }, + }); + + const actionHash3: ActionHash = await createMew(alice.cells[0], { + text: "this is for @alice", + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { Original: null }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const mentionedMewsBob: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: bob.agentPubKey, + }, + }); + assert.ok(mentionedMewsBob.length === 2, "one mew with mention"); + assert.deepEqual(mentionedMewsBob[0].action_hash, actionHash2); + + const mentionedMewsAlice: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + }, + }); + assert.ok(mentionedMewsAlice.length === 1, "one mew with mention"); + assert.deepEqual(mentionedMewsAlice[0].action_hash, actionHash3); + }, true); +}); + +it("Mentions list are time-paginated", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; // Add 2 players with the test app to the Scenario. The returned players // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); + const [alice] = await scenario.addPlayersWithApps([appSource]); // Shortcut peer discovery through gossip and register all agents in every // conductor of the scenario. await scenario.shareAllAgents(); - await createMew(alice.cells[0], { - text: "this is for @bob", - links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], - mew_type: { Original: null }, + const mewContent1 = "My Mew with @mention 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with @mention 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with @mention 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, }); - const actionHash2: ActionHash = await createMew(bob.cells[0], { - text: "this is for @bob 2", - links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], - mew_type: { Original: null }, + const mewContent4 = "My Mew with @mention 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, }); - const actionHash3: ActionHash = await createMew(alice.cells[0], { - text: "this is for @alice", + const mewContent5 = "My Mew with @mention 5"; + const createMewInput5: Mew = { + text: mewContent5, links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { Original: null }, + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + const mewContent6 = "My Mew with @mention 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); - const mentionedMewsBob: FeedMew[] = await alice.cells[0].callZome({ + const mewContent7 = "My Mew with @mention 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: bob.agentPubKey, - }, + fn_name: "create_mew", + payload: createMewInput7, }); - assert.ok(mentionedMewsBob.length === 2, "one mew with mention"); - assert.deepEqual(mentionedMewsBob[0].action_hash, actionHash2); - const mentionedMewsAlice: FeedMew[] = await alice.cells[0].callZome({ + const page1: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_mews_for_mention_with_context", payload: { mention: alice.agentPubKey, + page: { + start_time: null, + limit: 2, + }, }, }); - assert.ok(mentionedMewsAlice.length === 1, "one mew with mention"); - assert.deepEqual(mentionedMewsAlice[0].action_hash, actionHash3); - }, true); - }); - - it("Mentions list are time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with @mention 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with @mention 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with @mention 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with @mention 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with @mention 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with @mention 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with @mention 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - start_time: null, - limit: 2, - }, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - }, + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - }, + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - }, + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); - }); + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); +// }); diff --git a/tests/src/mewsfeed/mews/mew-to-responses.test.ts b/tests/src/mewsfeed/mews/mew-to-responses.test.ts index ea01b686..6e0e9f2a 100644 --- a/tests/src/mewsfeed/mews/mew-to-responses.test.ts +++ b/tests/src/mewsfeed/mews/mew-to-responses.test.ts @@ -4,76 +4,147 @@ import { assert, describe, expect, it } from "vitest"; import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types.js"; import { mewsfeedAppBundleSource } from "../../common.js"; -describe.concurrent("mew-to-responses", () => { - it("Agent can reply to a mew", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); +// describe.concurrent("mew-to-responses", () => { +it("Agent can reply to a mew", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const aliceReplyContent = "alice-test-reply"; + const aliceReplyInput: Mew = { + text: aliceReplyContent, + links: [], + mew_type: { [MewTypeName.Reply]: action_hash }, + }; + const reply_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceReplyInput, + }); + + const replyMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: reply_action_hash, + }); + assert.ok(MewTypeName.Reply in replyMew.mew.mew_type, "mew is a reply"); + assert.equal( + replyMew.mew.text, + aliceReplyContent, + "reply is alice's reply" + ); - const aliceReplyContent = "alice-test-reply"; - const aliceReplyInput: Mew = { - text: aliceReplyContent, - links: [], - mew_type: { [MewTypeName.Reply]: action_hash }, - }; - const reply_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceReplyInput, - }); + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); + assert.ok(originalMew.replies_count === 1, "original mew has 1 reply"); + assert.isTrue( + originalMew.is_replied, + "original mew's reply is alice's reply" + ); + }, true); +}); - const replyMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: reply_action_hash, - }); - assert.ok(MewTypeName.Reply in replyMew.mew.mew_type, "mew is a reply"); - assert.equal( - replyMew.mew.text, - aliceReplyContent, - "reply is alice's reply" - ); +it("Agent can mewmew a mew, only once", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const aliceMewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: action_hash }, + }; + const mewmew_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewmewInput, + }); + + const mewmew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmew_action_hash, + }); + assert.ok(MewTypeName.Mewmew in mewmew.mew.mew_type, "mew is a mewmew"); + assert.deepEqual(mewmew.mew, aliceMewmewInput, "mewmew is alice's mewmew"); + + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); + assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); + assert.isTrue( + originalMew.is_mewmewed, + "original mew's mewmew is alice's mewmew" + ); - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.replies_count === 1, "original mew has 1 reply"); - assert.isTrue( - originalMew.is_replied, - "original mew's reply is alice's reply" - ); - }, true); - }); + // Mewmew the same mew again + const response = alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewmewInput, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + }, true); +}); - it("Agent can mewmew a mew, only once", async () => { - await runScenario(async (scenario) => { +it("Agent can quote a mew", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -97,28 +168,27 @@ describe.concurrent("mew-to-responses", () => { payload: aliceMewInput, }); - const aliceMewmewInput: Mew = { - text: "", + const aliceQuoteText = "alice-test-quote"; + const aliceQuoteInput: Mew = { + text: aliceQuoteText, links: [], - mew_type: { [MewTypeName.Mewmew]: action_hash }, + mew_type: { + [MewTypeName.Quote]: action_hash, + }, }; - const mewmew_action_hash: ActionHash = await alice.cells[0].callZome({ + const quote_action_hash: ActionHash = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: aliceMewmewInput, + payload: aliceQuoteInput, }); - const mewmew: FeedMew = await alice.cells[0].callZome({ + const quote: FeedMew = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: mewmew_action_hash, + payload: quote_action_hash, }); - assert.ok(MewTypeName.Mewmew in mewmew.mew.mew_type, "mew is a mewmew"); - assert.deepEqual( - mewmew.mew, - aliceMewmewInput, - "mewmew is alice's mewmew" - ); + assert.ok(MewTypeName.Quote in quote.mew.mew_type, "mew is a quote"); + assert.equal(quote.mew.text, aliceQuoteText, "quote is alice's quote"); const originalMew: FeedMew = await alice.cells[0].callZome({ zome_name: "mews", @@ -130,92 +200,14 @@ describe.concurrent("mew-to-responses", () => { "mew is an original mew" ); assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); + assert.ok(originalMew.quotes_count === 1, "original mew has 1 quote"); assert.isTrue( - originalMew.is_mewmewed, - "original mew's mewmew is alice's mewmew" + originalMew.is_quoted, + "original mew's quote is alice's quote" ); - - // Mewmew the same mew again - const response = alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewmewInput, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - }, true); - }); - - it("Agent can quote a mew", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const aliceQuoteText = "alice-test-quote"; - const aliceQuoteInput: Mew = { - text: aliceQuoteText, - links: [], - mew_type: { - [MewTypeName.Quote]: action_hash, - }, - }; - const quote_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceQuoteInput, - }); - - const quote: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quote_action_hash, - }); - assert.ok(MewTypeName.Quote in quote.mew.mew_type, "mew is a quote"); - assert.equal(quote.mew.text, aliceQuoteText, "quote is alice's quote"); - - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal( - originalMew.mew.text, - aliceMewContent, - "mew is alice's mew" - ); - assert.ok(originalMew.quotes_count === 1, "original mew has 1 quote"); - assert.isTrue( - originalMew.is_quoted, - "original mew's quote is alice's quote" - ); - }, - true, - { timeout: 500000 } - ); - }); + }, + true, + { timeout: 500000 } + ); }); +// }); diff --git a/tests/src/mewsfeed/mews/mew-with-context.test.ts b/tests/src/mewsfeed/mews/mew-with-context.test.ts index 4cf985c5..e9c5b5df 100644 --- a/tests/src/mewsfeed/mews/mew-with-context.test.ts +++ b/tests/src/mewsfeed/mews/mew-with-context.test.ts @@ -5,344 +5,344 @@ import { FeedMew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -describe.concurrent("mew-with-context", () => { - it("Mew with context contains licks count and is_licked", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob licks the mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "like", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - let feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.licks_count).toEqual(1); - expect(feedMew.is_licked).true; - - // Alice gets the mew with context - let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.licks_count).toEqual(1); - expect(aliceFeedMew.is_licked).false; - - // Bob unlicks the mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "unlike", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - feedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.licks_count).toEqual(0); - expect(feedMew.is_licked).false; - - // Alice gets the mew with context - aliceFeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.licks_count).toEqual(0); - expect(aliceFeedMew.is_licked).false; - }, - true, - { timeout: 100000 } - ); - }); - - it("Mew with context contains replies count and is_replied", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies the mew - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "my reply blah blah", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - const feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.replies_count).toEqual(1); - expect(feedMew.is_replied).true; - - // Alice gets the mew with context - const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.replies_count).toEqual(1); - expect(aliceFeedMew.is_replied).false; - }, - true, - { timeout: 100000 } - ); - }); - - it("Mew with context contains quotes count and is_quoted", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies the mew - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "this is a quote blah blah", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - const feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.quotes_count).toEqual(1); - expect(feedMew.is_quoted).true; - - // Alice gets the mew with context - const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.quotes_count).toEqual(1); - expect(aliceFeedMew.is_quoted).false; - }, - true, - { timeout: 100000 } - ); - }); - - it("Mew with context contains mewmews count and is_mewmewed", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob mewmews the mew - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - const feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.mewmews_count).toEqual(1); - expect(feedMew.is_mewmewed).true; - console.warn("bob got mew"); - - // Alice gets the mew with context - const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - console.warn("alice got mew"); - - expect(aliceFeedMew.mewmews_count).toEqual(1); - expect(aliceFeedMew.is_mewmewed).false; - }, - true, - { timeout: 100000 } - ); - }); - - it("Mew with context contains is_pinned", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob pins the mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - let feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.is_pinned).true; - - // Alice gets the mew with context - let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.is_pinned).false; - - // Bob unpins the mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - feedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.is_pinned).false; - - // Alice gets the mew with context - aliceFeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.is_pinned).false; - }, - true, - { timeout: 500000 } - ); - }); +// describe.concurrent("mew-with-context", () => { +it("Mew with context contains licks count and is_licked", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob licks the mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "like", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + let feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.licks_count).toEqual(1); + expect(feedMew.is_licked).true; + + // Alice gets the mew with context + let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.licks_count).toEqual(1); + expect(aliceFeedMew.is_licked).false; + + // Bob unlicks the mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "unlike", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + feedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.licks_count).toEqual(0); + expect(feedMew.is_licked).false; + + // Alice gets the mew with context + aliceFeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.licks_count).toEqual(0); + expect(aliceFeedMew.is_licked).false; + }, + true, + { timeout: 100000 } + ); }); + +it("Mew with context contains replies count and is_replied", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies the mew + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "my reply blah blah", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + const feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.replies_count).toEqual(1); + expect(feedMew.is_replied).true; + + // Alice gets the mew with context + const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.replies_count).toEqual(1); + expect(aliceFeedMew.is_replied).false; + }, + true, + { timeout: 100000 } + ); +}); + +it("Mew with context contains quotes count and is_quoted", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies the mew + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "this is a quote blah blah", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + const feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.quotes_count).toEqual(1); + expect(feedMew.is_quoted).true; + + // Alice gets the mew with context + const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.quotes_count).toEqual(1); + expect(aliceFeedMew.is_quoted).false; + }, + true, + { timeout: 100000 } + ); +}); + +it("Mew with context contains mewmews count and is_mewmewed", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob mewmews the mew + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + const feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.mewmews_count).toEqual(1); + expect(feedMew.is_mewmewed).true; + console.warn("bob got mew"); + + // Alice gets the mew with context + const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + console.warn("alice got mew"); + + expect(aliceFeedMew.mewmews_count).toEqual(1); + expect(aliceFeedMew.is_mewmewed).false; + }, + true, + { timeout: 100000 } + ); +}); + +it("Mew with context contains is_pinned", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob pins the mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + let feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.is_pinned).true; + + // Alice gets the mew with context + let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.is_pinned).false; + + // Bob unpins the mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + feedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.is_pinned).false; + + // Alice gets the mew with context + aliceFeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.is_pinned).false; + }, + true, + { timeout: 500000 } + ); +}); +// }); diff --git a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts index 49e48992..6315d8a0 100644 --- a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts @@ -4,75 +4,75 @@ import { assert, describe, it } from "vitest"; import { FeedMew } from "../../../../ui/src/types/types.js"; import { createMew } from "./common.js"; -describe.concurrent("pinner-to-mews", () => { - it("link a Pinner to a Mew", async () => { - await runScenario( - async (scenario) => { - // Construct proper paths for your app. - // This assumes app bundle created by the `hc app pack` command. - const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; +// describe.concurrent("pinner-to-mews", () => { +it("link a Pinner to a Mew", async () => { + await runScenario( + async (scenario) => { + // Construct proper paths for your app. + // This assumes app bundle created by the `hc app pack` command. + const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; - // Set up the app to be installed - const appSource = { appBundleSource: { path: testAppPath } }; + // Set up the app to be installed + const appSource = { appBundleSource: { path: testAppPath } }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - const baseAddress = alice.agentPubKey; - const targetActionHash: ActionHash = await createMew(alice.cells[0]); + const baseAddress = alice.agentPubKey; + const targetActionHash: ActionHash = await createMew(alice.cells[0]); - // Bob gets the links, should be empty - let linksOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); + // Bob gets the links, should be empty + let linksOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); - // Alice creates a link from Pinner to Mew - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: targetActionHash, - }); + // Alice creates a link from Pinner to Mew + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: targetActionHash, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 1); - assert.deepEqual(targetActionHash, linksOutput[0].action_hash); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 1); + assert.deepEqual(targetActionHash, linksOutput[0].action_hash); - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: targetActionHash, - }); + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: targetActionHash, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - }, - true, - { timeout: 500000 } - ); - }); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + }, + true, + { timeout: 500000 } + ); }); +// }); diff --git a/tests/src/mewsfeed/mews/tags-to-mews.test.ts b/tests/src/mewsfeed/mews/tags-to-mews.test.ts index 01a1deff..c0445e5c 100644 --- a/tests/src/mewsfeed/mews/tags-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/tags-to-mews.test.ts @@ -10,184 +10,369 @@ import { } from "../../../../ui/src/types/types.js"; import { mewsfeedAppBundleSource } from "../../common.js"; -describe.concurrent("tags-to-mews", () => { - it("Hashtag, cashtag and mention", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); +// describe.concurrent("tags-to-mews", () => { +it("Hashtag, cashtag and mention", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = + "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; + const createMewInput: Mew = { + text: mewContent, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a valid mew" + ); - const mewContent = - "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; - const createMewInput: Mew = { - text: mewContent, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; + const hashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + }, + }); + assert.ok(hashtaggedMews.length === 1, "one mew with hashtag"); + assert.equal(hashtaggedMews[0].mew.text, mewContent, "mew content matches"); + + const arabicHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#سعيدة", + }, + }); + assert.ok(arabicHashtaggedMews.length === 1, "one mew with arabic hashtag"); + assert.equal( + arabicHashtaggedMews[0].mew.text, + mewContent, + "mew content matches" + ); - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a valid mew" - ); + // get hashtag containing emojis -- invalid hashtag! + const emojiHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#😃😃😃", + }, + }); + assert.ok(emojiHashtaggedMews.length === 0, "no mew with emoji hashtag"); + + const cashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + }, + }); + assert.ok(cashtaggedMews.length === 1, "one mew with cashtag"); + + const mentionedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + }, + }); + assert.ok(mentionedMews.length === 1, "one mew with mention"); + }, true); +}); - const hashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - }, - }); - assert.ok(hashtaggedMews.length === 1, "one mew with hashtag"); - assert.equal( - hashtaggedMews[0].mew.text, - mewContent, - "mew content matches" - ); +it("Prefix index should return hashtags and cashtags", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = + "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; + const createMewInput: Mew = { + text: mewContent, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a valid mew" + ); - const arabicHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#سعيدة", - }, - }); - assert.ok( - arabicHashtaggedMews.length === 1, - "one mew with arabic hashtag" - ); - assert.equal( - arabicHashtaggedMews[0].mew.text, - mewContent, - "mew content matches" - ); + const hashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "has", + limit: 10, + }, + }); + assert.ok(hashtags.length === 1, "one hashtag"); + assert.equal(hashtags[0], "#hashtag", "hashtag search result matches"); + + const arabicHashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "سعيدة", + limit: 10, + }, + }); + assert.ok(arabicHashtags.length === 1, "one arabic hashtag"); + assert.equal(arabicHashtags[0], "#سعيدة", "hashtag search result matches"); + + // get hashtag containing emojis -- invalid hashtag! + const emojiHashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "😃😃😃", + limit: 10, + }, + }); + assert.ok(emojiHashtags.length === 0, "no emoji hashtags"); + + const cashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "cas", + limit: 10, + }, + }); + assert.ok(cashtags.length === 1, "one cashtag"); + assert.equal(cashtags[0], "$cashtag", "hashtag search result matches"); + }, true); +}); - // get hashtag containing emojis -- invalid hashtag! - const emojiHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#😃😃😃", +it("Hashtags list are time-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + limit: 2, }, - }); - assert.ok(emojiHashtaggedMews.length === 0, "no mew with emoji hashtag"); + }, + }); - const cashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - }, - }); - assert.ok(cashtaggedMews.length === 1, "one mew with cashtag"); + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); - const mentionedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, }, - }); - assert.ok(mentionedMews.length === 1, "one mew with mention"); - }, true); - }); - - it("Prefix index should return hashtags and cashtags", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = - "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; - const createMewInput: Mew = { - text: mewContent, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a valid mew" - ); - - const hashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "has", - limit: 10, + }, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page2[page1.length - 1].action_hash, + limit: 2, }, - }); - assert.ok(hashtags.length === 1, "one hashtag"); - assert.equal(hashtags[0], "#hashtag", "hashtag search result matches"); - - const arabicHashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "سعيدة", - limit: 10, + }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page3[page1.length - 1].action_hash, + limit: 2, }, - }); - assert.ok(arabicHashtags.length === 1, "one arabic hashtag"); - assert.equal( - arabicHashtags[0], - "#سعيدة", - "hashtag search result matches" - ); - - // get hashtag containing emojis -- invalid hashtag! - const emojiHashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "😃😃😃", - limit: 10, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, }, - }); - assert.ok(emojiHashtags.length === 0, "no emoji hashtags"); + }, + }); - const cashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "cas", - limit: 10, - }, - }); - assert.ok(cashtags.length === 1, "one cashtag"); - assert.equal(cashtags[0], "$cashtag", "hashtag search result matches"); - }, true); - }); + assert.lengthOf(page5, 0); + }, true); +}); - it("Hashtags list are time-paginated", async () => { - await runScenario(async (scenario) => { +it("Cashtags list are time-paginated", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -199,7 +384,7 @@ describe.concurrent("tags-to-mews", () => { // conductor of the scenario. await scenario.shareAllAgents(); - const mewContent1 = "My Mew with #hashtag 1"; + const mewContent1 = "My Mew with $cashtag 1"; const createMewInput1: Mew = { text: mewContent1, links: [], @@ -211,7 +396,7 @@ describe.concurrent("tags-to-mews", () => { payload: createMewInput1, }); - const mewContent2 = "My Mew with #hashtag 2"; + const mewContent2 = "My Mew with $cashtag 2"; const createMewInput2: Mew = { text: mewContent2, links: [], @@ -223,7 +408,7 @@ describe.concurrent("tags-to-mews", () => { payload: createMewInput2, }); - const mewContent3 = "My Mew with #hashtag 3"; + const mewContent3 = "My Mew with $cashtag 3"; const createMewInput3: Mew = { text: mewContent3, links: [], @@ -235,7 +420,7 @@ describe.concurrent("tags-to-mews", () => { payload: createMewInput3, }); - const mewContent4 = "My Mew with #hashtag 4"; + const mewContent4 = "My Mew with $cashtag 4"; const createMewInput4: Mew = { text: mewContent4, links: [], @@ -247,7 +432,7 @@ describe.concurrent("tags-to-mews", () => { payload: createMewInput4, }); - const mewContent5 = "My Mew with #hashtag 5"; + const mewContent5 = "My Mew with $cashtag 5"; const createMewInput5: Mew = { text: mewContent5, links: [], @@ -259,7 +444,7 @@ describe.concurrent("tags-to-mews", () => { payload: createMewInput5, }); - const mewContent6 = "My Mew with #hashtag 6"; + const mewContent6 = "My Mew with $cashtag 6"; const createMewInput6: Mew = { text: mewContent6, links: [], @@ -271,7 +456,7 @@ describe.concurrent("tags-to-mews", () => { payload: createMewInput6, }); - const mewContent7 = "My Mew with #hashtag 7"; + const mewContent7 = "My Mew with $cashtag 7"; const createMewInput7: Mew = { text: mewContent7, links: [], @@ -285,11 +470,13 @@ describe.concurrent("tags-to-mews", () => { const page1: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", + fn_name: "get_mews_for_cashtag_with_context", payload: { - hashtag: "#hashtag", + cashtag: "$cashtag", page: { + start_time: null, limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, }, }); @@ -302,12 +489,13 @@ describe.concurrent("tags-to-mews", () => { const page2: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", + fn_name: "get_mews_for_cashtag_with_context", payload: { - hashtag: "#hashtag", + cashtag: "$cashtag", page: { after_hash: page1[page1.length - 1].action_hash, limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, }, }); @@ -322,12 +510,13 @@ describe.concurrent("tags-to-mews", () => { const page3: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", + fn_name: "get_mews_for_cashtag_with_context", payload: { - hashtag: "#hashtag", + cashtag: "$cashtag", page: { - after_hash: page2[page1.length - 1].action_hash, + after_hash: page2[page2.length - 1].action_hash, limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, }, }); @@ -344,12 +533,13 @@ describe.concurrent("tags-to-mews", () => { const page4: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", + fn_name: "get_mews_for_cashtag_with_context", payload: { - hashtag: "#hashtag", + cashtag: "$cashtag", page: { - after_hash: page3[page1.length - 1].action_hash, + after_hash: page3[page3.length - 1].action_hash, limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, }, }); @@ -367,222 +557,21 @@ describe.concurrent("tags-to-mews", () => { const page5: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", + fn_name: "get_mews_for_cashtag_with_context", payload: { - hashtag: "#hashtag", + cashtag: "$cashtag", page: { after_hash: page4[page4.length - 1].action_hash, limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, }, }); assert.lengthOf(page5, 0); - }, true); - }); - - it("Cashtags list are time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with $cashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with $cashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with $cashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with $cashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with $cashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with $cashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with $cashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - start_time: null, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, - }, - }); - - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); - }); + }, + true, + { timeout: 500000 } + ); }); +// }); From 0b190e7d10ed562c2764fd1a0bd83836ed3a306a Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Wed, 1 Nov 2023 10:26:58 -0600 Subject: [PATCH 10/22] delete stress test file --- tests/src/stress-test-local.spec.ts | 77 ----------------------------- 1 file changed, 77 deletions(-) delete mode 100644 tests/src/stress-test-local.spec.ts diff --git a/tests/src/stress-test-local.spec.ts b/tests/src/stress-test-local.spec.ts deleted file mode 100644 index 88f6bae0..00000000 --- a/tests/src/stress-test-local.spec.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { TryCpScenario } from "@holochain/tryorama"; -import { Mew } from "../../ui/src/types/types"; -import { test } from "vitest"; -import { ActionHash, encodeHashToBase64, AppBundle } from "@holochain/client"; - -const ZOME_NAME = "mews"; - -const TRYCP_SERVER_PORT = 9000; - -// 172.26.211.71 -// 172.26.206.61 -// 172.26.212.148 - -const holoportIps = ["172.26.211.71"]; -// const holoportIps = ["172.26.212.148", "172.26.211.71"]; -// const holoportIps = ["172.26.212.148", "172.26.206.61", "172.26.211.71"]; -const holoportUrls = holoportIps.map( - (ip) => new URL(`ws://${ip}:${TRYCP_SERVER_PORT}`) -); - -const app: { bundle: AppBundle } = { - bundle: { - manifest: { - manifest_version: "1", - name: "holofuel", - roles: [ - { - dna: { - url: "https://github.com/jost-s/hc-utils/releases/download/0.2.1-beta-rc.0/holofuel.dna", - modifiers: { - network_seed: Date.now().toString(), - }, - }, - name: "role", - }, - ], - }, - resources: {}, - }, -}; - -console.log(`Distributed test across ${holoportIps.length} HoloPorts`); -console.log(); - -test("stress test local", async (t) => { - const scenario = new TryCpScenario(); - const numberOfAgentsPerConductor = 10; - - try { - const clientsPlayers = await scenario.addClientsPlayers(holoportUrls, { - app, - numberOfAgentsPerConductor, - }); - - const mew: Mew = { - text: "01234567890", - links: [], - mew_type: { Original: null }, - }; - await Promise.all( - clientsPlayers[0].players.map((player, index) => { - return player.cells[0] - .callZome({ - zome_name: ZOME_NAME, - fn_name: "create_mew", - payload: mew, - }) - .then((actionHash: ActionHash) => { - console.log(index, "response", encodeHashToBase64(actionHash)); - t.expect(actionHash).not.toBeNull(); - }); - }) - ); - } catch (error) { - console.log("ererere", error); - } -}); From af79b3a0b44a11449581f8695b3b5c87378272c3 Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Wed, 1 Nov 2023 10:28:18 -0600 Subject: [PATCH 11/22] tests: run concutrrently again --- .../agent_pins/pinner-to-hashes.test.ts | 176 +-- .../follows/follower-to-creators.test.ts | 638 ++++----- .../mewsfeed/likes/liker-to-hashes.test.ts | 228 +-- tests/src/mewsfeed/mews/agent-mews.test.ts | 428 +++--- .../mews/agent-to-notifications.test.ts | 1220 ++++++++--------- .../src/mewsfeed/mews/dna-properties.test.ts | 288 ++-- .../mews/followed-creators-mews.test.ts | 987 ++++++------- .../src/mewsfeed/mews/mention-to-mews.test.ts | 430 +++--- .../mewsfeed/mews/mew-to-responses.test.ts | 322 ++--- .../mewsfeed/mews/mew-with-context.test.ts | 680 ++++----- .../src/mewsfeed/mews/pinner-to-mews.test.ts | 120 +- tests/src/mewsfeed/mews/tags-to-mews.test.ts | 769 ++++++----- 12 files changed, 3159 insertions(+), 3127 deletions(-) diff --git a/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts b/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts index 87d943fe..921edb96 100644 --- a/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts +++ b/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts @@ -3,92 +3,92 @@ import { assert, describe, it } from "vitest"; import { AgentPubKey, HoloHash, fakeActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -// describe.concurrent("pinner-to-hashes", () => { -it("link a Pinner to a Hash", async () => { - await runScenario( - async (scenario) => { - // Construct proper paths for your app. - // This assumes app bundle created by the `hc app pack` command. - const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; - - // Set up the app to be installed - const appSource = { appBundleSource: { path: testAppPath } }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetHash = await fakeActionHash(); - - // Bob gets the links, should be empty - let linksOutput: HoloHash[] = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Pinner to Hash - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: targetHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - const pinnersOutput: AgentPubKey[] = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_pinners_for_hash", - payload: targetHash, - }); - assert.equal(pinnersOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: targetHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_pinners_for_hash", - payload: targetHash, - }); - - assert.equal(linksOutput.length, 0); - }, - true, - { timeout: 500000 } - ); +describe.concurrent("pinner-to-hashes", () => { + it("link a Pinner to a Hash", async () => { + await runScenario( + async (scenario) => { + // Construct proper paths for your app. + // This assumes app bundle created by the `hc app pack` command. + const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; + + // Set up the app to be installed + const appSource = { appBundleSource: { path: testAppPath } }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetHash = await fakeActionHash(); + + // Bob gets the links, should be empty + let linksOutput: HoloHash[] = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Pinner to Hash + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: targetHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + const pinnersOutput: AgentPubKey[] = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_pinners_for_hash", + payload: targetHash, + }); + assert.equal(pinnersOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: targetHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_pinners_for_hash", + payload: targetHash, + }); + + assert.equal(linksOutput.length, 0); + }, + true, + { timeout: 500000 } + ); + }); }); -// }); diff --git a/tests/src/mewsfeed/follows/follower-to-creators.test.ts b/tests/src/mewsfeed/follows/follower-to-creators.test.ts index de459980..9623fa22 100644 --- a/tests/src/mewsfeed/follows/follower-to-creators.test.ts +++ b/tests/src/mewsfeed/follows/follower-to-creators.test.ts @@ -3,310 +3,187 @@ import { dhtSync, runScenario } from "@holochain/tryorama"; import { assert, describe, expect, it } from "vitest"; import { mewsfeedAppBundleSource } from "../../common"; -// describe.concurrent("follower-to-creators", () => { -it("link a Follower to a Creator", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = bob.agentPubKey; - - // Bob gets the links, should be empty - let linksOutput: Record[] = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Follower to Creator - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); +describe.concurrent("follower-to-creators", () => { + it("link a Follower to a Creator", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: targetAddress, - }, - }); - assert.equal(linksOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + const baseAddress = alice.agentPubKey; + const targetAddress = bob.agentPubKey; - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: targetAddress, - }, - }); - assert.equal(linksOutput.length, 0); - }, true); -}); + // Bob gets the links, should be empty + let linksOutput: Record[] = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 0); -it("Agent cannot follow themselves", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice tries to follow herself - const response = alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - }, true); -}); + // Alice creates a link from Follower to Creator + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); -it("Agent can only change their own follows", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = bob.agentPubKey; - - // Alice follows bob - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to remove alices' follow - const response = bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - - // Alice removes her own follow - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "unfollow", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to add a follow for allice - const response2 = bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); - await expect(response2).rejects.toThrowError(/InvalidCommit/); - }, true); -}); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); -it("Creators list are hash-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 1); - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol, john, steve, mary] = - await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - appSource, + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: targetAddress, + }, + }); + assert.equal(linksOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: targetAddress, + }, + }); + assert.equal(linksOutput.length, 0); + }, true); + }); + + it("Agent cannot follow themselves", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice tries to follow herself + const response = alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + }, true); + }); + + it("Agent can only change their own follows", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ appSource, appSource, ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a link from Follower to Creator - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: bob.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: carol.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: john.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: steve.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: mary.agentPubKey, - }, - }); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + const baseAddress = alice.agentPubKey; + const targetAddress = bob.agentPubKey; - const page1: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - limit: 2, - }, - }, - }); - - assert.deepEqual(page1[0], mary.agentPubKey); - assert.deepEqual(page1[1], steve.agentPubKey); - - const page2: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - after_agentpubkey: page1[1], - limit: 2, - }, - }, - }); - assert.deepEqual(page2[0], john.agentPubKey); - assert.deepEqual(page2[1], carol.agentPubKey); - - const page3: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - after_agentpubkey: page2[1], - limit: 2, + // Alice follows bob + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to remove alices' follow + const response = bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, }, - }, - }); - assert.lengthOf(page3, 1); - assert.deepEqual(page3[0], bob.agentPubKey); - - const page5: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - after_agentpubkey: page3[0], - limit: 2, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + + // Alice removes her own follow + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "unfollow", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to add a follow for allice + const response2 = bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, }, - }, - }); - assert.lengthOf(page5, 0); - }, true); -}); + }); + await expect(response2).rejects.toThrowError(/InvalidCommit/); + }, true); + }); -it("Followers list are hash-paginated", async () => { - await runScenario( - async (scenario) => { + it("Creators list are hash-paginated", async () => { + await runScenario(async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -327,57 +204,54 @@ it("Followers list are hash-paginated", async () => { await scenario.shareAllAgents(); // Alice creates a link from Follower to Creator - await bob.cells[0].callZome({ + await alice.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, + base_follower: alice.agentPubKey, + target_creator: bob.agentPubKey, }, }); - await carol.cells[0].callZome({ + await alice.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: carol.agentPubKey, - target_creator: alice.agentPubKey, + base_follower: alice.agentPubKey, + target_creator: carol.agentPubKey, }, }); - await john.cells[0].callZome({ + await alice.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: john.agentPubKey, - target_creator: alice.agentPubKey, + base_follower: alice.agentPubKey, + target_creator: john.agentPubKey, }, }); - await steve.cells[0].callZome({ + await alice.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: steve.agentPubKey, - target_creator: alice.agentPubKey, + base_follower: alice.agentPubKey, + target_creator: steve.agentPubKey, }, }); - await mary.cells[0].callZome({ + await alice.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: mary.agentPubKey, - target_creator: alice.agentPubKey, + base_follower: alice.agentPubKey, + target_creator: mary.agentPubKey, }, }); - await dhtSync( - [alice, bob, carol, john, steve, mary], - alice.cells[0].cell_id[0] - ); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); const page1: AgentPubKey[] = await alice.cells[0].callZome({ zome_name: "follows", - fn_name: "get_followers_for_creator", + fn_name: "get_creators_for_follower", payload: { - creator: alice.agentPubKey, + follower: alice.agentPubKey, page: { limit: 2, }, @@ -389,9 +263,9 @@ it("Followers list are hash-paginated", async () => { const page2: AgentPubKey[] = await alice.cells[0].callZome({ zome_name: "follows", - fn_name: "get_followers_for_creator", + fn_name: "get_creators_for_follower", payload: { - creator: alice.agentPubKey, + follower: alice.agentPubKey, page: { after_agentpubkey: page1[1], limit: 2, @@ -403,9 +277,9 @@ it("Followers list are hash-paginated", async () => { const page3: AgentPubKey[] = await alice.cells[0].callZome({ zome_name: "follows", - fn_name: "get_followers_for_creator", + fn_name: "get_creators_for_follower", payload: { - creator: alice.agentPubKey, + follower: alice.agentPubKey, page: { after_agentpubkey: page2[1], limit: 2, @@ -417,9 +291,9 @@ it("Followers list are hash-paginated", async () => { const page5: AgentPubKey[] = await alice.cells[0].callZome({ zome_name: "follows", - fn_name: "get_followers_for_creator", + fn_name: "get_creators_for_follower", payload: { - creator: alice.agentPubKey, + follower: alice.agentPubKey, page: { after_agentpubkey: page3[0], limit: 2, @@ -427,9 +301,135 @@ it("Followers list are hash-paginated", async () => { }, }); assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); + }, true); + }); + + it("Followers list are hash-paginated", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol, john, steve, mary] = + await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a link from Follower to Creator + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + await carol.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: carol.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + await john.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: john.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + await steve.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: steve.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + await mary.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: mary.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + await dhtSync( + [alice, bob, carol, john, steve, mary], + alice.cells[0].cell_id[0] + ); + + const page1: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + limit: 2, + }, + }, + }); + + assert.deepEqual(page1[0], mary.agentPubKey); + assert.deepEqual(page1[1], steve.agentPubKey); + + const page2: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + after_agentpubkey: page1[1], + limit: 2, + }, + }, + }); + assert.deepEqual(page2[0], john.agentPubKey); + assert.deepEqual(page2[1], carol.agentPubKey); + + const page3: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + after_agentpubkey: page2[1], + limit: 2, + }, + }, + }); + assert.lengthOf(page3, 1); + assert.deepEqual(page3[0], bob.agentPubKey); + + const page5: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: alice.agentPubKey, + page: { + after_agentpubkey: page3[0], + limit: 2, + }, + }, + }); + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); + }); }); -// }); diff --git a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts index 34418b34..b2c697a5 100644 --- a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts +++ b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts @@ -3,94 +3,9 @@ import { dhtSync, runScenario } from "@holochain/tryorama"; import { assert, describe, expect, it } from "vitest"; import { mewsfeedAppBundleSource } from "../../common"; -// describe.concurrent("liker-to-hashes", () => { -it("link a Liker to a Hash", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = await fakeActionHash(); - - // Bob gets the links, should be empty - let linksOutput: Record[] = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Liker to Hash - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: baseAddress, - target_hash: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_likers_for_hash", - payload: targetAddress, - }); - assert.equal(linksOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: baseAddress, - target_hash: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_likers_for_hash", - payload: targetAddress, - }); - assert.equal(linksOutput.length, 0); - }, true); -}); - -it("Agent can only change their own likes", async () => { - await runScenario( - async (scenario) => { +describe.concurrent("liker-to-hashes", () => { + it("link a Liker to a Hash", async () => { + await runScenario(async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -105,50 +20,135 @@ it("Agent can only change their own likes", async () => { // conductor of the scenario. await scenario.shareAllAgents(); + const baseAddress = alice.agentPubKey; const targetAddress = await fakeActionHash(); - // Alice likes hash - await alice.cells[0].callZome({ + // Bob gets the links, should be empty + let linksOutput: Record[] = await bob.cells[0].callZome({ zome_name: "likes", - fn_name: "like", - payload: targetAddress, + fn_name: "get_hashes_for_liker", + payload: baseAddress, }); + assert.equal(linksOutput.length, 0); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to remove alices' like - const response = bob.cells[0].callZome({ + // Alice creates a link from Liker to Hash + await alice.cells[0].callZome({ zome_name: "likes", - fn_name: "remove_hash_for_liker", + fn_name: "add_hash_for_liker", payload: { - base_liker: alice.agentPubKey, + base_liker: baseAddress, target_hash: targetAddress, }, }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - // Alice removes her own like - await alice.cells[0].callZome({ + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ zome_name: "likes", - fn_name: "unlike", - payload: targetAddress, + fn_name: "get_hashes_for_liker", + payload: baseAddress, }); + assert.equal(linksOutput.length, 1); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_likers_for_hash", + payload: targetAddress, + }); + assert.equal(linksOutput.length, 1); - // Bob tries to add a like for allice - const response2 = bob.cells[0].callZome({ + await alice.cells[0].callZome({ zome_name: "likes", - fn_name: "add_hash_for_liker", + fn_name: "remove_hash_for_liker", payload: { - base_liker: alice.agentPubKey, + base_liker: baseAddress, target_hash: targetAddress, }, }); - await expect(response2).rejects.toThrowError(/InvalidCommit/); - }, - true, - { timeout: 500000 } - ); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_likers_for_hash", + payload: targetAddress, + }); + assert.equal(linksOutput.length, 0); + }, true); + }); + + it("Agent can only change their own likes", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const targetAddress = await fakeActionHash(); + + // Alice likes hash + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "like", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to remove alices' like + const response = bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: alice.agentPubKey, + target_hash: targetAddress, + }, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + + // Alice removes her own like + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "unlike", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to add a like for allice + const response2 = bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: alice.agentPubKey, + target_hash: targetAddress, + }, + }); + await expect(response2).rejects.toThrowError(/InvalidCommit/); + }, + true, + { timeout: 500000 } + ); + }); }); -// }); diff --git a/tests/src/mewsfeed/mews/agent-mews.test.ts b/tests/src/mewsfeed/mews/agent-mews.test.ts index 34bef6dc..b0621a7d 100644 --- a/tests/src/mewsfeed/mews/agent-mews.test.ts +++ b/tests/src/mewsfeed/mews/agent-mews.test.ts @@ -5,246 +5,246 @@ import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -// describe.concurrent("agent-mews", () => { -it("create a Mew and get agent mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Bob gets agent mews - let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - }, - }); - assert.equal(collectionOutput.length, 0); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets agent mews again - collectionOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - }, - }); - assert.equal(collectionOutput.length, 1); - assert.deepEqual(actionHash, collectionOutput[0].action_hash); - }, true); -}); - -it("Agent mews lists are time-paginated", async () => { - await runScenario( - async (scenario) => { +describe.concurrent("agent-mews", () => { + it("create a Mew and get agent mews", async () => { + await runScenario(async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; // Add 2 players with the test app to the Scenario. The returned players // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); // Shortcut peer discovery through gossip and register all agents in every // conductor of the scenario. await scenario.shareAllAgents(); - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - limit: 2, - }, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ + // Bob gets agent mews + let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_agent_mews_with_context", payload: { agent: alice.agentPubKey, - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, }, }); + assert.equal(collectionOutput.length, 0); - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - const page3: FeedMew[] = await alice.cells[0].callZome({ + // Bob gets agent mews again + collectionOutput = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_agent_mews_with_context", payload: { agent: alice.agentPubKey, - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - }, }, }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, + assert.equal(collectionOutput.length, 1); + assert.deepEqual(actionHash, collectionOutput[0].action_hash); + }, true); + }); + + it("Agent mews lists are time-paginated", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + limit: 2, + }, }, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, + }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + }, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, + }, + }); - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); + }); }); -// }); diff --git a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts index d8417014..ab4bca57 100644 --- a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts +++ b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts @@ -11,463 +11,74 @@ import { import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -// describe.concurrent("agent-to-notifications", () => { -it("notifications include my agent follows & unfollows", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Bob follows Alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - // Bob unfollows Alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyAgentUnfollowed]: null }, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyAgentFollowed]: null }, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, true); -}); +describe.concurrent("agent-to-notifications", () => { + it("notifications include my agent follows & unfollows", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; -it("notifications include my mews' likes & unlikes", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - const feedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob likes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - // Bob unlikes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewUnlicked]: null }, - feed_mew: feedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewLicked]: null }, - feed_mew: feedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, true); -}); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); -it("notifications include my mews' pins & unpins", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - const feedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob likes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "add_hash_for_pinner", - payload: { - base_pinner: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - // Bob unlikes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "remove_hash_for_pinner", - payload: { - base_pinner: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewUnpinned]: null }, - feed_mew: feedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewPinned]: null }, - feed_mew: feedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, true); -}); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); -it("notifications include my mews' replies, quotes, mewmews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies to Alice's mew - const replyInput: Mew = { - text: "test reply 12345", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, - }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, - }); - - // Bob mewmews Alice's mew - const mewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }; - const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewmewInput, - }); - const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmewActionHash, - }); - - // Bob quotes Alice's mew - const quoteInput: Mew = { - text: "a response to a quoted mew", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }; - const quoteActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: quoteInput, - }); - const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quoteActionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: quoteFeedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: mewmewFeedMew, - }); - expect(notifications[2]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(3); - }, true); -}); + // Bob follows Alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); -it("notifications include replies, quotes, mewmews to mews that I also responded to", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Carol creates a Mew - const actionHash: ActionHash = await createMew(carol.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice reply's to Carol's mew - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "test reply 12345", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }, - }); - - // Bob replies to Carol's mew - const replyInput: Mew = { - text: "test reply 12345", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, - }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, - }); - - // Bob mewmews Carol's mew - const mewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }; - const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewmewInput, - }); - const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmewActionHash, - }); - - // Bob quotes Carol's mew - const quoteInput: Mew = { - text: "a response to a quoted mew", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }; - const quoteActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: quoteInput, - }); - const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quoteActionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: quoteFeedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: mewmewFeedMew, - }); - expect(notifications[2]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: replyFeedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(3); - }, true); -}); + // Bob unfollows Alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyAgentUnfollowed]: null }, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyAgentFollowed]: null }, + }); -it("notifications list is time-paginated", async () => { - await runScenario( - async (scenario) => { + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, true); + }); + + it("notifications include my mews' likes & unlikes", async () => { + await runScenario(async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -485,253 +96,642 @@ it("notifications list is time-paginated", async () => { // Alice creates a Mew const actionHash: ActionHash = await createMew(alice.cells[0]); assert.ok(actionHash); + const feedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob replies to Alice's mew - const replyInput: Mew = { - text: "xyxyxyxy test reply 1", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, + // Bob likes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: bob.agentPubKey, + target_hash: actionHash, + }, }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, + + // Bob unlikes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: bob.agentPubKey, + target_hash: actionHash, + }, }); - // Bob replies to Alice's mew - const replyInput2: Mew = { - text: "xyxyxyxy test reply 2", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash2: ActionHash = await bob.cells[0].callZome({ + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "create_mew", - payload: replyInput2, + fn_name: "get_my_notifications", + payload: null, }); - const replyFeedMew2: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash2, + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewUnlicked]: null }, + feed_mew: feedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewLicked]: null }, + feed_mew: feedMew, }); - // Bob replies to Alice's mew - const replyInput3: Mew = { - text: "xyxyxyxy test reply 3", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash3: ActionHash = await bob.cells[0].callZome({ + // Alice gets notifications count + const count = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "create_mew", - payload: replyInput3, + fn_name: "count_my_notifications", + payload: null, }); - const replyFeedMew3: FeedMew = await bob.cells[0].callZome({ + expect(count).toEqual(2); + }, true); + }); + + it("notifications include my mews' pins & unpins", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + const feedMew: FeedMew = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: replyActionHash3, + payload: actionHash, }); - // Bob replies to Alice's mew - const replyInput4: Mew = { - text: "xyxyxyxy test reply 4", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash4: ActionHash = await bob.cells[0].callZome({ + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob likes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "add_hash_for_pinner", + payload: { + base_pinner: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + // Bob unlikes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "remove_hash_for_pinner", + payload: { + base_pinner: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "create_mew", - payload: replyInput4, + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewUnpinned]: null }, + feed_mew: feedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewPinned]: null }, + feed_mew: feedMew, }); - const replyFeedMew4: FeedMew = await bob.cells[0].callZome({ + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash4, + fn_name: "count_my_notifications", + payload: null, }); + expect(count).toEqual(2); + }, true); + }); + + it("notifications include my mews' replies, quotes, mewmews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); // Bob replies to Alice's mew - const replyInput5: Mew = { - text: "xyxyxyxy test reply 5", + const replyInput: Mew = { + text: "test reply 12345", links: [], mew_type: { [MewTypeName.Reply]: actionHash }, }; - const replyActionHash5: ActionHash = await bob.cells[0].callZome({ + const replyActionHash: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: replyInput5, + payload: replyInput, }); - const replyFeedMew5: FeedMew = await bob.cells[0].callZome({ + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: replyActionHash5, + payload: replyActionHash, }); - // Bob replies to Alice's mew - const replyInput6: Mew = { - text: "xyxyxyxy test reply 6", + // Bob mewmews Alice's mew + const mewmewInput: Mew = { + text: "", links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, + mew_type: { [MewTypeName.Mewmew]: actionHash }, }; - const replyActionHash6: ActionHash = await bob.cells[0].callZome({ + const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: replyInput6, + payload: mewmewInput, }); - const replyFeedMew6: FeedMew = await bob.cells[0].callZome({ + const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: replyActionHash6, + payload: mewmewActionHash, }); - // Bob replies to Alice's mew - const replyInput7: Mew = { - text: "xyxyxyxy test reply 7", + // Bob quotes Alice's mew + const quoteInput: Mew = { + text: "a response to a quoted mew", links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, + mew_type: { [MewTypeName.Quote]: actionHash }, }; - const replyActionHash7: ActionHash = await bob.cells[0].callZome({ + const quoteActionHash: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: replyInput7, + payload: quoteInput, }); - const replyFeedMew7: FeedMew = await bob.cells[0].callZome({ + const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: replyActionHash7, + payload: quoteActionHash, }); await dhtSync([alice, bob], alice.cells[0].cell_id[0]); // Alice gets notifications - const page1 = await alice.cells[0].callZome({ + const notifications = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_notifications", - payload: { - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, + payload: null, }); - // Notifications should be orderded by action time descending (newest first) - expect(page1[0]).toMatchObject({ + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: quoteFeedMew, + }); + expect(notifications[1]).toMatchObject({ agent: bob.agentPubKey, notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew7, + feed_mew: mewmewFeedMew, }); - expect(page1[1]).toMatchObject({ + expect(notifications[2]).toMatchObject({ agent: bob.agentPubKey, notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew6, + feed_mew: replyFeedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, }); + expect(count).toEqual(3); + }, true); + }); - expect(page1[0].timestamp).greaterThanOrEqual(page1[1].timestamp); + it("notifications include replies, quotes, mewmews to mews that I also responded to", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Alice gets notifications - const page2 = await alice.cells[0].callZome({ + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Carol creates a Mew + const actionHash: ActionHash = await createMew(carol.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice reply's to Carol's mew + await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_notifications", + fn_name: "create_mew", payload: { - after_timestamp: page1[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, }, }); - // Notifications should be orderded by action time descending (newest first) - expect(page2[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew5, + // Bob replies to Carol's mew + const replyInput: Mew = { + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, }); - expect(page2[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew4, + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, }); - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp); - - // Alice gets notifications - const page3 = await alice.cells[0].callZome({ + // Bob mewmews Carol's mew + const mewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }; + const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page2[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, + fn_name: "create_mew", + payload: mewmewInput, + }); + const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmewActionHash, }); - // Notifications should be orderded by action time descending (newest first) - expect(page3[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew3, + // Bob quotes Carol's mew + const quoteInput: Mew = { + text: "a response to a quoted mew", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }; + const quoteActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: quoteInput, }); - expect(page3[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew2, + const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quoteActionHash, }); - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp) - .greaterThanOrEqual(page3[0].timestamp) - .greaterThanOrEqual(page3[1].timestamp); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); // Alice gets notifications - const page4 = await alice.cells[0].callZome({ + const notifications = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_notifications", - payload: { - after_timestamp: page3[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, + payload: null, }); - // Notifications should be orderded by action time descending (newest first) - assert.lengthOf(page4, 1); - expect(page4[0]).toMatchObject({ + expect(notifications[0]).toMatchObject({ agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: quoteFeedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: mewmewFeedMew, + }); + expect(notifications[2]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, feed_mew: replyFeedMew, }); - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp) - .greaterThanOrEqual(page3[0].timestamp) - .greaterThanOrEqual(page3[1].timestamp) - .greaterThanOrEqual(page4[0].timestamp); - - const page5 = await alice.cells[0].callZome({ + // Alice gets notifications count + const count = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page4[0].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, + fn_name: "count_my_notifications", + payload: null, }); - - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); + expect(count).toEqual(3); + }, true); + }); + + it("notifications list is time-paginated", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies to Alice's mew + const replyInput: Mew = { + text: "xyxyxyxy test reply 1", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob replies to Alice's mew + const replyInput2: Mew = { + text: "xyxyxyxy test reply 2", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash2: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput2, + }); + const replyFeedMew2: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash2, + }); + + // Bob replies to Alice's mew + const replyInput3: Mew = { + text: "xyxyxyxy test reply 3", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash3: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput3, + }); + const replyFeedMew3: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash3, + }); + + // Bob replies to Alice's mew + const replyInput4: Mew = { + text: "xyxyxyxy test reply 4", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash4: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput4, + }); + const replyFeedMew4: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash4, + }); + + // Bob replies to Alice's mew + const replyInput5: Mew = { + text: "xyxyxyxy test reply 5", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash5: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput5, + }); + const replyFeedMew5: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash5, + }); + + // Bob replies to Alice's mew + const replyInput6: Mew = { + text: "xyxyxyxy test reply 6", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash6: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput6, + }); + const replyFeedMew6: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash6, + }); + + // Bob replies to Alice's mew + const replyInput7: Mew = { + text: "xyxyxyxy test reply 7", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash7: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput7, + }); + const replyFeedMew7: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash7, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const page1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(page1[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew7, + }); + expect(page1[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew6, + }); + + expect(page1[0].timestamp).greaterThanOrEqual(page1[1].timestamp); + + // Alice gets notifications + const page2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page1[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(page2[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew5, + }); + expect(page2[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew4, + }); + + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp); + + // Alice gets notifications + const page3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page2[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(page3[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew3, + }); + expect(page3[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew2, + }); + + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp) + .greaterThanOrEqual(page3[0].timestamp) + .greaterThanOrEqual(page3[1].timestamp); + + // Alice gets notifications + const page4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page3[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + // Notifications should be orderded by action time descending (newest first) + assert.lengthOf(page4, 1); + expect(page4[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew, + }); + + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp) + .greaterThanOrEqual(page3[0].timestamp) + .greaterThanOrEqual(page3[1].timestamp) + .greaterThanOrEqual(page4[0].timestamp); + + const page5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: { + after_timestamp: page4[0].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, + }); + + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); + }); }); -// }); diff --git a/tests/src/mewsfeed/mews/dna-properties.test.ts b/tests/src/mewsfeed/mews/dna-properties.test.ts index 6879ee20..e0379043 100644 --- a/tests/src/mewsfeed/mews/dna-properties.test.ts +++ b/tests/src/mewsfeed/mews/dna-properties.test.ts @@ -7,149 +7,105 @@ import { mewsfeedAppBundleSourceNoLengthLimits, } from "../../common.js"; -// describe.concurrent("dna-properties", () => { -it("Mew must not be longer than DNA property mew_characters_max chars", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const createMewInput: Mew = { - text: new Array(200).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length" - ); +describe.concurrent("dna-properties", () => { + it("Mew must not be longer than DNA property mew_characters_max chars", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - createMewInput.text = new Array(201).fill("a").join(""); - try { - await alice.cells[0].callZome({ + const createMewInput: Mew = { + text: new Array(200).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", payload: createMewInput, }); - assert.fail("mew content longer than mew_characters_max is valid"); - } catch (error) { - assert.ok(true, "mew content longer than mew_characters_max is invalid"); - } - }, true); -}); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length" + ); + + createMewInput.text = new Array(201).fill("a").join(""); + try { + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.fail("mew content longer than mew_characters_max is valid"); + } catch (error) { + assert.ok( + true, + "mew content longer than mew_characters_max is invalid" + ); + } + }, true); + }); + + it("Mew must not be shorter than DNA property mew_characters_min chars", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; -it("Mew must not be shorter than DNA property mew_characters_min chars", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const createMewInput: Mew = { - text: new Array(10).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length" - ); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); - createMewInput.text = new Array(2).fill("a").join(""); - try { - await alice.cells[0].callZome({ + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const createMewInput: Mew = { + text: new Array(10).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", payload: createMewInput, }); - assert.fail("mew content shorter than mew_characters_min is valid"); - } catch (error) { - assert.ok(true, "mew content shorter than mew_characters_min is invalid"); - } - }, true); -}); - -it("Mew can be any length if DNA property mew_characters_min and mew_characters_max not set", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { - appBundleSource: mewsfeedAppBundleSourceNoLengthLimits, - }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // 0 charactres - const createMewInput2: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash2: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - assert.deepEqual( - action_hash2.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length 0" - ); - - // 1000 charactres - const createMewInput3: Mew = { - text: new Array(1000).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash3: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - assert.deepEqual( - action_hash3.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length 1000" - ); - }, true); -}); - -it("Can get deserialized DNA Properties", async () => { - await runScenario( - async (scenario) => { + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length" + ); + + createMewInput.text = new Array(2).fill("a").join(""); + try { + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.fail("mew content shorter than mew_characters_min is valid"); + } catch (error) { + assert.ok( + true, + "mew content shorter than mew_characters_min is invalid" + ); + } + }, true); + }); + + it("Mew can be any length if DNA property mew_characters_min and mew_characters_max not set", async () => { + await runScenario(async (scenario) => { // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + const appSource = { + appBundleSource: mewsfeedAppBundleSourceNoLengthLimits, + }; // Add 2 players with the test app to the Scenario. The returned players // can be destructured. @@ -159,16 +115,66 @@ it("Can get deserialized DNA Properties", async () => { // conductor of the scenario. await scenario.shareAllAgents(); - const properties = await alice.cells[0].callZome({ + // 0 charactres + const createMewInput2: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash2: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + assert.deepEqual( + action_hash2.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length 0" + ); + + // 1000 charactres + const createMewInput3: Mew = { + text: new Array(1000).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash3: ActionHash = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_dna_properties", - payload: null, + fn_name: "create_mew", + payload: createMewInput3, }); - expect(properties).toHaveProperty("mew_characters_min", 5); - expect(properties).toHaveProperty("mew_characters_max", 200); - }, - true, - { timeout: 500000 } - ); + assert.deepEqual( + action_hash3.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length 1000" + ); + }, true); + }); + + it("Can get deserialized DNA Properties", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const properties = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_dna_properties", + payload: null, + }); + expect(properties).toHaveProperty("mew_characters_min", 5); + expect(properties).toHaveProperty("mew_characters_max", 200); + }, + true, + { timeout: 500000 } + ); + }); }); -// }); diff --git a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts index 4c3dea25..ab46d6bb 100644 --- a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts +++ b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts @@ -5,399 +5,58 @@ import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -// describe.concurrent("followed-creators-mews", () => { -it("create a Mew and get followed creators mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Bob follows alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - - // Bob gets followed creators mews - let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.equal(collectionOutput.length, 0); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets followed creators mews again - collectionOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - - assert.equal(collectionOutput.length, 1); - assert.deepEqual(actionHash, collectionOutput[0].action_hash); - }, true); -}); +describe.concurrent("followed-creators-mews", () => { + it("create a Mew and get followed creators mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; -it("Followed creators mews should include mews of followed creator", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = "test-mew"; - const mewInput: Mew = { - text: mewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewInput, - }); - - const bobMewsFeedInitial: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - bobMewsFeedInitial.length === 0, - "bob's mews feed is initially empty" - ); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); - assert.equal( - bobMewsFeed[0].mew.text, - mewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - }, true); -}); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); -it("Followed creators mews should include own mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewsFeedInitial: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - aliceMewsFeedInitial.length === 0, - "alice's mews feed is initially empty" - ); + // Bob follows alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); - const mewContent = "test-mew"; - const mewInput: Mew = { - text: mewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewInput, - }); - - const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(aliceMewsFeed.length === 1, "alice's mews feed includes her mew"); - assert.equal(aliceMewsFeed[0].mew.text, mewContent, "mew content matches"); - }, true); -}); + // Bob gets followed creators mews + let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.equal(collectionOutput.length, 0); -it("Followed creators mews should not include mews of non-followed creator", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const carolMewContent = "carol-test-mew"; - const carolMewInput: Mew = { - text: carolMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await carol.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: carolMewInput, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); - assert.equal( - bobMewsFeed[0].mew.text, - aliceMewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - }, true); -}); + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); -it("Unfollowing should exclude creators mews from feed", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const bobMewsFeedWhenFollowing: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - bobMewsFeedWhenFollowing.length === 1, - "bob's mews feed includes 1 mew" - ); - assert.equal( - bobMewsFeedWhenFollowing[0].mew.text, - aliceMewContent, - "mew content in bob's mews feed matches alice's mew content" - ); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "unfollow", - payload: alice.agentPubKey, - }); - - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 0, "bob's mews feed is empty"); - }, true); -}); + // Bob gets followed creators mews again + collectionOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); -it("Followed creators mews should be ordered by timestamp in descending order", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const firstMewContent = "first-test-mew"; - const firstMewInput: Mew = { - text: firstMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: firstMewInput, - }); - - const secondMewContent = "second-test-mew"; - const secondMewInput: Mew = { - text: secondMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: secondMewInput, - }); - - const thirdMewContent = "third-test-mew"; - const thirdMewInput: Mew = { - text: thirdMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await carol.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: thirdMewInput, - }); - - const fourthMewContent = "fourth-test-mew"; - const fourthMewInput: Mew = { - text: fourthMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: fourthMewInput, - }); - // alice starts following bob and carol - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: bob.agentPubKey, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: carol.agentPubKey, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - aliceMewsFeed.length === 4, - "alice's mews feed includes all 4 mews" - ); - assert.equal( - aliceMewsFeed[0].mew.text, - fourthMewContent, - "mew 1 in feed is fourth mew" - ); - assert.equal( - aliceMewsFeed[1].mew.text, - thirdMewContent, - "mew 2 in feed is third mew" - ); - assert.equal( - aliceMewsFeed[2].mew.text, - secondMewContent, - "mew 3 in feed is second mew" - ); - assert.equal( - aliceMewsFeed[3].mew.text, - firstMewContent, - "mew 4 in feed is first mew" - ); - }, true); -}); + assert.equal(collectionOutput.length, 1); + assert.deepEqual(actionHash, collectionOutput[0].action_hash); + }, true); + }); -it("Followed creators mews list are time-paginated", async () => { - await runScenario( - async (scenario) => { + it("Followed creators mews should include mews of followed creator", async () => { + await runScenario(async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -412,88 +71,188 @@ it("Followed creators mews list are time-paginated", async () => { // conductor of the scenario. await scenario.shareAllAgents(); - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, + const mewContent = "test-mew"; + const mewInput: Mew = { + text: mewContent, links: [], mew_type: { [MewTypeName.Original]: null }, }; - const mewActionHash1 = await alice.cells[0].callZome({ + await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: createMewInput1, + payload: mewInput, }); - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ + const bobMewsFeedInitial: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, }); + assert.ok( + bobMewsFeedInitial.length === 0, + "bob's mews feed is initially empty" + ); - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, }); + assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal( + bobMewsFeed[0].mew.text, + mewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + }, true); + }); + + it("Followed creators mews should include own mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, + const aliceMewsFeedInitial: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeedInitial.length === 0, + "alice's mews feed is initially empty" + ); + + const mewContent = "test-mew"; + const mewInput: Mew = { + text: mewContent, links: [], mew_type: { [MewTypeName.Original]: null }, }; - const mewActionHash4 = await alice.cells[0].callZome({ + await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: createMewInput4, + payload: mewInput, }); - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, + const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeed.length === 1, + "alice's mews feed includes her mew" + ); + assert.equal( + aliceMewsFeed[0].mew.text, + mewContent, + "mew content matches" + ); + }, true); + }); + + it("Followed creators mews should not include mews of non-followed creator", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, links: [], mew_type: { [MewTypeName.Original]: null }, }; - const mewActionHash5 = await alice.cells[0].callZome({ + await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: createMewInput5, + payload: aliceMewInput, }); - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, + const carolMewContent = "carol-test-mew"; + const carolMewInput: Mew = { + text: carolMewContent, links: [], mew_type: { [MewTypeName.Original]: null }, }; - const mewActionHash6 = await alice.cells[0].callZome({ + await carol.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: createMewInput6, + payload: carolMewInput, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal( + bobMewsFeed[0].mew.text, + aliceMewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + }, true); + }); + + it("Unfollowing should exclude creators mews from feed", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, links: [], mew_type: { [MewTypeName.Original]: null }, }; - const mewActionHash7 = await alice.cells[0].callZome({ + await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: createMewInput7, + payload: aliceMewInput, }); await bob.cells[0].callZome({ @@ -501,89 +260,337 @@ it("Followed creators mews list are time-paginated", async () => { fn_name: "follow", payload: alice.agentPubKey, }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - const page1: FeedMew[] = await bob.cells[0].callZome({ + const bobMewsFeedWhenFollowing: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_followed_creators_mews_with_context", - payload: { - limit: 2, - }, + payload: null, }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp + assert.ok( + bobMewsFeedWhenFollowing.length === 1, + "bob's mews feed includes 1 mew" + ); + assert.equal( + bobMewsFeedWhenFollowing[0].mew.text, + aliceMewContent, + "mew content in bob's mews feed matches alice's mew content" ); - const page2: FeedMew[] = await bob.cells[0].callZome({ + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "unfollow", + payload: alice.agentPubKey, + }); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, + payload: null, }); + assert.ok(bobMewsFeed.length === 0, "bob's mews feed is empty"); + }, true); + }); - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); + it("Followed creators mews should be ordered by timestamp in descending order", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - const page3: FeedMew[] = await bob.cells[0].callZome({ + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const firstMewContent = "first-test-mew"; + const firstMewInput: Mew = { + text: firstMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - }, + fn_name: "create_mew", + payload: firstMewInput, }); - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); + const secondMewContent = "second-test-mew"; + const secondMewInput: Mew = { + text: secondMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: secondMewInput, + }); - const page4: FeedMew[] = await bob.cells[0].callZome({ + const thirdMewContent = "third-test-mew"; + const thirdMewInput: Mew = { + text: thirdMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await carol.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - }, + fn_name: "create_mew", + payload: thirdMewInput, }); - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await bob.cells[0].callZome({ + const fourthMewContent = "fourth-test-mew"; + const fourthMewInput: Mew = { + text: fourthMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - }, + fn_name: "create_mew", + payload: fourthMewInput, + }); + // alice starts following bob and carol + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: bob.agentPubKey, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: carol.agentPubKey, }); - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeed.length === 4, + "alice's mews feed includes all 4 mews" + ); + assert.equal( + aliceMewsFeed[0].mew.text, + fourthMewContent, + "mew 1 in feed is fourth mew" + ); + assert.equal( + aliceMewsFeed[1].mew.text, + thirdMewContent, + "mew 2 in feed is third mew" + ); + assert.equal( + aliceMewsFeed[2].mew.text, + secondMewContent, + "mew 3 in feed is second mew" + ); + assert.equal( + aliceMewsFeed[3].mew.text, + firstMewContent, + "mew 4 in feed is first mew" + ); + }, true); + }); + + it("Followed creators mews list are time-paginated", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const page1: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + limit: 2, + }, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, + }); + + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); + }); }); -// }); diff --git a/tests/src/mewsfeed/mews/mention-to-mews.test.ts b/tests/src/mewsfeed/mews/mention-to-mews.test.ts index 7166bed8..8f439987 100644 --- a/tests/src/mewsfeed/mews/mention-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/mention-to-mews.test.ts @@ -10,259 +10,259 @@ import { import { mewsfeedAppBundleSource } from "../../common.js"; import { createMew } from "./common.js"; -// describe.concurrent("mention-to-mews", () => { -it("mention in mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - await createMew(alice.cells[0], { - text: "this is for @bob", - links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], - mew_type: { Original: null }, - }); - - const actionHash2: ActionHash = await createMew(bob.cells[0], { - text: "this is for @bob 2", - links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], - mew_type: { Original: null }, - }); - - const actionHash3: ActionHash = await createMew(alice.cells[0], { - text: "this is for @alice", - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { Original: null }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const mentionedMewsBob: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: bob.agentPubKey, - }, - }); - assert.ok(mentionedMewsBob.length === 2, "one mew with mention"); - assert.deepEqual(mentionedMewsBob[0].action_hash, actionHash2); - - const mentionedMewsAlice: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - }, - }); - assert.ok(mentionedMewsAlice.length === 1, "one mew with mention"); - assert.deepEqual(mentionedMewsAlice[0].action_hash, actionHash3); - }, true); -}); - -it("Mentions list are time-paginated", async () => { - await runScenario( - async (scenario) => { +describe.concurrent("mention-to-mews", () => { + it("mention in mews", async () => { + await runScenario(async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; // Add 2 players with the test app to the Scenario. The returned players // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); // Shortcut peer discovery through gossip and register all agents in every // conductor of the scenario. await scenario.shareAllAgents(); - const mewContent1 = "My Mew with @mention 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with @mention 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with @mention 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, + await createMew(alice.cells[0], { + text: "this is for @bob", + links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], + mew_type: { Original: null }, }); - const mewContent4 = "My Mew with @mention 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, + const actionHash2: ActionHash = await createMew(bob.cells[0], { + text: "this is for @bob 2", + links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], + mew_type: { Original: null }, }); - const mewContent5 = "My Mew with @mention 5"; - const createMewInput5: Mew = { - text: mewContent5, + const actionHash3: ActionHash = await createMew(alice.cells[0], { + text: "this is for @alice", links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, + mew_type: { Original: null }, }); - const mewContent6 = "My Mew with @mention 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with @mention 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - const page1: FeedMew[] = await alice.cells[0].callZome({ + const mentionedMewsBob: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_mews_for_mention_with_context", payload: { - mention: alice.agentPubKey, - page: { - start_time: null, - limit: 2, - }, + mention: bob.agentPubKey, }, }); + assert.ok(mentionedMewsBob.length === 2, "one mew with mention"); + assert.deepEqual(mentionedMewsBob[0].action_hash, actionHash2); - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ + const mentionedMewsAlice: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_mews_for_mention_with_context", payload: { mention: alice.agentPubKey, - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, }, }); + assert.ok(mentionedMewsAlice.length === 1, "one mew with mention"); + assert.deepEqual(mentionedMewsAlice[0].action_hash, actionHash3); + }, true); + }); - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); + it("Mentions list are time-paginated", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with @mention 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with @mention 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with @mention 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with @mention 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with @mention 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with @mention 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with @mention 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + start_time: null, + limit: 2, + }, }, - }, - }); + }); - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + }, + }, + }); - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, + }, + }); + + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); + }); }); -// }); diff --git a/tests/src/mewsfeed/mews/mew-to-responses.test.ts b/tests/src/mewsfeed/mews/mew-to-responses.test.ts index 6e0e9f2a..ea01b686 100644 --- a/tests/src/mewsfeed/mews/mew-to-responses.test.ts +++ b/tests/src/mewsfeed/mews/mew-to-responses.test.ts @@ -4,147 +4,76 @@ import { assert, describe, expect, it } from "vitest"; import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types.js"; import { mewsfeedAppBundleSource } from "../../common.js"; -// describe.concurrent("mew-to-responses", () => { -it("Agent can reply to a mew", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const aliceReplyContent = "alice-test-reply"; - const aliceReplyInput: Mew = { - text: aliceReplyContent, - links: [], - mew_type: { [MewTypeName.Reply]: action_hash }, - }; - const reply_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceReplyInput, - }); - - const replyMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: reply_action_hash, - }); - assert.ok(MewTypeName.Reply in replyMew.mew.mew_type, "mew is a reply"); - assert.equal( - replyMew.mew.text, - aliceReplyContent, - "reply is alice's reply" - ); +describe.concurrent("mew-to-responses", () => { + it("Agent can reply to a mew", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.replies_count === 1, "original mew has 1 reply"); - assert.isTrue( - originalMew.is_replied, - "original mew's reply is alice's reply" - ); - }, true); -}); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); -it("Agent can mewmew a mew, only once", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const aliceMewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: action_hash }, - }; - const mewmew_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewmewInput, - }); - - const mewmew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmew_action_hash, - }); - assert.ok(MewTypeName.Mewmew in mewmew.mew.mew_type, "mew is a mewmew"); - assert.deepEqual(mewmew.mew, aliceMewmewInput, "mewmew is alice's mewmew"); - - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); - assert.isTrue( - originalMew.is_mewmewed, - "original mew's mewmew is alice's mewmew" - ); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - // Mewmew the same mew again - const response = alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewmewInput, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - }, true); -}); + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const aliceReplyContent = "alice-test-reply"; + const aliceReplyInput: Mew = { + text: aliceReplyContent, + links: [], + mew_type: { [MewTypeName.Reply]: action_hash }, + }; + const reply_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceReplyInput, + }); + + const replyMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: reply_action_hash, + }); + assert.ok(MewTypeName.Reply in replyMew.mew.mew_type, "mew is a reply"); + assert.equal( + replyMew.mew.text, + aliceReplyContent, + "reply is alice's reply" + ); + + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); + assert.ok(originalMew.replies_count === 1, "original mew has 1 reply"); + assert.isTrue( + originalMew.is_replied, + "original mew's reply is alice's reply" + ); + }, true); + }); -it("Agent can quote a mew", async () => { - await runScenario( - async (scenario) => { + it("Agent can mewmew a mew, only once", async () => { + await runScenario(async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -168,27 +97,28 @@ it("Agent can quote a mew", async () => { payload: aliceMewInput, }); - const aliceQuoteText = "alice-test-quote"; - const aliceQuoteInput: Mew = { - text: aliceQuoteText, + const aliceMewmewInput: Mew = { + text: "", links: [], - mew_type: { - [MewTypeName.Quote]: action_hash, - }, + mew_type: { [MewTypeName.Mewmew]: action_hash }, }; - const quote_action_hash: ActionHash = await alice.cells[0].callZome({ + const mewmew_action_hash: ActionHash = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: aliceQuoteInput, + payload: aliceMewmewInput, }); - const quote: FeedMew = await alice.cells[0].callZome({ + const mewmew: FeedMew = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: quote_action_hash, + payload: mewmew_action_hash, }); - assert.ok(MewTypeName.Quote in quote.mew.mew_type, "mew is a quote"); - assert.equal(quote.mew.text, aliceQuoteText, "quote is alice's quote"); + assert.ok(MewTypeName.Mewmew in mewmew.mew.mew_type, "mew is a mewmew"); + assert.deepEqual( + mewmew.mew, + aliceMewmewInput, + "mewmew is alice's mewmew" + ); const originalMew: FeedMew = await alice.cells[0].callZome({ zome_name: "mews", @@ -200,14 +130,92 @@ it("Agent can quote a mew", async () => { "mew is an original mew" ); assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.quotes_count === 1, "original mew has 1 quote"); + assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); assert.isTrue( - originalMew.is_quoted, - "original mew's quote is alice's quote" + originalMew.is_mewmewed, + "original mew's mewmew is alice's mewmew" ); - }, - true, - { timeout: 500000 } - ); + + // Mewmew the same mew again + const response = alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewmewInput, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + }, true); + }); + + it("Agent can quote a mew", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const aliceQuoteText = "alice-test-quote"; + const aliceQuoteInput: Mew = { + text: aliceQuoteText, + links: [], + mew_type: { + [MewTypeName.Quote]: action_hash, + }, + }; + const quote_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceQuoteInput, + }); + + const quote: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quote_action_hash, + }); + assert.ok(MewTypeName.Quote in quote.mew.mew_type, "mew is a quote"); + assert.equal(quote.mew.text, aliceQuoteText, "quote is alice's quote"); + + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal( + originalMew.mew.text, + aliceMewContent, + "mew is alice's mew" + ); + assert.ok(originalMew.quotes_count === 1, "original mew has 1 quote"); + assert.isTrue( + originalMew.is_quoted, + "original mew's quote is alice's quote" + ); + }, + true, + { timeout: 500000 } + ); + }); }); -// }); diff --git a/tests/src/mewsfeed/mews/mew-with-context.test.ts b/tests/src/mewsfeed/mews/mew-with-context.test.ts index e9c5b5df..270f07e3 100644 --- a/tests/src/mewsfeed/mews/mew-with-context.test.ts +++ b/tests/src/mewsfeed/mews/mew-with-context.test.ts @@ -5,344 +5,344 @@ import { FeedMew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -// describe.concurrent("mew-with-context", () => { -it("Mew with context contains licks count and is_licked", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob licks the mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "like", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - let feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.licks_count).toEqual(1); - expect(feedMew.is_licked).true; - - // Alice gets the mew with context - let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.licks_count).toEqual(1); - expect(aliceFeedMew.is_licked).false; - - // Bob unlicks the mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "unlike", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - feedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.licks_count).toEqual(0); - expect(feedMew.is_licked).false; - - // Alice gets the mew with context - aliceFeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.licks_count).toEqual(0); - expect(aliceFeedMew.is_licked).false; - }, - true, - { timeout: 100000 } - ); -}); - -it("Mew with context contains replies count and is_replied", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies the mew - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "my reply blah blah", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - const feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.replies_count).toEqual(1); - expect(feedMew.is_replied).true; - - // Alice gets the mew with context - const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.replies_count).toEqual(1); - expect(aliceFeedMew.is_replied).false; - }, - true, - { timeout: 100000 } - ); -}); - -it("Mew with context contains quotes count and is_quoted", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies the mew - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "this is a quote blah blah", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - const feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.quotes_count).toEqual(1); - expect(feedMew.is_quoted).true; - - // Alice gets the mew with context - const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.quotes_count).toEqual(1); - expect(aliceFeedMew.is_quoted).false; - }, - true, - { timeout: 100000 } - ); -}); - -it("Mew with context contains mewmews count and is_mewmewed", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob mewmews the mew - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - const feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.mewmews_count).toEqual(1); - expect(feedMew.is_mewmewed).true; - console.warn("bob got mew"); - - // Alice gets the mew with context - const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - console.warn("alice got mew"); - - expect(aliceFeedMew.mewmews_count).toEqual(1); - expect(aliceFeedMew.is_mewmewed).false; - }, - true, - { timeout: 100000 } - ); -}); - -it("Mew with context contains is_pinned", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob pins the mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - let feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.is_pinned).true; - - // Alice gets the mew with context - let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.is_pinned).false; - - // Bob unpins the mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - feedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.is_pinned).false; - - // Alice gets the mew with context - aliceFeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.is_pinned).false; - }, - true, - { timeout: 500000 } - ); -}); +describe.concurrent("mew-with-context", () => { + it("Mew with context contains licks count and is_licked", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob licks the mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "like", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + let feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.licks_count).toEqual(1); + expect(feedMew.is_licked).true; + + // Alice gets the mew with context + let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.licks_count).toEqual(1); + expect(aliceFeedMew.is_licked).false; + + // Bob unlicks the mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "unlike", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + feedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.licks_count).toEqual(0); + expect(feedMew.is_licked).false; + + // Alice gets the mew with context + aliceFeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.licks_count).toEqual(0); + expect(aliceFeedMew.is_licked).false; + }, + true, + { timeout: 100000 } + ); + }); + + it("Mew with context contains replies count and is_replied", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies the mew + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "my reply blah blah", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + const feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.replies_count).toEqual(1); + expect(feedMew.is_replied).true; + + // Alice gets the mew with context + const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.replies_count).toEqual(1); + expect(aliceFeedMew.is_replied).false; + }, + true, + { timeout: 100000 } + ); + }); + + it("Mew with context contains quotes count and is_quoted", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies the mew + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "this is a quote blah blah", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + const feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.quotes_count).toEqual(1); + expect(feedMew.is_quoted).true; + + // Alice gets the mew with context + const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.quotes_count).toEqual(1); + expect(aliceFeedMew.is_quoted).false; + }, + true, + { timeout: 100000 } + ); + }); + + it("Mew with context contains mewmews count and is_mewmewed", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob mewmews the mew + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + const feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.mewmews_count).toEqual(1); + expect(feedMew.is_mewmewed).true; + console.warn("bob got mew"); + + // Alice gets the mew with context + const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + console.warn("alice got mew"); + + expect(aliceFeedMew.mewmews_count).toEqual(1); + expect(aliceFeedMew.is_mewmewed).false; + }, + true, + { timeout: 100000 } + ); + }); + + it("Mew with context contains is_pinned", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob pins the mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + let feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.is_pinned).true; + + // Alice gets the mew with context + let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.is_pinned).false; + + // Bob unpins the mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + feedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.is_pinned).false; + + // Alice gets the mew with context + aliceFeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.is_pinned).false; + }, + true, + { timeout: 500000 } + ); + }); // }); diff --git a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts index 6315d8a0..49e48992 100644 --- a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts @@ -4,75 +4,75 @@ import { assert, describe, it } from "vitest"; import { FeedMew } from "../../../../ui/src/types/types.js"; import { createMew } from "./common.js"; -// describe.concurrent("pinner-to-mews", () => { -it("link a Pinner to a Mew", async () => { - await runScenario( - async (scenario) => { - // Construct proper paths for your app. - // This assumes app bundle created by the `hc app pack` command. - const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; +describe.concurrent("pinner-to-mews", () => { + it("link a Pinner to a Mew", async () => { + await runScenario( + async (scenario) => { + // Construct proper paths for your app. + // This assumes app bundle created by the `hc app pack` command. + const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; - // Set up the app to be installed - const appSource = { appBundleSource: { path: testAppPath } }; + // Set up the app to be installed + const appSource = { appBundleSource: { path: testAppPath } }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - const baseAddress = alice.agentPubKey; - const targetActionHash: ActionHash = await createMew(alice.cells[0]); + const baseAddress = alice.agentPubKey; + const targetActionHash: ActionHash = await createMew(alice.cells[0]); - // Bob gets the links, should be empty - let linksOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); + // Bob gets the links, should be empty + let linksOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); - // Alice creates a link from Pinner to Mew - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: targetActionHash, - }); + // Alice creates a link from Pinner to Mew + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: targetActionHash, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 1); - assert.deepEqual(targetActionHash, linksOutput[0].action_hash); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 1); + assert.deepEqual(targetActionHash, linksOutput[0].action_hash); - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: targetActionHash, - }); + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: targetActionHash, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - }, - true, - { timeout: 500000 } - ); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + }, + true, + { timeout: 500000 } + ); + }); }); -// }); diff --git a/tests/src/mewsfeed/mews/tags-to-mews.test.ts b/tests/src/mewsfeed/mews/tags-to-mews.test.ts index c0445e5c..01a1deff 100644 --- a/tests/src/mewsfeed/mews/tags-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/tags-to-mews.test.ts @@ -10,369 +10,184 @@ import { } from "../../../../ui/src/types/types.js"; import { mewsfeedAppBundleSource } from "../../common.js"; -// describe.concurrent("tags-to-mews", () => { -it("Hashtag, cashtag and mention", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = - "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; - const createMewInput: Mew = { - text: mewContent, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a valid mew" - ); +describe.concurrent("tags-to-mews", () => { + it("Hashtag, cashtag and mention", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - const hashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - }, - }); - assert.ok(hashtaggedMews.length === 1, "one mew with hashtag"); - assert.equal(hashtaggedMews[0].mew.text, mewContent, "mew content matches"); - - const arabicHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#سعيدة", - }, - }); - assert.ok(arabicHashtaggedMews.length === 1, "one mew with arabic hashtag"); - assert.equal( - arabicHashtaggedMews[0].mew.text, - mewContent, - "mew content matches" - ); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); - // get hashtag containing emojis -- invalid hashtag! - const emojiHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#😃😃😃", - }, - }); - assert.ok(emojiHashtaggedMews.length === 0, "no mew with emoji hashtag"); - - const cashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - }, - }); - assert.ok(cashtaggedMews.length === 1, "one mew with cashtag"); - - const mentionedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - }, - }); - assert.ok(mentionedMews.length === 1, "one mew with mention"); - }, true); -}); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); -it("Prefix index should return hashtags and cashtags", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = - "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; - const createMewInput: Mew = { - text: mewContent, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a valid mew" - ); + const mewContent = + "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; + const createMewInput: Mew = { + text: mewContent, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; - const hashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "has", - limit: 10, - }, - }); - assert.ok(hashtags.length === 1, "one hashtag"); - assert.equal(hashtags[0], "#hashtag", "hashtag search result matches"); - - const arabicHashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "سعيدة", - limit: 10, - }, - }); - assert.ok(arabicHashtags.length === 1, "one arabic hashtag"); - assert.equal(arabicHashtags[0], "#سعيدة", "hashtag search result matches"); - - // get hashtag containing emojis -- invalid hashtag! - const emojiHashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "😃😃😃", - limit: 10, - }, - }); - assert.ok(emojiHashtags.length === 0, "no emoji hashtags"); - - const cashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "cas", - limit: 10, - }, - }); - assert.ok(cashtags.length === 1, "one cashtag"); - assert.equal(cashtags[0], "$cashtag", "hashtag search result matches"); - }, true); -}); + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a valid mew" + ); -it("Hashtags list are time-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - limit: 2, + const hashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", }, - }, - }); + }); + assert.ok(hashtaggedMews.length === 1, "one mew with hashtag"); + assert.equal( + hashtaggedMews[0].mew.text, + mewContent, + "mew content matches" + ); - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); + const arabicHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#سعيدة", + }, + }); + assert.ok( + arabicHashtaggedMews.length === 1, + "one mew with arabic hashtag" + ); + assert.equal( + arabicHashtaggedMews[0].mew.text, + mewContent, + "mew content matches" + ); - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, + // get hashtag containing emojis -- invalid hashtag! + const emojiHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#😃😃😃", }, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page2[page1.length - 1].action_hash, - limit: 2, + }); + assert.ok(emojiHashtaggedMews.length === 0, "no mew with emoji hashtag"); + + const cashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", }, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page3[page1.length - 1].action_hash, - limit: 2, + }); + assert.ok(cashtaggedMews.length === 1, "one mew with cashtag"); + + const mentionedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, }, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, + }); + assert.ok(mentionedMews.length === 1, "one mew with mention"); + }, true); + }); + + it("Prefix index should return hashtags and cashtags", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = + "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; + const createMewInput: Mew = { + text: mewContent, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a valid mew" + ); + + const hashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "has", + limit: 10, }, - }, - }); + }); + assert.ok(hashtags.length === 1, "one hashtag"); + assert.equal(hashtags[0], "#hashtag", "hashtag search result matches"); - assert.lengthOf(page5, 0); - }, true); -}); + const arabicHashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "سعيدة", + limit: 10, + }, + }); + assert.ok(arabicHashtags.length === 1, "one arabic hashtag"); + assert.equal( + arabicHashtags[0], + "#سعيدة", + "hashtag search result matches" + ); -it("Cashtags list are time-paginated", async () => { - await runScenario( - async (scenario) => { + // get hashtag containing emojis -- invalid hashtag! + const emojiHashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "😃😃😃", + limit: 10, + }, + }); + assert.ok(emojiHashtags.length === 0, "no emoji hashtags"); + + const cashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "cas", + limit: 10, + }, + }); + assert.ok(cashtags.length === 1, "one cashtag"); + assert.equal(cashtags[0], "$cashtag", "hashtag search result matches"); + }, true); + }); + + it("Hashtags list are time-paginated", async () => { + await runScenario(async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -384,7 +199,7 @@ it("Cashtags list are time-paginated", async () => { // conductor of the scenario. await scenario.shareAllAgents(); - const mewContent1 = "My Mew with $cashtag 1"; + const mewContent1 = "My Mew with #hashtag 1"; const createMewInput1: Mew = { text: mewContent1, links: [], @@ -396,7 +211,7 @@ it("Cashtags list are time-paginated", async () => { payload: createMewInput1, }); - const mewContent2 = "My Mew with $cashtag 2"; + const mewContent2 = "My Mew with #hashtag 2"; const createMewInput2: Mew = { text: mewContent2, links: [], @@ -408,7 +223,7 @@ it("Cashtags list are time-paginated", async () => { payload: createMewInput2, }); - const mewContent3 = "My Mew with $cashtag 3"; + const mewContent3 = "My Mew with #hashtag 3"; const createMewInput3: Mew = { text: mewContent3, links: [], @@ -420,7 +235,7 @@ it("Cashtags list are time-paginated", async () => { payload: createMewInput3, }); - const mewContent4 = "My Mew with $cashtag 4"; + const mewContent4 = "My Mew with #hashtag 4"; const createMewInput4: Mew = { text: mewContent4, links: [], @@ -432,7 +247,7 @@ it("Cashtags list are time-paginated", async () => { payload: createMewInput4, }); - const mewContent5 = "My Mew with $cashtag 5"; + const mewContent5 = "My Mew with #hashtag 5"; const createMewInput5: Mew = { text: mewContent5, links: [], @@ -444,7 +259,7 @@ it("Cashtags list are time-paginated", async () => { payload: createMewInput5, }); - const mewContent6 = "My Mew with $cashtag 6"; + const mewContent6 = "My Mew with #hashtag 6"; const createMewInput6: Mew = { text: mewContent6, links: [], @@ -456,7 +271,7 @@ it("Cashtags list are time-paginated", async () => { payload: createMewInput6, }); - const mewContent7 = "My Mew with $cashtag 7"; + const mewContent7 = "My Mew with #hashtag 7"; const createMewInput7: Mew = { text: mewContent7, links: [], @@ -470,13 +285,11 @@ it("Cashtags list are time-paginated", async () => { const page1: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", + fn_name: "get_mews_for_hashtag_with_context", payload: { - cashtag: "$cashtag", + hashtag: "#hashtag", page: { - start_time: null, limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, }, }, }); @@ -489,13 +302,12 @@ it("Cashtags list are time-paginated", async () => { const page2: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", + fn_name: "get_mews_for_hashtag_with_context", payload: { - cashtag: "$cashtag", + hashtag: "#hashtag", page: { after_hash: page1[page1.length - 1].action_hash, limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, }, }, }); @@ -510,13 +322,12 @@ it("Cashtags list are time-paginated", async () => { const page3: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", + fn_name: "get_mews_for_hashtag_with_context", payload: { - cashtag: "$cashtag", + hashtag: "#hashtag", page: { - after_hash: page2[page2.length - 1].action_hash, + after_hash: page2[page1.length - 1].action_hash, limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, }, }, }); @@ -533,13 +344,12 @@ it("Cashtags list are time-paginated", async () => { const page4: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", + fn_name: "get_mews_for_hashtag_with_context", payload: { - cashtag: "$cashtag", + hashtag: "#hashtag", page: { - after_hash: page3[page3.length - 1].action_hash, + after_hash: page3[page1.length - 1].action_hash, limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, }, }, }); @@ -557,21 +367,222 @@ it("Cashtags list are time-paginated", async () => { const page5: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", + fn_name: "get_mews_for_hashtag_with_context", payload: { - cashtag: "$cashtag", + hashtag: "#hashtag", page: { after_hash: page4[page4.length - 1].action_hash, limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, }, }, }); assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); + }, true); + }); + + it("Cashtags list are time-paginated", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with $cashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with $cashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with $cashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with $cashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with $cashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with $cashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with $cashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + start_time: null, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, + }, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, + }, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, + }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, + }, + }, + }); + + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); + }); }); -// }); From ec4230d51f6a9e49afb05ade5f65f17ddfe83c85 Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Wed, 1 Nov 2023 11:08:05 -0600 Subject: [PATCH 12/22] de-parallize tests again --- .../agent_pins/pinner-to-hashes.test.ts | 176 ++- .../follows/follower-to-creators.test.ts | 638 +++++---- .../mewsfeed/likes/liker-to-hashes.test.ts | 228 ++- tests/src/mewsfeed/mews/agent-mews.test.ts | 428 +++--- .../mews/agent-to-notifications.test.ts | 1220 ++++++++--------- .../src/mewsfeed/mews/dna-properties.test.ts | 288 ++-- .../mews/followed-creators-mews.test.ts | 987 +++++++------ .../src/mewsfeed/mews/mention-to-mews.test.ts | 430 +++--- .../mewsfeed/mews/mew-to-responses.test.ts | 322 +++-- .../mewsfeed/mews/mew-with-context.test.ts | 682 +++++---- .../src/mewsfeed/mews/pinner-to-mews.test.ts | 120 +- tests/src/mewsfeed/mews/tags-to-mews.test.ts | 769 +++++------ 12 files changed, 3116 insertions(+), 3172 deletions(-) diff --git a/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts b/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts index 921edb96..05e140dd 100644 --- a/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts +++ b/tests/src/mewsfeed/agent_pins/pinner-to-hashes.test.ts @@ -1,94 +1,92 @@ -import { assert, describe, it } from "vitest"; +import { assert, it } from "vitest"; import { AgentPubKey, HoloHash, fakeActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -describe.concurrent("pinner-to-hashes", () => { - it("link a Pinner to a Hash", async () => { - await runScenario( - async (scenario) => { - // Construct proper paths for your app. - // This assumes app bundle created by the `hc app pack` command. - const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; - - // Set up the app to be installed - const appSource = { appBundleSource: { path: testAppPath } }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetHash = await fakeActionHash(); - - // Bob gets the links, should be empty - let linksOutput: HoloHash[] = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Pinner to Hash - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: targetHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - const pinnersOutput: AgentPubKey[] = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_pinners_for_hash", - payload: targetHash, - }); - assert.equal(pinnersOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: targetHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_hashes_for_pinner", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "get_pinners_for_hash", - payload: targetHash, - }); - - assert.equal(linksOutput.length, 0); - }, - true, - { timeout: 500000 } - ); - }); +it("link a Pinner to a Hash", async () => { + await runScenario( + async (scenario) => { + // Construct proper paths for your app. + // This assumes app bundle created by the `hc app pack` command. + const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; + + // Set up the app to be installed + const appSource = { appBundleSource: { path: testAppPath } }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetHash = await fakeActionHash(); + + // Bob gets the links, should be empty + let linksOutput: HoloHash[] = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Pinner to Hash + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: targetHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + const pinnersOutput: AgentPubKey[] = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_pinners_for_hash", + payload: targetHash, + }); + assert.equal(pinnersOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: targetHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_hashes_for_pinner", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "get_pinners_for_hash", + payload: targetHash, + }); + + assert.equal(linksOutput.length, 0); + }, + true, + { timeout: 500000 } + ); }); diff --git a/tests/src/mewsfeed/follows/follower-to-creators.test.ts b/tests/src/mewsfeed/follows/follower-to-creators.test.ts index 9623fa22..14d136c7 100644 --- a/tests/src/mewsfeed/follows/follower-to-creators.test.ts +++ b/tests/src/mewsfeed/follows/follower-to-creators.test.ts @@ -1,189 +1,311 @@ import { AgentPubKey, Record } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -import { assert, describe, expect, it } from "vitest"; +import { assert, expect, it } from "vitest"; import { mewsfeedAppBundleSource } from "../../common"; -describe.concurrent("follower-to-creators", () => { - it("link a Follower to a Creator", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = bob.agentPubKey; - - // Bob gets the links, should be empty - let linksOutput: Record[] = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Follower to Creator - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: targetAddress, - }, - }); - assert.equal(linksOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); +it("link a Follower to a Creator", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = bob.agentPubKey; + + // Bob gets the links, should be empty + let linksOutput: Record[] = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Follower to Creator + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: targetAddress, - }, - }); - assert.equal(linksOutput.length, 0); - }, true); - }); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: targetAddress, + }, + }); + assert.equal(linksOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); - it("Agent cannot follow themselves", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: targetAddress, + }, + }); + assert.equal(linksOutput.length, 0); + }, true); +}); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); +it("Agent cannot follow themselves", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice tries to follow herself + const response = alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + }, true); +}); - // Alice tries to follow herself - const response = alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - }, true); - }); +it("Agent can only change their own follows", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = bob.agentPubKey; + + // Alice follows bob + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to remove alices' follow + const response = bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + + // Alice removes her own follow + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "unfollow", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to add a follow for allice + const response2 = bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); + await expect(response2).rejects.toThrowError(/InvalidCommit/); + }, true); +}); - it("Agent can only change their own follows", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; +it("Creators list are hash-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol, john, steve, mary] = + await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + appSource, appSource, appSource, ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = bob.agentPubKey; - - // Alice follows bob - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: targetAddress, - }); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a link from Follower to Creator + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: bob.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: carol.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: john.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: steve.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: mary.agentPubKey, + }, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob tries to remove alices' follow - const response = bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, + const page1: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + limit: 2, }, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - - // Alice removes her own follow - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "unfollow", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to add a follow for allice - const response2 = bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, + }, + }); + + assert.deepEqual(page1[0], mary.agentPubKey); + assert.deepEqual(page1[1], steve.agentPubKey); + + const page2: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page1[1], + limit: 2, }, - }); - await expect(response2).rejects.toThrowError(/InvalidCommit/); - }, true); - }); + }, + }); + assert.deepEqual(page2[0], john.agentPubKey); + assert.deepEqual(page2[1], carol.agentPubKey); + + const page3: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page2[1], + limit: 2, + }, + }, + }); + assert.lengthOf(page3, 1); + assert.deepEqual(page3[0], bob.agentPubKey); + + const page5: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page3[0], + limit: 2, + }, + }, + }); + assert.lengthOf(page5, 0); + }, true); +}); - it("Creators list are hash-paginated", async () => { - await runScenario(async (scenario) => { +it("Followers list are hash-paginated", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -204,54 +326,57 @@ describe.concurrent("follower-to-creators", () => { await scenario.shareAllAgents(); // Alice creates a link from Follower to Creator - await alice.cells[0].callZome({ + await bob.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: alice.agentPubKey, - target_creator: bob.agentPubKey, + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, }, }); - await alice.cells[0].callZome({ + await carol.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: alice.agentPubKey, - target_creator: carol.agentPubKey, + base_follower: carol.agentPubKey, + target_creator: alice.agentPubKey, }, }); - await alice.cells[0].callZome({ + await john.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: alice.agentPubKey, - target_creator: john.agentPubKey, + base_follower: john.agentPubKey, + target_creator: alice.agentPubKey, }, }); - await alice.cells[0].callZome({ + await steve.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: alice.agentPubKey, - target_creator: steve.agentPubKey, + base_follower: steve.agentPubKey, + target_creator: alice.agentPubKey, }, }); - await alice.cells[0].callZome({ + await mary.cells[0].callZome({ zome_name: "follows", fn_name: "add_creator_for_follower", payload: { - base_follower: alice.agentPubKey, - target_creator: mary.agentPubKey, + base_follower: mary.agentPubKey, + target_creator: alice.agentPubKey, }, }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync( + [alice, bob, carol, john, steve, mary], + alice.cells[0].cell_id[0] + ); const page1: AgentPubKey[] = await alice.cells[0].callZome({ zome_name: "follows", - fn_name: "get_creators_for_follower", + fn_name: "get_followers_for_creator", payload: { - follower: alice.agentPubKey, + creator: alice.agentPubKey, page: { limit: 2, }, @@ -263,9 +388,9 @@ describe.concurrent("follower-to-creators", () => { const page2: AgentPubKey[] = await alice.cells[0].callZome({ zome_name: "follows", - fn_name: "get_creators_for_follower", + fn_name: "get_followers_for_creator", payload: { - follower: alice.agentPubKey, + creator: alice.agentPubKey, page: { after_agentpubkey: page1[1], limit: 2, @@ -277,9 +402,9 @@ describe.concurrent("follower-to-creators", () => { const page3: AgentPubKey[] = await alice.cells[0].callZome({ zome_name: "follows", - fn_name: "get_creators_for_follower", + fn_name: "get_followers_for_creator", payload: { - follower: alice.agentPubKey, + creator: alice.agentPubKey, page: { after_agentpubkey: page2[1], limit: 2, @@ -291,9 +416,9 @@ describe.concurrent("follower-to-creators", () => { const page5: AgentPubKey[] = await alice.cells[0].callZome({ zome_name: "follows", - fn_name: "get_creators_for_follower", + fn_name: "get_followers_for_creator", payload: { - follower: alice.agentPubKey, + creator: alice.agentPubKey, page: { after_agentpubkey: page3[0], limit: 2, @@ -301,135 +426,8 @@ describe.concurrent("follower-to-creators", () => { }, }); assert.lengthOf(page5, 0); - }, true); - }); - - it("Followers list are hash-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol, john, steve, mary] = - await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a link from Follower to Creator - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await carol.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: carol.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await john.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: john.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await steve.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: steve.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - await mary.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: mary.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - await dhtSync( - [alice, bob, carol, john, steve, mary], - alice.cells[0].cell_id[0] - ); - - const page1: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - limit: 2, - }, - }, - }); - - assert.deepEqual(page1[0], mary.agentPubKey); - assert.deepEqual(page1[1], steve.agentPubKey); - - const page2: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page1[1], - limit: 2, - }, - }, - }); - assert.deepEqual(page2[0], john.agentPubKey); - assert.deepEqual(page2[1], carol.agentPubKey); - - const page3: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page2[1], - limit: 2, - }, - }, - }); - assert.lengthOf(page3, 1); - assert.deepEqual(page3[0], bob.agentPubKey); - - const page5: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: alice.agentPubKey, - page: { - after_agentpubkey: page3[0], - limit: 2, - }, - }, - }); - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); - }); + }, + true, + { timeout: 500000 } + ); }); diff --git a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts index b2c697a5..4016e279 100644 --- a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts +++ b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts @@ -1,11 +1,95 @@ import { Record, fakeActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -import { assert, describe, expect, it } from "vitest"; +import { assert, expect, it } from "vitest"; import { mewsfeedAppBundleSource } from "../../common"; -describe.concurrent("liker-to-hashes", () => { - it("link a Liker to a Hash", async () => { - await runScenario(async (scenario) => { +it("link a Liker to a Hash", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = await fakeActionHash(); + + // Bob gets the links, should be empty + let linksOutput: Record[] = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Liker to Hash + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: baseAddress, + target_hash: targetAddress, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_likers_for_hash", + payload: targetAddress, + }); + assert.equal(linksOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: baseAddress, + target_hash: targetAddress, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_likers_for_hash", + payload: targetAddress, + }); + assert.equal(linksOutput.length, 0); + }, true); +}); + +it("Agent can only change their own likes", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -20,135 +104,49 @@ describe.concurrent("liker-to-hashes", () => { // conductor of the scenario. await scenario.shareAllAgents(); - const baseAddress = alice.agentPubKey; const targetAddress = await fakeActionHash(); - // Bob gets the links, should be empty - let linksOutput: Record[] = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Liker to Hash + // Alice likes hash await alice.cells[0].callZome({ zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: baseAddress, - target_hash: targetAddress, - }, + fn_name: "like", + payload: targetAddress, }); await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_likers_for_hash", - payload: targetAddress, - }); - assert.equal(linksOutput.length, 1); - - await alice.cells[0].callZome({ + // Bob tries to remove alices' like + const response = bob.cells[0].callZome({ zome_name: "likes", fn_name: "remove_hash_for_liker", payload: { - base_liker: baseAddress, + base_liker: alice.agentPubKey, target_hash: targetAddress, }, }); + await expect(response).rejects.toThrowError(/InvalidCommit/); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ + // Alice removes her own like + await alice.cells[0].callZome({ zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, + fn_name: "unlike", + payload: targetAddress, }); - assert.equal(linksOutput.length, 0); - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to add a like for allice + const response2 = bob.cells[0].callZome({ zome_name: "likes", - fn_name: "get_likers_for_hash", - payload: targetAddress, + fn_name: "add_hash_for_liker", + payload: { + base_liker: alice.agentPubKey, + target_hash: targetAddress, + }, }); - assert.equal(linksOutput.length, 0); - }, true); - }); - - it("Agent can only change their own likes", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const targetAddress = await fakeActionHash(); - - // Alice likes hash - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "like", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to remove alices' like - const response = bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: alice.agentPubKey, - target_hash: targetAddress, - }, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - - // Alice removes her own like - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "unlike", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to add a like for allice - const response2 = bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: alice.agentPubKey, - target_hash: targetAddress, - }, - }); - await expect(response2).rejects.toThrowError(/InvalidCommit/); - }, - true, - { timeout: 500000 } - ); - }); + await expect(response2).rejects.toThrowError(/InvalidCommit/); + }, + true, + { timeout: 500000 } + ); }); diff --git a/tests/src/mewsfeed/mews/agent-mews.test.ts b/tests/src/mewsfeed/mews/agent-mews.test.ts index b0621a7d..ddffd9ab 100644 --- a/tests/src/mewsfeed/mews/agent-mews.test.ts +++ b/tests/src/mewsfeed/mews/agent-mews.test.ts @@ -1,250 +1,248 @@ import { ActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -import { assert, describe, expect, it } from "vitest"; +import { assert, expect, it } from "vitest"; import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -describe.concurrent("agent-mews", () => { - it("create a Mew and get agent mews", async () => { - await runScenario(async (scenario) => { +it("create a Mew and get agent mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Bob gets agent mews + let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + }, + }); + assert.equal(collectionOutput.length, 0); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets agent mews again + collectionOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + }, + }); + assert.equal(collectionOutput.length, 1); + assert.deepEqual(actionHash, collectionOutput[0].action_hash); + }, true); +}); + +it("Agent mews lists are time-paginated", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; // Add 2 players with the test app to the Scenario. The returned players // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); + const [alice] = await scenario.addPlayersWithApps([appSource]); // Shortcut peer discovery through gossip and register all agents in every // conductor of the scenario. await scenario.shareAllAgents(); - // Bob gets agent mews - let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + limit: 2, + }, + }, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_agent_mews_with_context", payload: { agent: alice.agentPubKey, + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, }, }); - assert.equal(collectionOutput.length, 0); - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); - // Bob gets agent mews again - collectionOutput = await bob.cells[0].callZome({ + const page3: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_agent_mews_with_context", payload: { agent: alice.agentPubKey, + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, }, }); - assert.equal(collectionOutput.length, 1); - assert.deepEqual(actionHash, collectionOutput[0].action_hash); - }, true); - }); - - it("Agent mews lists are time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - limit: 2, - }, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - }, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - }, + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_agent_mews_with_context", - payload: { - agent: alice.agentPubKey, - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - }, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_agent_mews_with_context", + payload: { + agent: alice.agentPubKey, + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); - }); + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); diff --git a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts index ab4bca57..6543c8f1 100644 --- a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts +++ b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts @@ -1,6 +1,6 @@ import { ActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -import { assert, describe, expect, it } from "vitest"; +import { assert, expect, it } from "vitest"; import { FeedMew, Mew, @@ -11,74 +11,462 @@ import { import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -describe.concurrent("agent-to-notifications", () => { - it("notifications include my agent follows & unfollows", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Bob follows Alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - // Bob unfollows Alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); +it("notifications include my agent follows & unfollows", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Bob follows Alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + // Bob unfollows Alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyAgentUnfollowed]: null }, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyAgentFollowed]: null }, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, true); +}); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); +it("notifications include my mews' likes & unlikes", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + const feedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob likes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + // Bob unlikes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewUnlicked]: null }, + feed_mew: feedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewLicked]: null }, + feed_mew: feedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, true); +}); - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); +it("notifications include my mews' pins & unpins", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + const feedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob likes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "add_hash_for_pinner", + payload: { + base_pinner: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + // Bob unlikes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "remove_hash_for_pinner", + payload: { + base_pinner: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewUnpinned]: null }, + feed_mew: feedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewPinned]: null }, + feed_mew: feedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, true); +}); - // Notifications should be orderded by action time descending (newest first) - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyAgentUnfollowed]: null }, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyAgentFollowed]: null }, - }); +it("notifications include my mews' replies, quotes, mewmews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies to Alice's mew + const replyInput: Mew = { + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob mewmews Alice's mew + const mewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }; + const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewmewInput, + }); + const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmewActionHash, + }); + + // Bob quotes Alice's mew + const quoteInput: Mew = { + text: "a response to a quoted mew", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }; + const quoteActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: quoteInput, + }); + const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quoteActionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: quoteFeedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: mewmewFeedMew, + }); + expect(notifications[2]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(3); + }, true); +}); - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, true); - }); +it("notifications include replies, quotes, mewmews to mews that I also responded to", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Carol creates a Mew + const actionHash: ActionHash = await createMew(carol.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice reply's to Carol's mew + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }, + }); + + // Bob replies to Carol's mew + const replyInput: Mew = { + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob mewmews Carol's mew + const mewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }; + const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewmewInput, + }); + const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmewActionHash, + }); + + // Bob quotes Carol's mew + const quoteInput: Mew = { + text: "a response to a quoted mew", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }; + const quoteActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: quoteInput, + }); + const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quoteActionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: quoteFeedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: mewmewFeedMew, + }); + expect(notifications[2]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: replyFeedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(3); + }, true); +}); - it("notifications include my mews' likes & unlikes", async () => { - await runScenario(async (scenario) => { +it("notifications list is time-paginated", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -96,642 +484,252 @@ describe.concurrent("agent-to-notifications", () => { // Alice creates a Mew const actionHash: ActionHash = await createMew(alice.cells[0]); assert.ok(actionHash); - const feedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob likes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - // Bob unlikes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: bob.agentPubKey, - target_hash: actionHash, - }, - }); await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ + // Bob replies to Alice's mew + const replyInput: Mew = { + text: "xyxyxyxy test reply 1", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewUnlicked]: null }, - feed_mew: feedMew, + fn_name: "create_mew", + payload: replyInput, }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewLicked]: null }, - feed_mew: feedMew, + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, }); - // Alice gets notifications count - const count = await alice.cells[0].callZome({ + // Bob replies to Alice's mew + const replyInput2: Mew = { + text: "xyxyxyxy test reply 2", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash2: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, + fn_name: "create_mew", + payload: replyInput2, }); - expect(count).toEqual(2); - }, true); - }); - - it("notifications include my mews' pins & unpins", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - const feedMew: FeedMew = await alice.cells[0].callZome({ + const replyFeedMew2: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob likes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "add_hash_for_pinner", - payload: { - base_pinner: bob.agentPubKey, - target_hash: actionHash, - }, + payload: replyActionHash2, }); - // Bob unlikes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "remove_hash_for_pinner", - payload: { - base_pinner: bob.agentPubKey, - target_hash: actionHash, - }, + // Bob replies to Alice's mew + const replyInput3: Mew = { + text: "xyxyxyxy test reply 3", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash3: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput3, }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ + const replyFeedMew3: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, + fn_name: "get_mew_with_context", + payload: replyActionHash3, }); - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewUnpinned]: null }, - feed_mew: feedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewPinned]: null }, - feed_mew: feedMew, + // Bob replies to Alice's mew + const replyInput4: Mew = { + text: "xyxyxyxy test reply 4", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash4: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput4, }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ + const replyFeedMew4: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, + fn_name: "get_mew_with_context", + payload: replyActionHash4, }); - expect(count).toEqual(2); - }, true); - }); - - it("notifications include my mews' replies, quotes, mewmews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); // Bob replies to Alice's mew - const replyInput: Mew = { - text: "test reply 12345", + const replyInput5: Mew = { + text: "xyxyxyxy test reply 5", links: [], mew_type: { [MewTypeName.Reply]: actionHash }, }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ + const replyActionHash5: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: replyInput, + payload: replyInput5, }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + const replyFeedMew5: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: replyActionHash, + payload: replyActionHash5, }); - // Bob mewmews Alice's mew - const mewmewInput: Mew = { - text: "", + // Bob replies to Alice's mew + const replyInput6: Mew = { + text: "xyxyxyxy test reply 6", links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, + mew_type: { [MewTypeName.Reply]: actionHash }, }; - const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ + const replyActionHash6: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: mewmewInput, + payload: replyInput6, }); - const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + const replyFeedMew6: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: mewmewActionHash, + payload: replyActionHash6, }); - // Bob quotes Alice's mew - const quoteInput: Mew = { - text: "a response to a quoted mew", + // Bob replies to Alice's mew + const replyInput7: Mew = { + text: "xyxyxyxy test reply 7", links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, + mew_type: { [MewTypeName.Reply]: actionHash }, }; - const quoteActionHash: ActionHash = await bob.cells[0].callZome({ + const replyActionHash7: ActionHash = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: quoteInput, + payload: replyInput7, }); - const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ + const replyFeedMew7: FeedMew = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: quoteActionHash, + payload: replyActionHash7, }); await dhtSync([alice, bob], alice.cells[0].cell_id[0]); // Alice gets notifications - const notifications = await alice.cells[0].callZome({ + const page1 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_notifications", - payload: null, + payload: { + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, }); - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: quoteFeedMew, - }); - expect(notifications[1]).toMatchObject({ + // Notifications should be orderded by action time descending (newest first) + expect(page1[0]).toMatchObject({ agent: bob.agentPubKey, notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: mewmewFeedMew, + feed_mew: replyFeedMew7, }); - expect(notifications[2]).toMatchObject({ + expect(page1[1]).toMatchObject({ agent: bob.agentPubKey, notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, + feed_mew: replyFeedMew6, }); - expect(count).toEqual(3); - }, true); - }); - - it("notifications include replies, quotes, mewmews to mews that I also responded to", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - // Carol creates a Mew - const actionHash: ActionHash = await createMew(carol.cells[0]); - assert.ok(actionHash); + expect(page1[0].timestamp).greaterThanOrEqual(page1[1].timestamp); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice reply's to Carol's mew - await alice.cells[0].callZome({ + // Alice gets notifications + const page2 = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "create_mew", + fn_name: "get_my_notifications", payload: { - text: "test reply 12345", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, + after_timestamp: page1[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, }, }); - // Bob replies to Carol's mew - const replyInput: Mew = { - text: "test reply 12345", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, + // Notifications should be orderded by action time descending (newest first) + expect(page2[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew5, }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, + expect(page2[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew4, }); - // Bob mewmews Carol's mew - const mewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }; - const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewmewInput, - }); - const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp); + + // Alice gets notifications + const page3 = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmewActionHash, + fn_name: "get_my_notifications", + payload: { + after_timestamp: page2[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, }); - // Bob quotes Carol's mew - const quoteInput: Mew = { - text: "a response to a quoted mew", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }; - const quoteActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: quoteInput, + // Notifications should be orderded by action time descending (newest first) + expect(page3[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew3, }); - const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quoteActionHash, + expect(page3[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew2, }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp) + .greaterThanOrEqual(page3[0].timestamp) + .greaterThanOrEqual(page3[1].timestamp); // Alice gets notifications - const notifications = await alice.cells[0].callZome({ + const page4 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: quoteFeedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, + payload: { + after_timestamp: page3[1].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, }, - feed_mew: mewmewFeedMew, }); - expect(notifications[2]).toMatchObject({ + + // Notifications should be orderded by action time descending (newest first) + assert.lengthOf(page4, 1); + expect(page4[0]).toMatchObject({ agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, feed_mew: replyFeedMew, }); - // Alice gets notifications count - const count = await alice.cells[0].callZome({ + expect(page1[0].timestamp) + .greaterThanOrEqual(page1[1].timestamp) + .greaterThanOrEqual(page2[0].timestamp) + .greaterThanOrEqual(page2[1].timestamp) + .greaterThanOrEqual(page3[0].timestamp) + .greaterThanOrEqual(page3[1].timestamp) + .greaterThanOrEqual(page4[0].timestamp); + + const page5 = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, + fn_name: "get_my_notifications", + payload: { + after_timestamp: page4[0].timestamp, + direction: { [PaginationDirectionName.Descending]: null }, + limit: 2, + }, }); - expect(count).toEqual(3); - }, true); - }); - - it("notifications list is time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies to Alice's mew - const replyInput: Mew = { - text: "xyxyxyxy test reply 1", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, - }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, - }); - - // Bob replies to Alice's mew - const replyInput2: Mew = { - text: "xyxyxyxy test reply 2", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash2: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput2, - }); - const replyFeedMew2: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash2, - }); - - // Bob replies to Alice's mew - const replyInput3: Mew = { - text: "xyxyxyxy test reply 3", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash3: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput3, - }); - const replyFeedMew3: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash3, - }); - - // Bob replies to Alice's mew - const replyInput4: Mew = { - text: "xyxyxyxy test reply 4", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash4: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput4, - }); - const replyFeedMew4: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash4, - }); - - // Bob replies to Alice's mew - const replyInput5: Mew = { - text: "xyxyxyxy test reply 5", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash5: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput5, - }); - const replyFeedMew5: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash5, - }); - - // Bob replies to Alice's mew - const replyInput6: Mew = { - text: "xyxyxyxy test reply 6", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash6: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput6, - }); - const replyFeedMew6: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash6, - }); - - // Bob replies to Alice's mew - const replyInput7: Mew = { - text: "xyxyxyxy test reply 7", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash7: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput7, - }); - const replyFeedMew7: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash7, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const page1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page1[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew7, - }); - expect(page1[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew6, - }); - - expect(page1[0].timestamp).greaterThanOrEqual(page1[1].timestamp); - - // Alice gets notifications - const page2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page1[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page2[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew5, - }); - expect(page2[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew4, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp); - - // Alice gets notifications - const page3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page2[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(page3[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew3, - }); - expect(page3[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew2, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp) - .greaterThanOrEqual(page3[0].timestamp) - .greaterThanOrEqual(page3[1].timestamp); - - // Alice gets notifications - const page4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page3[1].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - // Notifications should be orderded by action time descending (newest first) - assert.lengthOf(page4, 1); - expect(page4[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew, - }); - - expect(page1[0].timestamp) - .greaterThanOrEqual(page1[1].timestamp) - .greaterThanOrEqual(page2[0].timestamp) - .greaterThanOrEqual(page2[1].timestamp) - .greaterThanOrEqual(page3[0].timestamp) - .greaterThanOrEqual(page3[1].timestamp) - .greaterThanOrEqual(page4[0].timestamp); - - const page5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: { - after_timestamp: page4[0].timestamp, - direction: { [PaginationDirectionName.Descending]: null }, - limit: 2, - }, - }); - - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); - }); + + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); diff --git a/tests/src/mewsfeed/mews/dna-properties.test.ts b/tests/src/mewsfeed/mews/dna-properties.test.ts index e0379043..5a26fdd5 100644 --- a/tests/src/mewsfeed/mews/dna-properties.test.ts +++ b/tests/src/mewsfeed/mews/dna-properties.test.ts @@ -1,111 +1,154 @@ import { ActionHash } from "@holochain/client"; import { runScenario } from "@holochain/tryorama"; -import { assert, describe, expect, it } from "vitest"; +import { assert, expect, it } from "vitest"; import { Mew, MewTypeName } from "../../../../ui/src/types/types.js"; import { mewsfeedAppBundleSource, mewsfeedAppBundleSourceNoLengthLimits, } from "../../common.js"; -describe.concurrent("dna-properties", () => { - it("Mew must not be longer than DNA property mew_characters_max chars", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); +it("Mew must not be longer than DNA property mew_characters_max chars", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const createMewInput: Mew = { + text: new Array(200).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length" + ); - const createMewInput: Mew = { - text: new Array(200).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ + createMewInput.text = new Array(201).fill("a").join(""); + try { + await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", payload: createMewInput, }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length" - ); - - createMewInput.text = new Array(201).fill("a").join(""); - try { - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.fail("mew content longer than mew_characters_max is valid"); - } catch (error) { - assert.ok( - true, - "mew content longer than mew_characters_max is invalid" - ); - } - }, true); - }); - - it("Mew must not be shorter than DNA property mew_characters_min chars", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); + assert.fail("mew content longer than mew_characters_max is valid"); + } catch (error) { + assert.ok(true, "mew content longer than mew_characters_max is invalid"); + } + }, true); +}); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); +it("Mew must not be shorter than DNA property mew_characters_min chars", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const createMewInput: Mew = { + text: new Array(10).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length" + ); - const createMewInput: Mew = { - text: new Array(10).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ + createMewInput.text = new Array(2).fill("a").join(""); + try { + await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", payload: createMewInput, }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length" - ); - - createMewInput.text = new Array(2).fill("a").join(""); - try { - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.fail("mew content shorter than mew_characters_min is valid"); - } catch (error) { - assert.ok( - true, - "mew content shorter than mew_characters_min is invalid" - ); - } - }, true); - }); - - it("Mew can be any length if DNA property mew_characters_min and mew_characters_max not set", async () => { - await runScenario(async (scenario) => { + assert.fail("mew content shorter than mew_characters_min is valid"); + } catch (error) { + assert.ok(true, "mew content shorter than mew_characters_min is invalid"); + } + }, true); +}); + +it("Mew can be any length if DNA property mew_characters_min and mew_characters_max not set", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { + appBundleSource: mewsfeedAppBundleSourceNoLengthLimits, + }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // 0 charactres + const createMewInput2: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash2: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + assert.deepEqual( + action_hash2.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length 0" + ); + + // 1000 charactres + const createMewInput3: Mew = { + text: new Array(1000).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash3: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + assert.deepEqual( + action_hash3.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length 1000" + ); + }, true); +}); + +it("Can get deserialized DNA Properties", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed - const appSource = { - appBundleSource: mewsfeedAppBundleSourceNoLengthLimits, - }; + const appSource = { appBundleSource: mewsfeedAppBundleSource }; // Add 2 players with the test app to the Scenario. The returned players // can be destructured. @@ -115,66 +158,15 @@ describe.concurrent("dna-properties", () => { // conductor of the scenario. await scenario.shareAllAgents(); - // 0 charactres - const createMewInput2: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash2: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - assert.deepEqual( - action_hash2.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length 0" - ); - - // 1000 charactres - const createMewInput3: Mew = { - text: new Array(1000).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash3: ActionHash = await alice.cells[0].callZome({ + const properties = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, + fn_name: "get_dna_properties", + payload: null, }); - assert.deepEqual( - action_hash3.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length 1000" - ); - }, true); - }); - - it("Can get deserialized DNA Properties", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const properties = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_dna_properties", - payload: null, - }); - expect(properties).toHaveProperty("mew_characters_min", 5); - expect(properties).toHaveProperty("mew_characters_max", 200); - }, - true, - { timeout: 500000 } - ); - }); + expect(properties).toHaveProperty("mew_characters_min", 5); + expect(properties).toHaveProperty("mew_characters_max", 200); + }, + true, + { timeout: 500000 } + ); }); diff --git a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts index ab46d6bb..2fddd59b 100644 --- a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts +++ b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts @@ -1,62 +1,402 @@ import { ActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -import { assert, describe, expect, it } from "vitest"; +import { assert, expect, it } from "vitest"; import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -describe.concurrent("followed-creators-mews", () => { - it("create a Mew and get followed creators mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; +it("create a Mew and get followed creators mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Bob follows alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + // Bob gets followed creators mews + let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.equal(collectionOutput.length, 0); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets followed creators mews again + collectionOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + + assert.equal(collectionOutput.length, 1); + assert.deepEqual(actionHash, collectionOutput[0].action_hash); + }, true); +}); - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); +it("Followed creators mews should include mews of followed creator", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = "test-mew"; + const mewInput: Mew = { + text: mewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewInput, + }); + + const bobMewsFeedInitial: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + bobMewsFeedInitial.length === 0, + "bob's mews feed is initially empty" + ); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal( + bobMewsFeed[0].mew.text, + mewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + }, true); +}); - // Bob follows alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); +it("Followed creators mews should include own mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewsFeedInitial: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeedInitial.length === 0, + "alice's mews feed is initially empty" + ); - // Bob gets followed creators mews - let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.equal(collectionOutput.length, 0); + const mewContent = "test-mew"; + const mewInput: Mew = { + text: mewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewInput, + }); + + const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(aliceMewsFeed.length === 1, "alice's mews feed includes her mew"); + assert.equal(aliceMewsFeed[0].mew.text, mewContent, "mew content matches"); + }, true); +}); - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); +it("Followed creators mews should not include mews of non-followed creator", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const carolMewContent = "carol-test-mew"; + const carolMewInput: Mew = { + text: carolMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await carol.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: carolMewInput, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal( + bobMewsFeed[0].mew.text, + aliceMewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + }, true); +}); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); +it("Unfollowing should exclude creators mews from feed", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const bobMewsFeedWhenFollowing: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + bobMewsFeedWhenFollowing.length === 1, + "bob's mews feed includes 1 mew" + ); + assert.equal( + bobMewsFeedWhenFollowing[0].mew.text, + aliceMewContent, + "mew content in bob's mews feed matches alice's mew content" + ); - // Bob gets followed creators mews again - collectionOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "unfollow", + payload: alice.agentPubKey, + }); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 0, "bob's mews feed is empty"); + }, true); +}); - assert.equal(collectionOutput.length, 1); - assert.deepEqual(actionHash, collectionOutput[0].action_hash); - }, true); - }); +it("Followed creators mews should be ordered by timestamp in descending order", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const firstMewContent = "first-test-mew"; + const firstMewInput: Mew = { + text: firstMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: firstMewInput, + }); + + const secondMewContent = "second-test-mew"; + const secondMewInput: Mew = { + text: secondMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: secondMewInput, + }); + + const thirdMewContent = "third-test-mew"; + const thirdMewInput: Mew = { + text: thirdMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await carol.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: thirdMewInput, + }); + + const fourthMewContent = "fourth-test-mew"; + const fourthMewInput: Mew = { + text: fourthMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: fourthMewInput, + }); + // alice starts following bob and carol + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: bob.agentPubKey, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: carol.agentPubKey, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeed.length === 4, + "alice's mews feed includes all 4 mews" + ); + assert.equal( + aliceMewsFeed[0].mew.text, + fourthMewContent, + "mew 1 in feed is fourth mew" + ); + assert.equal( + aliceMewsFeed[1].mew.text, + thirdMewContent, + "mew 2 in feed is third mew" + ); + assert.equal( + aliceMewsFeed[2].mew.text, + secondMewContent, + "mew 3 in feed is second mew" + ); + assert.equal( + aliceMewsFeed[3].mew.text, + firstMewContent, + "mew 4 in feed is first mew" + ); + }, true); +}); - it("Followed creators mews should include mews of followed creator", async () => { - await runScenario(async (scenario) => { +it("Followed creators mews list are time-paginated", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -71,188 +411,88 @@ describe.concurrent("followed-creators-mews", () => { // conductor of the scenario. await scenario.shareAllAgents(); - const mewContent = "test-mew"; - const mewInput: Mew = { - text: mewContent, + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, links: [], mew_type: { [MewTypeName.Original]: null }, }; - await alice.cells[0].callZome({ + const mewActionHash1 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: mewInput, - }); - - const bobMewsFeedInitial: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - bobMewsFeedInitial.length === 0, - "bob's mews feed is initially empty" - ); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, + payload: createMewInput1, }); - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); - assert.equal( - bobMewsFeed[0].mew.text, - mewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - }, true); - }); - - it("Followed creators mews should include own mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewsFeedInitial: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - aliceMewsFeedInitial.length === 0, - "alice's mews feed is initially empty" - ); - - const mewContent = "test-mew"; - const mewInput: Mew = { - text: mewContent, + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, links: [], mew_type: { [MewTypeName.Original]: null }, }; - await alice.cells[0].callZome({ + const mewActionHash2 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: mewInput, + payload: createMewInput2, }); - const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, + fn_name: "create_mew", + payload: createMewInput3, }); - assert.ok( - aliceMewsFeed.length === 1, - "alice's mews feed includes her mew" - ); - assert.equal( - aliceMewsFeed[0].mew.text, - mewContent, - "mew content matches" - ); - }, true); - }); - - it("Followed creators mews should not include mews of non-followed creator", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, links: [], mew_type: { [MewTypeName.Original]: null }, }; - await alice.cells[0].callZome({ + const mewActionHash4 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: aliceMewInput, + payload: createMewInput4, }); - const carolMewContent = "carol-test-mew"; - const carolMewInput: Mew = { - text: carolMewContent, + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, links: [], mew_type: { [MewTypeName.Original]: null }, }; - await carol.cells[0].callZome({ + const mewActionHash5 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: carolMewInput, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, + payload: createMewInput5, }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, + fn_name: "create_mew", + payload: createMewInput6, }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); - assert.equal( - bobMewsFeed[0].mew.text, - aliceMewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - }, true); - }); - - it("Unfollowing should exclude creators mews from feed", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, links: [], mew_type: { [MewTypeName.Original]: null }, }; - await alice.cells[0].callZome({ + const mewActionHash7 = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: aliceMewInput, + payload: createMewInput7, }); await bob.cells[0].callZome({ @@ -260,337 +500,88 @@ describe.concurrent("followed-creators-mews", () => { fn_name: "follow", payload: alice.agentPubKey, }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - const bobMewsFeedWhenFollowing: FeedMew[] = await bob.cells[0].callZome({ + const page1: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_followed_creators_mews_with_context", - payload: null, + payload: { + limit: 2, + }, }); - assert.ok( - bobMewsFeedWhenFollowing.length === 1, - "bob's mews feed includes 1 mew" - ); - assert.equal( - bobMewsFeedWhenFollowing[0].mew.text, - aliceMewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "unfollow", - payload: alice.agentPubKey, - }); + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + const page2: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_followed_creators_mews_with_context", - payload: null, + payload: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, }); - assert.ok(bobMewsFeed.length === 0, "bob's mews feed is empty"); - }, true); - }); - it("Followed creators mews should be ordered by timestamp in descending order", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const firstMewContent = "first-test-mew"; - const firstMewInput: Mew = { - text: firstMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: firstMewInput, - }); - - const secondMewContent = "second-test-mew"; - const secondMewInput: Mew = { - text: secondMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await bob.cells[0].callZome({ + const page3: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "create_mew", - payload: secondMewInput, + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, + }, }); - const thirdMewContent = "third-test-mew"; - const thirdMewInput: Mew = { - text: thirdMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await carol.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: thirdMewInput, - }); + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); - const fourthMewContent = "fourth-test-mew"; - const fourthMewInput: Mew = { - text: fourthMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ + const page4: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", - fn_name: "create_mew", - payload: fourthMewInput, - }); - // alice starts following bob and carol - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: bob.agentPubKey, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: carol.agentPubKey, + fn_name: "get_my_followed_creators_mews_with_context", + payload: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, + }, }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_my_followed_creators_mews_with_context", - payload: null, + payload: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, }); - assert.ok( - aliceMewsFeed.length === 4, - "alice's mews feed includes all 4 mews" - ); - assert.equal( - aliceMewsFeed[0].mew.text, - fourthMewContent, - "mew 1 in feed is fourth mew" - ); - assert.equal( - aliceMewsFeed[1].mew.text, - thirdMewContent, - "mew 2 in feed is third mew" - ); - assert.equal( - aliceMewsFeed[2].mew.text, - secondMewContent, - "mew 3 in feed is second mew" - ); - assert.equal( - aliceMewsFeed[3].mew.text, - firstMewContent, - "mew 4 in feed is first mew" - ); - }, true); - }); - - it("Followed creators mews list are time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const page1: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - limit: 2, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - }, - }); - - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); - }); + + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); diff --git a/tests/src/mewsfeed/mews/mention-to-mews.test.ts b/tests/src/mewsfeed/mews/mention-to-mews.test.ts index 8f439987..43d8da4f 100644 --- a/tests/src/mewsfeed/mews/mention-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/mention-to-mews.test.ts @@ -1,6 +1,6 @@ import { ActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -import { assert, describe, expect, it } from "vitest"; +import { assert, expect, it } from "vitest"; import { FeedMew, LinkTargetName, @@ -10,259 +10,257 @@ import { import { mewsfeedAppBundleSource } from "../../common.js"; import { createMew } from "./common.js"; -describe.concurrent("mention-to-mews", () => { - it("mention in mews", async () => { - await runScenario(async (scenario) => { +it("mention in mews", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + await createMew(alice.cells[0], { + text: "this is for @bob", + links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], + mew_type: { Original: null }, + }); + + const actionHash2: ActionHash = await createMew(bob.cells[0], { + text: "this is for @bob 2", + links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], + mew_type: { Original: null }, + }); + + const actionHash3: ActionHash = await createMew(alice.cells[0], { + text: "this is for @alice", + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { Original: null }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const mentionedMewsBob: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: bob.agentPubKey, + }, + }); + assert.ok(mentionedMewsBob.length === 2, "one mew with mention"); + assert.deepEqual(mentionedMewsBob[0].action_hash, actionHash2); + + const mentionedMewsAlice: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + }, + }); + assert.ok(mentionedMewsAlice.length === 1, "one mew with mention"); + assert.deepEqual(mentionedMewsAlice[0].action_hash, actionHash3); + }, true); +}); + +it("Mentions list are time-paginated", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; // Add 2 players with the test app to the Scenario. The returned players // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); + const [alice] = await scenario.addPlayersWithApps([appSource]); // Shortcut peer discovery through gossip and register all agents in every // conductor of the scenario. await scenario.shareAllAgents(); - await createMew(alice.cells[0], { - text: "this is for @bob", - links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], - mew_type: { Original: null }, + const mewContent1 = "My Mew with @mention 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with @mention 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with @mention 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, }); - const actionHash2: ActionHash = await createMew(bob.cells[0], { - text: "this is for @bob 2", - links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], - mew_type: { Original: null }, + const mewContent4 = "My Mew with @mention 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, }); - const actionHash3: ActionHash = await createMew(alice.cells[0], { - text: "this is for @alice", + const mewContent5 = "My Mew with @mention 5"; + const createMewInput5: Mew = { + text: mewContent5, links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { Original: null }, + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + const mewContent6 = "My Mew with @mention 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); - const mentionedMewsBob: FeedMew[] = await alice.cells[0].callZome({ + const mewContent7 = "My Mew with @mention 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: bob.agentPubKey, - }, + fn_name: "create_mew", + payload: createMewInput7, }); - assert.ok(mentionedMewsBob.length === 2, "one mew with mention"); - assert.deepEqual(mentionedMewsBob[0].action_hash, actionHash2); - const mentionedMewsAlice: FeedMew[] = await alice.cells[0].callZome({ + const page1: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_mews_for_mention_with_context", payload: { mention: alice.agentPubKey, + page: { + start_time: null, + limit: 2, + }, }, }); - assert.ok(mentionedMewsAlice.length === 1, "one mew with mention"); - assert.deepEqual(mentionedMewsAlice[0].action_hash, actionHash3); - }, true); - }); - - it("Mentions list are time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with @mention 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with @mention 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with @mention 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with @mention 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with @mention 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with @mention 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with @mention 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - start_time: null, - limit: 2, - }, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - }, + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - }, + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page2[page2.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - }, + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + page: { + after_hash: page3[page3.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - }, + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, }, - }); + }, + }); - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); - }); + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); diff --git a/tests/src/mewsfeed/mews/mew-to-responses.test.ts b/tests/src/mewsfeed/mews/mew-to-responses.test.ts index ea01b686..c63f81ea 100644 --- a/tests/src/mewsfeed/mews/mew-to-responses.test.ts +++ b/tests/src/mewsfeed/mews/mew-to-responses.test.ts @@ -1,79 +1,149 @@ import { ActionHash } from "@holochain/client"; import { runScenario } from "@holochain/tryorama"; -import { assert, describe, expect, it } from "vitest"; +import { assert, expect, it } from "vitest"; import { FeedMew, Mew, MewTypeName } from "../../../../ui/src/types/types.js"; import { mewsfeedAppBundleSource } from "../../common.js"; -describe.concurrent("mew-to-responses", () => { - it("Agent can reply to a mew", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); +it("Agent can reply to a mew", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const aliceReplyContent = "alice-test-reply"; + const aliceReplyInput: Mew = { + text: aliceReplyContent, + links: [], + mew_type: { [MewTypeName.Reply]: action_hash }, + }; + const reply_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceReplyInput, + }); + + const replyMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: reply_action_hash, + }); + assert.ok(MewTypeName.Reply in replyMew.mew.mew_type, "mew is a reply"); + assert.equal( + replyMew.mew.text, + aliceReplyContent, + "reply is alice's reply" + ); - const aliceReplyContent = "alice-test-reply"; - const aliceReplyInput: Mew = { - text: aliceReplyContent, - links: [], - mew_type: { [MewTypeName.Reply]: action_hash }, - }; - const reply_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceReplyInput, - }); + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); + assert.ok(originalMew.replies_count === 1, "original mew has 1 reply"); + assert.isTrue( + originalMew.is_replied, + "original mew's reply is alice's reply" + ); + }, true); +}); - const replyMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: reply_action_hash, - }); - assert.ok(MewTypeName.Reply in replyMew.mew.mew_type, "mew is a reply"); - assert.equal( - replyMew.mew.text, - aliceReplyContent, - "reply is alice's reply" - ); +it("Agent can mewmew a mew, only once", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const aliceMewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: action_hash }, + }; + const mewmew_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewmewInput, + }); + + const mewmew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmew_action_hash, + }); + assert.ok(MewTypeName.Mewmew in mewmew.mew.mew_type, "mew is a mewmew"); + assert.deepEqual(mewmew.mew, aliceMewmewInput, "mewmew is alice's mewmew"); + + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); + assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); + assert.isTrue( + originalMew.is_mewmewed, + "original mew's mewmew is alice's mewmew" + ); - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.replies_count === 1, "original mew has 1 reply"); - assert.isTrue( - originalMew.is_replied, - "original mew's reply is alice's reply" - ); - }, true); - }); + // Mewmew the same mew again + const response = alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewmewInput, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + }, true); +}); - it("Agent can mewmew a mew, only once", async () => { - await runScenario(async (scenario) => { +it("Agent can quote a mew", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -97,28 +167,27 @@ describe.concurrent("mew-to-responses", () => { payload: aliceMewInput, }); - const aliceMewmewInput: Mew = { - text: "", + const aliceQuoteText = "alice-test-quote"; + const aliceQuoteInput: Mew = { + text: aliceQuoteText, links: [], - mew_type: { [MewTypeName.Mewmew]: action_hash }, + mew_type: { + [MewTypeName.Quote]: action_hash, + }, }; - const mewmew_action_hash: ActionHash = await alice.cells[0].callZome({ + const quote_action_hash: ActionHash = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", - payload: aliceMewmewInput, + payload: aliceQuoteInput, }); - const mewmew: FeedMew = await alice.cells[0].callZome({ + const quote: FeedMew = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "get_mew_with_context", - payload: mewmew_action_hash, + payload: quote_action_hash, }); - assert.ok(MewTypeName.Mewmew in mewmew.mew.mew_type, "mew is a mewmew"); - assert.deepEqual( - mewmew.mew, - aliceMewmewInput, - "mewmew is alice's mewmew" - ); + assert.ok(MewTypeName.Quote in quote.mew.mew_type, "mew is a quote"); + assert.equal(quote.mew.text, aliceQuoteText, "quote is alice's quote"); const originalMew: FeedMew = await alice.cells[0].callZome({ zome_name: "mews", @@ -130,92 +199,13 @@ describe.concurrent("mew-to-responses", () => { "mew is an original mew" ); assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); + assert.ok(originalMew.quotes_count === 1, "original mew has 1 quote"); assert.isTrue( - originalMew.is_mewmewed, - "original mew's mewmew is alice's mewmew" + originalMew.is_quoted, + "original mew's quote is alice's quote" ); - - // Mewmew the same mew again - const response = alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewmewInput, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - }, true); - }); - - it("Agent can quote a mew", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const aliceQuoteText = "alice-test-quote"; - const aliceQuoteInput: Mew = { - text: aliceQuoteText, - links: [], - mew_type: { - [MewTypeName.Quote]: action_hash, - }, - }; - const quote_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceQuoteInput, - }); - - const quote: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quote_action_hash, - }); - assert.ok(MewTypeName.Quote in quote.mew.mew_type, "mew is a quote"); - assert.equal(quote.mew.text, aliceQuoteText, "quote is alice's quote"); - - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal( - originalMew.mew.text, - aliceMewContent, - "mew is alice's mew" - ); - assert.ok(originalMew.quotes_count === 1, "original mew has 1 quote"); - assert.isTrue( - originalMew.is_quoted, - "original mew's quote is alice's quote" - ); - }, - true, - { timeout: 500000 } - ); - }); + }, + true, + { timeout: 500000 } + ); }); diff --git a/tests/src/mewsfeed/mews/mew-with-context.test.ts b/tests/src/mewsfeed/mews/mew-with-context.test.ts index 270f07e3..7b93cd4b 100644 --- a/tests/src/mewsfeed/mews/mew-with-context.test.ts +++ b/tests/src/mewsfeed/mews/mew-with-context.test.ts @@ -1,348 +1,346 @@ import { ActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -import { assert, describe, expect, it } from "vitest"; +import { assert, expect, it } from "vitest"; import { FeedMew, MewTypeName } from "../../../../ui/src/types/types"; import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; -describe.concurrent("mew-with-context", () => { - it("Mew with context contains licks count and is_licked", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob licks the mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "like", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - let feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.licks_count).toEqual(1); - expect(feedMew.is_licked).true; - - // Alice gets the mew with context - let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.licks_count).toEqual(1); - expect(aliceFeedMew.is_licked).false; - - // Bob unlicks the mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "unlike", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - feedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.licks_count).toEqual(0); - expect(feedMew.is_licked).false; - - // Alice gets the mew with context - aliceFeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.licks_count).toEqual(0); - expect(aliceFeedMew.is_licked).false; - }, - true, - { timeout: 100000 } - ); - }); - - it("Mew with context contains replies count and is_replied", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies the mew - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "my reply blah blah", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - const feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.replies_count).toEqual(1); - expect(feedMew.is_replied).true; - - // Alice gets the mew with context - const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.replies_count).toEqual(1); - expect(aliceFeedMew.is_replied).false; - }, - true, - { timeout: 100000 } - ); - }); - - it("Mew with context contains quotes count and is_quoted", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies the mew - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "this is a quote blah blah", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - const feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.quotes_count).toEqual(1); - expect(feedMew.is_quoted).true; - - // Alice gets the mew with context - const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.quotes_count).toEqual(1); - expect(aliceFeedMew.is_quoted).false; - }, - true, - { timeout: 100000 } - ); - }); - - it("Mew with context contains mewmews count and is_mewmewed", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob mewmews the mew - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - const feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.mewmews_count).toEqual(1); - expect(feedMew.is_mewmewed).true; - console.warn("bob got mew"); - - // Alice gets the mew with context - const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - console.warn("alice got mew"); - - expect(aliceFeedMew.mewmews_count).toEqual(1); - expect(aliceFeedMew.is_mewmewed).false; - }, - true, - { timeout: 100000 } - ); - }); - - it("Mew with context contains is_pinned", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob pins the mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - let feedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.is_pinned).true; - - // Alice gets the mew with context - let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.is_pinned).false; - - // Bob unpins the mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the mew with context - feedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(feedMew.is_pinned).false; - - // Alice gets the mew with context - aliceFeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - expect(aliceFeedMew.is_pinned).false; - }, - true, - { timeout: 500000 } - ); - }); -// }); +it("Mew with context contains licks count and is_licked", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob licks the mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "like", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + let feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.licks_count).toEqual(1); + expect(feedMew.is_licked).true; + + // Alice gets the mew with context + let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.licks_count).toEqual(1); + expect(aliceFeedMew.is_licked).false; + + // Bob unlicks the mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "unlike", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + feedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.licks_count).toEqual(0); + expect(feedMew.is_licked).false; + + // Alice gets the mew with context + aliceFeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.licks_count).toEqual(0); + expect(aliceFeedMew.is_licked).false; + }, + true, + { timeout: 100000 } + ); +}); + +it("Mew with context contains replies count and is_replied", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies the mew + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "my reply blah blah", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + const feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.replies_count).toEqual(1); + expect(feedMew.is_replied).true; + + // Alice gets the mew with context + const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.replies_count).toEqual(1); + expect(aliceFeedMew.is_replied).false; + }, + true, + { timeout: 100000 } + ); +}); + +it("Mew with context contains quotes count and is_quoted", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies the mew + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "this is a quote blah blah", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + const feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.quotes_count).toEqual(1); + expect(feedMew.is_quoted).true; + + // Alice gets the mew with context + const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.quotes_count).toEqual(1); + expect(aliceFeedMew.is_quoted).false; + }, + true, + { timeout: 100000 } + ); +}); + +it("Mew with context contains mewmews count and is_mewmewed", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob mewmews the mew + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + const feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.mewmews_count).toEqual(1); + expect(feedMew.is_mewmewed).true; + console.warn("bob got mew"); + + // Alice gets the mew with context + const aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + console.warn("alice got mew"); + + expect(aliceFeedMew.mewmews_count).toEqual(1); + expect(aliceFeedMew.is_mewmewed).false; + }, + true, + { timeout: 100000 } + ); +}); + +it("Mew with context contains is_pinned", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob pins the mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + let feedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.is_pinned).true; + + // Alice gets the mew with context + let aliceFeedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.is_pinned).false; + + // Bob unpins the mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the mew with context + feedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(feedMew.is_pinned).false; + + // Alice gets the mew with context + aliceFeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + expect(aliceFeedMew.is_pinned).false; + }, + true, + { timeout: 500000 } + ); +}); diff --git a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts index 49e48992..89f9a436 100644 --- a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts @@ -1,78 +1,76 @@ import { ActionHash } from "@holochain/client"; import { dhtSync, runScenario } from "@holochain/tryorama"; -import { assert, describe, it } from "vitest"; +import { assert, it } from "vitest"; import { FeedMew } from "../../../../ui/src/types/types.js"; import { createMew } from "./common.js"; -describe.concurrent("pinner-to-mews", () => { - it("link a Pinner to a Mew", async () => { - await runScenario( - async (scenario) => { - // Construct proper paths for your app. - // This assumes app bundle created by the `hc app pack` command. - const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; +it("link a Pinner to a Mew", async () => { + await runScenario( + async (scenario) => { + // Construct proper paths for your app. + // This assumes app bundle created by the `hc app pack` command. + const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; - // Set up the app to be installed - const appSource = { appBundleSource: { path: testAppPath } }; + // Set up the app to be installed + const appSource = { appBundleSource: { path: testAppPath } }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - const baseAddress = alice.agentPubKey; - const targetActionHash: ActionHash = await createMew(alice.cells[0]); + const baseAddress = alice.agentPubKey; + const targetActionHash: ActionHash = await createMew(alice.cells[0]); - // Bob gets the links, should be empty - let linksOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); + // Bob gets the links, should be empty + let linksOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); - // Alice creates a link from Pinner to Mew - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "pin_hash", - payload: targetActionHash, - }); + // Alice creates a link from Pinner to Mew + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "pin_hash", + payload: targetActionHash, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 1); - assert.deepEqual(targetActionHash, linksOutput[0].action_hash); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 1); + assert.deepEqual(targetActionHash, linksOutput[0].action_hash); - await alice.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "unpin_hash", - payload: targetActionHash, - }); + await alice.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "unpin_hash", + payload: targetActionHash, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_pinner_with_context", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - }, - true, - { timeout: 500000 } - ); - }); + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_pinner_with_context", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + }, + true, + { timeout: 500000 } + ); }); diff --git a/tests/src/mewsfeed/mews/tags-to-mews.test.ts b/tests/src/mewsfeed/mews/tags-to-mews.test.ts index 01a1deff..3867bf43 100644 --- a/tests/src/mewsfeed/mews/tags-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/tags-to-mews.test.ts @@ -1,6 +1,6 @@ import { ActionHash } from "@holochain/client"; import { runScenario } from "@holochain/tryorama"; -import { assert, describe, expect, it } from "vitest"; +import { assert, expect, it } from "vitest"; import { FeedMew, LinkTargetName, @@ -10,184 +10,368 @@ import { } from "../../../../ui/src/types/types.js"; import { mewsfeedAppBundleSource } from "../../common.js"; -describe.concurrent("tags-to-mews", () => { - it("Hashtag, cashtag and mention", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); +it("Hashtag, cashtag and mention", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = + "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; + const createMewInput: Mew = { + text: mewContent, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a valid mew" + ); - const mewContent = - "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; - const createMewInput: Mew = { - text: mewContent, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; + const hashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + }, + }); + assert.ok(hashtaggedMews.length === 1, "one mew with hashtag"); + assert.equal(hashtaggedMews[0].mew.text, mewContent, "mew content matches"); + + const arabicHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#سعيدة", + }, + }); + assert.ok(arabicHashtaggedMews.length === 1, "one mew with arabic hashtag"); + assert.equal( + arabicHashtaggedMews[0].mew.text, + mewContent, + "mew content matches" + ); - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a valid mew" - ); + // get hashtag containing emojis -- invalid hashtag! + const emojiHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#😃😃😃", + }, + }); + assert.ok(emojiHashtaggedMews.length === 0, "no mew with emoji hashtag"); + + const cashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + }, + }); + assert.ok(cashtaggedMews.length === 1, "one mew with cashtag"); + + const mentionedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + }, + }); + assert.ok(mentionedMews.length === 1, "one mew with mention"); + }, true); +}); - const hashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - }, - }); - assert.ok(hashtaggedMews.length === 1, "one mew with hashtag"); - assert.equal( - hashtaggedMews[0].mew.text, - mewContent, - "mew content matches" - ); +it("Prefix index should return hashtags and cashtags", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = + "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; + const createMewInput: Mew = { + text: mewContent, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a valid mew" + ); - const arabicHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#سعيدة", - }, - }); - assert.ok( - arabicHashtaggedMews.length === 1, - "one mew with arabic hashtag" - ); - assert.equal( - arabicHashtaggedMews[0].mew.text, - mewContent, - "mew content matches" - ); + const hashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "has", + limit: 10, + }, + }); + assert.ok(hashtags.length === 1, "one hashtag"); + assert.equal(hashtags[0], "#hashtag", "hashtag search result matches"); + + const arabicHashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "سعيدة", + limit: 10, + }, + }); + assert.ok(arabicHashtags.length === 1, "one arabic hashtag"); + assert.equal(arabicHashtags[0], "#سعيدة", "hashtag search result matches"); + + // get hashtag containing emojis -- invalid hashtag! + const emojiHashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "😃😃😃", + limit: 10, + }, + }); + assert.ok(emojiHashtags.length === 0, "no emoji hashtags"); + + const cashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "cas", + limit: 10, + }, + }); + assert.ok(cashtags.length === 1, "one cashtag"); + assert.equal(cashtags[0], "$cashtag", "hashtag search result matches"); + }, true); +}); - // get hashtag containing emojis -- invalid hashtag! - const emojiHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#😃😃😃", +it("Hashtags list are time-paginated", async () => { + await runScenario(async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + limit: 2, }, - }); - assert.ok(emojiHashtaggedMews.length === 0, "no mew with emoji hashtag"); + }, + }); - const cashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - }, - }); - assert.ok(cashtaggedMews.length === 1, "one mew with cashtag"); + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); - const mentionedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, }, - }); - assert.ok(mentionedMews.length === 1, "one mew with mention"); - }, true); - }); - - it("Prefix index should return hashtags and cashtags", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = - "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; - const createMewInput: Mew = { - text: mewContent, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a valid mew" - ); - - const hashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "has", - limit: 10, + }, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page2[page1.length - 1].action_hash, + limit: 2, }, - }); - assert.ok(hashtags.length === 1, "one hashtag"); - assert.equal(hashtags[0], "#hashtag", "hashtag search result matches"); - - const arabicHashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "سعيدة", - limit: 10, + }, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page3[page1.length - 1].action_hash, + limit: 2, }, - }); - assert.ok(arabicHashtags.length === 1, "one arabic hashtag"); - assert.equal( - arabicHashtags[0], - "#سعيدة", - "hashtag search result matches" - ); - - // get hashtag containing emojis -- invalid hashtag! - const emojiHashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "😃😃😃", - limit: 10, + }, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, }, - }); - assert.ok(emojiHashtags.length === 0, "no emoji hashtags"); + }, + }); - const cashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "cas", - limit: 10, - }, - }); - assert.ok(cashtags.length === 1, "one cashtag"); - assert.equal(cashtags[0], "$cashtag", "hashtag search result matches"); - }, true); - }); + assert.lengthOf(page5, 0); + }, true); +}); - it("Hashtags list are time-paginated", async () => { - await runScenario(async (scenario) => { +it("Cashtags list are time-paginated", async () => { + await runScenario( + async (scenario) => { // Set up the app to be installed const appSource = { appBundleSource: mewsfeedAppBundleSource }; @@ -199,7 +383,7 @@ describe.concurrent("tags-to-mews", () => { // conductor of the scenario. await scenario.shareAllAgents(); - const mewContent1 = "My Mew with #hashtag 1"; + const mewContent1 = "My Mew with $cashtag 1"; const createMewInput1: Mew = { text: mewContent1, links: [], @@ -211,7 +395,7 @@ describe.concurrent("tags-to-mews", () => { payload: createMewInput1, }); - const mewContent2 = "My Mew with #hashtag 2"; + const mewContent2 = "My Mew with $cashtag 2"; const createMewInput2: Mew = { text: mewContent2, links: [], @@ -223,7 +407,7 @@ describe.concurrent("tags-to-mews", () => { payload: createMewInput2, }); - const mewContent3 = "My Mew with #hashtag 3"; + const mewContent3 = "My Mew with $cashtag 3"; const createMewInput3: Mew = { text: mewContent3, links: [], @@ -235,7 +419,7 @@ describe.concurrent("tags-to-mews", () => { payload: createMewInput3, }); - const mewContent4 = "My Mew with #hashtag 4"; + const mewContent4 = "My Mew with $cashtag 4"; const createMewInput4: Mew = { text: mewContent4, links: [], @@ -247,7 +431,7 @@ describe.concurrent("tags-to-mews", () => { payload: createMewInput4, }); - const mewContent5 = "My Mew with #hashtag 5"; + const mewContent5 = "My Mew with $cashtag 5"; const createMewInput5: Mew = { text: mewContent5, links: [], @@ -259,7 +443,7 @@ describe.concurrent("tags-to-mews", () => { payload: createMewInput5, }); - const mewContent6 = "My Mew with #hashtag 6"; + const mewContent6 = "My Mew with $cashtag 6"; const createMewInput6: Mew = { text: mewContent6, links: [], @@ -271,7 +455,7 @@ describe.concurrent("tags-to-mews", () => { payload: createMewInput6, }); - const mewContent7 = "My Mew with #hashtag 7"; + const mewContent7 = "My Mew with $cashtag 7"; const createMewInput7: Mew = { text: mewContent7, links: [], @@ -285,11 +469,13 @@ describe.concurrent("tags-to-mews", () => { const page1: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", + fn_name: "get_mews_for_cashtag_with_context", payload: { - hashtag: "#hashtag", + cashtag: "$cashtag", page: { + start_time: null, limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, }, }); @@ -302,12 +488,13 @@ describe.concurrent("tags-to-mews", () => { const page2: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", + fn_name: "get_mews_for_cashtag_with_context", payload: { - hashtag: "#hashtag", + cashtag: "$cashtag", page: { after_hash: page1[page1.length - 1].action_hash, limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, }, }); @@ -322,12 +509,13 @@ describe.concurrent("tags-to-mews", () => { const page3: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", + fn_name: "get_mews_for_cashtag_with_context", payload: { - hashtag: "#hashtag", + cashtag: "$cashtag", page: { - after_hash: page2[page1.length - 1].action_hash, + after_hash: page2[page2.length - 1].action_hash, limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, }, }); @@ -344,12 +532,13 @@ describe.concurrent("tags-to-mews", () => { const page4: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", + fn_name: "get_mews_for_cashtag_with_context", payload: { - hashtag: "#hashtag", + cashtag: "$cashtag", page: { - after_hash: page3[page1.length - 1].action_hash, + after_hash: page3[page3.length - 1].action_hash, limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, }, }); @@ -367,222 +556,20 @@ describe.concurrent("tags-to-mews", () => { const page5: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", + fn_name: "get_mews_for_cashtag_with_context", payload: { - hashtag: "#hashtag", + cashtag: "$cashtag", page: { after_hash: page4[page4.length - 1].action_hash, limit: 2, + order: { [PaginationDirectionName.Ascending]: null }, }, }, }); assert.lengthOf(page5, 0); - }, true); - }); - - it("Cashtags list are time-paginated", async () => { - await runScenario( - async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with $cashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with $cashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with $cashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with $cashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with $cashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with $cashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with $cashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - start_time: null, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page2[page2.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page3[page3.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, - order: { [PaginationDirectionName.Ascending]: null }, - }, - }, - }); - - assert.lengthOf(page5, 0); - }, - true, - { timeout: 500000 } - ); - }); + }, + true, + { timeout: 500000 } + ); }); From 87861d026a1b43aa765f45cc7da621d4cd1d0e34 Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Wed, 1 Nov 2023 13:57:58 -0600 Subject: [PATCH 13/22] ci: run debug session --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5be01931..ccfa4d1d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -64,5 +64,8 @@ jobs: target key: ${{ runner.os }}-build-${{ hashFiles('Cargo.lock') }} + - name: tmate session + uses: mxschmitt/action-tmate@v3 + - name: Test with tryorama run: nix develop -c $SHELL -c "npm run test" From ec46f0109b9199432fe7a6444e5ebb02c22721f1 Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Fri, 3 Nov 2023 19:04:56 -0600 Subject: [PATCH 14/22] reinstate 500000 ms timeout --- .../follows/follower-to-creators.test.ts | 580 ++++++------ .../mewsfeed/likes/liker-to-hashes.test.ts | 166 ++-- .../mews/agent-to-notifications.test.ts | 890 +++++++++--------- .../src/mewsfeed/mews/dna-properties.test.ts | 258 ++--- .../mews/followed-creators-mews.test.ts | 773 +++++++-------- .../src/mewsfeed/mews/mention-to-mews.test.ts | 98 +- .../mewsfeed/mews/mew-to-responses.test.ts | 128 +-- .../mewsfeed/mews/mew-with-context.test.ts | 8 +- tests/src/mewsfeed/mews/tags-to-mews.test.ts | 711 +++++++------- 9 files changed, 1868 insertions(+), 1744 deletions(-) diff --git a/tests/src/mewsfeed/follows/follower-to-creators.test.ts b/tests/src/mewsfeed/follows/follower-to-creators.test.ts index 14d136c7..67f5bde9 100644 --- a/tests/src/mewsfeed/follows/follower-to-creators.test.ts +++ b/tests/src/mewsfeed/follows/follower-to-creators.test.ts @@ -4,303 +4,319 @@ import { assert, expect, it } from "vitest"; import { mewsfeedAppBundleSource } from "../../common"; it("link a Follower to a Creator", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = bob.agentPubKey; - - // Bob gets the links, should be empty - let linksOutput: Record[] = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Follower to Creator - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: targetAddress, - }, - }); - assert.equal(linksOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: baseAddress, - }, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_followers_for_creator", - payload: { - creator: targetAddress, - }, - }); - assert.equal(linksOutput.length, 0); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = bob.agentPubKey; + + // Bob gets the links, should be empty + let linksOutput: Record[] = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Follower to Creator + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: targetAddress, + }, + }); + assert.equal(linksOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: baseAddress, + }, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_followers_for_creator", + payload: { + creator: targetAddress, + }, + }); + assert.equal(linksOutput.length, 0); + }, + true, + { timeout: 500000 } + ); }); it("Agent cannot follow themselves", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice tries to follow herself - const response = alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice tries to follow herself + const response = alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + }, + true, + { timeout: 500000 } + ); }); it("Agent can only change their own follows", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = bob.agentPubKey; - - // Alice follows bob - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to remove alices' follow - const response = bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - - // Alice removes her own follow - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "unfollow", - payload: targetAddress, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob tries to add a follow for allice - const response2 = bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: baseAddress, - target_creator: targetAddress, - }, - }); - await expect(response2).rejects.toThrowError(/InvalidCommit/); - }, true); -}); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; -it("Creators list are hash-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol, john, steve, mary] = - await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - appSource, + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ appSource, appSource, ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a link from Follower to Creator - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: bob.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: carol.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: john.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: steve.agentPubKey, - }, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: alice.agentPubKey, - target_creator: mary.agentPubKey, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const page1: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - limit: 2, + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = bob.agentPubKey; + + // Alice follows bob + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to remove alices' follow + const response = bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, }, - }, - }); - - assert.deepEqual(page1[0], mary.agentPubKey); - assert.deepEqual(page1[1], steve.agentPubKey); - - const page2: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - after_agentpubkey: page1[1], - limit: 2, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + + // Alice removes her own follow + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "unfollow", + payload: targetAddress, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob tries to add a follow for allice + const response2 = bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: baseAddress, + target_creator: targetAddress, + }, + }); + await expect(response2).rejects.toThrowError(/InvalidCommit/); + }, + true, + { timeout: 500000 } + ); +}); + +it("Creators list are hash-paginated", async () => { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol, john, steve, mary] = + await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a link from Follower to Creator + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: bob.agentPubKey, }, - }, - }); - assert.deepEqual(page2[0], john.agentPubKey); - assert.deepEqual(page2[1], carol.agentPubKey); - - const page3: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - after_agentpubkey: page2[1], - limit: 2, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: carol.agentPubKey, }, - }, - }); - assert.lengthOf(page3, 1); - assert.deepEqual(page3[0], bob.agentPubKey); - - const page5: AgentPubKey[] = await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "get_creators_for_follower", - payload: { - follower: alice.agentPubKey, - page: { - after_agentpubkey: page3[0], - limit: 2, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: john.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: steve.agentPubKey, + }, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: alice.agentPubKey, + target_creator: mary.agentPubKey, }, - }, - }); - assert.lengthOf(page5, 0); - }, true); + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const page1: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + limit: 2, + }, + }, + }); + + assert.deepEqual(page1[0], mary.agentPubKey); + assert.deepEqual(page1[1], steve.agentPubKey); + + const page2: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page1[1], + limit: 2, + }, + }, + }); + assert.deepEqual(page2[0], john.agentPubKey); + assert.deepEqual(page2[1], carol.agentPubKey); + + const page3: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page2[1], + limit: 2, + }, + }, + }); + assert.lengthOf(page3, 1); + assert.deepEqual(page3[0], bob.agentPubKey); + + const page5: AgentPubKey[] = await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "get_creators_for_follower", + payload: { + follower: alice.agentPubKey, + page: { + after_agentpubkey: page3[0], + limit: 2, + }, + }, + }); + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); it("Followers list are hash-paginated", async () => { diff --git a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts index 4016e279..8e810092 100644 --- a/tests/src/mewsfeed/likes/liker-to-hashes.test.ts +++ b/tests/src/mewsfeed/likes/liker-to-hashes.test.ts @@ -4,87 +4,91 @@ import { assert, expect, it } from "vitest"; import { mewsfeedAppBundleSource } from "../../common"; it("link a Liker to a Hash", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const baseAddress = alice.agentPubKey; - const targetAddress = await fakeActionHash(); - - // Bob gets the links, should be empty - let linksOutput: Record[] = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Alice creates a link from Liker to Hash - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: baseAddress, - target_hash: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 1); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_likers_for_hash", - payload: targetAddress, - }); - assert.equal(linksOutput.length, 1); - - await alice.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: baseAddress, - target_hash: targetAddress, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets the links again - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_hashes_for_liker", - payload: baseAddress, - }); - assert.equal(linksOutput.length, 0); - - // Bob gets the links in the inverse direction - linksOutput = await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "get_likers_for_hash", - payload: targetAddress, - }); - assert.equal(linksOutput.length, 0); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const baseAddress = alice.agentPubKey; + const targetAddress = await fakeActionHash(); + + // Bob gets the links, should be empty + let linksOutput: Record[] = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Alice creates a link from Liker to Hash + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: baseAddress, + target_hash: targetAddress, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 1); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_likers_for_hash", + payload: targetAddress, + }); + assert.equal(linksOutput.length, 1); + + await alice.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: baseAddress, + target_hash: targetAddress, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets the links again + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_hashes_for_liker", + payload: baseAddress, + }); + assert.equal(linksOutput.length, 0); + + // Bob gets the links in the inverse direction + linksOutput = await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "get_likers_for_hash", + payload: targetAddress, + }); + assert.equal(linksOutput.length, 0); + }, + true, + { timeout: 500000 } + ); }); it("Agent can only change their own likes", async () => { diff --git a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts index 6543c8f1..b8d28a43 100644 --- a/tests/src/mewsfeed/mews/agent-to-notifications.test.ts +++ b/tests/src/mewsfeed/mews/agent-to-notifications.test.ts @@ -12,456 +12,476 @@ import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; it("notifications include my agent follows & unfollows", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Bob follows Alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "add_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - // Bob unfollows Alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "remove_creator_for_follower", - payload: { - base_follower: bob.agentPubKey, - target_creator: alice.agentPubKey, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - // Notifications should be orderded by action time descending (newest first) - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyAgentUnfollowed]: null }, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyAgentFollowed]: null }, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Bob follows Alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "add_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + // Bob unfollows Alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "remove_creator_for_follower", + payload: { + base_follower: bob.agentPubKey, + target_creator: alice.agentPubKey, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + // Notifications should be orderded by action time descending (newest first) + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyAgentUnfollowed]: null }, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyAgentFollowed]: null }, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, + true, + { timeout: 500000 } + ); }); it("notifications include my mews' likes & unlikes", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - const feedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob likes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "add_hash_for_liker", - payload: { - base_liker: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - // Bob unlikes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "likes", - fn_name: "remove_hash_for_liker", - payload: { - base_liker: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewUnlicked]: null }, - feed_mew: feedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewLicked]: null }, - feed_mew: feedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + const feedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob likes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "add_hash_for_liker", + payload: { + base_liker: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + // Bob unlikes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "likes", + fn_name: "remove_hash_for_liker", + payload: { + base_liker: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewUnlicked]: null }, + feed_mew: feedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewLicked]: null }, + feed_mew: feedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, + true, + { timeout: 500000 } + ); }); it("notifications include my mews' pins & unpins", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - const feedMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: actionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob likes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "add_hash_for_pinner", - payload: { - base_pinner: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - // Bob unlikes Alice's Mew - await bob.cells[0].callZome({ - zome_name: "agent_pins", - fn_name: "remove_hash_for_pinner", - payload: { - base_pinner: bob.agentPubKey, - target_hash: actionHash, - }, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewUnpinned]: null }, - feed_mew: feedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewPinned]: null }, - feed_mew: feedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(2); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + const feedMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: actionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob likes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "add_hash_for_pinner", + payload: { + base_pinner: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + // Bob unlikes Alice's Mew + await bob.cells[0].callZome({ + zome_name: "agent_pins", + fn_name: "remove_hash_for_pinner", + payload: { + base_pinner: bob.agentPubKey, + target_hash: actionHash, + }, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewUnpinned]: null }, + feed_mew: feedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewPinned]: null }, + feed_mew: feedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(2); + }, + true, + { timeout: 500000 } + ); }); it("notifications include my mews' replies, quotes, mewmews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob replies to Alice's mew - const replyInput: Mew = { - text: "test reply 12345", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, - }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, - }); - - // Bob mewmews Alice's mew - const mewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }; - const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewmewInput, - }); - const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmewActionHash, - }); - - // Bob quotes Alice's mew - const quoteInput: Mew = { - text: "a response to a quoted mew", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }; - const quoteActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: quoteInput, - }); - const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quoteActionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: quoteFeedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: mewmewFeedMew, - }); - expect(notifications[2]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { [NotificationTypeName.MyMewResponded]: null }, - feed_mew: replyFeedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(3); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob replies to Alice's mew + const replyInput: Mew = { + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob mewmews Alice's mew + const mewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }; + const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewmewInput, + }); + const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmewActionHash, + }); + + // Bob quotes Alice's mew + const quoteInput: Mew = { + text: "a response to a quoted mew", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }; + const quoteActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: quoteInput, + }); + const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quoteActionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: quoteFeedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: mewmewFeedMew, + }); + expect(notifications[2]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { [NotificationTypeName.MyMewResponded]: null }, + feed_mew: replyFeedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(3); + }, + true, + { timeout: 500000 } + ); }); it("notifications include replies, quotes, mewmews to mews that I also responded to", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Carol creates a Mew - const actionHash: ActionHash = await createMew(carol.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice reply's to Carol's mew - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: { + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Carol creates a Mew + const actionHash: ActionHash = await createMew(carol.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice reply's to Carol's mew + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: { + text: "test reply 12345", + links: [], + mew_type: { [MewTypeName.Reply]: actionHash }, + }, + }); + + // Bob replies to Carol's mew + const replyInput: Mew = { text: "test reply 12345", links: [], mew_type: { [MewTypeName.Reply]: actionHash }, - }, - }); - - // Bob replies to Carol's mew - const replyInput: Mew = { - text: "test reply 12345", - links: [], - mew_type: { [MewTypeName.Reply]: actionHash }, - }; - const replyActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: replyInput, - }); - const replyFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: replyActionHash, - }); - - // Bob mewmews Carol's mew - const mewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: actionHash }, - }; - const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewmewInput, - }); - const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmewActionHash, - }); - - // Bob quotes Carol's mew - const quoteInput: Mew = { - text: "a response to a quoted mew", - links: [], - mew_type: { [MewTypeName.Quote]: actionHash }, - }; - const quoteActionHash: ActionHash = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: quoteInput, - }); - const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: quoteActionHash, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Alice gets notifications - const notifications = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_notifications", - payload: null, - }); - - expect(notifications[0]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: quoteFeedMew, - }); - expect(notifications[1]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: mewmewFeedMew, - }); - expect(notifications[2]).toMatchObject({ - agent: bob.agentPubKey, - notification_type: { - [NotificationTypeName.FollowedYarnResponded]: null, - }, - feed_mew: replyFeedMew, - }); - - // Alice gets notifications count - const count = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "count_my_notifications", - payload: null, - }); - expect(count).toEqual(3); - }, true); + }; + const replyActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: replyInput, + }); + const replyFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: replyActionHash, + }); + + // Bob mewmews Carol's mew + const mewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: actionHash }, + }; + const mewmewActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewmewInput, + }); + const mewmewFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmewActionHash, + }); + + // Bob quotes Carol's mew + const quoteInput: Mew = { + text: "a response to a quoted mew", + links: [], + mew_type: { [MewTypeName.Quote]: actionHash }, + }; + const quoteActionHash: ActionHash = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: quoteInput, + }); + const quoteFeedMew: FeedMew = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: quoteActionHash, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Alice gets notifications + const notifications = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_notifications", + payload: null, + }); + + expect(notifications[0]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: quoteFeedMew, + }); + expect(notifications[1]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: mewmewFeedMew, + }); + expect(notifications[2]).toMatchObject({ + agent: bob.agentPubKey, + notification_type: { + [NotificationTypeName.FollowedYarnResponded]: null, + }, + feed_mew: replyFeedMew, + }); + + // Alice gets notifications count + const count = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "count_my_notifications", + payload: null, + }); + expect(count).toEqual(3); + }, + true, + { timeout: 500000 } + ); }); it("notifications list is time-paginated", async () => { diff --git a/tests/src/mewsfeed/mews/dna-properties.test.ts b/tests/src/mewsfeed/mews/dna-properties.test.ts index 5a26fdd5..b8f750a5 100644 --- a/tests/src/mewsfeed/mews/dna-properties.test.ts +++ b/tests/src/mewsfeed/mews/dna-properties.test.ts @@ -8,140 +8,158 @@ import { } from "../../common.js"; it("Mew must not be longer than DNA property mew_characters_max chars", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const createMewInput: Mew = { - text: new Array(200).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length" - ); - - createMewInput.text = new Array(201).fill("a").join(""); - try { - await alice.cells[0].callZome({ + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const createMewInput: Mew = { + text: new Array(200).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", payload: createMewInput, }); - assert.fail("mew content longer than mew_characters_max is valid"); - } catch (error) { - assert.ok(true, "mew content longer than mew_characters_max is invalid"); - } - }, true); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length" + ); + + createMewInput.text = new Array(201).fill("a").join(""); + try { + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.fail("mew content longer than mew_characters_max is valid"); + } catch (error) { + assert.ok( + true, + "mew content longer than mew_characters_max is invalid" + ); + } + }, + true, + { timeout: 500000 } + ); }); it("Mew must not be shorter than DNA property mew_characters_min chars", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const createMewInput: Mew = { - text: new Array(10).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length" - ); - - createMewInput.text = new Array(2).fill("a").join(""); - try { - await alice.cells[0].callZome({ + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const createMewInput: Mew = { + text: new Array(10).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ zome_name: "mews", fn_name: "create_mew", payload: createMewInput, }); - assert.fail("mew content shorter than mew_characters_min is valid"); - } catch (error) { - assert.ok(true, "mew content shorter than mew_characters_min is invalid"); - } - }, true); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length" + ); + + createMewInput.text = new Array(2).fill("a").join(""); + try { + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.fail("mew content shorter than mew_characters_min is valid"); + } catch (error) { + assert.ok( + true, + "mew content shorter than mew_characters_min is invalid" + ); + } + }, + true, + { timeout: 500000 } + ); }); it("Mew can be any length if DNA property mew_characters_min and mew_characters_max not set", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { - appBundleSource: mewsfeedAppBundleSourceNoLengthLimits, - }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // 0 charactres - const createMewInput2: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash2: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - assert.deepEqual( - action_hash2.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length 0" - ); - - // 1000 charactres - const createMewInput3: Mew = { - text: new Array(1000).fill("a").join(""), - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash3: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - assert.deepEqual( - action_hash3.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a mew of valid length 1000" - ); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { + appBundleSource: mewsfeedAppBundleSourceNoLengthLimits, + }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // 0 charactres + const createMewInput2: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash2: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + assert.deepEqual( + action_hash2.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length 0" + ); + + // 1000 charactres + const createMewInput3: Mew = { + text: new Array(1000).fill("a").join(""), + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash3: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + assert.deepEqual( + action_hash3.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a mew of valid length 1000" + ); + }, + true, + { timeout: 500000 } + ); }); it("Can get deserialized DNA Properties", async () => { diff --git a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts index 2fddd59b..0c055b97 100644 --- a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts +++ b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts @@ -6,392 +6,423 @@ import { mewsfeedAppBundleSource } from "../../common"; import { createMew } from "./common"; it("create a Mew and get followed creators mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - // Bob follows alice - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - - // Bob gets followed creators mews - let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.equal(collectionOutput.length, 0); - - // Alice creates a Mew - const actionHash: ActionHash = await createMew(alice.cells[0]); - assert.ok(actionHash); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - // Bob gets followed creators mews again - collectionOutput = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - - assert.equal(collectionOutput.length, 1); - assert.deepEqual(actionHash, collectionOutput[0].action_hash); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + // Bob follows alice + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + // Bob gets followed creators mews + let collectionOutput: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.equal(collectionOutput.length, 0); + + // Alice creates a Mew + const actionHash: ActionHash = await createMew(alice.cells[0]); + assert.ok(actionHash); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob gets followed creators mews again + collectionOutput = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + + assert.equal(collectionOutput.length, 1); + assert.deepEqual(actionHash, collectionOutput[0].action_hash); + }, + true, + { timeout: 500000 } + ); }); it("Followed creators mews should include mews of followed creator", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = "test-mew"; - const mewInput: Mew = { - text: mewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewInput, - }); - - const bobMewsFeedInitial: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - bobMewsFeedInitial.length === 0, - "bob's mews feed is initially empty" - ); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); - assert.equal( - bobMewsFeed[0].mew.text, - mewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = "test-mew"; + const mewInput: Mew = { + text: mewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewInput, + }); + + const bobMewsFeedInitial: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + bobMewsFeedInitial.length === 0, + "bob's mews feed is initially empty" + ); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal( + bobMewsFeed[0].mew.text, + mewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + }, + true, + { timeout: 500000 } + ); }); it("Followed creators mews should include own mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewsFeedInitial: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - aliceMewsFeedInitial.length === 0, - "alice's mews feed is initially empty" - ); - - const mewContent = "test-mew"; - const mewInput: Mew = { - text: mewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: mewInput, - }); - - const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(aliceMewsFeed.length === 1, "alice's mews feed includes her mew"); - assert.equal(aliceMewsFeed[0].mew.text, mewContent, "mew content matches"); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewsFeedInitial: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeedInitial.length === 0, + "alice's mews feed is initially empty" + ); + + const mewContent = "test-mew"; + const mewInput: Mew = { + text: mewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: mewInput, + }); + + const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeed.length === 1, + "alice's mews feed includes her mew" + ); + assert.equal( + aliceMewsFeed[0].mew.text, + mewContent, + "mew content matches" + ); + }, + true, + { timeout: 500000 } + ); }); it("Followed creators mews should not include mews of non-followed creator", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - const carolMewContent = "carol-test-mew"; - const carolMewInput: Mew = { - text: carolMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await carol.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: carolMewInput, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); - assert.equal( - bobMewsFeed[0].mew.text, - aliceMewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + const carolMewContent = "carol-test-mew"; + const carolMewInput: Mew = { + text: carolMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await carol.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: carolMewInput, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal( + bobMewsFeed[0].mew.text, + aliceMewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + }, + true, + { timeout: 500000 } + ); }); it("Unfollowing should exclude creators mews from feed", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: alice.agentPubKey, - }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const bobMewsFeedWhenFollowing: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - bobMewsFeedWhenFollowing.length === 1, - "bob's mews feed includes 1 mew" - ); - assert.equal( - bobMewsFeedWhenFollowing[0].mew.text, - aliceMewContent, - "mew content in bob's mews feed matches alice's mew content" - ); - - await bob.cells[0].callZome({ - zome_name: "follows", - fn_name: "unfollow", - payload: alice.agentPubKey, - }); - - const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok(bobMewsFeed.length === 0, "bob's mews feed is empty"); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: alice.agentPubKey, + }); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const bobMewsFeedWhenFollowing: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + bobMewsFeedWhenFollowing.length === 1, + "bob's mews feed includes 1 mew" + ); + assert.equal( + bobMewsFeedWhenFollowing[0].mew.text, + aliceMewContent, + "mew content in bob's mews feed matches alice's mew content" + ); + + await bob.cells[0].callZome({ + zome_name: "follows", + fn_name: "unfollow", + payload: alice.agentPubKey, + }); + + const bobMewsFeed: FeedMew[] = await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok(bobMewsFeed.length === 0, "bob's mews feed is empty"); + }, + true, + { timeout: 500000 } + ); }); it("Followed creators mews should be ordered by timestamp in descending order", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob, carol] = await scenario.addPlayersWithApps([ - appSource, - appSource, - appSource, - ]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const firstMewContent = "first-test-mew"; - const firstMewInput: Mew = { - text: firstMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: firstMewInput, - }); - - const secondMewContent = "second-test-mew"; - const secondMewInput: Mew = { - text: secondMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await bob.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: secondMewInput, - }); - - const thirdMewContent = "third-test-mew"; - const thirdMewInput: Mew = { - text: thirdMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await carol.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: thirdMewInput, - }); - - const fourthMewContent = "fourth-test-mew"; - const fourthMewInput: Mew = { - text: fourthMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: fourthMewInput, - }); - // alice starts following bob and carol - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: bob.agentPubKey, - }); - await alice.cells[0].callZome({ - zome_name: "follows", - fn_name: "follow", - payload: carol.agentPubKey, - }); - - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - - const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_my_followed_creators_mews_with_context", - payload: null, - }); - assert.ok( - aliceMewsFeed.length === 4, - "alice's mews feed includes all 4 mews" - ); - assert.equal( - aliceMewsFeed[0].mew.text, - fourthMewContent, - "mew 1 in feed is fourth mew" - ); - assert.equal( - aliceMewsFeed[1].mew.text, - thirdMewContent, - "mew 2 in feed is third mew" - ); - assert.equal( - aliceMewsFeed[2].mew.text, - secondMewContent, - "mew 3 in feed is second mew" - ); - assert.equal( - aliceMewsFeed[3].mew.text, - firstMewContent, - "mew 4 in feed is first mew" - ); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob, carol] = await scenario.addPlayersWithApps([ + appSource, + appSource, + appSource, + ]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const firstMewContent = "first-test-mew"; + const firstMewInput: Mew = { + text: firstMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: firstMewInput, + }); + + const secondMewContent = "second-test-mew"; + const secondMewInput: Mew = { + text: secondMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await bob.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: secondMewInput, + }); + + const thirdMewContent = "third-test-mew"; + const thirdMewInput: Mew = { + text: thirdMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await carol.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: thirdMewInput, + }); + + const fourthMewContent = "fourth-test-mew"; + const fourthMewInput: Mew = { + text: fourthMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: fourthMewInput, + }); + // alice starts following bob and carol + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: bob.agentPubKey, + }); + await alice.cells[0].callZome({ + zome_name: "follows", + fn_name: "follow", + payload: carol.agentPubKey, + }); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + const aliceMewsFeed: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_my_followed_creators_mews_with_context", + payload: null, + }); + assert.ok( + aliceMewsFeed.length === 4, + "alice's mews feed includes all 4 mews" + ); + assert.equal( + aliceMewsFeed[0].mew.text, + fourthMewContent, + "mew 1 in feed is fourth mew" + ); + assert.equal( + aliceMewsFeed[1].mew.text, + thirdMewContent, + "mew 2 in feed is third mew" + ); + assert.equal( + aliceMewsFeed[2].mew.text, + secondMewContent, + "mew 3 in feed is second mew" + ); + assert.equal( + aliceMewsFeed[3].mew.text, + firstMewContent, + "mew 4 in feed is first mew" + ); + }, + true, + { timeout: 500000 } + ); }); it("Followed creators mews list are time-paginated", async () => { diff --git a/tests/src/mewsfeed/mews/mention-to-mews.test.ts b/tests/src/mewsfeed/mews/mention-to-mews.test.ts index 43d8da4f..324d6eff 100644 --- a/tests/src/mewsfeed/mews/mention-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/mention-to-mews.test.ts @@ -11,61 +11,65 @@ import { mewsfeedAppBundleSource } from "../../common.js"; import { createMew } from "./common.js"; it("mention in mews", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice, bob] = await scenario.addPlayersWithApps([ - appSource, - appSource, - ]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice, bob] = await scenario.addPlayersWithApps([ + appSource, + appSource, + ]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - await createMew(alice.cells[0], { - text: "this is for @bob", - links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], - mew_type: { Original: null }, - }); + await createMew(alice.cells[0], { + text: "this is for @bob", + links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], + mew_type: { Original: null }, + }); - const actionHash2: ActionHash = await createMew(bob.cells[0], { - text: "this is for @bob 2", - links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], - mew_type: { Original: null }, - }); + const actionHash2: ActionHash = await createMew(bob.cells[0], { + text: "this is for @bob 2", + links: [{ [LinkTargetName.Mention]: bob.agentPubKey }], + mew_type: { Original: null }, + }); - const actionHash3: ActionHash = await createMew(alice.cells[0], { - text: "this is for @alice", - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { Original: null }, - }); + const actionHash3: ActionHash = await createMew(alice.cells[0], { + text: "this is for @alice", + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { Original: null }, + }); - await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - const mentionedMewsBob: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: bob.agentPubKey, - }, - }); - assert.ok(mentionedMewsBob.length === 2, "one mew with mention"); - assert.deepEqual(mentionedMewsBob[0].action_hash, actionHash2); + const mentionedMewsBob: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: bob.agentPubKey, + }, + }); + assert.ok(mentionedMewsBob.length === 2, "one mew with mention"); + assert.deepEqual(mentionedMewsBob[0].action_hash, actionHash2); - const mentionedMewsAlice: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - }, - }); - assert.ok(mentionedMewsAlice.length === 1, "one mew with mention"); - assert.deepEqual(mentionedMewsAlice[0].action_hash, actionHash3); - }, true); + const mentionedMewsAlice: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + }, + }); + assert.ok(mentionedMewsAlice.length === 1, "one mew with mention"); + assert.deepEqual(mentionedMewsAlice[0].action_hash, actionHash3); + }, + true, + { timeout: 500000 } + ); }); it("Mentions list are time-paginated", async () => { diff --git a/tests/src/mewsfeed/mews/mew-to-responses.test.ts b/tests/src/mewsfeed/mews/mew-to-responses.test.ts index c63f81ea..965cee49 100644 --- a/tests/src/mewsfeed/mews/mew-to-responses.test.ts +++ b/tests/src/mewsfeed/mews/mew-to-responses.test.ts @@ -72,73 +72,81 @@ it("Agent can reply to a mew", async () => { }); it("Agent can mewmew a mew, only once", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); - const aliceMewContent = "alice-test-mew"; - const aliceMewInput: Mew = { - text: aliceMewContent, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewInput, - }); + const aliceMewContent = "alice-test-mew"; + const aliceMewInput: Mew = { + text: aliceMewContent, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewInput, + }); - const aliceMewmewInput: Mew = { - text: "", - links: [], - mew_type: { [MewTypeName.Mewmew]: action_hash }, - }; - const mewmew_action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewmewInput, - }); + const aliceMewmewInput: Mew = { + text: "", + links: [], + mew_type: { [MewTypeName.Mewmew]: action_hash }, + }; + const mewmew_action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewmewInput, + }); - const mewmew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: mewmew_action_hash, - }); - assert.ok(MewTypeName.Mewmew in mewmew.mew.mew_type, "mew is a mewmew"); - assert.deepEqual(mewmew.mew, aliceMewmewInput, "mewmew is alice's mewmew"); + const mewmew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: mewmew_action_hash, + }); + assert.ok(MewTypeName.Mewmew in mewmew.mew.mew_type, "mew is a mewmew"); + assert.deepEqual( + mewmew.mew, + aliceMewmewInput, + "mewmew is alice's mewmew" + ); - const originalMew: FeedMew = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mew_with_context", - payload: action_hash, - }); - assert.ok( - MewTypeName.Original in originalMew.mew.mew_type, - "mew is an original mew" - ); - assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); - assert.isTrue( - originalMew.is_mewmewed, - "original mew's mewmew is alice's mewmew" - ); + const originalMew: FeedMew = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mew_with_context", + payload: action_hash, + }); + assert.ok( + MewTypeName.Original in originalMew.mew.mew_type, + "mew is an original mew" + ); + assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); + assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); + assert.isTrue( + originalMew.is_mewmewed, + "original mew's mewmew is alice's mewmew" + ); - // Mewmew the same mew again - const response = alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: aliceMewmewInput, - }); - await expect(response).rejects.toThrowError(/InvalidCommit/); - }, true); + // Mewmew the same mew again + const response = alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: aliceMewmewInput, + }); + await expect(response).rejects.toThrowError(/InvalidCommit/); + }, + true, + { timeout: 500000 } + ); }); it("Agent can quote a mew", async () => { diff --git a/tests/src/mewsfeed/mews/mew-with-context.test.ts b/tests/src/mewsfeed/mews/mew-with-context.test.ts index 7b93cd4b..c2be1113 100644 --- a/tests/src/mewsfeed/mews/mew-with-context.test.ts +++ b/tests/src/mewsfeed/mews/mew-with-context.test.ts @@ -83,7 +83,7 @@ it("Mew with context contains licks count and is_licked", async () => { expect(aliceFeedMew.is_licked).false; }, true, - { timeout: 100000 } + { timeout: 500000 } ); }); @@ -142,7 +142,7 @@ it("Mew with context contains replies count and is_replied", async () => { expect(aliceFeedMew.is_replied).false; }, true, - { timeout: 100000 } + { timeout: 500000 } ); }); @@ -201,7 +201,7 @@ it("Mew with context contains quotes count and is_quoted", async () => { expect(aliceFeedMew.is_quoted).false; }, true, - { timeout: 100000 } + { timeout: 500000 } ); }); @@ -263,7 +263,7 @@ it("Mew with context contains mewmews count and is_mewmewed", async () => { expect(aliceFeedMew.is_mewmewed).false; }, true, - { timeout: 100000 } + { timeout: 500000 } ); }); diff --git a/tests/src/mewsfeed/mews/tags-to-mews.test.ts b/tests/src/mewsfeed/mews/tags-to-mews.test.ts index 3867bf43..21d52887 100644 --- a/tests/src/mewsfeed/mews/tags-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/tags-to-mews.test.ts @@ -11,362 +11,385 @@ import { import { mewsfeedAppBundleSource } from "../../common.js"; it("Hashtag, cashtag and mention", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = - "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; - const createMewInput: Mew = { - text: mewContent, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a valid mew" - ); - - const hashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - }, - }); - assert.ok(hashtaggedMews.length === 1, "one mew with hashtag"); - assert.equal(hashtaggedMews[0].mew.text, mewContent, "mew content matches"); - - const arabicHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#سعيدة", - }, - }); - assert.ok(arabicHashtaggedMews.length === 1, "one mew with arabic hashtag"); - assert.equal( - arabicHashtaggedMews[0].mew.text, - mewContent, - "mew content matches" - ); - - // get hashtag containing emojis -- invalid hashtag! - const emojiHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#😃😃😃", - }, - }); - assert.ok(emojiHashtaggedMews.length === 0, "no mew with emoji hashtag"); - - const cashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_cashtag_with_context", - payload: { - cashtag: "$cashtag", - }, - }); - assert.ok(cashtaggedMews.length === 1, "one mew with cashtag"); - - const mentionedMews: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_mention_with_context", - payload: { - mention: alice.agentPubKey, - }, - }); - assert.ok(mentionedMews.length === 1, "one mew with mention"); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = + "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; + const createMewInput: Mew = { + text: mewContent, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a valid mew" + ); + + const hashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + }, + }); + assert.ok(hashtaggedMews.length === 1, "one mew with hashtag"); + assert.equal( + hashtaggedMews[0].mew.text, + mewContent, + "mew content matches" + ); + + const arabicHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#سعيدة", + }, + }); + assert.ok( + arabicHashtaggedMews.length === 1, + "one mew with arabic hashtag" + ); + assert.equal( + arabicHashtaggedMews[0].mew.text, + mewContent, + "mew content matches" + ); + + // get hashtag containing emojis -- invalid hashtag! + const emojiHashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#😃😃😃", + }, + }); + assert.ok(emojiHashtaggedMews.length === 0, "no mew with emoji hashtag"); + + const cashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_cashtag_with_context", + payload: { + cashtag: "$cashtag", + }, + }); + assert.ok(cashtaggedMews.length === 1, "one mew with cashtag"); + + const mentionedMews: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_mention_with_context", + payload: { + mention: alice.agentPubKey, + }, + }); + assert.ok(mentionedMews.length === 1, "one mew with mention"); + }, + true, + { timeout: 500000 } + ); }); it("Prefix index should return hashtags and cashtags", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent = - "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; - const createMewInput: Mew = { - text: mewContent, - links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], - mew_type: { [MewTypeName.Original]: null }, - }; - - const action_hash: ActionHash = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput, - }); - assert.deepEqual( - action_hash.slice(0, 3), - Buffer.from([132, 41, 36]), - "alice created a valid mew" - ); - - const hashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "has", - limit: 10, - }, - }); - assert.ok(hashtags.length === 1, "one hashtag"); - assert.equal(hashtags[0], "#hashtag", "hashtag search result matches"); - - const arabicHashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "سعيدة", - limit: 10, - }, - }); - assert.ok(arabicHashtags.length === 1, "one arabic hashtag"); - assert.equal(arabicHashtags[0], "#سعيدة", "hashtag search result matches"); - - // get hashtag containing emojis -- invalid hashtag! - const emojiHashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "😃😃😃", - limit: 10, - }, - }); - assert.ok(emojiHashtags.length === 0, "no emoji hashtags"); - - const cashtags: string[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "search_tags", - payload: { - query: "cas", - limit: 10, - }, - }); - assert.ok(cashtags.length === 1, "one cashtag"); - assert.equal(cashtags[0], "$cashtag", "hashtag search result matches"); - }, true); + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent = + "My Mew with #hashtag #سعيدة #😃😃😃 and $cashtag and @mention"; + const createMewInput: Mew = { + text: mewContent, + links: [{ [LinkTargetName.Mention]: alice.agentPubKey }], + mew_type: { [MewTypeName.Original]: null }, + }; + + const action_hash: ActionHash = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput, + }); + assert.deepEqual( + action_hash.slice(0, 3), + Buffer.from([132, 41, 36]), + "alice created a valid mew" + ); + + const hashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "has", + limit: 10, + }, + }); + assert.ok(hashtags.length === 1, "one hashtag"); + assert.equal(hashtags[0], "#hashtag", "hashtag search result matches"); + + const arabicHashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "سعيدة", + limit: 10, + }, + }); + assert.ok(arabicHashtags.length === 1, "one arabic hashtag"); + assert.equal( + arabicHashtags[0], + "#سعيدة", + "hashtag search result matches" + ); + + // get hashtag containing emojis -- invalid hashtag! + const emojiHashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "😃😃😃", + limit: 10, + }, + }); + assert.ok(emojiHashtags.length === 0, "no emoji hashtags"); + + const cashtags: string[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "search_tags", + payload: { + query: "cas", + limit: 10, + }, + }); + assert.ok(cashtags.length === 1, "one cashtag"); + assert.equal(cashtags[0], "$cashtag", "hashtag search result matches"); + }, + true, + { timeout: 500000 } + ); }); it("Hashtags list are time-paginated", async () => { - await runScenario(async (scenario) => { - // Set up the app to be installed - const appSource = { appBundleSource: mewsfeedAppBundleSource }; - - // Add 2 players with the test app to the Scenario. The returned players - // can be destructured. - const [alice] = await scenario.addPlayersWithApps([appSource]); - - // Shortcut peer discovery through gossip and register all agents in every - // conductor of the scenario. - await scenario.shareAllAgents(); - - const mewContent1 = "My Mew with #hashtag 1"; - const createMewInput1: Mew = { - text: mewContent1, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash1 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput1, - }); - - const mewContent2 = "My Mew with #hashtag 2"; - const createMewInput2: Mew = { - text: mewContent2, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash2 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput2, - }); - - const mewContent3 = "My Mew with #hashtag 3"; - const createMewInput3: Mew = { - text: mewContent3, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash3 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput3, - }); - - const mewContent4 = "My Mew with #hashtag 4"; - const createMewInput4: Mew = { - text: mewContent4, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash4 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput4, - }); - - const mewContent5 = "My Mew with #hashtag 5"; - const createMewInput5: Mew = { - text: mewContent5, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash5 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput5, - }); - - const mewContent6 = "My Mew with #hashtag 6"; - const createMewInput6: Mew = { - text: mewContent6, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash6 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput6, - }); - - const mewContent7 = "My Mew with #hashtag 7"; - const createMewInput7: Mew = { - text: mewContent7, - links: [], - mew_type: { [MewTypeName.Original]: null }, - }; - const mewActionHash7 = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "create_mew", - payload: createMewInput7, - }); - - const page1: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - limit: 2, + await runScenario( + async (scenario) => { + // Set up the app to be installed + const appSource = { appBundleSource: mewsfeedAppBundleSource }; + + // Add 2 players with the test app to the Scenario. The returned players + // can be destructured. + const [alice] = await scenario.addPlayersWithApps([appSource]); + + // Shortcut peer discovery through gossip and register all agents in every + // conductor of the scenario. + await scenario.shareAllAgents(); + + const mewContent1 = "My Mew with #hashtag 1"; + const createMewInput1: Mew = { + text: mewContent1, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash1 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput1, + }); + + const mewContent2 = "My Mew with #hashtag 2"; + const createMewInput2: Mew = { + text: mewContent2, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash2 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput2, + }); + + const mewContent3 = "My Mew with #hashtag 3"; + const createMewInput3: Mew = { + text: mewContent3, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash3 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput3, + }); + + const mewContent4 = "My Mew with #hashtag 4"; + const createMewInput4: Mew = { + text: mewContent4, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash4 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput4, + }); + + const mewContent5 = "My Mew with #hashtag 5"; + const createMewInput5: Mew = { + text: mewContent5, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash5 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput5, + }); + + const mewContent6 = "My Mew with #hashtag 6"; + const createMewInput6: Mew = { + text: mewContent6, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash6 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput6, + }); + + const mewContent7 = "My Mew with #hashtag 7"; + const createMewInput7: Mew = { + text: mewContent7, + links: [], + mew_type: { [MewTypeName.Original]: null }, + }; + const mewActionHash7 = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "create_mew", + payload: createMewInput7, + }); + + const page1: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + limit: 2, + }, }, - }, - }); - - assert.deepEqual(page1[0].action_hash, mewActionHash7); - assert.deepEqual(page1[1].action_hash, mewActionHash6); - expect(page1[0].action.timestamp).greaterThanOrEqual( - page1[1].action.timestamp - ); - - const page2: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page1[page1.length - 1].action_hash, - limit: 2, + }); + + assert.deepEqual(page1[0].action_hash, mewActionHash7); + assert.deepEqual(page1[1].action_hash, mewActionHash6); + expect(page1[0].action.timestamp).greaterThanOrEqual( + page1[1].action.timestamp + ); + + const page2: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page1[page1.length - 1].action_hash, + limit: 2, + }, }, - }, - }); - - assert.deepEqual(page2[0].action_hash, mewActionHash5); - assert.deepEqual(page2[1].action_hash, mewActionHash4); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp); - - const page3: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page2[page1.length - 1].action_hash, - limit: 2, + }); + + assert.deepEqual(page2[0].action_hash, mewActionHash5); + assert.deepEqual(page2[1].action_hash, mewActionHash4); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp); + + const page3: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page2[page1.length - 1].action_hash, + limit: 2, + }, }, - }, - }); - - assert.deepEqual(page3[0].action_hash, mewActionHash3); - assert.deepEqual(page3[1].action_hash, mewActionHash2); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp); - - const page4: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page3[page1.length - 1].action_hash, - limit: 2, + }); + + assert.deepEqual(page3[0].action_hash, mewActionHash3); + assert.deepEqual(page3[1].action_hash, mewActionHash2); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp); + + const page4: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page3[page1.length - 1].action_hash, + limit: 2, + }, }, - }, - }); - - assert.lengthOf(page4, 1); - assert.deepEqual(page4[0].action_hash, mewActionHash1); - - expect(page1[0].action.timestamp) - .greaterThanOrEqual(page1[1].action.timestamp) - .greaterThanOrEqual(page2[0].action.timestamp) - .greaterThanOrEqual(page2[1].action.timestamp) - .greaterThanOrEqual(page3[0].action.timestamp) - .greaterThanOrEqual(page3[1].action.timestamp) - .greaterThanOrEqual(page4[0].action.timestamp); - - const page5: FeedMew[] = await alice.cells[0].callZome({ - zome_name: "mews", - fn_name: "get_mews_for_hashtag_with_context", - payload: { - hashtag: "#hashtag", - page: { - after_hash: page4[page4.length - 1].action_hash, - limit: 2, + }); + + assert.lengthOf(page4, 1); + assert.deepEqual(page4[0].action_hash, mewActionHash1); + + expect(page1[0].action.timestamp) + .greaterThanOrEqual(page1[1].action.timestamp) + .greaterThanOrEqual(page2[0].action.timestamp) + .greaterThanOrEqual(page2[1].action.timestamp) + .greaterThanOrEqual(page3[0].action.timestamp) + .greaterThanOrEqual(page3[1].action.timestamp) + .greaterThanOrEqual(page4[0].action.timestamp); + + const page5: FeedMew[] = await alice.cells[0].callZome({ + zome_name: "mews", + fn_name: "get_mews_for_hashtag_with_context", + payload: { + hashtag: "#hashtag", + page: { + after_hash: page4[page4.length - 1].action_hash, + limit: 2, + }, }, - }, - }); + }); - assert.lengthOf(page5, 0); - }, true); + assert.lengthOf(page5, 0); + }, + true, + { timeout: 500000 } + ); }); it("Cashtags list are time-paginated", async () => { From 93bfc1f85af5c6e2bb9cc81e16417d80548b07bf Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Fri, 3 Nov 2023 19:57:55 -0600 Subject: [PATCH 15/22] ci: remove tmate session --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ccfa4d1d..bbf2041a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -64,8 +64,8 @@ jobs: target key: ${{ runner.os }}-build-${{ hashFiles('Cargo.lock') }} - - name: tmate session - uses: mxschmitt/action-tmate@v3 + # - name: tmate session + # uses: mxschmitt/action-tmate@v3 - name: Test with tryorama run: nix develop -c $SHELL -c "npm run test" From 024902177e60794639f68447a77049e467783f21 Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Mon, 6 Nov 2023 12:11:47 -0600 Subject: [PATCH 16/22] just run one test file --- tests/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/package.json b/tests/package.json index cbc07860..384278ba 100644 --- a/tests/package.json +++ b/tests/package.json @@ -2,7 +2,7 @@ "name": "tests", "private": true, "scripts": { - "test": "vitest run" + "test": "vitest run src/mewsfeed/mews/followed-creators-mews.test.ts" }, "dependencies": { "@holochain/client": "^0.16.3", From 62a0ed0b5ef7618b66c5a572323c7aa806f53a0d Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Mon, 6 Nov 2023 12:27:42 -0600 Subject: [PATCH 17/22] terminal debug one single test --- .github/workflows/test.yml | 4 ++-- tests/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bbf2041a..ccfa4d1d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -64,8 +64,8 @@ jobs: target key: ${{ runner.os }}-build-${{ hashFiles('Cargo.lock') }} - # - name: tmate session - # uses: mxschmitt/action-tmate@v3 + - name: tmate session + uses: mxschmitt/action-tmate@v3 - name: Test with tryorama run: nix develop -c $SHELL -c "npm run test" diff --git a/tests/package.json b/tests/package.json index 384278ba..20e6ffb0 100644 --- a/tests/package.json +++ b/tests/package.json @@ -2,7 +2,7 @@ "name": "tests", "private": true, "scripts": { - "test": "vitest run src/mewsfeed/mews/followed-creators-mews.test.ts" + "test": "vitest run src/mewsfeed/mews/pinner-to-mews.test.ts" }, "dependencies": { "@holochain/client": "^0.16.3", From 15b0f305686a38530bb3d1f246beb58e1adaf22e Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Mon, 6 Nov 2023 15:40:42 -0600 Subject: [PATCH 18/22] more logs --- .../src/mewsfeed/mews/pinner-to-mews.test.ts | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts index 89f9a436..9eca1bb8 100644 --- a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts @@ -7,6 +7,7 @@ import { createMew } from "./common.js"; it("link a Pinner to a Mew", async () => { await runScenario( async (scenario) => { + console.time("1"); // Construct proper paths for your app. // This assumes app bundle created by the `hc app pack` command. const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; @@ -20,14 +21,23 @@ it("link a Pinner to a Mew", async () => { appSource, appSource, ]); + console.log("app installed"); + console.timeEnd("1"); // Shortcut peer discovery through gossip and register all agents in every // conductor of the scenario. + console.time("2"); await scenario.shareAllAgents(); + console.log("all agents shared"); + console.timeEnd("2"); + console.time("3"); const baseAddress = alice.agentPubKey; const targetActionHash: ActionHash = await createMew(alice.cells[0]); + console.timeEnd("3"); + console.log("created mew"); + console.time("4"); // Bob gets the links, should be empty let linksOutput: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", @@ -35,17 +45,26 @@ it("link a Pinner to a Mew", async () => { payload: baseAddress, }); assert.equal(linksOutput.length, 0); + console.log("get mews for pinner with context"); + console.timeEnd("4"); // Alice creates a link from Pinner to Mew + console.time("5"); await alice.cells[0].callZome({ zome_name: "agent_pins", fn_name: "pin_hash", payload: targetActionHash, }); + console.timeEnd("5"); + console.log("get mews for pinner with context"); + console.time("6"); await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + console.timeEnd("6"); + console.log("dht sync awaited"); // Bob gets the links again + console.time("7"); linksOutput = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mews_for_pinner_with_context", @@ -53,22 +72,33 @@ it("link a Pinner to a Mew", async () => { }); assert.equal(linksOutput.length, 1); assert.deepEqual(targetActionHash, linksOutput[0].action_hash); + console.timeEnd("7"); + console.log("bob got links again"); + console.time("8"); await alice.cells[0].callZome({ zome_name: "agent_pins", fn_name: "unpin_hash", payload: targetActionHash, }); + console.timeEnd("8"); + console.log("unpin hash"); + console.time("9"); await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + console.timeEnd("9"); + console.log("dht awaited again"); // Bob gets the links again + console.time("10"); linksOutput = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mews_for_pinner_with_context", payload: baseAddress, }); assert.equal(linksOutput.length, 0); + console.timeEnd("10"); + console.log("get mews a final time"); }, true, { timeout: 500000 } From 2e445fab09caacd4176eab2e951ae4d1c8160a81 Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Mon, 6 Nov 2023 16:00:36 -0600 Subject: [PATCH 19/22] revert to normal tests --- .github/workflows/test.yml | 4 ++-- tests/package.json | 2 +- tests/vitest.config.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ccfa4d1d..bbf2041a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -64,8 +64,8 @@ jobs: target key: ${{ runner.os }}-build-${{ hashFiles('Cargo.lock') }} - - name: tmate session - uses: mxschmitt/action-tmate@v3 + # - name: tmate session + # uses: mxschmitt/action-tmate@v3 - name: Test with tryorama run: nix develop -c $SHELL -c "npm run test" diff --git a/tests/package.json b/tests/package.json index 20e6ffb0..cbc07860 100644 --- a/tests/package.json +++ b/tests/package.json @@ -2,7 +2,7 @@ "name": "tests", "private": true, "scripts": { - "test": "vitest run src/mewsfeed/mews/pinner-to-mews.test.ts" + "test": "vitest run" }, "dependencies": { "@holochain/client": "^0.16.3", diff --git a/tests/vitest.config.ts b/tests/vitest.config.ts index e81c748a..48b357b5 100644 --- a/tests/vitest.config.ts +++ b/tests/vitest.config.ts @@ -3,7 +3,7 @@ import { defineConfig } from "vitest/config"; export default defineConfig({ test: { threads: false, - testTimeout: 60 * 1000 * 10, // 10 mins + testTimeout: 600 * 1000 * 10, // 10 mins outputDiffLines: 100, outputDiffMaxSize: 100000, }, From e4097d916aa963ad3c8148e8ed6acc8eac1b48ee Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Mon, 6 Nov 2023 16:02:45 -0600 Subject: [PATCH 20/22] revert log outputs --- .../src/mewsfeed/mews/pinner-to-mews.test.ts | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts index 9eca1bb8..89f9a436 100644 --- a/tests/src/mewsfeed/mews/pinner-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/pinner-to-mews.test.ts @@ -7,7 +7,6 @@ import { createMew } from "./common.js"; it("link a Pinner to a Mew", async () => { await runScenario( async (scenario) => { - console.time("1"); // Construct proper paths for your app. // This assumes app bundle created by the `hc app pack` command. const testAppPath = process.cwd() + "/../workdir/mewsfeed.happ"; @@ -21,23 +20,14 @@ it("link a Pinner to a Mew", async () => { appSource, appSource, ]); - console.log("app installed"); - console.timeEnd("1"); // Shortcut peer discovery through gossip and register all agents in every // conductor of the scenario. - console.time("2"); await scenario.shareAllAgents(); - console.log("all agents shared"); - console.timeEnd("2"); - console.time("3"); const baseAddress = alice.agentPubKey; const targetActionHash: ActionHash = await createMew(alice.cells[0]); - console.timeEnd("3"); - console.log("created mew"); - console.time("4"); // Bob gets the links, should be empty let linksOutput: FeedMew[] = await bob.cells[0].callZome({ zome_name: "mews", @@ -45,26 +35,17 @@ it("link a Pinner to a Mew", async () => { payload: baseAddress, }); assert.equal(linksOutput.length, 0); - console.log("get mews for pinner with context"); - console.timeEnd("4"); // Alice creates a link from Pinner to Mew - console.time("5"); await alice.cells[0].callZome({ zome_name: "agent_pins", fn_name: "pin_hash", payload: targetActionHash, }); - console.timeEnd("5"); - console.log("get mews for pinner with context"); - console.time("6"); await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - console.timeEnd("6"); - console.log("dht sync awaited"); // Bob gets the links again - console.time("7"); linksOutput = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mews_for_pinner_with_context", @@ -72,33 +53,22 @@ it("link a Pinner to a Mew", async () => { }); assert.equal(linksOutput.length, 1); assert.deepEqual(targetActionHash, linksOutput[0].action_hash); - console.timeEnd("7"); - console.log("bob got links again"); - console.time("8"); await alice.cells[0].callZome({ zome_name: "agent_pins", fn_name: "unpin_hash", payload: targetActionHash, }); - console.timeEnd("8"); - console.log("unpin hash"); - console.time("9"); await dhtSync([alice, bob], alice.cells[0].cell_id[0]); - console.timeEnd("9"); - console.log("dht awaited again"); // Bob gets the links again - console.time("10"); linksOutput = await bob.cells[0].callZome({ zome_name: "mews", fn_name: "get_mews_for_pinner_with_context", payload: baseAddress, }); assert.equal(linksOutput.length, 0); - console.timeEnd("10"); - console.log("get mews a final time"); }, true, { timeout: 500000 } From 179dd2980ba61325615663f68b628490735224ca Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Tue, 7 Nov 2023 10:55:58 -0600 Subject: [PATCH 21/22] ci: remove commented debug term --- .github/workflows/test.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bbf2041a..5be01931 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -64,8 +64,5 @@ jobs: target key: ${{ runner.os }}-build-${{ hashFiles('Cargo.lock') }} - # - name: tmate session - # uses: mxschmitt/action-tmate@v3 - - name: Test with tryorama run: nix develop -c $SHELL -c "npm run test" From bfb26956e0cd8a16c2d3d559e3e299a9a2f54ab4 Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Tue, 7 Nov 2023 11:57:29 -0600 Subject: [PATCH 22/22] test: refactor assert === to equal --- .../mews/followed-creators-mews.test.ts | 31 +++++++++++-------- .../src/mewsfeed/mews/mention-to-mews.test.ts | 4 +-- .../mewsfeed/mews/mew-to-responses.test.ts | 6 ++-- tests/src/mewsfeed/mews/tags-to-mews.test.ts | 16 +++++----- 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts index 0c055b97..b2ff09fd 100644 --- a/tests/src/mewsfeed/mews/followed-creators-mews.test.ts +++ b/tests/src/mewsfeed/mews/followed-creators-mews.test.ts @@ -92,8 +92,9 @@ it("Followed creators mews should include mews of followed creator", async () => fn_name: "get_my_followed_creators_mews_with_context", payload: null, }); - assert.ok( - bobMewsFeedInitial.length === 0, + assert.equal( + bobMewsFeedInitial.length, + 0, "bob's mews feed is initially empty" ); @@ -108,7 +109,7 @@ it("Followed creators mews should include mews of followed creator", async () => fn_name: "get_my_followed_creators_mews_with_context", payload: null, }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal(bobMewsFeed.length, 1, "bob's mews feed includes 1 mew"); assert.equal( bobMewsFeed[0].mew.text, mewContent, @@ -139,8 +140,9 @@ it("Followed creators mews should include own mews", async () => { fn_name: "get_my_followed_creators_mews_with_context", payload: null, }); - assert.ok( - aliceMewsFeedInitial.length === 0, + assert.equal( + aliceMewsFeedInitial.length, + 0, "alice's mews feed is initially empty" ); @@ -161,8 +163,9 @@ it("Followed creators mews should include own mews", async () => { fn_name: "get_my_followed_creators_mews_with_context", payload: null, }); - assert.ok( - aliceMewsFeed.length === 1, + assert.equal( + aliceMewsFeed.length, + 1, "alice's mews feed includes her mew" ); assert.equal( @@ -230,7 +233,7 @@ it("Followed creators mews should not include mews of non-followed creator", asy fn_name: "get_my_followed_creators_mews_with_context", payload: null, }); - assert.ok(bobMewsFeed.length === 1, "bob's mews feed includes 1 mew"); + assert.equal(bobMewsFeed.length, 1, "bob's mews feed includes 1 mew"); assert.equal( bobMewsFeed[0].mew.text, aliceMewContent, @@ -283,8 +286,9 @@ it("Unfollowing should exclude creators mews from feed", async () => { fn_name: "get_my_followed_creators_mews_with_context", payload: null, }); - assert.ok( - bobMewsFeedWhenFollowing.length === 1, + assert.equal( + bobMewsFeedWhenFollowing.length, + 1, "bob's mews feed includes 1 mew" ); assert.equal( @@ -304,7 +308,7 @@ it("Unfollowing should exclude creators mews from feed", async () => { fn_name: "get_my_followed_creators_mews_with_context", payload: null, }); - assert.ok(bobMewsFeed.length === 0, "bob's mews feed is empty"); + assert.equal(bobMewsFeed.length, 0, "bob's mews feed is empty"); }, true, { timeout: 500000 } @@ -395,8 +399,9 @@ it("Followed creators mews should be ordered by timestamp in descending order", fn_name: "get_my_followed_creators_mews_with_context", payload: null, }); - assert.ok( - aliceMewsFeed.length === 4, + assert.equal( + aliceMewsFeed.length, + 4, "alice's mews feed includes all 4 mews" ); assert.equal( diff --git a/tests/src/mewsfeed/mews/mention-to-mews.test.ts b/tests/src/mewsfeed/mews/mention-to-mews.test.ts index 324d6eff..a555db88 100644 --- a/tests/src/mewsfeed/mews/mention-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/mention-to-mews.test.ts @@ -54,7 +54,7 @@ it("mention in mews", async () => { mention: bob.agentPubKey, }, }); - assert.ok(mentionedMewsBob.length === 2, "one mew with mention"); + assert.equal(mentionedMewsBob.length, 2, "one mew with mention"); assert.deepEqual(mentionedMewsBob[0].action_hash, actionHash2); const mentionedMewsAlice: FeedMew[] = await alice.cells[0].callZome({ @@ -64,7 +64,7 @@ it("mention in mews", async () => { mention: alice.agentPubKey, }, }); - assert.ok(mentionedMewsAlice.length === 1, "one mew with mention"); + assert.equal(mentionedMewsAlice.length, 1, "one mew with mention"); assert.deepEqual(mentionedMewsAlice[0].action_hash, actionHash3); }, true, diff --git a/tests/src/mewsfeed/mews/mew-to-responses.test.ts b/tests/src/mewsfeed/mews/mew-to-responses.test.ts index 965cee49..61871fca 100644 --- a/tests/src/mewsfeed/mews/mew-to-responses.test.ts +++ b/tests/src/mewsfeed/mews/mew-to-responses.test.ts @@ -63,7 +63,7 @@ it("Agent can reply to a mew", async () => { "mew is an original mew" ); assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.replies_count === 1, "original mew has 1 reply"); + assert.equal(originalMew.replies_count, 1, "original mew has 1 reply"); assert.isTrue( originalMew.is_replied, "original mew's reply is alice's reply" @@ -130,7 +130,7 @@ it("Agent can mewmew a mew, only once", async () => { "mew is an original mew" ); assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.mewmews_count === 1, "original mew has 1 mewmew"); + assert.equal(originalMew.mewmews_count, 1, "original mew has 1 mewmew"); assert.isTrue( originalMew.is_mewmewed, "original mew's mewmew is alice's mewmew" @@ -207,7 +207,7 @@ it("Agent can quote a mew", async () => { "mew is an original mew" ); assert.equal(originalMew.mew.text, aliceMewContent, "mew is alice's mew"); - assert.ok(originalMew.quotes_count === 1, "original mew has 1 quote"); + assert.equal(originalMew.quotes_count, 1, "original mew has 1 quote"); assert.isTrue( originalMew.is_quoted, "original mew's quote is alice's quote" diff --git a/tests/src/mewsfeed/mews/tags-to-mews.test.ts b/tests/src/mewsfeed/mews/tags-to-mews.test.ts index 21d52887..fb9367a7 100644 --- a/tests/src/mewsfeed/mews/tags-to-mews.test.ts +++ b/tests/src/mewsfeed/mews/tags-to-mews.test.ts @@ -50,7 +50,7 @@ it("Hashtag, cashtag and mention", async () => { hashtag: "#hashtag", }, }); - assert.ok(hashtaggedMews.length === 1, "one mew with hashtag"); + assert.equal(hashtaggedMews.length, 1, "one mew with hashtag"); assert.equal( hashtaggedMews[0].mew.text, mewContent, @@ -82,7 +82,7 @@ it("Hashtag, cashtag and mention", async () => { hashtag: "#😃😃😃", }, }); - assert.ok(emojiHashtaggedMews.length === 0, "no mew with emoji hashtag"); + assert.equal(emojiHashtaggedMews.length, 0, "no mew with emoji hashtag"); const cashtaggedMews: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", @@ -91,7 +91,7 @@ it("Hashtag, cashtag and mention", async () => { cashtag: "$cashtag", }, }); - assert.ok(cashtaggedMews.length === 1, "one mew with cashtag"); + assert.equal(cashtaggedMews.length, 1, "one mew with cashtag"); const mentionedMews: FeedMew[] = await alice.cells[0].callZome({ zome_name: "mews", @@ -100,7 +100,7 @@ it("Hashtag, cashtag and mention", async () => { mention: alice.agentPubKey, }, }); - assert.ok(mentionedMews.length === 1, "one mew with mention"); + assert.equal(mentionedMews.length, 1, "one mew with mention"); }, true, { timeout: 500000 } @@ -148,7 +148,7 @@ it("Prefix index should return hashtags and cashtags", async () => { limit: 10, }, }); - assert.ok(hashtags.length === 1, "one hashtag"); + assert.equal(hashtags.length, 1, "one hashtag"); assert.equal(hashtags[0], "#hashtag", "hashtag search result matches"); const arabicHashtags: string[] = await alice.cells[0].callZome({ @@ -159,7 +159,7 @@ it("Prefix index should return hashtags and cashtags", async () => { limit: 10, }, }); - assert.ok(arabicHashtags.length === 1, "one arabic hashtag"); + assert.equal(arabicHashtags.length, 1, "one arabic hashtag"); assert.equal( arabicHashtags[0], "#سعيدة", @@ -175,7 +175,7 @@ it("Prefix index should return hashtags and cashtags", async () => { limit: 10, }, }); - assert.ok(emojiHashtags.length === 0, "no emoji hashtags"); + assert.equal(emojiHashtags.length, 0, "no emoji hashtags"); const cashtags: string[] = await alice.cells[0].callZome({ zome_name: "mews", @@ -185,7 +185,7 @@ it("Prefix index should return hashtags and cashtags", async () => { limit: 10, }, }); - assert.ok(cashtags.length === 1, "one cashtag"); + assert.equal(cashtags.length, 1, "one cashtag"); assert.equal(cashtags[0], "$cashtag", "hashtag search result matches"); }, true,