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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 45 additions & 5 deletions .github/workflows/android-regression.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,58 @@ jobs:
- name: Download APK & extract it
run: |
pwd

# Check if devnet is accessible before choosing APK
echo "Checking devnet accessibility for APK selection..."
DEVNET_ACCESSIBLE=false

# Retry logic matching your TypeScript function
for attempt in 1 2 3; do
echo "Devnet check attempt $attempt/3..."
if curl -s --connect-timeout 5 --max-time 10 http://sesh-net.local:1280 >/dev/null 2>&1; then
echo "Devnet is accessible on attempt $attempt"
DEVNET_ACCESSIBLE=true
break
else
echo "Attempt $attempt failed"
if [ $attempt -lt 3 ]; then
echo "Waiting ${attempt}s before retry..."
sleep $attempt
fi
fi
done

if [ "$DEVNET_ACCESSIBLE" = "false" ]; then
echo "Devnet is not accessible after 3 attempts"
fi

# Download and extract APK
wget -q -O session-android.apk.tar.xz ${{ github.event.inputs.APK_URL }}
tar xf session-android.apk.tar.xz
mv session-android-*universal extracted

if ls extracted/*automaticQa.apk; then
mv extracted/*automaticQa.apk extracted/session-android.apk
echo "IS_AUTOMATIC_QA=true" >> $GITHUB_ENV
elif ls extracted/*qa.apk; then
# Choose APK based on devnet accessibility
if ls extracted/*automaticQa.apk 1>/dev/null 2>&1; then
if [ "$DEVNET_ACCESSIBLE" = "true" ]; then
echo "Using AQA build (devnet accessible)"
mv extracted/*automaticQa.apk extracted/session-android.apk
echo "IS_AUTOMATIC_QA=true" >> $GITHUB_ENV
else
echo "AQA build available but devnet not accessible - falling back to regular QA build"
if ls extracted/*qa.apk 1>/dev/null 2>&1; then
mv extracted/*qa.apk extracted/session-android.apk
echo "IS_AUTOMATIC_QA=false" >> $GITHUB_ENV
else
echo "No regular QA build found as fallback"
exit 1
fi
fi
elif ls extracted/*qa.apk 1>/dev/null 2>&1; then
echo "Using regular QA build"
mv extracted/*qa.apk extracted/session-android.apk
echo "IS_AUTOMATIC_QA=false" >> $GITHUB_ENV
else
echo "Error: No .qa APK found (only .qa builds are supported)"
echo "No suitable APK found"
exit 1
fi

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"prettier": "^3.3.3",
"sharp": "^0.34.2",
"sinon": "^19.0.2",
"ssim.js": "^3.5.0",
"sync-request-curl": "^3.3.3",
"ts-node": "^10.9.1",
"typescript": "^5.6.3",
Expand Down
4 changes: 2 additions & 2 deletions run/screenshots/android/app_disguise.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/android/conversation_alice.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/android/conversation_bob.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions run/screenshots/android/landingpage_new_account.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions run/screenshots/android/landingpage_restore_account.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/android/settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/android/settings_appearance.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/android/settings_conversations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/android/settings_notifications.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/android/settings_privacy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/android/upm_home.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions run/screenshots/ios/app_disguise.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/ios/conversation_alice.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/ios/conversation_bob.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions run/screenshots/ios/landingpage_new_account.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions run/screenshots/ios/landingpage_restore_account.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/ios/settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/ios/settings_appearance.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/ios/settings_conversations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/ios/settings_notifications.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions run/screenshots/ios/settings_privacy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 4 additions & 5 deletions run/test/specs/app_disguise_icons.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import { USERNAME } from '../../types/testing';
import { AppearanceMenuItem, SelectAppIcon, UserSettings } from './locators/settings';
import { newUser } from './utils/create_account';
import { closeApp, openAppOnPlatformSingleDevice, SupportedPlatformsType } from './utils/open_app';
import { AppDisguisePageScreenshot } from './utils/screenshot_paths';
import { verifyElementScreenshot } from './utils/verify_screenshots';
import { verifyPageScreenshot } from './utils/verify_screenshots';

bothPlatformsIt({
title: 'App disguise icons',
title: 'Check app disguise icon layout',
risk: 'medium',
countOfDevicesNeeded: 1,
testCb: appDisguiseIcons,
Expand All @@ -31,9 +30,9 @@ async function appDisguiseIcons(platform: SupportedPlatformsType, testInfo: Test
await device.clickOnElementAll(new UserSettings(device));
await device.clickOnElementAll(new AppearanceMenuItem(device));
});
await test.step(TestSteps.VERIFY.ELEMENT_SCREENSHOT('app disguise icons'), async () => {
await test.step(TestSteps.VERIFY.SCREENSHOT('app disguise icons'), async () => {
await device.clickOnElementAll(new SelectAppIcon(device));
await verifyElementScreenshot(device, new AppDisguisePageScreenshot(device), testInfo);
await verifyPageScreenshot(device, platform, 'app_disguise', testInfo, 0.99);
});
await test.step(TestSteps.SETUP.CLOSE_APP, async () => {
await closeApp(device);
Expand Down
3 changes: 2 additions & 1 deletion run/test/specs/check_avatar_color.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ import { isSameColor } from './utils/check_colour';
import { closeApp, SupportedPlatformsType } from './utils/open_app';

bothPlatformsIt({
title: 'Avatar color',
title: 'Check placeholder avatar color',
risk: 'medium',
countOfDevicesNeeded: 2,
testCb: avatarColor,
allureSuites: {
parent: 'Visual Checks',
suite: 'Settings',
},
allureDescription: `Verifies that a user's placeholder avatar color appears the same to a contact`,
});
Expand Down
3 changes: 3 additions & 0 deletions run/test/specs/community_emoji_react.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ bothPlatformsIt({
suite: 'Emoji reacts',
},
allureDescription: 'Verifies that an emoji reaction can be sent and is received in a community',
allureLinks: {
android: 'SES-4608',
},
});

async function sendEmojiReactionCommunity(platform: SupportedPlatformsType, testInfo: TestInfo) {
Expand Down
4 changes: 2 additions & 2 deletions run/test/specs/disappearing_call.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { TestInfo } from '@playwright/test';

import { bothPlatformsItSeparate } from '../../types/sessionIt';
import { DISAPPEARING_TIMES } from '../../types/testing';
import { CallButton, NotificationSettings, NotificationSwitch } from './locators/conversation';
import { CallButton, NotificationsModalButton, NotificationSwitch } from './locators/conversation';
import { ContinueButton } from './locators/global';
import { open_Alice1_Bob1_friends } from './state_builder';
import { sleepFor } from './utils';
Expand Down Expand Up @@ -123,7 +123,7 @@ async function disappearingCallMessage1o1Android(
await alice1.clickOnElementById(
'com.android.permissioncontroller:id/permission_allow_foreground_only_button'
);
await alice1.clickOnElementAll(new NotificationSettings(alice1));
await alice1.clickOnElementAll(new NotificationsModalButton(alice1));
await alice1.clickOnElementAll(new NotificationSwitch(alice1));
// Return to conversation
await alice1.navigateBack(false);
Expand Down
19 changes: 9 additions & 10 deletions run/test/specs/landing_page_new_account.spec.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import type { TestInfo } from '@playwright/test';
import { type TestInfo } from '@playwright/test';

import { bothPlatformsIt } from '../../types/sessionIt';
import { USERNAME } from '../../types/testing';
import { newUser } from './utils/create_account';
import { closeApp, openAppOnPlatformSingleDevice, SupportedPlatformsType } from './utils/open_app';
import { EmptyLandingPageScreenshot } from './utils/screenshot_paths';
import { verifyElementScreenshot } from './utils/verify_screenshots';
import { verifyPageScreenshot } from './utils/verify_screenshots';

bothPlatformsIt({
title: 'Landing page new account',
title: 'Check landing page (new account) layout',
risk: 'low',
testCb: landingPageNewAccount,
countOfDevicesNeeded: 1,
allureSuites: {
parent: 'Visual Checks',
suite: 'Onboarding',
},
allureDescription: `Verifies that the landing page for a new account matches the expected baseline`,
});

async function landingPageNewAccount(platform: SupportedPlatformsType, testInfo: TestInfo) {
const { device } = await openAppOnPlatformSingleDevice(platform, testInfo);
await newUser(device, USERNAME.ALICE);
// Verify that the party popper is shown on the landing page
await verifyElementScreenshot(
device,
new EmptyLandingPageScreenshot(device),
testInfo,
'new_account'
);
await verifyPageScreenshot(device, platform, 'landingpage_new_account', testInfo, 0.995);
await closeApp(device);
}
17 changes: 8 additions & 9 deletions run/test/specs/landing_page_restore_account.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,25 @@ import { USERNAME } from '@session-foundation/qa-seeder';
import { bothPlatformsIt } from '../../types/sessionIt';
import { linkedDevice } from './utils/link_device';
import { closeApp, openAppTwoDevices, SupportedPlatformsType } from './utils/open_app';
import { EmptyLandingPageScreenshot } from './utils/screenshot_paths';
import { verifyElementScreenshot } from './utils/verify_screenshots';
import { verifyPageScreenshot } from './utils/verify_screenshots';

bothPlatformsIt({
title: 'Landing page restore account',
title: 'Check landing page (restored account) layout',
risk: 'low',
testCb: landingPageRestoreAccount,
countOfDevicesNeeded: 2,
allureSuites: {
parent: 'Visual Checks',
suite: 'Onboarding',
},
allureDescription: `Verifies that the landing page for a restored account matches the expected baseline`,
});

async function landingPageRestoreAccount(platform: SupportedPlatformsType, testInfo: TestInfo) {
// Creating a linked device is used as a shortcut to restore an account
const { device1: alice1, device2: alice2 } = await openAppTwoDevices(platform, testInfo);
await linkedDevice(alice1, alice2, USERNAME.ALICE);
// Verify that the Session logo is shown on the landing page
await verifyElementScreenshot(
alice2,
new EmptyLandingPageScreenshot(alice2),
testInfo,
'restore_account'
);
await verifyPageScreenshot(alice2, platform, 'landingpage_restore_account', testInfo, 0.995);
await closeApp(alice1, alice2);
}
60 changes: 52 additions & 8 deletions run/test/specs/locators/conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,9 @@ export class OutgoingMessageStatusSent extends LocatorsInterface {
switch (this.platform) {
case 'android':
return {
strategy: '-android uiautomator',
selector:
'new UiSelector().resourceId("network.loki.messenger.qa:id/messageStatusTextView").text("Sent")',
strategy: 'id',
selector: 'network.loki.messenger.qa:id/messageStatusTextView',
text: 'Sent',
} as const;
case 'ios':
return {
Expand Down Expand Up @@ -234,12 +234,20 @@ export class ConversationHeaderName extends LocatorsInterface {
}
}

export class NotificationSettings extends LocatorsInterface {
export class NotificationsModalButton extends LocatorsInterface {
public build() {
return {
strategy: 'accessibility id',
selector: 'Notifications',
} as const;
switch (this.platform) {
case 'android':
return {
strategy: 'accessibility id',
selector: 'Notifications',
} as const;
case 'ios':
return {
strategy: 'accessibility id',
selector: 'Notifications',
} as const;
}
}
}

Expand Down Expand Up @@ -585,3 +593,39 @@ export class EmojiReactsCount extends LocatorsInterface {
}
}
}

export class MessageLengthCountdown extends LocatorsInterface {
constructor(
device: DeviceWrapper,
private length?: string
) {
super(device);
}
public build(): StrategyExtractionObj {
switch (this.platform) {
case 'android':
return {
strategy: 'id',
selector: 'network.loki.messenger.qa:id/characterLimitText',
text: this.length,
} as const;
case 'ios':
return {
strategy: 'xpath',
selector: `//XCUIElementTypeStaticText[@name="${this.length}"]`,
text: this.length,
} as const;
}
}
}

export class MessageLengthOkayButton extends LocatorsInterface {
public build(): StrategyExtractionObj {
switch (this.platform) {
case 'android':
return { strategy: 'id', selector: 'Okay' } as const;
case 'ios':
return { strategy: 'xpath', selector: '//XCUIElementTypeButton[@name="Okay"]' } as const;
}
}
}
Loading
Loading