diff --git a/.github/workflows/ui-automated-tests.yml b/.github/workflows/ui-automated-tests.yml index 1a5e8a78c7..2a5b213745 100644 --- a/.github/workflows/ui-automated-tests.yml +++ b/.github/workflows/ui-automated-tests.yml @@ -32,7 +32,7 @@ jobs: uses: actions/checkout@v4 with: repository: Satellite-im/Warp - ref: 7381a8f759df2973604848d68f4d01353d4f925e + ref: b574da4ab10cfd7bf38ec0e2b499232a2e8f8eff - name: Set up cargo cache 🛠️ uses: Swatinem/rust-cache@v2 @@ -219,7 +219,7 @@ jobs: uses: actions/checkout@v4 with: repository: Satellite-im/Warp - ref: 7381a8f759df2973604848d68f4d01353d4f925e + ref: b574da4ab10cfd7bf38ec0e2b499232a2e8f8eff path: "./warp" - name: Download Key file 🗳️ @@ -248,8 +248,12 @@ jobs: working-directory: ./apps run: | unzip Uplink-Mac-Universal.zip + cp -r ./Uplink.app ./Uplink2.app + perl -i -pe 's/im.satellite.uplink/im.satellite.uplinkChatUserB/g' ./Uplink2.app/Contents/Info.plist cp -r ./Uplink.app /Applications/ + cp -r ./Uplink2.app /Applications/ sudo xattr -r -d com.apple.quarantine /Applications/Uplink.app + sudo xattr -r -d com.apple.quarantine /Applications/Uplink2.app - name: Setup Node.js 🔨 uses: actions/setup-node@v3 @@ -350,7 +354,7 @@ jobs: uses: actions/checkout@v4 with: repository: Satellite-im/Warp - ref: 7381a8f759df2973604848d68f4d01353d4f925e + ref: b574da4ab10cfd7bf38ec0e2b499232a2e8f8eff path: "./warp" - name: Download Key file 🗳️ @@ -494,7 +498,7 @@ jobs: uses: actions/checkout@v4 with: repository: Satellite-im/Warp - ref: 7381a8f759df2973604848d68f4d01353d4f925e + ref: b574da4ab10cfd7bf38ec0e2b499232a2e8f8eff path: "./warp" - name: Download Key file 🗳️ diff --git a/config/wdio.mac.app.conf.ts b/config/wdio.mac.app.conf.ts index 3da785ee90..54b3331263 100644 --- a/config/wdio.mac.app.conf.ts +++ b/config/wdio.mac.app.conf.ts @@ -58,7 +58,8 @@ export const config: WebdriverIO.Config = { "appium:arguments": ["--path", homedir() + "/.uplink"], "appium:systemPort": 4724, "appium:prerun": { - command: 'do shell script "rm -rf ~/.uplink"', + command: + 'do shell script "rm -rf ~/.uplink && rm -rf ~/.uplinkUserB"', }, }, ], diff --git a/config/wdio.mac.ci.conf.ts b/config/wdio.mac.ci.conf.ts index 3675f25d09..6dee1f5292 100644 --- a/config/wdio.mac.ci.conf.ts +++ b/config/wdio.mac.ci.conf.ts @@ -57,7 +57,8 @@ export const config: WebdriverIO.Config = { "appium:arguments": ["--path", homedir() + "/.uplink"], "appium:systemPort": 4724, "appium:prerun": { - command: 'do shell script "rm -rf ~/.uplink"', + command: + 'do shell script "rm -rf ~/.uplink && rm -rf ~/.uplinkUserB"', }, }, ], diff --git a/scripts/replace_node.ps1 b/scripts/replace_node.ps1 index 67a0fe9c1d..a8b1745965 100644 --- a/scripts/replace_node.ps1 +++ b/scripts/replace_node.ps1 @@ -5,14 +5,14 @@ $modRsFilePath = ".\common\src\warp_runner\mod.rs" $modRsContent = Get-Content -Path $modRsFilePath -Raw # Replace the old address with the new address in the mod.rs content -$newModRsContentFirst = $modRsContent -replace "/ip4/104.236.194.35/tcp/34053/", "/ip4/127.0.0.1/tcp/4444/" +$newModRsContentFirst = $modRsContent -replace "/ip4/159.65.41.31/tcp/8848/", "/ip4/127.0.0.1/tcp/4444/" # Set the new address based on the content of peerID.txt $peerIDFilePath = ".\warp\peerID.txt" $newPeerID = (Get-Content -Path $peerIDFilePath | Select-String -Pattern '/ip4/\d+\.\d+\.\d+\.\d+/tcp/\d+/p2p/(\S+)').Matches.Groups[1].Value # Define the old address to be replaced -$oldPeerId = "12D3KooWJSes8386p2T1sMeZ2DzsNJThKkZWbj4US6uPMpEgBTHu" +$oldPeerId = "12D3KooWRF2bz3KDRPvBs1FASRDRk7BfdYc1RUcfwKsz7UBEu7mL" # Replace the old address with the new address in the mod.rs content $newModRsContentTwo = $newModRsContentFirst -replace $oldPeerId, $newPeerID diff --git a/scripts/replace_node.sh b/scripts/replace_node.sh index 053c1cacea..0edac95a46 100644 --- a/scripts/replace_node.sh +++ b/scripts/replace_node.sh @@ -4,7 +4,7 @@ local_peer_id=$(grep -o 'Local PeerID: [^[:space:]]*' ./warp/peerID.txt | awk '{print $NF}') # Update the values in ./common/src/warp_runner/mod.rs and store in a temporary file -sed -e "s#/ip4/104.236.194.35/tcp/34053/p2p/12D3KooWJSes8386p2T1sMeZ2DzsNJThKkZWbj4US6uPMpEgBTHu#/ip4/127.0.0.1/tcp/4444/p2p/$local_peer_id#" ./common/src/warp_runner/mod.rs > temp_file +sed -e "s#/ip4/159.65.41.31/tcp/8848/p2p/12D3KooWRF2bz3KDRPvBs1FASRDRk7BfdYc1RUcfwKsz7UBEu7mL#/ip4/127.0.0.1/tcp/4444/p2p/$local_peer_id#" ./common/src/warp_runner/mod.rs > temp_file # Replace the original mod.rs with the modified content mv temp_file ./common/src/warp_runner/mod.rs diff --git a/tests/helpers/commands.ts b/tests/helpers/commands.ts index 26e3f42118..b58f20b3ed 100644 --- a/tests/helpers/commands.ts +++ b/tests/helpers/commands.ts @@ -152,11 +152,16 @@ export async function launchFirstApplication() { } export async function launchSecondApplication() { - await launchAppMacOS( - MACOS_USER_B_BUNDLE_ID, - "/.uplinkUserB", - "/Applications/Uplink2.app", - ); + const customPath = ".uplinkUserB"; + if (process.env.DRIVER === WINDOWS_DRIVER) { + await launchAppWindows(WINDOWS_APP, customPath); + } else if (process.env.DRIVER === MACOS_DRIVER) { + await launchAppMacOS( + MACOS_USER_B_BUNDLE_ID, + "/" + customPath, + "/Applications/Uplink2.app", + ); + } await browser.pause(5000); } @@ -225,19 +230,15 @@ export async function closeFirstApplication() { } export async function closeSecondApplication() { - await driver.executeScript("macos: terminateApp", [ - { - bundleId: MACOS_USER_B_BUNDLE_ID, - }, - ]); + if (process.env.DRIVER === WINDOWS_DRIVER) { + await closeAppWindows(WINDOWS_APP); + } else if (process.env.DRIVER === MACOS_DRIVER) { + await closeAppMacOS(MACOS_USER_B_BUNDLE_ID); + } } export async function closeThirdApplication() { - await driver.executeScript("macos: terminateApp", [ - { - bundleId: MACOS_USER_C_BUNDLE_ID, - }, - ]); + await closeAppMacOS(MACOS_USER_C_BUNDLE_ID); } export async function maximizeWindow() { @@ -294,12 +295,21 @@ export async function launchAppMacOS( ]); } -export async function launchAppWindows(appLocation: string) { - await driver.executeScript("windows: launchApp", [ - { - app: join(process.cwd(), appLocation), - }, - ]); +export async function launchAppWindows(appLocation: string, path: string = "") { + if (path === "") { + await driver.executeScript("windows: launchApp", [ + { + app: join(process.cwd(), appLocation), + }, + ]); + } else { + await driver.executeScript("windows: launchApp", [ + { + app: join(process.cwd(), appLocation), + "appium:appArguments": "--path " + join(process.cwd(), path), + }, + ]); + } } export async function queryAppStateMacOS(bundle: string) { diff --git a/tests/specs/17-offline-requests.spec.ts b/tests/specs/17-offline-requests.spec.ts index f6c10b6e67..58580f17af 100644 --- a/tests/specs/17-offline-requests.spec.ts +++ b/tests/specs/17-offline-requests.spec.ts @@ -2,15 +2,24 @@ require("module-alias/register"); import { createNewUser } from "@helpers/commandsNewUser"; import { getUserKey, - grabCacheFolder, resetApp, - resetAndLoginWithCache, saveTestKeys, + closeApplication, + launchSecondApplication, + launchApplication, + closeSecondApplication, } from "@helpers/commands"; +import ChatsLayout from "@screenobjects/chats/ChatsLayout"; +import CreatePinScreen from "@screenobjects/account-creation/CreatePinScreen"; import FriendsScreen from "@screenobjects/friends/FriendsScreen"; +import InputBar from "@screenobjects/chats/InputBar"; +import MessageGroupLocal from "@screenobjects/chats/MessageGroupLocal"; +import MessageGroupRemote from "@screenobjects/chats/MessageGroupRemote"; +import MessageLocal from "@screenobjects/chats/MessageLocal"; +import MessageRemote from "@screenobjects/chats/MessageRemote"; import SettingsProfileScreen from "@screenobjects/settings/SettingsProfileScreen"; +import Topbar from "@screenobjects/chats/Topbar"; import WelcomeScreen from "@screenobjects/welcome-screen/WelcomeScreen"; -import CreatePinScreen from "@screenobjects/account-creation/CreatePinScreen"; const userA: string = "UserA"; const userB: string = "UserB"; @@ -39,17 +48,13 @@ export default async function offlineRequestsTests() { // Grab cache folder and restart await saveTestKeys(userA, didkey); - - // Update profile picture from user A - - // Update banner picture from user A - await grabCacheFolder(userA); + await closeApplication(); }); // Wait until toast notification is closed it("Offline Friend Requests - Create account user #2", async () => { // Create New User and go to Settings Profile Screen - await resetApp(); + await launchSecondApplication(); await createNewUser(userB, true); await WelcomeScreen.goToFriends(); }); @@ -80,15 +85,15 @@ export default async function offlineRequestsTests() { // Grab cache folder and restart await saveTestKeys(userB, didkey); - await grabCacheFolder(userB); + await closeSecondApplication(); }); it("Offline Friend Requests - User #1 accepts offline friend request received", async () => { // Clear cache and reset app - await resetAndLoginWithCache("UserA"); + await launchApplication(); + await CreatePinScreen.loginWithTestUser(); // Go to Friends Screen - await CreatePinScreen.loginWithTestUser(); await WelcomeScreen.goToFriends(); await FriendsScreen.waitForIsShown(true); @@ -103,18 +108,15 @@ export default async function offlineRequestsTests() { await FriendsScreen.goToAllFriendsList(); await FriendsScreen.validateAllFriendsListIsShown(); await FriendsScreen.validateAllFriendsListIsNotEmpty(); - - // Go to Chat with User #2 - await FriendsScreen.chatWithFriendButton.click(); - await FriendsScreen.validateSpinnerIsNotShown(); + await closeApplication(); }); it("Offline Friend Requests - Validate offline friend request was accepted", async () => { - // Clear cache and reset app - await resetAndLoginWithCache(userB); + // Launch second app + await launchSecondApplication(); + await CreatePinScreen.loginWithTestUser(); // Go to Friends Screen - await CreatePinScreen.loginWithTestUser(); await WelcomeScreen.goToFriends(); await FriendsScreen.waitForIsShown(true); @@ -124,4 +126,102 @@ export default async function offlineRequestsTests() { await FriendsScreen.validateAllFriendsListIsNotEmpty(); await FriendsScreen.waitUntilUserAcceptedFriendRequest(); }); + + it("Offline Messages - Chat screen displays Messages secured text displayed on top of conversation", async () => { + // Go to Chat with User A + await FriendsScreen.goToChatWithFriend(); + await Topbar.validateTopbarExists(); + + // Validate E2E message is displayed on top of chat + const encryptedMessagesText = await ChatsLayout.encryptedMessagesText; + await encryptedMessagesText.waitForExist(); + await expect(encryptedMessagesText).toHaveTextContaining( + "Messages are secured by end-to-end encryption and sent over a peer-to-peer network.", + ); + }); + + it("Offline Messages - Send a message to offline user", async () => { + // Send message to the other user + await InputBar.typeMessageOnInput("Testing..."); + await InputBar.clickOnSendMessage(); + await MessageLocal.waitForMessageSentToExist("Testing..."); + + const textFromMessage = + await MessageLocal.getCustomMessageContents("Testing..."); + await expect(textFromMessage).toHaveText("Testing..."); + }); + + it("Offline Messages - Validate Chat Message displays timestamp and user who sent it", async () => { + //Timestamp from last message sent should be displayed + const timeAgo = await MessageGroupLocal.getLastMessageSentTimeAgo(); + await expect(timeAgo).toHaveTextContaining( + /- (?:\d{1,2}\s+(?:second|minute)s?\s+ago|now)$/, + ); + await expect(timeAgo).toHaveTextContaining("UserB"); + }); + + it("Offline Messages - Validate Chat Message sent contents", async () => { + //Any message you sent yourself should appear within a colored message bubble + const messageText = + await MessageLocal.getCustomMessageContents("Testing..."); + await expect(messageText).toHaveText("Testing..."); + }); + + it("Offline Messages - Validate Chat Message displays username picture", async () => { + //Your user image should be displayed next to the message + const userImage = await MessageGroupLocal.getLastGroupWrapSentImage(); + await userImage.waitForExist(); + }); + + it("Offline Messages - Topbar information", async () => { + // Validate user image, username is displayed on Chat Topbar + await Topbar.validateTopbarUserImage(); + await Topbar.validateTopbarUserName("UserA"); + + // Terminate Second Application + await closeSecondApplication(); + }); + + it("Offline Messages - Assert user can receive messages while being offline", async () => { + // Open first application + await launchApplication(); + await CreatePinScreen.loginWithTestUser(); + + // Go to the current list of All friends and then open a Chat conversation with UserB + await WelcomeScreen.goToFriends(); + await FriendsScreen.waitForIsShown(true); + await FriendsScreen.chatWithFriendButton.waitForExist(); + await FriendsScreen.hoverOnChatWithFriendButton("UserB"); + await FriendsScreen.chatWithFriendButton.click(); + await FriendsScreen.validateSpinnerIsNotShown(); + await Topbar.validateTopbarExists(); + }); + + it("Offline Messages - Assert message received from UserB", async () => { + // Validate message received from Chat User A + await MessageRemote.waitForReceivingMessage("Testing..."); + + //Any message you sent yourself should appear within a colored message bubble + const textFromMessage = + await MessageRemote.getCustomMessageContents("Testing..."); + await expect(textFromMessage).toHaveText("Testing..."); + }); + + it("Offline Messages - Validate Chat Message Group from remote user displays username picture", async () => { + //Your user image should be displayed next to the message + const userImage = await MessageGroupRemote.getLastGroupWrapReceivedImage(); + await userImage.waitForExist(); + }); + + it("Offline Messages - Validate Chat Message received displays timestamp and user who sent it", async () => { + //Timestamp should be displayed when you send a message + const timeAgo = await MessageGroupRemote.getLastMessageReceivedTimeAgo(); + await expect(timeAgo).toHaveTextContaining( + /- (?:\d{1,2}\s+(?:second|minute)s?\s+ago|now)$/, + ); + await expect(timeAgo).toHaveTextContaining("UserB"); + + // Grab cache folder + await closeApplication(); + }); } diff --git a/tests/specs/reusable-accounts/01-create-accounts-and-friends.spec.ts b/tests/specs/reusable-accounts/01-create-accounts-and-friends.spec.ts index 4e089ffc5b..d3f4081eac 100644 --- a/tests/specs/reusable-accounts/01-create-accounts-and-friends.spec.ts +++ b/tests/specs/reusable-accounts/01-create-accounts-and-friends.spec.ts @@ -105,8 +105,10 @@ export default async function createChatAccountsTests() { // Create a new account and go to Settings Profile await CreatePinScreen.waitForIsShown(true); - const username = "ChatUserB"; - await createNewUser(username); + await createNewUser("ChatUserB"); + }); + + it("Chat User B - Save Did Key from User", async () => { await WelcomeScreen.goToSettings(); await SettingsProfileScreen.validateSettingsProfileIsShown(); @@ -125,7 +127,7 @@ export default async function createChatAccountsTests() { // Grab cache folder and restart const didkey = await SettingsProfileScreen.getCopiedDidFromStatusInput(); - await saveTestKeys(username, didkey); + await saveTestKeys("ChatUserB", didkey); await SettingsProfileScreen.deleteStatus(); });