Tests: Make Detox work on Android (#3051)

This commit is contained in:
Anant Bhasin 2021-12-02 18:49:15 +05:30 committed by GitHub
parent 010d88530c
commit f69b82dae9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 837 additions and 507 deletions

View File

@ -1419,6 +1419,7 @@ Array [
</Text>
</View>
<View
accessibilityLabel="Use"
accessible={true}
focusable={true}
onClick={[Function]}
@ -1581,6 +1582,7 @@ Array [
</Text>
</View>
<View
accessibilityLabel="Use"
accessible={true}
focusable={true}
onClick={[Function]}
@ -41244,6 +41246,7 @@ exports[`Storyshots Message Show a button as attachment 1`] = `
Test Button
</Text>
<View
accessibilityLabel="Text button"
accessible={true}
focusable={true}
onClick={[Function]}

View File

@ -151,6 +151,8 @@ android {
missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60" // See note below!
}
resValue "string", "rn_config_reader_custom_package", "chat.rocket.reactnative"
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
signingConfigs {
@ -203,6 +205,10 @@ android {
dimension = "app"
buildConfigField "boolean", "IS_OFFICIAL", "false"
}
e2e {
dimension = "app"
buildConfigField "boolean", "IS_OFFICIAL", "false"
}
foss {
dimension = "type"
buildConfigField "boolean", "FDROID_BUILD", "true"
@ -230,6 +236,16 @@ android {
java.srcDirs = ['src/main/java', 'src/play/java']
manifest.srcFile 'src/play/AndroidManifest.xml'
}
e2ePlayDebug {
java.srcDirs = ['src/main/java', 'src/play/java']
res.srcDirs = ['src/experimental/res']
manifest.srcFile 'src/play/AndroidManifest.xml'
}
e2ePlayRelease {
java.srcDirs = ['src/main/java', 'src/play/java']
res.srcDirs = ['src/experimental/res']
manifest.srcFile 'src/play/AndroidManifest.xml'
}
}
applicationVariants.all { variant ->
@ -294,6 +310,8 @@ dependencies {
implementation "com.tencent:mmkv-static:1.2.1"
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation "com.squareup.okhttp3:okhttp-urlconnection:4.9.0"
androidTestImplementation('com.wix:detox:+') { transitive = true }
androidTestImplementation 'junit:junit:4.12'
}
// Run this once to be able to run the application with BUCK

View File

@ -0,0 +1,32 @@
// Replace "com.example" here and below with your app's package name from the top of MainActivity.java
package chat.rocket.reactnative;
import com.wix.detox.Detox;
import com.wix.detox.config.DetoxConfig;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class DetoxTest {
@Rule
// Replace 'MainActivity' with the value of android:name entry in
// <activity> in AndroidManifest.xml
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class, false, false);
@Test
public void runDetoxTests() {
DetoxConfig detoxConfig = new DetoxConfig();
detoxConfig.idlePolicyConfig.masterTimeoutSec = 90;
detoxConfig.idlePolicyConfig.idleResourceTimeoutSec = 60;
detoxConfig.rnContextLoadTimeoutSec = (chat.rocket.reactnative.BuildConfig.DEBUG ? 180 : 60);
Detox.runTests(mActivityRule, detoxConfig);
}
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config xmlns:tools="http://schemas.android.com/tools">
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user"
tools:ignore="AcceptsUserCertificates" />
</trust-anchors>
</base-config>
</network-security-config>

View File

@ -53,6 +53,10 @@ allprojects {
url("$rootDir/../node_modules/jsc-android/dist")
}
maven {
url "$rootDir/../node_modules/detox/Detox-android"
}
maven {
url jitsi_url
}

View File

@ -124,7 +124,11 @@ const ActionSheet = React.memo(
const renderFooter = () =>
data?.hasCancel ? (
<Button onPress={hide} style={[styles.button, { backgroundColor: themes[theme].auxiliaryBackground }]} theme={theme}>
<Button
onPress={hide}
style={[styles.button, { backgroundColor: themes[theme].auxiliaryBackground }]}
theme={theme}
accessibilityLabel={I18n.t('Cancel')}>
<Text style={[styles.text, { color: themes[theme].bodyText }]}>{I18n.t('Cancel')}</Text>
</Button>
) : null;

View File

@ -70,6 +70,7 @@ export default class Button extends React.PureComponent<Partial<IButtonProps>, a
disabled && styles.disabled,
style
]}
accessibilityLabel={title}
{...otherProps}>
{loading ? (
<ActivityIndicator color={textColor} />

View File

@ -43,7 +43,11 @@ const Content = React.memo(
content = <Text style={[styles.text, { color: themes[props.theme].bodyText }]}>{I18n.t('Sent_an_attachment')}</Text>;
} else if (props.isEncrypted) {
content = (
<Text style={[styles.textInfo, { color: themes[props.theme].auxiliaryText }]}>{I18n.t('Encrypted_message')}</Text>
<Text
style={[styles.textInfo, { color: themes[props.theme].auxiliaryText }]}
accessibilityLabel={I18n.t('Encrypted_message')}>
{I18n.t('Encrypted_message')}
</Text>
);
} else {
const { baseUrl, user, onLinkPress } = useContext(MessageContext);

View File

@ -1,5 +1,5 @@
// https://github.com/RocketChat/Rocket.Chat/blob/develop/definition/ITeam.ts
export const TEAM_TYPE = {
exports.TEAM_TYPE = {
PUBLIC: 0,
PRIVATE: 1
};

View File

@ -63,7 +63,11 @@ export default class DirectoryOptions extends PureComponent<IDirectoryOptionsPro
}
return (
<Touch onPress={() => changeType(itemType)} style={styles.dropdownItemButton} theme={theme}>
<Touch
onPress={() => changeType(itemType)}
style={styles.dropdownItemButton}
theme={theme}
accessibilityLabel={I18n.t(text)}>
<View style={styles.dropdownItemContainer}>
<CustomIcon style={[styles.dropdownItemIcon, { color: themes[theme].bodyText }]} size={22} name={icon} />
<Text style={[styles.dropdownItemText, { color: themes[theme].bodyText }]}>{I18n.t(text)}</Text>
@ -90,7 +94,7 @@ export default class DirectoryOptions extends PureComponent<IDirectoryOptionsPro
</TouchableWithoutFeedback>
<Animated.View
style={[styles.dropdownContainer, { transform: [{ translateY }], backgroundColor: themes[theme].backgroundColor }]}>
<Touch onPress={this.close} theme={theme}>
<Touch onPress={this.close} theme={theme} accessibilityLabel={I18n.t('Search_by')}>
<View
style={[
styles.dropdownContainerHeader,

View File

@ -918,7 +918,6 @@ class RoomActionsView extends React.Component {
event: this.convertTeamToChannel
})
}
testID='room-actions-convert-channel-to-team'
left={() => <List.Icon name='channel-public' />}
showActionIndicator
/>

View File

@ -25,7 +25,7 @@ const Item = React.memo(({ left, right, text, onPress, testID, current, theme }:
style={[styles.item, current && { backgroundColor: themes[theme].borderColor }]}>
<View style={styles.itemHorizontal}>{left}</View>
<View style={styles.itemCenter}>
<Text style={[styles.itemText, { color: themes[theme].titleText }]} numberOfLines={1}>
<Text style={[styles.itemText, { color: themes[theme].titleText }]} numberOfLines={1} accessibilityLabel={text}>
{text}
</Text>
</View>

View File

@ -1,10 +1,33 @@
const { exec } = require('child_process');
const data = require('../data');
const platformTypes = {
android: {
// Android types
alertButtonType: 'android.widget.Button',
scrollViewType: 'android.widget.ScrollView',
textInputType: 'android.widget.EditText',
textMatcher: 'text'
},
ios: {
// iOS types
alertButtonType: '_UIAlertControllerActionView',
scrollViewType: 'UIScrollView',
textInputType: '_UIAlertControllerTextField',
textMatcher: 'label'
}
};
function sleep(ms) {
return new Promise(res => setTimeout(res, ms));
}
async function navigateToWorkspace(server = data.server) {
await waitFor(element(by.id('new-server-view')))
.toBeVisible()
.withTimeout(60000);
await element(by.id('new-server-view-input')).typeText(`${server}\n`);
await element(by.id('new-server-view-input')).replaceText(`${server}`);
await element(by.id('new-server-view-input')).tapReturnKey();
await waitFor(element(by.id('workspace-view')))
.toBeVisible()
.withTimeout(60000);
@ -41,6 +64,8 @@ async function login(username, password) {
}
async function logout() {
const deviceType = device.getPlatform();
const { scrollViewType, textMatcher } = platformTypes[deviceType];
await element(by.id('rooms-list-view-sidebar')).tap();
await waitFor(element(by.id('sidebar-view')))
.toBeVisible()
@ -52,14 +77,14 @@ async function logout() {
await waitFor(element(by.id('settings-view')))
.toBeVisible()
.withTimeout(2000);
await element(by.type('UIScrollView')).atIndex(1).scrollTo('bottom');
await element(by.type(scrollViewType)).atIndex(1).scrollTo('bottom');
await element(by.id('settings-logout')).tap();
const logoutAlertMessage = 'You will be logged out of this application.';
await waitFor(element(by.text(logoutAlertMessage)).atIndex(0))
await waitFor(element(by[textMatcher](logoutAlertMessage)).atIndex(0))
.toExist()
.withTimeout(10000);
await expect(element(by.text(logoutAlertMessage)).atIndex(0)).toExist();
await element(by.text('Logout')).tap();
await expect(element(by[textMatcher](logoutAlertMessage)).atIndex(0)).toExist();
await element(by[textMatcher]('Logout')).atIndex(0).tap();
await waitFor(element(by.id('new-server-view')))
.toBeVisible()
.withTimeout(10000);
@ -67,66 +92,73 @@ async function logout() {
}
async function mockMessage(message, isThread = false) {
const deviceType = device.getPlatform();
const { textMatcher } = platformTypes[deviceType];
const input = isThread ? 'messagebox-input-thread' : 'messagebox-input';
await element(by.id(input)).tap();
await element(by.id(input)).typeText(`${data.random}${message}`);
await element(by.id(input)).replaceText(`${data.random}${message}`);
await sleep(300);
await element(by.id('messagebox-send-message')).tap();
await waitFor(element(by.label(`${data.random}${message}`)))
await waitFor(element(by[textMatcher](`${data.random}${message}`)))
.toExist()
.withTimeout(60000);
await expect(element(by.label(`${data.random}${message}`))).toExist();
await element(by.label(`${data.random}${message}`))
await element(by[textMatcher](`${data.random}${message}`))
.atIndex(0)
.tap();
}
async function starMessage(message) {
const deviceType = device.getPlatform();
const { textMatcher } = platformTypes[deviceType];
const messageLabel = `${data.random}${message}`;
await element(by.label(messageLabel)).atIndex(0).longPress();
await element(by[textMatcher](messageLabel)).atIndex(0).longPress();
await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await element(by.label('Star')).atIndex(0).tap();
await element(by[textMatcher]('Star')).atIndex(0).tap();
await waitFor(element(by.id('action-sheet')))
.not.toExist()
.withTimeout(5000);
}
async function pinMessage(message) {
const deviceType = device.getPlatform();
const { textMatcher } = platformTypes[deviceType];
const messageLabel = `${data.random}${message}`;
await waitFor(element(by.label(messageLabel)).atIndex(0)).toExist();
await element(by.label(messageLabel)).atIndex(0).longPress();
await waitFor(element(by[textMatcher](messageLabel)).atIndex(0)).toExist();
await element(by[textMatcher](messageLabel)).atIndex(0).longPress();
await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await element(by.label('Pin')).atIndex(0).tap();
await element(by[textMatcher]('Pin')).atIndex(0).tap();
await waitFor(element(by.id('action-sheet')))
.not.toExist()
.withTimeout(5000);
}
async function dismissReviewNag() {
await waitFor(element(by.text('Are you enjoying this app?')))
const deviceType = device.getPlatform();
const { textMatcher } = platformTypes[deviceType];
await waitFor(element(by[textMatcher]('Are you enjoying this app?')))
.toExist()
.withTimeout(60000);
await element(by.label('No').and(by.type('_UIAlertControllerActionView'))).tap(); // Tap `no` on ask for review alert
await element(by[textMatcher]('No')).atIndex(0).tap(); // Tap `no` on ask for review alert
}
async function tapBack() {
await element(by.id('header-back')).atIndex(0).tap();
}
function sleep(ms) {
return new Promise(res => setTimeout(res, ms));
}
async function searchRoom(room) {
await waitFor(element(by.id('rooms-list-view')))
.toBeVisible()
.withTimeout(30000);
await element(by.id('rooms-list-view-search')).tap();
await expect(element(by.id('rooms-list-view-search-input'))).toExist();
await waitFor(element(by.id('rooms-list-view-search-input')))
.toExist()
.withTimeout(5000);
await element(by.id('rooms-list-view-search-input')).typeText(room);
await sleep(300);
await element(by.id('rooms-list-view-search-input')).replaceText(room);
await sleep(300);
await waitFor(element(by.id(`rooms-list-view-item-${room}`)))
.toBeVisible()
@ -162,6 +194,29 @@ const checkServer = async server => {
await element(by.id('sidebar-close-drawer')).tap();
};
function runCommand(command) {
return new Promise((resolve, reject) => {
exec(command, (error, stdout, stderr) => {
if (error) {
reject(new Error(`exec error: ${stderr}`));
return;
}
resolve();
});
});
}
async function prepareAndroid() {
if (device.getPlatform() !== 'android') {
return;
}
await runCommand('adb shell settings put secure spell_checker_enabled 0');
await runCommand('adb shell settings put secure autofill_service null');
await runCommand('adb shell settings put global window_animation_scale 0.0');
await runCommand('adb shell settings put global transition_animation_scale 0.0');
await runCommand('adb shell settings put global animator_duration_scale 0.0');
}
module.exports = {
navigateToWorkspace,
navigateToLogin,
@ -176,5 +231,7 @@ module.exports = {
sleep,
searchRoom,
tryTapping,
checkServer
checkServer,
platformTypes,
prepareAndroid
};

View File

@ -1,4 +1,5 @@
const { navigateToLogin, login, sleep, tapBack, mockMessage, searchRoom, logout } = require('../../helpers/app');
const { navigateToLogin, login, sleep, tapBack, mockMessage, searchRoom, logout, platformTypes } = require('../../helpers/app');
const data = require('../../data');
const testuser = data.users.regular;
@ -17,8 +18,9 @@ const checkServer = async server => {
};
const checkBanner = async () => {
await waitFor(element(by.id('listheader-encryption').withDescendant(by.label('Save Your Encryption Password'))))
.toBeVisible()
// TODO: Assert 'Save Your Encryption Password'
await waitFor(element(by.id('listheader-encryption')))
.toExist()
.withTimeout(10000);
};
@ -58,9 +60,13 @@ async function navigateSecurityPrivacy() {
describe('E2E Encryption', () => {
const room = `encrypted${data.random}`;
const newPassword = 'abc';
let alertButtonType;
let scrollViewType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, scrollViewType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(testuser.username, testuser.password);
});
@ -187,11 +193,11 @@ describe('E2E Encryption', () => {
it('should change password', async () => {
await element(by.id('e2e-encryption-security-view-password')).typeText(newPassword);
await element(by.id('e2e-encryption-security-view-change-password')).tap();
await waitFor(element(by.text('Are you sure?')))
await waitFor(element(by[textMatcher]('Are you sure?')))
.toExist()
.withTimeout(2000);
await expect(element(by.text("Make sure you've saved it carefully somewhere else."))).toExist();
await element(by.label('Yes, change it').and(by.type('_UIAlertControllerActionView'))).tap();
await expect(element(by[textMatcher]("Make sure you've saved it carefully somewhere else."))).toExist();
await element(by[textMatcher]('Yes, change it')).atIndex(0).tap();
await waitForToast();
});
@ -216,7 +222,7 @@ describe('E2E Encryption', () => {
.toBeVisible()
.withTimeout(2000);
await navigateToRoom(room);
await waitFor(element(by.label(`${data.random}message`)).atIndex(0))
await waitFor(element(by[textMatcher](`${data.random}message`)).atIndex(0))
.toExist()
.withTimeout(2000);
});
@ -230,7 +236,7 @@ describe('E2E Encryption', () => {
await navigateToLogin();
await login(testuser.username, testuser.password);
await navigateToRoom(room);
await waitFor(element(by.label(`${data.random}message`)).atIndex(0))
await waitFor(element(by[textMatcher](`${data.random}message`)).atIndex(0))
.not.toExist()
.withTimeout(2000);
await expect(element(by.label('Encrypted message')).atIndex(0)).toExist();
@ -241,10 +247,11 @@ describe('E2E Encryption', () => {
await waitFor(element(by.id('rooms-list-view')))
.toBeVisible()
.withTimeout(2000);
await waitFor(element(by.id('listheader-encryption').withDescendant(by.label('Enter Your E2E Password'))))
// TODO: assert 'Enter Your E2E Password'
await waitFor(element(by.id('listheader-encryption')))
.toBeVisible()
.withTimeout(2000);
await element(by.id('listheader-encryption').withDescendant(by.label('Enter Your E2E Password'))).tap();
await element(by.id('listheader-encryption')).tap();
await waitFor(element(by.id('e2e-enter-your-password-view')))
.toBeVisible()
.withTimeout(2000);
@ -254,43 +261,52 @@ describe('E2E Encryption', () => {
.not.toExist()
.withTimeout(10000);
await navigateToRoom(room);
await waitFor(element(by.label(`${data.random}message`)).atIndex(0))
await waitFor(element(by[textMatcher](`${data.random}message`)).atIndex(0))
.toExist()
.withTimeout(2000);
});
});
describe('Reset E2E key', () => {
it('should reset e2e key', async () => {
before(async () => {
await tapBack();
await waitFor(element(by.id('rooms-list-view')))
.toBeVisible()
.withTimeout(2000);
});
it('should reset e2e key', async () => {
// FIXME: too flaky on Android for now... let's fix it later
// It's also flaky on iOS, but it works from time to time
if (device.getPlatform() === 'android') {
return;
}
await navigateSecurityPrivacy();
await element(by.id('security-privacy-view-e2e-encryption')).tap();
await waitFor(element(by.id('e2e-encryption-security-view')))
.toBeVisible()
.withTimeout(2000);
await element(by.id('e2e-encryption-security-view-reset-key').and(by.label('Reset E2E Key'))).tap();
await waitFor(element(by.text('Are you sure?')))
await waitFor(element(by[textMatcher]('Are you sure?')))
.toExist()
.withTimeout(2000);
await expect(element(by.text("You're going to be logged out."))).toExist();
await element(by.label('Yes, reset it').and(by.type('UILabel'))).tap();
await expect(element(by[textMatcher]("You're going to be logged out."))).toExist();
await element(by[textMatcher]('Yes, reset it').and(by.type(alertButtonType))).tap();
await sleep(2000);
await waitFor(element(by[textMatcher]("You've been logged out by the server. Please log in again.")))
.toExist()
.withTimeout(20000);
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('workspace-view')))
.toBeVisible()
.withTimeout(10000);
await waitFor(element(by.text("You've been logged out by the server. Please log in again.")))
.toExist()
.withTimeout(2000);
await element(by.label('OK').and(by.type('_UIAlertControllerActionView'))).tap();
await element(by.id('workspace-view-login')).tap();
await waitFor(element(by.id('login-view')))
.toBeVisible()
.withTimeout(2000);
await login(testuser.username, testuser.password);
await waitFor(element(by.id('listheader-encryption').withDescendant(by.label('Save Your Encryption Password'))))
// TODO: assert 'Save Your Encryption Password'
await waitFor(element(by.id('listheader-encryption')))
.toBeVisible()
.withTimeout(2000);
});
@ -298,6 +314,14 @@ describe('E2E Encryption', () => {
});
describe('Persist Banner', () => {
before(async () => {
// reinstall the app because of one flaky test above
if (device.getPlatform() === 'android') {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin();
await login(testuser.username, testuser.password);
}
});
it('check save banner', async () => {
await checkServer(data.server);
await checkBanner();
@ -315,7 +339,8 @@ describe('E2E Encryption', () => {
await waitFor(element(by.id('new-server-view')))
.toBeVisible()
.withTimeout(60000);
await element(by.id('new-server-view-input')).typeText(`${data.alternateServer}\n`);
await element(by.id('new-server-view-input')).typeText(`${data.alternateServer}`);
await element(by.id('new-server-view-input')).tapReturnKey();
await waitFor(element(by.id('workspace-view')))
.toBeVisible()
.withTimeout(60000);
@ -328,7 +353,7 @@ describe('E2E Encryption', () => {
await element(by.id('register-view-name')).replaceText(data.registeringUser.username);
await element(by.id('register-view-username')).replaceText(data.registeringUser.username);
await element(by.id('register-view-email')).replaceText(data.registeringUser.email);
await element(by.id('register-view-password')).typeText(data.registeringUser.password);
await element(by.id('register-view-password')).replaceText(data.registeringUser.password);
await element(by.id('register-view-submit')).tap();
await waitFor(element(by.id('rooms-list-view')))
.toBeVisible()

View File

@ -1,15 +1,17 @@
// const OTP = require('otp.js');
// const GA = OTP.googleAuthenticator;
const { navigateToLogin, login, mockMessage, tapBack, searchRoom } = require('../../helpers/app');
const { navigateToLogin, login, mockMessage, tapBack, searchRoom, platformTypes } = require('../../helpers/app');
const data = require('../../data');
const testuser = data.users.regular;
const otheruser = data.users.alternate;
describe('Broadcast room', () => {
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(testuser.username, testuser.password);
});
@ -101,7 +103,7 @@ describe('Broadcast room', () => {
});
it('should have the message created earlier', async () => {
await waitFor(element(by.label(`${data.random}message`)))
await waitFor(element(by[textMatcher](`${data.random}message`)))
.toExist()
.withTimeout(60000);
});

View File

@ -1,4 +1,4 @@
const { navigateToLogin, login, sleep } = require('../../helpers/app');
const { navigateToLogin, login, sleep, platformTypes } = require('../../helpers/app');
const data = require('../../data');
const profileChangeUser = data.users.profileChanges;
@ -14,8 +14,14 @@ async function waitForToast() {
}
describe('Profile screen', () => {
let textInputType;
let scrollViewType;
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ textInputType, scrollViewType, alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(profileChangeUser.username, profileChangeUser.password);
await element(by.id('rooms-list-view-sidebar')).tap();
@ -92,8 +98,8 @@ describe('Profile screen', () => {
describe('Usage', () => {
it('should change name and username', async () => {
await element(by.id('profile-view-name')).replaceText(`${profileChangeUser.username}new`);
await element(by.id('profile-view-username')).typeText(`${profileChangeUser.username}new`);
await element(by.type('UIScrollView')).atIndex(1).swipe('up');
await element(by.id('profile-view-username')).replaceText(`${profileChangeUser.username}new`);
await element(by.type(scrollViewType)).atIndex(1).swipe('up');
await element(by.id('profile-view-submit')).tap();
await waitForToast();
});
@ -102,12 +108,13 @@ describe('Profile screen', () => {
await element(by.id('profile-view-email')).replaceText(`mobile+profileChangesNew${data.random}@rocket.chat`);
await element(by.id('profile-view-new-password')).replaceText(`${profileChangeUser.password}new`);
await element(by.id('profile-view-submit')).tap();
await element(by.type('_UIAlertControllerTextField')).typeText(`${profileChangeUser.password}\n`);
await element(by.type(textInputType)).replaceText(`${profileChangeUser.password}`);
await element(by[textMatcher]('Save').and(by.type(alertButtonType))).tap();
await waitForToast();
});
it('should reset avatar', async () => {
await element(by.type('UIScrollView')).atIndex(1).swipe('up');
await element(by.type(scrollViewType)).atIndex(1).swipe('up');
await element(by.id('profile-view-reset-avatar')).tap();
await waitForToast();
});

View File

@ -1,11 +1,15 @@
const { navigateToLogin, login } = require('../../helpers/app');
const { navigateToLogin, login, platformTypes } = require('../../helpers/app');
const data = require('../../data');
const testuser = data.users.regular;
describe('Settings screen', () => {
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(testuser.username, testuser.password);
await waitFor(element(by.id('rooms-list-view')))
@ -72,10 +76,10 @@ describe('Settings screen', () => {
.toBeVisible()
.withTimeout(2000);
await element(by.id('settings-view-clear-cache')).tap();
await waitFor(element(by.text('This will clear all your offline data.')))
await waitFor(element(by[textMatcher]('This will clear all your offline data.')))
.toExist()
.withTimeout(2000);
await element(by.label('Clear').and(by.type('_UIAlertControllerActionView'))).tap();
await element(by[textMatcher]('Clear').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('rooms-list-view')))
.toBeVisible()
.withTimeout(5000);

View File

@ -1,5 +1,5 @@
const data = require('../../data');
const { navigateToLogin, login, mockMessage, tapBack, searchRoom } = require('../../helpers/app');
const { navigateToLogin, login, mockMessage, tapBack, searchRoom, platformTypes } = require('../../helpers/app');
const testuser = data.users.regular;
const room = data.channels.detoxpublic.name;
@ -7,21 +7,24 @@ const room = data.channels.detoxpublic.name;
async function navigateToRoom() {
await searchRoom(room);
await element(by.id(`rooms-list-view-item-${room}`)).tap();
await waitFor(element(by.id('room-view')))
.toBeVisible()
await waitFor(element(by.id('room-view')).atIndex(0))
.toExist()
.withTimeout(5000);
}
async function navigateToRoomActions() {
await element(by.id('room-header')).tap();
await element(by.id(`room-view-title-${room}`)).tap();
await waitFor(element(by.id('room-actions-view')))
.toBeVisible()
.withTimeout(5000);
}
describe('Join public room', () => {
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(testuser.username, testuser.password);
await navigateToRoom();
@ -32,10 +35,6 @@ describe('Join public room', () => {
await expect(element(by.id('room-view'))).toBeVisible();
});
// it('should have messages list', async() => {
// await expect(element(by.id('room-view-messages'))).toBeVisible();
// });
// Render - Header
describe('Header', () => {
it('should have actions button ', async () => {
@ -75,16 +74,10 @@ describe('Join public room', () => {
await expect(element(by.id('room-actions-info'))).toBeVisible();
});
// it('should have voice', async() => {
// await expect(element(by.id('room-actions-voice'))).toBeVisible();
// });
// it('should have video', async() => {
// await expect(element(by.id('room-actions-video'))).toBeVisible();
// });
it('should have members', async () => {
await expect(element(by.id('room-actions-members'))).toBeVisible();
await waitFor(element(by.id('room-actions-members')))
.toBeVisible()
.withTimeout(2000);
});
it('should have files', async () => {
@ -147,32 +140,29 @@ describe('Join public room', () => {
await navigateToRoomActions();
await expect(element(by.id('room-actions-view'))).toBeVisible();
await expect(element(by.id('room-actions-info'))).toBeVisible();
// await expect(element(by.id('room-actions-voice'))).toBeVisible();
// await expect(element(by.id('room-actions-video'))).toBeVisible();
await expect(element(by.id('room-actions-members'))).toBeVisible();
await expect(element(by.id('room-actions-files'))).toBeVisible();
await expect(element(by.id('room-actions-mentioned'))).toBeVisible();
await expect(element(by.id('room-actions-starred'))).toBeVisible();
await element(by.id('room-actions-scrollview')).swipe('down');
await expect(element(by.id('room-actions-share'))).toBeVisible();
await expect(element(by.id('room-actions-pinned'))).toBeVisible();
await expect(element(by.id('room-actions-notifications'))).toBeVisible();
await element(by.id('room-actions-scrollview')).scrollTo('bottom');
await expect(element(by.id('room-actions-leave-channel'))).toBeVisible();
});
it('should leave room', async () => {
await element(by.id('room-actions-leave-channel')).tap();
await waitFor(element(by.text('Yes, leave it!')))
await waitFor(element(by[textMatcher]('Yes, leave it!').and(by.type(alertButtonType))))
.toBeVisible()
.withTimeout(5000);
await expect(element(by.text('Yes, leave it!'))).toBeVisible();
await element(by.text('Yes, leave it!')).tap();
await element(by[textMatcher]('Yes, leave it!').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('rooms-list-view')))
.toBeVisible()
.withTimeout(10000);
await waitFor(element(by.id(`rooms-list-view-item-${room}`)))
.toBeNotVisible()
.withTimeout(60000);
.withTimeout(60000); // flaky on Android
});
});
});

View File

@ -45,8 +45,9 @@ describe('Status screen', () => {
.withTimeout(2000);
});
// TODO: flaky
it('should change status text', async () => {
await element(by.id('status-view-input')).typeText('status-text-new');
await element(by.id('status-view-input')).replaceText('status-text-new');
await element(by.id('status-view-submit')).tap();
await waitForToast();
await waitFor(element(by.label('status-text-new').withAncestor(by.id('sidebar-custom-status'))))

View File

@ -1,8 +1,8 @@
const data = require('../../data');
const { navigateToLogin, login, checkServer } = require('../../helpers/app');
const { navigateToLogin, login, checkServer, platformTypes } = require('../../helpers/app');
const reopenAndCheckServer = async server => {
await device.launchApp({ permissions: { notifications: 'YES' } });
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true });
await waitFor(element(by.id('rooms-list-view')))
.toBeVisible()
.withTimeout(10000);
@ -37,7 +37,8 @@ describe('Change server', () => {
await waitFor(element(by.id('new-server-view')))
.toBeVisible()
.withTimeout(6000);
await element(by.id('new-server-view-input')).typeText(`${data.alternateServer}\n`);
await element(by.id('new-server-view-input')).replaceText(`${data.alternateServer}`);
await element(by.id('new-server-view-input')).tapReturnKey();
await waitFor(element(by.id('workspace-view')))
.toBeVisible()
.withTimeout(10000);

View File

@ -1,5 +1,5 @@
const data = require('../../data');
const { navigateToLogin, login, mockMessage, searchRoom } = require('../../helpers/app');
const { navigateToLogin, login, mockMessage, searchRoom, sleep } = require('../../helpers/app');
const testuser = data.users.regular;
const room = data.channels.detoxpublicprotected.name;
@ -9,15 +9,25 @@ async function navigateToRoom() {
await searchRoom(room);
await element(by.id(`rooms-list-view-item-${room}`)).tap();
await waitFor(element(by.id('room-view')))
.toBeVisible()
.toExist()
.withTimeout(5000);
}
async function openJoinCode() {
await element(by.id('room-view-join-button')).tap();
await waitFor(element(by.id('join-code')))
.toBeVisible()
.withTimeout(5000);
await waitFor(element(by.id('room-view-join-button')))
.toExist()
.withTimeout(2000);
let n = 0;
while (n < 3) {
try {
await element(by.id('room-view-join-button')).tap();
await waitFor(element(by.id('join-code')))
.toBeVisible()
.withTimeout(500);
} catch (error) {
n += 1;
}
}
}
describe('Join protected room', () => {

View File

@ -10,7 +10,7 @@ async function navigateToRoom(search) {
.withTimeout(10000);
await sleep(300); // app takes some time to animate
await element(by.id(`directory-view-item-${search}`)).tap();
await waitFor(element(by.id('room-view')))
await waitFor(element(by.id('room-view')).atIndex(0))
.toExist()
.withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${search}`)))
@ -44,20 +44,20 @@ describe('Join room from directory', () => {
.toExist()
.withTimeout(2000);
await element(by.id('directory-view-dropdown')).tap();
await element(by.label('Users')).tap();
await element(by.label('Search by')).tap();
await element(by.label('Users')).atIndex(0).tap();
await element(by.label('Search by')).atIndex(0).tap();
await navigateToRoom(data.users.alternate.username);
});
it('should search user and navigate', async () => {
it('should search team and navigate', async () => {
await tapBack();
await element(by.id('rooms-list-view-directory')).tap();
await waitFor(element(by.id('directory-view')))
.toExist()
.withTimeout(2000);
await element(by.id('directory-view-dropdown')).tap();
await element(by.label('Teams')).tap();
await element(by.label('Search by')).tap();
await element(by.label('Teams')).atIndex(0).tap();
await element(by.label('Search by')).atIndex(0).tap();
await navigateToRoom(data.teams.private.name);
});
});

View File

@ -1,9 +1,12 @@
const data = require('../../data');
const { sleep, navigateToLogin, login, checkServer } = require('../../helpers/app');
const { sleep, navigateToLogin, login, checkServer, platformTypes } = require('../../helpers/app');
describe('Delete server', () => {
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
});
@ -23,7 +26,8 @@ describe('Delete server', () => {
await waitFor(element(by.id('new-server-view')))
.toBeVisible()
.withTimeout(10000);
await element(by.id('new-server-view-input')).typeText(`${data.alternateServer}\n`);
await element(by.id('new-server-view-input')).replaceText(`${data.alternateServer}`);
await element(by.id('new-server-view-input')).tapReturnKey();
await waitFor(element(by.id('workspace-view')))
.toBeVisible()
.withTimeout(10000);
@ -36,7 +40,7 @@ describe('Delete server', () => {
await element(by.id('register-view-name')).replaceText(data.registeringUser3.username);
await element(by.id('register-view-username')).replaceText(data.registeringUser3.username);
await element(by.id('register-view-email')).replaceText(data.registeringUser3.email);
await element(by.id('register-view-password')).typeText(data.registeringUser3.password);
await element(by.id('register-view-password')).replaceText(data.registeringUser3.password);
await element(by.id('register-view-submit')).tap();
await waitFor(element(by.id('rooms-list-view')))
.toBeVisible()
@ -51,7 +55,7 @@ describe('Delete server', () => {
.toBeVisible()
.withTimeout(5000);
await element(by.id(`rooms-list-header-server-${data.server}`)).longPress(1500);
await element(by.label('Delete').and(by.type('_UIAlertControllerActionView'))).tap();
await element(by[textMatcher]('Delete').and(by.type(alertButtonType))).tap();
await element(by.id('rooms-list-header-server-dropdown-button')).tap();
await waitFor(element(by.id('rooms-list-header-server-dropdown')))
.toBeVisible()

View File

@ -1,10 +1,13 @@
const data = require('../../data');
const { tapBack, checkServer, navigateToRegister } = require('../../helpers/app');
const { tapBack, checkServer, navigateToRegister, platformTypes } = require('../../helpers/app');
const { get, login, sendMessage } = require('../../helpers/data_setup');
const DEEPLINK_METHODS = { AUTH: 'auth', ROOM: 'room' };
let amp = '&';
const getDeepLink = (method, server, params) => {
const deeplink = `rocketchat://${method}?host=${server.replace(/^(http:\/\/|https:\/\/)/, '')}&${params}`;
const deeplink = `rocketchat://${method}?host=${server.replace(/^(http:\/\/|https:\/\/)/, '')}${amp}${params}`;
console.log(`Deeplinking to: ${deeplink}`);
return deeplink;
};
@ -12,11 +15,17 @@ const getDeepLink = (method, server, params) => {
describe('Deep linking', () => {
let userId;
let authToken;
let scrollViewType;
let threadId;
let textMatcher;
let alertButtonType;
const threadMessage = `to-thread-${data.random}`;
before(async () => {
const loginResult = await login(data.users.regular.username, data.users.regular.password);
({ userId, authToken } = loginResult);
const deviceType = device.getPlatform();
amp = deviceType === 'android' ? '\\&' : '&';
({ scrollViewType, textMatcher, alertButtonType } = platformTypes[deviceType]);
// create a thread with api
const result = await sendMessage(data.users.regular, data.groups.alternate2.name, threadMessage);
threadId = result.message._id;
@ -28,10 +37,9 @@ describe('Deep linking', () => {
await device.launchApp({
permissions: { notifications: 'YES' },
delete: true,
url: getDeepLink(DEEPLINK_METHODS.AUTH, data.server, 'userId=123&token=abc'),
sourceApp: 'com.apple.mobilesafari'
url: getDeepLink(DEEPLINK_METHODS.AUTH, data.server, `userId=123${amp}token=abc`)
});
await waitFor(element(by.text("You've been logged out by the server. Please log in again.")))
await waitFor(element(by[textMatcher]("You've been logged out by the server. Please log in again.")))
.toExist()
.withTimeout(10000); // TODO: we need to improve this message
});
@ -43,9 +51,8 @@ describe('Deep linking', () => {
url: getDeepLink(
DEEPLINK_METHODS.AUTH,
data.server,
`userId=${userId}&token=${authToken}&path=group/${data.groups.private.name}`
),
sourceApp: 'com.apple.mobilesafari'
`userId=${userId}${amp}token=${authToken}${amp}path=group/${data.groups.private.name}`
)
});
await waitFor(element(by.id(`room-view-title-${data.groups.private.name}`)))
.toExist()
@ -56,7 +63,7 @@ describe('Deep linking', () => {
.withTimeout(10000);
await checkServer(data.server);
await waitFor(element(by.id(`rooms-list-view-item-${data.groups.private.name}`)))
.toBeVisible()
.toExist()
.withTimeout(2000);
};
@ -70,7 +77,8 @@ describe('Deep linking', () => {
await element(by.id('register-view-name')).replaceText(data.registeringUser4.username);
await element(by.id('register-view-username')).replaceText(data.registeringUser4.username);
await element(by.id('register-view-email')).replaceText(data.registeringUser4.email);
await element(by.id('register-view-password')).typeText(data.registeringUser4.password);
await element(by.id('register-view-password')).replaceText(data.registeringUser4.password);
await element(by.type(scrollViewType)).atIndex(0).scrollTo('bottom');
await element(by.id('register-view-submit')).tap();
await waitFor(element(by.id('rooms-list-view')))
.toBeVisible()
@ -85,8 +93,7 @@ describe('Deep linking', () => {
await device.launchApp({
permissions: { notifications: 'YES' },
newInstance: true,
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `path=group/${data.groups.private.name}`),
sourceApp: 'com.apple.mobilesafari'
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `path=group/${data.groups.private.name}`)
});
await waitFor(element(by.id(`room-view-title-${data.groups.private.name}`)))
.toExist()
@ -97,8 +104,7 @@ describe('Deep linking', () => {
await device.launchApp({
permissions: { notifications: 'YES' },
newInstance: true,
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `path=group/${data.groups.alternate2.name}/thread/${threadId}`),
sourceApp: 'com.apple.mobilesafari'
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `path=group/${data.groups.alternate2.name}/thread/${threadId}`)
});
await waitFor(element(by.id(`room-view-title-${threadMessage}`)))
.toExist()
@ -110,8 +116,7 @@ describe('Deep linking', () => {
await device.launchApp({
permissions: { notifications: 'YES' },
newInstance: true,
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `rid=${roomResult.data.group._id}`),
sourceApp: 'com.apple.mobilesafari'
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `rid=${roomResult.data.group._id}`)
});
await waitFor(element(by.id(`room-view-title-${data.groups.private.name}`)))
.toExist()
@ -135,8 +140,7 @@ describe('Deep linking', () => {
await device.launchApp({
permissions: { notifications: 'YES' },
newInstance: true,
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `path=group/${data.groups.private.name}`),
sourceApp: 'com.apple.mobilesafari'
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `path=group/${data.groups.private.name}`)
});
await waitFor(element(by.id(`room-view-title-${data.groups.private.name}`)))
.toExist()
@ -147,8 +151,7 @@ describe('Deep linking', () => {
await device.launchApp({
permissions: { notifications: 'YES' },
newInstance: true,
url: getDeepLink(DEEPLINK_METHODS.ROOM, 'https://google.com'),
sourceApp: 'com.apple.mobilesafari'
url: getDeepLink(DEEPLINK_METHODS.ROOM, 'https://google.com')
});
await waitFor(element(by.id('rooms-list-view')))
.toBeVisible()

View File

@ -29,6 +29,9 @@ const navToLanguage = async () => {
describe('i18n', () => {
describe('OS language', () => {
it("OS set to 'en' and proper translate to 'en'", async () => {
if (device.getPlatform() === 'android') {
return; // FIXME: Passing language with launch parameters doesn't work with Android
}
await device.launchApp({
...defaultLaunchArgs,
languageAndLocale: {
@ -44,6 +47,9 @@ describe('i18n', () => {
});
it("OS set to unavailable language and fallback to 'en'", async () => {
if (device.getPlatform() === 'android') {
return; // FIXME: Passing language with launch parameters doesn't work with Android
}
await device.launchApp({
...defaultLaunchArgs,
languageAndLocale: {
@ -74,7 +80,7 @@ describe('i18n', () => {
describe('Rocket.Chat language', () => {
before(async () => {
await device.launchApp(defaultLaunchArgs);
await device.launchApp({ ...defaultLaunchArgs, delete: true });
await navigateToLogin();
await login(testuser.username, testuser.password);
});
@ -113,7 +119,7 @@ describe('i18n', () => {
it("should set unsupported language and fallback to 'en'", async () => {
await post('users.setPreferences', { data: { language: 'eo' } }); // Set language to Esperanto
await device.launchApp(defaultLaunchArgs);
await device.launchApp({ ...defaultLaunchArgs, newInstance: true });
await waitFor(element(by.id('rooms-list-view')))
.toBeVisible()
.withTimeout(10000);

View File

@ -1,4 +1,4 @@
const { login, navigateToLogin } = require('../../helpers/app');
const { login, navigateToLogin, sleep } = require('../../helpers/app');
const data = require('../../data');
const goToDisplayPref = async () => {
@ -14,7 +14,7 @@ const goToRoomList = async () => {
await element(by.id('sidebar-chats')).tap();
};
describe('Rooms list screen', () => {
describe('Display prefs', () => {
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true, delete: true });
await navigateToLogin();
@ -89,7 +89,9 @@ describe('Rooms list screen', () => {
await expect(element(by.id('display-pref-view-avatar-switch'))).toBeVisible();
await element(by.id('display-pref-view-avatar-switch')).tap();
await goToRoomList();
await expect(element(by.id('avatar'))).not.toBeVisible();
await waitFor(element(by.id('avatar').withAncestor(by.id('rooms-list-view-item-general'))))
.not.toBeVisible()
.withTimeout(2000);
});
});
});

View File

@ -3,9 +3,11 @@ const adapter = require('detox/runners/mocha/adapter');
const config = require('../../package.json').detox;
const { setup } = require('../helpers/data_setup');
const { prepareAndroid } = require('../helpers/app');
before(async () => {
await Promise.all([setup(), detox.init(config, { launchApp: false })]);
await prepareAndroid(); // Make Android less flaky
// await dataSetup()
// await detox.init(config, { launchApp: false });
// await device.launchApp({ permissions: { notifications: 'YES' } });

View File

@ -1,8 +1,12 @@
const data = require('../../data');
const { platformTypes } = require('../../helpers/app');
describe('Onboarding', () => {
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await waitFor(element(by.id('new-server-view')))
.toBeVisible()
.withTimeout(20000);
@ -19,17 +23,13 @@ describe('Onboarding', () => {
});
describe('Usage', () => {
// it('should navigate to create new workspace', async() => {
// // webviews are not supported by detox: https://github.com/wix/detox/issues/136#issuecomment-306591554
// });
it('should enter an invalid server and get error', async () => {
await element(by.id('new-server-view-input')).typeText('invalidtest\n');
const errorText = 'Oops!';
await waitFor(element(by.text(errorText)))
.toBeVisible()
.withTimeout(60000);
await element(by.text('OK')).tap();
await element(by.id('new-server-view-input')).replaceText('invalidtest');
await element(by.id('new-server-view-input')).tapReturnKey();
await waitFor(element(by[textMatcher]('Oops!')))
.toExist()
.withTimeout(10000);
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
});
it('should tap on "Join our open workspace" and navigate', async () => {
@ -44,7 +44,8 @@ describe('Onboarding', () => {
await waitFor(element(by.id('new-server-view')))
.toBeVisible()
.withTimeout(5000);
await element(by.id('new-server-view-input')).typeText(`${data.server}\n`);
await element(by.id('new-server-view-input')).replaceText(data.server);
await element(by.id('new-server-view-input')).tapReturnKey();
await waitFor(element(by.id('workspace-view')))
.toBeVisible()
.withTimeout(60000);

View File

@ -1,9 +1,12 @@
const data = require('../../data');
const { navigateToLogin } = require('../../helpers/app');
const { navigateToLogin, platformTypes } = require('../../helpers/app');
describe('Forgot password screen', () => {
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await element(by.id('login-view-forgot-password')).tap();
await waitFor(element(by.id('forgot-password-view')))
@ -29,10 +32,10 @@ describe('Forgot password screen', () => {
it('should reset password and navigate to login', async () => {
await element(by.id('forgot-password-view-email')).replaceText(data.users.existing.email);
await element(by.id('forgot-password-view-submit')).tap();
await waitFor(element(by.text('OK')))
await waitFor(element(by[textMatcher]('OK')))
.toExist()
.withTimeout(10000);
await element(by.text('OK')).tap();
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('login-view')))
.toBeVisible()
.withTimeout(60000);

View File

@ -1,9 +1,12 @@
const { navigateToRegister } = require('../../helpers/app');
const { navigateToRegister, platformTypes } = require('../../helpers/app');
const data = require('../../data');
describe('Create user screen', () => {
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToRegister();
});
@ -50,10 +53,10 @@ describe('Create user screen', () => {
await element(by.id('register-view-email')).replaceText(data.users.existing.email);
await element(by.id('register-view-password')).replaceText(data.registeringUser.password);
await element(by.id('register-view-submit')).tap();
await waitFor(element(by.text('Email already exists. [403]')).atIndex(0))
await waitFor(element(by[textMatcher]('Email already exists. [403]')).atIndex(0))
.toExist()
.withTimeout(10000);
await element(by.text('OK')).tap();
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
});
it('should submit username already taken and raise error', async () => {
@ -62,10 +65,10 @@ describe('Create user screen', () => {
await element(by.id('register-view-email')).replaceText(data.registeringUser.email);
await element(by.id('register-view-password')).replaceText(data.registeringUser.password);
await element(by.id('register-view-submit')).tap();
await waitFor(element(by.text('Username is already in use')).atIndex(0))
await waitFor(element(by[textMatcher]('Username is already in use')).atIndex(0))
.toExist()
.withTimeout(10000);
await element(by.text('OK')).tap();
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
});
it('should register', async () => {

View File

@ -1,9 +1,12 @@
const { navigateToLogin, tapBack } = require('../../helpers/app');
const { navigateToLogin, tapBack, platformTypes } = require('../../helpers/app');
const data = require('../../data');
describe('Login screen', () => {
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
});
@ -58,10 +61,10 @@ describe('Login screen', () => {
await element(by.id('login-view-email')).replaceText(data.users.regular.username);
await element(by.id('login-view-password')).replaceText('NotMyActualPassword');
await element(by.id('login-view-submit')).tap();
await waitFor(element(by.text('Your credentials were rejected! Please try again.')))
await waitFor(element(by[textMatcher]('Your credentials were rejected! Please try again.')))
.toBeVisible()
.withTimeout(10000);
await element(by.text('OK')).tap();
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
});
it('should login with success', async () => {

View File

@ -14,7 +14,9 @@ describe('Rooms list screen', () => {
});
it('should have room item', async () => {
await expect(element(by.id('rooms-list-view-item-general'))).toExist();
await waitFor(element(by.id('rooms-list-view-item-general')))
.toExist()
.withTimeout(10000);
});
// Render - Header

View File

@ -25,10 +25,10 @@ describe('Server history', () => {
it('should tap on a server history and navigate to login', async () => {
await element(by.id(`server-history-${data.server}`)).tap();
await waitFor(element(by.id('login-view')))
await waitFor(element(by.id('login-view-email')))
.toBeVisible()
.withTimeout(5000);
await expect(element(by.id('login-view-email'))).toHaveText(data.users.regular.username);
await expect(element(by.label(data.users.regular.username).withAncestor(by.id('login-view-email'))));
});
it('should delete server from history', async () => {

View File

@ -1,9 +1,12 @@
const data = require('../../data');
const { tapBack, navigateToLogin, login, tryTapping } = require('../../helpers/app');
const { tapBack, navigateToLogin, login, tryTapping, platformTypes } = require('../../helpers/app');
describe('Create room screen', () => {
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
});
@ -121,20 +124,26 @@ describe('Create room screen', () => {
describe('Usage', () => {
it('should get invalid room', async () => {
await element(by.id('create-channel-name')).typeText('general');
await element(by.id('create-channel-name')).replaceText('general');
await waitFor(element(by.id('create-channel-submit')))
.toExist()
.withTimeout(2000);
await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.text('A channel with name general exists')))
await waitFor(element(by[textMatcher]('A channel with name general exists')))
.toExist()
.withTimeout(60000);
await expect(element(by.text('A channel with name general exists'))).toExist();
await element(by.text('OK')).tap();
await expect(element(by[textMatcher]('A channel with name general exists'))).toExist();
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
});
it('should create public room', async () => {
const room = `public${data.random}`;
await element(by.id('create-channel-name')).replaceText('');
await element(by.id('create-channel-name')).typeText(room);
await element(by.id('create-channel-name')).replaceText(room);
await element(by.id('create-channel-type')).tap();
await waitFor(element(by.id('create-channel-submit')))
.toExist()
.withTimeout(2000);
await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view')))
.toExist()
@ -175,7 +184,10 @@ describe('Create room screen', () => {
await waitFor(element(by.id('create-channel-view')))
.toExist()
.withTimeout(5000);
await element(by.id('create-channel-name')).typeText(room);
await element(by.id('create-channel-name')).replaceText(room);
await waitFor(element(by.id('create-channel-submit')))
.toExist()
.withTimeout(2000);
await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view')))
.toExist()
@ -213,7 +225,10 @@ describe('Create room screen', () => {
await waitFor(element(by.id('create-channel-view')))
.toExist()
.withTimeout(10000);
await element(by.id('create-channel-name')).typeText(room);
await element(by.id('create-channel-name')).replaceText(room);
await waitFor(element(by.id('create-channel-submit')))
.toExist()
.withTimeout(2000);
await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view')))
.toExist()

View File

@ -9,7 +9,8 @@ const {
starMessage,
pinMessage,
dismissReviewNag,
tryTapping
tryTapping,
platformTypes
} = require('../../helpers/app');
async function navigateToRoom(roomName) {
@ -22,9 +23,12 @@ async function navigateToRoom(roomName) {
describe('Room screen', () => {
const mainRoom = data.groups.private.name;
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
await navigateToRoom(mainRoom);
@ -79,7 +83,7 @@ describe('Room screen', () => {
describe('Messagebox', () => {
it('should send message', async () => {
await mockMessage('message');
await expect(element(by.label(`${data.random}message`)).atIndex(0)).toExist();
await expect(element(by[textMatcher](`${data.random}message`)).atIndex(0)).toExist();
});
it('should show/hide emoji keyboard', async () => {
@ -100,8 +104,8 @@ describe('Room screen', () => {
});
it('should show/hide emoji autocomplete', async () => {
await element(by.id('messagebox-input')).tap();
await element(by.id('messagebox-input')).typeText(':joy');
await sleep(300);
await waitFor(element(by.id('messagebox-container')))
.toExist()
.withTimeout(10000);
@ -112,9 +116,8 @@ describe('Room screen', () => {
});
it('should show and tap on emoji autocomplete', async () => {
await element(by.id('messagebox-input')).tap();
await element(by.id('messagebox-input')).replaceText(':');
await element(by.id('messagebox-input')).typeText('joy'); // workaround for number keyboard
await element(by.id('messagebox-input')).typeText(':joy');
await sleep(300);
await waitFor(element(by.id('messagebox-container')))
.toExist()
.withTimeout(10000);
@ -124,9 +127,8 @@ describe('Room screen', () => {
});
it('should not show emoji autocomplete on semicolon in middle of a string', async () => {
await element(by.id('messagebox-input')).tap();
// await element(by.id('messagebox-input')).replaceText(':');
await element(by.id('messagebox-input')).typeText('name:is');
await sleep(300);
await waitFor(element(by.id('messagebox-container')))
.toNotExist()
.withTimeout(20000);
@ -135,8 +137,11 @@ describe('Room screen', () => {
it('should show and tap on user autocomplete and send mention', async () => {
const { username } = data.users.regular;
await element(by.id('messagebox-input')).tap();
const messageMention = `@${username}`;
const message = `${data.random}mention`;
const fullMessage = `${messageMention} ${message}`;
await element(by.id('messagebox-input')).typeText(`@${username}`);
await sleep(300);
await waitFor(element(by.id('messagebox-container')))
.toExist()
.withTimeout(4000);
@ -144,15 +149,24 @@ describe('Room screen', () => {
.toBeVisible()
.withTimeout(4000);
await tryTapping(element(by.id(`mention-item-${username}`)), 2000, true);
await expect(element(by.id('messagebox-input'))).toHaveText(`@${username} `);
await expect(element(by.id('messagebox-input'))).toHaveText(`${messageMention} `);
await tryTapping(element(by.id('messagebox-input')), 2000);
await element(by.id('messagebox-input')).typeText(`${data.random}mention`);
await element(by.id('messagebox-send-message')).tap();
// await waitFor(element(by.label(`@${ data.user } ${ data.random }mention`)).atIndex(0)).toExist().withTimeout(60000);
if (device.getPlatform() === 'ios') {
await element(by.id('messagebox-input')).typeText(message);
await element(by.id('messagebox-send-message')).tap();
const fullMessageMatcher = fullMessage.substr(1); // removes `@`
await waitFor(element(by[textMatcher](fullMessageMatcher)))
.toExist()
.withTimeout(60000);
await expect(element(by[textMatcher](fullMessageMatcher))).toExist();
await element(by[textMatcher](fullMessageMatcher)).atIndex(0).tap();
} else {
await element(by.id('messagebox-input')).replaceText(fullMessage);
await element(by.id('messagebox-send-message')).tap();
}
});
it('should not show user autocomplete on @ in the middle of a string', async () => {
await element(by.id('messagebox-input')).tap();
await element(by.id('messagebox-input')).typeText('email@gmail');
await waitFor(element(by.id('messagebox-container')))
.toNotExist()
@ -161,9 +175,7 @@ describe('Room screen', () => {
});
it('should show and tap on room autocomplete', async () => {
await element(by.id('messagebox-input')).tap();
await element(by.id('messagebox-input')).typeText('#general');
// await waitFor(element(by.id('messagebox-container'))).toExist().withTimeout(4000);
await waitFor(element(by.id('mention-item-general')))
.toBeVisible()
.withTimeout(4000);
@ -181,7 +193,6 @@ describe('Room screen', () => {
await element(by.id('messagebox-input')).clearText();
});
it('should draft message', async () => {
await element(by.id('messagebox-input')).tap();
await element(by.id('messagebox-input')).typeText(`${data.random}draft`);
await tapBack();
@ -197,25 +208,29 @@ describe('Room screen', () => {
describe('Message', () => {
it('should copy permalink', async () => {
await element(by.label(`${data.random}message`))
await element(by[textMatcher](`${data.random}message`))
.atIndex(0)
.longPress();
await expect(element(by.id('action-sheet'))).toExist();
await waitFor(element(by.id('action-sheet')))
.toExist()
.withTimeout(2000);
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await element(by.label('Permalink')).atIndex(0).tap();
await element(by[textMatcher]('Permalink')).atIndex(0).tap();
// TODO: test clipboard
});
it('should copy message', async () => {
await element(by.label(`${data.random}message`))
await element(by[textMatcher](`${data.random}message`))
.atIndex(0)
.longPress();
await expect(element(by.id('action-sheet'))).toExist();
await waitFor(element(by.id('action-sheet')))
.toExist()
.withTimeout(2000);
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await element(by.label('Copy')).atIndex(0).tap();
await element(by[textMatcher]('Copy')).atIndex(0).tap();
// TODO: test clipboard
});
@ -224,23 +239,33 @@ describe('Room screen', () => {
await starMessage('message');
await sleep(1000); // https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/2324
await element(by.label(`${data.random}message`))
await element(by[textMatcher](`${data.random}message`))
.atIndex(0)
.longPress();
await expect(element(by.id('action-sheet'))).toExist();
await waitFor(element(by.id('action-sheet')))
.toExist()
.withTimeout(2000);
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'slow', 0.5);
await waitFor(element(by.label('Unstar')).atIndex(0))
await waitFor(element(by[textMatcher]('Unstar')).atIndex(0))
.toExist()
.withTimeout(6000);
await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.8);
});
it('should react to message', async () => {
await element(by.label(`${data.random}message`))
await waitFor(element(by[textMatcher](`${data.random}message`)))
.toExist()
.withTimeout(60000);
await element(by[textMatcher](`${data.random}message`))
.atIndex(0)
.tap();
await element(by[textMatcher](`${data.random}message`))
.atIndex(0)
.longPress();
await expect(element(by.id('action-sheet'))).toExist();
await waitFor(element(by.id('action-sheet')))
.toExist()
.withTimeout(2000);
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await element(by.id('add-reaction')).tap();
@ -258,10 +283,12 @@ describe('Room screen', () => {
});
it('should react to message with frequently used emoji', async () => {
await element(by.label(`${data.random}message`))
await element(by[textMatcher](`${data.random}message`))
.atIndex(0)
.longPress();
await expect(element(by.id('action-sheet'))).toExist();
await waitFor(element(by.id('action-sheet')))
.toExist()
.withTimeout(2000);
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await waitFor(element(by.id('message-actions-emoji-+1')))
@ -273,7 +300,7 @@ describe('Room screen', () => {
.withTimeout(60000);
});
it('should show reaction picker on add reaction button pressed and have frequently used emoji', async () => {
it('should show reaction picker on add reaction button pressed and have frequently used emoji, and dismiss review nag', async () => {
await element(by.id('message-add-reaction')).tap();
await waitFor(element(by.id('reaction-picker')))
.toExist()
@ -291,10 +318,6 @@ describe('Room screen', () => {
.withTimeout(60000);
});
it('should ask for review', async () => {
await dismissReviewNag(); // TODO: Create a proper test for this elsewhere.
});
it('should remove reaction', async () => {
await element(by.id('message-reaction-:grinning:')).tap();
await waitFor(element(by.id('message-reaction-:grinning:')))
@ -302,32 +325,43 @@ describe('Room screen', () => {
.withTimeout(60000);
});
it('should ask for review', async () => {
await dismissReviewNag(); // TODO: Create a proper test for this elsewhere.
});
it('should edit message', async () => {
await mockMessage('edit');
await element(by.label(`${data.random}edit`))
await element(by[textMatcher](`${data.random}edit`))
.atIndex(0)
.longPress();
await expect(element(by.id('action-sheet'))).toExist();
await waitFor(element(by.id('action-sheet')))
.toExist()
.withTimeout(2000);
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await element(by.label('Edit')).atIndex(0).tap();
await element(by.id('messagebox-input')).typeText('ed');
await element(by[textMatcher]('Edit')).atIndex(0).tap();
await element(by.id('messagebox-input')).replaceText(`${data.random}edited`);
await element(by.id('messagebox-send-message')).tap();
await waitFor(element(by.label(`${data.random}edited (edited)`)).atIndex(0))
await waitFor(element(by[textMatcher](`${data.random}edited (edited)`)).atIndex(0))
.toExist()
.withTimeout(60000);
});
it('should quote message', async () => {
await mockMessage('quote');
await element(by.label(`${data.random}quote`))
await element(by[textMatcher](`${data.random}quote`))
.atIndex(0)
.longPress();
await expect(element(by.id('action-sheet'))).toExist();
await waitFor(element(by.id('action-sheet')))
.toExist()
.withTimeout(2000);
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await element(by.label('Quote')).atIndex(0).tap();
await element(by.id('messagebox-input')).typeText(`${data.random}quoted`);
await element(by[textMatcher]('Quote')).atIndex(0).tap();
await element(by.id('messagebox-input')).replaceText(`${data.random}quoted`);
await waitFor(element(by.id('messagebox-send-message')))
.toExist()
.withTimeout(2000);
await element(by.id('messagebox-send-message')).tap();
// TODO: test if quote was sent
@ -337,13 +371,13 @@ describe('Room screen', () => {
await mockMessage('pin');
await pinMessage('pin');
await waitFor(element(by.label(`${data.random}pin`)).atIndex(0))
await waitFor(element(by[textMatcher](`${data.random}pin`)).atIndex(0))
.toExist()
.withTimeout(5000);
await waitFor(element(by.label(`${data.users.regular.username} Message pinned`)).atIndex(0))
await waitFor(element(by[textMatcher](`${data.users.regular.username} Message pinned`)).atIndex(0))
.toExist()
.withTimeout(5000);
await element(by.label(`${data.random}pin`))
await element(by[textMatcher](`${data.random}pin`))
.atIndex(0)
.longPress();
await waitFor(element(by.id('action-sheet')))
@ -351,7 +385,7 @@ describe('Room screen', () => {
.withTimeout(1000);
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await waitFor(element(by.label('Unpin')).atIndex(0))
await waitFor(element(by[textMatcher]('Unpin')).atIndex(0))
.toExist()
.withTimeout(2000);
await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.8);
@ -359,26 +393,26 @@ describe('Room screen', () => {
it('should delete message', async () => {
await mockMessage('delete');
await waitFor(element(by.label(`${data.random}delete`)).atIndex(0)).toBeVisible();
await element(by.label(`${data.random}delete`))
await waitFor(element(by[textMatcher](`${data.random}delete`)).atIndex(0)).toBeVisible();
await element(by[textMatcher](`${data.random}delete`))
.atIndex(0)
.longPress();
await expect(element(by.id('action-sheet'))).toExist();
await waitFor(element(by.id('action-sheet')))
.toExist()
.withTimeout(2000);
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await waitFor(element(by.label('Delete')))
await waitFor(element(by[textMatcher]('Delete')))
.toExist()
.withTimeout(1000);
await element(by.label('Delete')).atIndex(0).tap();
await element(by[textMatcher]('Delete')).atIndex(0).tap();
const deleteAlertMessage = 'You will not be able to recover this message!';
await waitFor(element(by.text(deleteAlertMessage)).atIndex(0))
await waitFor(element(by[textMatcher](deleteAlertMessage)).atIndex(0))
.toExist()
.withTimeout(10000);
await element(by.text('Delete')).tap();
await waitFor(element(by.label(`${data.random}delete`)).atIndex(0))
await element(by[textMatcher]('Delete').and(by.type(alertButtonType))).tap();
await waitFor(element(by[textMatcher](`${data.random}delete`)).atIndex(0))
.toNotExist()
.withTimeout(2000);
});

View File

@ -1,5 +1,15 @@
const data = require('../../data');
const { navigateToLogin, login, tapBack, sleep, searchRoom, mockMessage, starMessage, pinMessage } = require('../../helpers/app');
const {
navigateToLogin,
login,
tapBack,
sleep,
searchRoom,
mockMessage,
starMessage,
pinMessage,
platformTypes
} = require('../../helpers/app');
const { sendMessage } = require('../../helpers/data_setup');
async function navigateToRoomActions(type) {
@ -43,10 +53,13 @@ async function waitForToast() {
}
describe('Room actions screen', () => {
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
});
describe('Render', () => {
@ -172,36 +185,12 @@ describe('Room actions screen', () => {
});
describe('Usage', () => {
describe('TDB', async () => {
// TODO: test into a jitsi call
// it('should NOT navigate to voice call', async() => {
// await waitFor(element(by.id('room-actions-voice'))).toExist();
// await element(by.id('room-actions-voice')).tap();
// await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(2000);
// await expect(element(by.id('room-actions-view'))).toExist();
// });
// TODO: test into a jitsi call
// it('should NOT navigate to video call', async() => {
// await element(by.id('room-actions-video')).tap();
// await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(2000);
// await expect(element(by.id('room-actions-view'))).toExist();
// });
// TODO: test share room link
// it('should NOT navigate to share room', async() => {
// await waitFor(element(by.id('room-actions-share'))).toExist();
// await element(by.id('room-actions-share')).tap();
// await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(2000);
// await expect(element(by.id('room-actions-view'))).toExist();
// });
});
describe('Common', () => {
it('should show mentioned messages', async () => {
await element(by.id('room-actions-mentioned')).tap();
await waitFor(element(by.id('mentioned-messages-view')))
.toExist()
.withTimeout(2000);
// await waitFor(element(by.text(` ${ data.random }mention`))).toExist().withTimeout(60000);
await backToActions();
});
@ -220,23 +209,25 @@ describe('Room actions screen', () => {
.withTimeout(5000);
// Go to starred messages
await element(by.id('room-actions-view')).swipe('up');
await waitFor(element(by.id('room-actions-starred'))).toExist();
await element(by.id('room-actions-starred')).tap();
await waitFor(element(by.id('starred-messages-view')))
.toExist()
.withTimeout(2000);
await waitFor(element(by.label(`${data.random}messageToStar`).withAncestor(by.id('starred-messages-view'))))
await waitFor(element(by[textMatcher](`${data.random}messageToStar`).withAncestor(by.id('starred-messages-view'))))
.toExist()
.withTimeout(60000);
// Unstar message
await element(by.label(`${data.random}messageToStar`))
await element(by[textMatcher](`${data.random}messageToStar`))
.atIndex(0)
.longPress();
await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.label('Unstar')).atIndex(0).tap();
await element(by[textMatcher]('Unstar')).atIndex(0).tap();
await waitFor(element(by.label(`${data.random}messageToStar`).withAncestor(by.id('starred-messages-view'))))
await waitFor(element(by[textMatcher](`${data.random}messageToStar`).withAncestor(by.id('starred-messages-view'))))
.toBeNotVisible()
.withTimeout(60000);
await backToActions();
@ -261,40 +252,22 @@ describe('Room actions screen', () => {
await waitFor(element(by.id('pinned-messages-view')))
.toExist()
.withTimeout(2000);
await waitFor(element(by.label(`${data.random}messageToPin`).withAncestor(by.id('pinned-messages-view'))))
await waitFor(element(by[textMatcher](`${data.random}messageToPin`).withAncestor(by.id('pinned-messages-view'))))
.toExist()
.withTimeout(6000);
await element(by.label(`${data.random}messageToPin`).withAncestor(by.id('pinned-messages-view')))
await element(by[textMatcher](`${data.random}messageToPin`).withAncestor(by.id('pinned-messages-view')))
.atIndex(0)
.longPress();
await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.label('Unpin')).atIndex(0).tap();
await element(by[textMatcher]('Unpin')).atIndex(0).tap();
await waitFor(element(by.label(`${data.random}messageToPin`).withAncestor(by.id('pinned-messages-view'))))
await waitFor(element(by[textMatcher](`${data.random}messageToPin`).withAncestor(by.id('pinned-messages-view'))))
.not.toExist()
.withTimeout(6000);
await backToActions();
});
// it('should search and find a message', async() => {
// //Go back to room and send a message
// await tapBack();
// await mockMessage('messageToFind');
// //Back into Room Actions
// await element(by.id('room-header')).tap();
// await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
// await element(by.id('room-actions-search')).tap();
// await waitFor(element(by.id('search-messages-view'))).toExist().withTimeout(2000);
// await expect(element(by.id('search-message-view-input'))).toExist();
// await element(by.id('search-message-view-input')).replaceText(`/${ data.random }messageToFind/`);
// await waitFor(element(by.label(`${ data.random }messageToFind`).withAncestor(by.id('search-messages-view')))).toExist().withTimeout(60000);
// await backToActions();
// });
});
describe('Notification', () => {
@ -370,14 +343,14 @@ describe('Room actions screen', () => {
.toExist()
.withTimeout(2000);
await element(by.id('room-actions-leave-channel')).tap();
await waitFor(element(by.text('Yes, leave it!')))
await waitFor(element(by[textMatcher]('Yes, leave it!')))
.toExist()
.withTimeout(2000);
await element(by.text('Yes, leave it!')).tap();
await waitFor(element(by.text('You are the last owner. Please set new owner before leaving the room.')))
await element(by[textMatcher]('Yes, leave it!').and(by.type(alertButtonType))).tap();
await waitFor(element(by[textMatcher]('You are the last owner. Please set new owner before leaving the room.')))
.toExist()
.withTimeout(8000);
await element(by.text('OK')).tap();
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('room-actions-view')))
.toExist()
.withTimeout(2000);
@ -404,6 +377,7 @@ describe('Room actions screen', () => {
.withTimeout(4000);
await element(by.id('select-users-view-search')).tap();
await element(by.id('select-users-view-search')).replaceText(user.username);
await sleep(300);
await waitFor(element(by.id(`select-users-view-item-${user.username}`)))
.toExist()
.withTimeout(10000);
@ -437,14 +411,30 @@ describe('Room actions screen', () => {
await waitFor(element(by.id(`room-members-view-item-${username}`)))
.toExist()
.withTimeout(5000);
await element(by.id(`room-members-view-item-${username}`)).tap();
await sleep(300);
await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
let n = 0;
while (n < 3) {
// Max tries three times, in case it does not register the click
try {
await element(by.id(`room-members-view-item-${username}`)).tap();
await sleep(300);
await waitFor(element(by.id('action-sheet')))
.toExist()
.withTimeout(5000);
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up');
return;
} catch (e) {
n += 1;
}
}
};
const closeActionSheet = async () => {
await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.6);
await waitFor(element(by.id('action-sheet')))
.toBeNotVisible()
.withTimeout(1000);
await sleep(100);
};
it('should show all users', async () => {
@ -471,11 +461,14 @@ describe('Room actions screen', () => {
it('should remove user from room', async () => {
await openActionSheet('rocket.cat');
await element(by.label('Remove from room')).atIndex(0).tap();
await waitFor(element(by.label('Are you sure?')))
await waitFor(element(by[textMatcher]('Remove from room')))
.toExist()
.withTimeout(2000);
await element(by[textMatcher]('Remove from room')).atIndex(0).tap();
await waitFor(element(by[textMatcher]('Are you sure?')))
.toExist()
.withTimeout(5000);
await element(by.label('Yes, remove user!').and(by.type('_UIAlertControllerActionView'))).tap();
await element(by[textMatcher]('Yes, remove user!').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('room-members-view-item-rocket.cat')))
.toBeNotVisible()
.withTimeout(60000);
@ -548,24 +541,24 @@ describe('Room actions screen', () => {
it('should set/remove as mute', async () => {
await openActionSheet(user.username);
await element(by.label('Mute')).atIndex(0).tap();
await waitFor(element(by.label('Are you sure?')))
await element(by[textMatcher]('Mute')).atIndex(0).tap();
await waitFor(element(by[textMatcher]('Are you sure?')))
.toExist()
.withTimeout(5000);
await element(by.label('Mute').and(by.type('_UIAlertControllerActionView'))).tap();
await element(by[textMatcher]('Mute').and(by.type(alertButtonType))).tap();
await waitForToast();
await openActionSheet(user.username);
await element(by.label('Unmute')).atIndex(0).tap();
await waitFor(element(by.label('Are you sure?')))
await element(by[textMatcher]('Unmute')).atIndex(0).tap();
await waitFor(element(by[textMatcher]('Are you sure?')))
.toExist()
.withTimeout(5000);
await element(by.label('Unmute').and(by.type('_UIAlertControllerActionView'))).tap();
await element(by[textMatcher]('Unmute').and(by.type(alertButtonType))).tap();
await waitForToast();
await openActionSheet(user.username);
// Tests if Remove as mute worked
await waitFor(element(by.label('Mute')))
await waitFor(element(by[textMatcher]('Mute')))
.toExist()
.withTimeout(5000);
await closeActionSheet();
@ -576,21 +569,21 @@ describe('Room actions screen', () => {
const channelName = `#${data.groups.private.name}`;
await sendMessage(user, channelName, message);
await openActionSheet(user.username);
await element(by.label('Ignore')).atIndex(0).tap();
await element(by[textMatcher]('Ignore')).atIndex(0).tap();
await waitForToast();
await backToActions();
await tapBack();
await waitFor(element(by.id('room-view')))
.toExist()
.withTimeout(60000);
await waitFor(element(by.label('Message ignored. Tap to display it.')).atIndex(0))
await waitFor(element(by[textMatcher]('Message ignored. Tap to display it.')).atIndex(0))
.toExist()
.withTimeout(60000);
await element(by.label('Message ignored. Tap to display it.')).atIndex(0).tap();
await waitFor(element(by.label(message)).atIndex(0))
await element(by[textMatcher]('Message ignored. Tap to display it.')).atIndex(0).tap();
await waitFor(element(by[textMatcher](message)).atIndex(0))
.toExist()
.withTimeout(60000);
await element(by.label(message)).atIndex(0).tap();
await element(by[textMatcher](message)).atIndex(0).tap();
});
it('should navigate to direct message', async () => {
@ -607,7 +600,7 @@ describe('Room actions screen', () => {
.toExist()
.withTimeout(60000);
await openActionSheet(user.username);
await element(by.label('Direct message')).atIndex(0).tap();
await element(by[textMatcher]('Direct message')).atIndex(0).tap();
await waitFor(element(by.id('room-view')))
.toExist()
.withTimeout(60000);
@ -630,11 +623,11 @@ describe('Room actions screen', () => {
it('should block/unblock user', async () => {
await waitFor(element(by.id('room-actions-block-user'))).toExist();
await element(by.id('room-actions-block-user')).tap();
await waitFor(element(by.label('Unblock user')))
await waitFor(element(by[textMatcher]('Unblock user')))
.toExist()
.withTimeout(60000);
await element(by.id('room-actions-block-user')).tap();
await waitFor(element(by.label('Block user')))
await waitFor(element(by[textMatcher]('Block user')))
.toExist()
.withTimeout(60000);
});

View File

@ -1,4 +1,4 @@
const { navigateToLogin, login, mockMessage, tapBack, searchRoom } = require('../../helpers/app');
const { navigateToLogin, login, mockMessage, tapBack, searchRoom, platformTypes } = require('../../helpers/app');
const data = require('../../data');
const channel = data.groups.private.name;
@ -12,8 +12,10 @@ const navigateToRoom = async () => {
};
describe('Discussion', () => {
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true, delete: true });
({ textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
});
@ -24,12 +26,12 @@ describe('Discussion', () => {
await waitFor(element(by.id('new-message-view')))
.toExist()
.withTimeout(2000);
await element(by.label('Create Discussion')).atIndex(0).tap();
await element(by[textMatcher]('Create Discussion')).atIndex(0).tap();
await waitFor(element(by.id('create-discussion-view')))
.toExist()
.withTimeout(60000);
await expect(element(by.id('create-discussion-view'))).toExist();
await element(by.label('Select a Channel...')).tap();
await element(by[textMatcher]('Select a Channel...')).tap();
await element(by.id('multi-select-search')).replaceText(`${channel}`);
await waitFor(element(by.id(`multi-select-item-${channel}`)))
.toExist()
@ -59,7 +61,7 @@ describe('Discussion', () => {
await waitFor(element(by.id('action-sheet')))
.toExist()
.withTimeout(2000);
await element(by.label('Create Discussion')).atIndex(0).tap();
await element(by[textMatcher]('Create Discussion')).atIndex(0).tap();
await waitFor(element(by.id('create-discussion-view')))
.toExist()
.withTimeout(2000);
@ -86,11 +88,11 @@ describe('Discussion', () => {
it('should create discussion', async () => {
const discussionName = `${data.random}message`;
await element(by.label(discussionName)).atIndex(0).longPress();
await element(by[textMatcher](discussionName)).atIndex(0).longPress();
await waitFor(element(by.id('action-sheet')))
.toExist()
.withTimeout(2000);
await element(by.label('Start a Discussion')).atIndex(0).tap();
await element(by[textMatcher]('Start a Discussion')).atIndex(0).tap();
await waitFor(element(by.id('create-discussion-view')))
.toExist()
.withTimeout(2000);
@ -136,6 +138,7 @@ describe('Discussion', () => {
});
it('should have starred', async () => {
await element(by.id('room-actions-scrollview')).swipe('up', 'slow', 0.5);
await expect(element(by.id('room-actions-starred'))).toBeVisible();
});

View File

@ -1,5 +1,14 @@
const data = require('../../data');
const { navigateToLogin, login, mockMessage, tapBack, sleep, searchRoom, dismissReviewNag } = require('../../helpers/app');
const {
navigateToLogin,
login,
mockMessage,
tapBack,
sleep,
searchRoom,
platformTypes,
dismissReviewNag
} = require('../../helpers/app');
async function navigateToRoom(roomName) {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
@ -7,21 +16,22 @@ async function navigateToRoom(roomName) {
await login(data.users.regular.username, data.users.regular.password);
await searchRoom(`${roomName}`);
await element(by.id(`rooms-list-view-item-${roomName}`)).tap();
await waitFor(element(by.id('room-view')))
.toBeVisible()
await waitFor(element(by.id(`room-view-title-${roomName}`)))
.toExist()
.withTimeout(5000);
}
describe('Threads', () => {
const mainRoom = data.groups.private.name;
let textMatcher;
before(async () => {
({ textMatcher } = platformTypes[device.getPlatform()]);
await navigateToRoom(mainRoom);
});
describe('Render', () => {
it('should have room screen', async () => {
await expect(element(by.id('room-view'))).toExist();
await waitFor(element(by.id(`room-view-title-${mainRoom}`)))
.toExist()
.withTimeout(5000);
@ -69,12 +79,15 @@ describe('Threads', () => {
const thread = `${data.random}thread`;
it('should create thread', async () => {
await mockMessage('thread');
await element(by.label(thread)).atIndex(0).longPress();
await element(by[textMatcher](thread)).atIndex(0).longPress();
await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await element(by.label('Reply in Thread')).atIndex(0).tap();
await element(by.id('messagebox-input')).typeText('replied');
await element(by[textMatcher]('Reply in Thread')).atIndex(0).tap();
await element(by.id('messagebox-input')).replaceText('replied');
await waitFor(element(by.id('messagebox-send-message')))
.toExist()
.withTimeout(2000);
await element(by.id('messagebox-send-message')).tap();
await waitFor(element(by.id(`message-thread-button-${thread}`)))
.toExist()
@ -84,9 +97,6 @@ describe('Threads', () => {
it('should navigate to thread from button', async () => {
await element(by.id(`message-thread-button-${thread}`)).tap();
await waitFor(element(by.id('room-view')))
.toExist()
.withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${thread}`)))
.toExist()
.withTimeout(5000);
@ -96,13 +106,9 @@ describe('Threads', () => {
it('should toggle follow thread', async () => {
await element(by.id(`message-thread-button-${thread}`)).tap();
await waitFor(element(by.id('room-view')))
.toExist()
.withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${thread}`)))
.toExist()
.withTimeout(5000);
await expect(element(by.id(`room-view-title-${thread}`))).toExist();
await element(by.id('room-view-header-unfollow')).tap();
await waitFor(element(by.id('room-view-header-follow')))
.toExist()
@ -119,14 +125,13 @@ describe('Threads', () => {
const messageText = 'threadonly';
await mockMessage(messageText, true);
await tapBack();
await waitFor(element(by.id('room-header').and(by.label(`${mainRoom}`))))
.toBeVisible()
.withTimeout(2000);
await waitFor(element(by.id('room-header').and(by.label(`${data.random}thread`))))
.toBeNotVisible()
.withTimeout(2000);
await sleep(500); // TODO: Find a better way to wait for the animation to finish and the messagebox-input to be available and usable :(
await waitFor(element(by.label(`${data.random}${messageText}`)).atIndex(0))
await waitFor(element(by.id(`room-view-title-${data.random}thread`)))
.not.toExist()
.withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${mainRoom}`)))
.toExist()
.withTimeout(5000);
await waitFor(element(by[textMatcher](`${data.random}${messageText}`)).atIndex(0))
.toNotExist()
.withTimeout(2000);
});
@ -137,40 +142,39 @@ describe('Threads', () => {
await waitFor(element(by.id('messagebox-input-thread')))
.toExist()
.withTimeout(5000);
await element(by.id('messagebox-input-thread')).typeText(messageText);
await element(by.id('messagebox-input-thread')).replaceText(messageText);
await element(by.id('messagebox-send-to-channel')).tap();
await element(by.id('messagebox-send-message')).tap();
await tapBack();
await waitFor(element(by.id('room-header').and(by.label(`${mainRoom}`))))
.toBeVisible()
.withTimeout(2000);
await waitFor(element(by.id('room-header').and(by.label(`${data.random}thread`))))
.toBeNotVisible()
.withTimeout(2000);
await sleep(500); // TODO: Find a better way to wait for the animation to finish and the messagebox-input to be available and usable :(
await waitFor(element(by.label(messageText)).atIndex(0))
await waitFor(element(by.id(`room-view-title-${data.random}thread`)))
.not.toExist()
.withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${mainRoom}`)))
.toExist()
.withTimeout(5000);
await waitFor(element(by[textMatcher](messageText)).atIndex(0))
.toExist()
.withTimeout(2000);
});
it('should navigate to thread from thread name', async () => {
const messageText = 'navthreadname';
await mockMessage('dummymessagebetweenthethread');
await dismissReviewNag(); // TODO: Create a proper test for this elsewhere.
await mockMessage('dummymessagebetweenthethread'); // TODO: Create a proper test for this elsewhere.
await dismissReviewNag();
await element(by.id(`message-thread-button-${thread}`)).tap();
await waitFor(element(by.id('messagebox-input-thread')))
.toExist()
.withTimeout(5000);
await element(by.id('messagebox-input-thread')).typeText(messageText);
await element(by.id('messagebox-input-thread')).replaceText(messageText);
await element(by.id('messagebox-send-to-channel')).tap();
await element(by.id('messagebox-send-message')).tap();
await tapBack();
await waitFor(element(by.id('room-header').and(by.label(`${mainRoom}`))))
.toBeVisible()
.withTimeout(2000);
await waitFor(element(by.id('room-header').and(by.label(`${data.random}thread`))))
.toBeNotVisible()
.withTimeout(2000);
await waitFor(element(by.id(`room-view-title-${data.random}thread`)))
.not.toExist()
.withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${mainRoom}`)))
.toExist()
.withTimeout(5000);
await waitFor(element(by.id(`message-thread-replied-on-${thread}`)))
.toBeVisible()
.withTimeout(2000);
@ -211,7 +215,7 @@ describe('Threads', () => {
await waitFor(element(by.id(`room-view-title-${thread}`)))
.toExist()
.withTimeout(5000);
await element(by.id('messagebox-input-thread')).typeText(`${thread}draft`);
await element(by.id('messagebox-input-thread')).replaceText(`${thread}draft`);
await tapBack();
await element(by.id(`message-thread-button-${thread}`)).tap();

View File

@ -1,9 +1,11 @@
const data = require('../../data');
const { navigateToLogin, login } = require('../../helpers/app');
const { navigateToLogin, login, platformTypes } = require('../../helpers/app');
describe('Group DM', () => {
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
});
@ -29,7 +31,7 @@ describe('Group DM', () => {
describe('Usage', () => {
it('should navigate to create DM', async () => {
await element(by.label('Create Direct Messages')).tap();
await element(by[textMatcher]('Create Direct Messages')).tap();
});
it('should add users', async () => {

View File

@ -1,5 +1,5 @@
const data = require('../../data');
const { navigateToLogin, login, searchRoom, sleep } = require('../../helpers/app');
const { navigateToLogin, login, searchRoom, sleep, platformTypes } = require('../../helpers/app');
const { sendMessage } = require('../../helpers/data_setup');
async function navigateToRoom(user) {
@ -12,9 +12,11 @@ async function navigateToRoom(user) {
describe('Mark as unread', () => {
const user = data.users.alternate.username;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
await navigateToRoom(user);
@ -26,16 +28,16 @@ describe('Mark as unread', () => {
const message = `${data.random}message-mark-as-unread`;
const channelName = `@${data.users.regular.username}`;
await sendMessage(data.users.alternate, channelName, message);
await waitFor(element(by.label(message)).atIndex(0))
await waitFor(element(by[textMatcher](message)).atIndex(0))
.toExist()
.withTimeout(30000);
await sleep(300);
await element(by.label(message)).atIndex(0).longPress();
await element(by[textMatcher](message)).atIndex(0).longPress();
await waitFor(element(by.id('action-sheet-handle')))
.toBeVisible()
.withTimeout(3000);
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await element(by.label('Mark Unread')).atIndex(0).tap();
await element(by[textMatcher]('Mark Unread')).atIndex(0).tap();
await waitFor(element(by.id('rooms-list-view')))
.toExist()
.withTimeout(5000);

View File

@ -1,5 +1,5 @@
const data = require('../../data');
const { navigateToLogin, login, tapBack, sleep, searchRoom } = require('../../helpers/app');
const { navigateToLogin, login, tapBack, sleep, searchRoom, platformTypes } = require('../../helpers/app');
const privateRoomName = data.groups.private.name;
@ -25,17 +25,20 @@ async function navigateToRoomInfo(type) {
.withTimeout(2000);
}
async function swipe(direction) {
await element(by.id('room-info-edit-view-list')).swipe(direction, 'fast', 0.8);
}
async function waitForToast() {
// await waitFor(element(by.id('toast'))).toExist().withTimeout(10000);
// await expect(element(by.id('toast'))).toExist();
// await waitFor(element(by.id('toast'))).toBeNotVisible().withTimeout(10000);
// await expect(element(by.id('toast'))).toBeNotVisible();
await sleep(300);
}
describe('Room info screen', () => {
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
});
@ -72,15 +75,15 @@ describe('Room info screen', () => {
});
it('should have description', async () => {
await expect(element(by.label('Description'))).toExist();
await expect(element(by[textMatcher]('Description'))).toExist();
});
it('should have topic', async () => {
await expect(element(by.label('Topic'))).toExist();
await expect(element(by[textMatcher]('Topic'))).toExist();
});
it('should have announcement', async () => {
await expect(element(by.label('Announcement'))).toExist();
await expect(element(by[textMatcher]('Announcement'))).toExist();
});
it('should have edit button', async () => {
@ -124,8 +127,7 @@ describe('Room info screen', () => {
});
it('should have type switch', async () => {
// Ugly hack to scroll on detox
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.8);
await swipe('up');
await expect(element(by.id('room-info-edit-view-t'))).toExist();
});
@ -150,44 +152,33 @@ describe('Room info screen', () => {
});
after(async () => {
// Ugly hack to scroll on detox
await element(by.id('room-info-edit-view-list')).swipe('down', 'fast', 0.8);
await swipe('down');
});
});
describe('Usage', () => {
// it('should enter "invalid name" and get error', async() => {
// await element(by.type('UIScrollView')).atIndex(1).swipe('down');
// await element(by.id('room-info-edit-view-name')).replaceText('invalid name');
// await element(by.type('UIScrollView')).atIndex(1).swipe('up');
// await element(by.id('room-info-edit-view-submit')).tap();
// await waitFor(element(by.text('There was an error while saving settings!'))).toExist().withTimeout(60000);
// await expect(element(by.text('There was an error while saving settings!'))).toExist();
// await element(by.text('OK')).tap();
// await waitFor(element(by.text('There was an error while saving settings!'))).toBeNotVisible().withTimeout(10000);
// await element(by.type('UIScrollView')).atIndex(1).swipe('down');
// });
it('should change room name', async () => {
await element(by.id('room-info-edit-view-name')).replaceText(`${privateRoomName}new`);
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await swipe('up');
await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast();
await tapBack();
await waitFor(element(by.id('room-info-view')))
.toExist()
.withTimeout(2000);
await expect(element(by.id('room-info-view-name'))).toHaveLabel(`${privateRoomName}new`);
const matcher = device.getPlatform() === 'android' ? 'toHaveText' : 'toHaveLabel';
await expect(element(by.id('room-info-view-name')))[matcher](`${privateRoomName}new`);
// change name to original
await element(by.id('room-info-view-edit-button')).tap();
await waitFor(element(by.id('room-info-edit-view')))
.toExist()
.withTimeout(2000);
await element(by.id('room-info-edit-view-name')).replaceText(`${privateRoomName}`);
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await swipe('up');
await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast();
await element(by.id('room-info-edit-view-list')).swipe('down', 'fast', 0.8);
await swipe('down');
});
it('should reset form', async () => {
@ -196,10 +187,11 @@ describe('Room info screen', () => {
await element(by.id('room-info-edit-view-topic')).replaceText('abc');
await element(by.id('room-info-edit-view-announcement')).replaceText('abc');
await element(by.id('room-info-edit-view-password')).replaceText('abc');
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-t')).tap();
await swipe('up');
await element(by.id('room-info-edit-view-ro')).longPress(); // https://github.com/facebook/react-native/issues/28032
await element(by.id('room-info-edit-view-react-when-ro')).tap();
await swipe('up');
await element(by.id('room-info-edit-view-reset')).tap();
// after reset
await expect(element(by.id('room-info-edit-view-name'))).toHaveText(privateRoomName);
@ -207,22 +199,23 @@ describe('Room info screen', () => {
await expect(element(by.id('room-info-edit-view-topic'))).toHaveText('');
await expect(element(by.id('room-info-edit-view-announcement'))).toHaveText('');
await expect(element(by.id('room-info-edit-view-password'))).toHaveText('');
await expect(element(by.id('room-info-edit-view-t'))).toHaveValue('1');
await expect(element(by.id('room-info-edit-view-ro'))).toHaveValue('0');
// await swipe('down');
await expect(element(by.id('room-info-edit-view-t'))).toHaveToggleValue(true);
await expect(element(by.id('room-info-edit-view-ro'))).toHaveToggleValue(false);
await expect(element(by.id('room-info-edit-view-react-when-ro'))).toBeNotVisible();
await element(by.id('room-info-edit-view-list')).swipe('down', 'fast', 0.8);
await swipe('down');
});
it('should change room description', async () => {
await element(by.id('room-info-edit-view-description')).replaceText('new description');
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await swipe('up');
await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast();
await tapBack();
await waitFor(element(by.id('room-info-view')))
.toExist()
.withTimeout(2000);
await expect(element(by.label('new description').withAncestor(by.id('room-info-view-description')))).toExist();
await expect(element(by[textMatcher]('new description').withAncestor(by.id('room-info-view-description')))).toExist();
});
it('should change room topic', async () => {
@ -234,14 +227,14 @@ describe('Room info screen', () => {
.toExist()
.withTimeout(2000);
await element(by.id('room-info-edit-view-topic')).replaceText('new topic');
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await swipe('up');
await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast();
await tapBack();
await waitFor(element(by.id('room-info-view')))
.toExist()
.withTimeout(2000);
await expect(element(by.label('new topic').withAncestor(by.id('room-info-view-topic')))).toExist();
await expect(element(by[textMatcher]('new topic').withAncestor(by.id('room-info-view-topic')))).toExist();
});
it('should change room announcement', async () => {
@ -253,14 +246,14 @@ describe('Room info screen', () => {
.toExist()
.withTimeout(2000);
await element(by.id('room-info-edit-view-announcement')).replaceText('new announcement');
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await swipe('up');
await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast();
await tapBack();
await waitFor(element(by.id('room-info-view')))
.toExist()
.withTimeout(2000);
await expect(element(by.label('new announcement').withAncestor(by.id('room-info-view-announcement')))).toExist();
await expect(element(by[textMatcher]('new announcement').withAncestor(by.id('room-info-view-announcement')))).toExist();
});
it('should change room password', async () => {
@ -271,61 +264,45 @@ describe('Room info screen', () => {
await waitFor(element(by.id('room-info-edit-view')))
.toExist()
.withTimeout(2000);
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-password')).replaceText('password');
await swipe('up');
await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast();
});
it('should change room type', async () => {
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await swipe('down');
await element(by.id('room-info-edit-view-t')).tap();
await swipe('up');
await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast();
await swipe('down');
await element(by.id('room-info-edit-view-t')).tap();
await swipe('up');
await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast();
});
// it('should change room read only and allow reactions', async() => {
// await sleep(1000);
// await element(by.type('UIScrollView')).atIndex(1).swipe('up');
// await element(by.id('room-info-edit-view-ro')).tap();
// await waitFor(element(by.id('room-info-edit-view-react-when-ro'))).toExist().withTimeout(2000);
// await expect(element(by.id('room-info-edit-view-react-when-ro'))).toExist();
// await element(by.id('room-info-edit-view-react-when-ro')).tap();
// await element(by.id('room-info-edit-view-submit')).tap();
// await waitForToast();
// // TODO: test if it's possible to react
// });
it('should archive room', async () => {
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-archive')).tap();
await waitFor(element(by.text('Yes, archive it!')))
await waitFor(element(by[textMatcher]('Yes, archive it!')))
.toExist()
.withTimeout(5000);
await element(by.text('Yes, archive it!')).tap();
await element(by[textMatcher]('Yes, archive it!').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('room-info-edit-view-unarchive')))
.toExist()
.withTimeout(60000);
await expect(element(by.id('room-info-edit-view-archive'))).toBeNotVisible();
// TODO: needs permission to unarchive
// await element(by.id('room-info-edit-view-archive')).tap();
// await waitFor(element(by.text('Yes, unarchive it!'))).toExist().withTimeout(5000);
// await expect(element(by.text('Yes, unarchive it!'))).toExist();
// await element(by.text('Yes, unarchive it!')).tap();
// await waitFor(element(by.text('ARCHIVE'))).toExist().withTimeout(60000);
// await expect(element(by.text('ARCHIVE'))).toExist();
});
it('should delete room', async () => {
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await swipe('up');
await element(by.id('room-info-edit-view-delete')).tap();
await waitFor(element(by.text('Yes, delete it!')))
await waitFor(element(by[textMatcher]('Yes, delete it!')))
.toExist()
.withTimeout(5000);
await element(by.text('Yes, delete it!')).tap();
await element(by[textMatcher]('Yes, delete it!').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('rooms-list-view')))
.toExist()
.withTimeout(10000);

View File

@ -1,5 +1,5 @@
const data = require('../../data');
const { navigateToLogin, tapBack, login, searchRoom } = require('../../helpers/app');
const { navigateToLogin, tapBack, login, searchRoom, sleep, platformTypes } = require('../../helpers/app');
async function navigateToRoom(roomName) {
await searchRoom(`${roomName}`);
@ -7,8 +7,14 @@ async function navigateToRoom(roomName) {
await waitFor(element(by.id('room-view')))
.toBeVisible()
.withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${roomName}`)))
.toExist()
.withTimeout(5000);
}
let textMatcher;
let alertButtonType;
async function clearCache() {
await waitFor(element(by.id('room-view')))
.toBeVisible()
@ -26,10 +32,10 @@ async function clearCache() {
.toBeVisible()
.withTimeout(2000);
await element(by.id('settings-view-clear-cache')).tap();
await waitFor(element(by.text('This will clear all your offline data.')))
await waitFor(element(by[textMatcher]('This will clear all your offline data.')))
.toExist()
.withTimeout(2000);
await element(by.label('Clear').and(by.type('_UIAlertControllerActionView'))).tap();
await element(by[textMatcher]('Clear').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('rooms-list-view')))
.toBeVisible()
.withTimeout(5000);
@ -39,6 +45,10 @@ async function clearCache() {
}
async function waitForLoading() {
if (device.getPlatform() === 'android') {
await sleep(10000);
return; // FIXME: Loading indicator doesn't animate properly on android
}
await waitFor(element(by.id('loading')))
.toBeVisible()
.withTimeout(5000);
@ -50,21 +60,22 @@ async function waitForLoading() {
describe('Room', () => {
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(data.adminUser, data.adminPassword);
});
it('should jump to an old message and load its surroundings', async () => {
await navigateToRoom('jumping');
await waitFor(element(by.label('Quote first message')))
await waitFor(element(by[textMatcher]('300')))
.toExist()
.withTimeout(5000);
await element(by.label('1')).atIndex(0).tap();
await element(by[textMatcher]('1')).atIndex(0).tap();
await waitForLoading();
await waitFor(element(by.label('1')).atIndex(0))
await waitFor(element(by[textMatcher]('1')).atIndex(0))
.toExist()
.withTimeout(10000);
await expect(element(by.label('2'))).toExist();
await expect(element(by[textMatcher]('2'))).toExist();
});
it('should tap FAB and scroll to bottom', async () => {
@ -72,7 +83,7 @@ describe('Room', () => {
.toExist()
.withTimeout(5000);
await element(by.id('nav-jump-to-bottom')).tap();
await waitFor(element(by.label('Quote first message')))
await waitFor(element(by[textMatcher]('Quote first message')))
.toExist()
.withTimeout(5000);
await clearCache();
@ -83,14 +94,15 @@ describe('Room', () => {
await waitFor(element(by.id('room-view-messages')))
.toExist()
.withTimeout(5000);
await waitFor(element(by.label('300')))
await waitFor(element(by[textMatcher]('300')))
.toExist()
.withTimeout(5000);
let found = false;
while (!found) {
await element(by.id('room-view-messages')).atIndex(0).scroll(500, 'up');
try {
await expect(element(by.label('249'))).toExist();
const direction = device.getPlatform() === 'android' ? 'down' : 'up';
await element(by.id('room-view-messages')).scroll(500, direction);
await expect(element(by[textMatcher]('249'))).toExist();
found = true;
} catch {
//
@ -101,107 +113,130 @@ describe('Room', () => {
it('should search for old message and load its surroundings', async () => {
await navigateToRoom('jumping');
await sleep(1000); // wait for proper load the room
await element(by.id('room-view-search')).tap();
await waitFor(element(by.id('search-messages-view')))
.toExist()
.withTimeout(5000);
await element(by.id('search-message-view-input')).typeText('30\n');
await waitFor(element(by.label('30')).atIndex(0))
await element(by.id('search-message-view-input')).replaceText('30');
await waitFor(element(by[textMatcher]('30')).atIndex(1))
.toExist()
.withTimeout(5000);
await element(by.label('30')).atIndex(0).tap();
.withTimeout(30000);
await element(by[textMatcher]('30')).atIndex(1).tap();
await waitForLoading();
await expect(element(by.label('30'))).toExist();
await expect(element(by.label('31'))).toExist();
await expect(element(by.label('32'))).toExist();
await waitFor(element(by[textMatcher]('30')).atIndex(0))
.toExist()
.withTimeout(30000);
await expect(element(by[textMatcher]('31'))).toExist();
await expect(element(by[textMatcher]('32'))).toExist();
});
it('should load newer and older messages', async () => {
await element(by.id('room-view-messages')).atIndex(0).swipe('down', 'fast', 0.8);
await waitFor(element(by.label('5')))
.toExist()
.withTimeout(10000);
await waitFor(element(by.label('Load Older')))
.toExist()
.withTimeout(5000);
await element(by.label('Load Older')).atIndex(0).tap();
await waitFor(element(by.label('4')))
// TODO: couldn't make it work on Android :(
if (device.getPlatform() === 'android') {
return;
}
let found = false;
while (!found) {
try {
// it doesn't recognize this list
await element(by.id('room-view-messages')).scroll(500, 'up');
await expect(element(by[textMatcher]('Load Older'))).toBeVisible();
await expect(element(by[textMatcher]('5'))).toExist();
found = true;
} catch {
//
}
}
await element(by[textMatcher]('Load Older')).atIndex(0).tap();
await waitFor(element(by[textMatcher]('4')))
.toExist()
.withTimeout(5000);
await element(by.id('room-view-messages')).atIndex(0).swipe('down', 'fast', 0.5);
await waitFor(element(by.label('1')))
await waitFor(element(by[textMatcher]('1')))
.toExist()
.withTimeout(5000);
await element(by.id('room-view-messages')).atIndex(0).swipe('up', 'fast', 0.5);
await waitFor(element(by.label('25')))
await waitFor(element(by[textMatcher]('25')))
.toExist()
.withTimeout(5000);
await element(by.id('room-view-messages')).atIndex(0).swipe('up', 'fast', 0.5);
await waitFor(element(by.label('50')))
await waitFor(element(by[textMatcher]('50')))
.toExist()
.withTimeout(5000);
await element(by.id('room-view-messages')).atIndex(0).swipe('up', 'slow', 0.5);
await waitFor(element(by.label('Load Newer')))
await waitFor(element(by[textMatcher]('Load Newer')))
.toExist()
.withTimeout(5000);
await element(by.label('Load Newer')).atIndex(0).tap();
await waitFor(element(by.label('104')))
await element(by[textMatcher]('Load Newer')).atIndex(0).tap();
await waitFor(element(by[textMatcher]('104')))
.toExist()
.withTimeout(5000);
await waitFor(element(by.label('Load Newer')))
await waitFor(element(by[textMatcher]('Load Newer')))
.toExist()
.withTimeout(5000);
await element(by.label('Load Newer')).atIndex(0).tap();
await waitFor(element(by.label('154')))
await element(by[textMatcher]('Load Newer')).atIndex(0).tap();
await waitFor(element(by[textMatcher]('154')))
.toExist()
.withTimeout(5000);
await waitFor(element(by.label('Load Newer')))
await waitFor(element(by[textMatcher]('Load Newer')))
.toExist()
.withTimeout(5000);
await element(by.label('Load Newer')).atIndex(0).tap();
await waitFor(element(by.label('Load Newer')))
await element(by[textMatcher]('Load Newer')).atIndex(0).tap();
await waitFor(element(by[textMatcher]('Load Newer')))
.toNotExist()
.withTimeout(5000);
await expect(element(by.label('Load More'))).toNotExist();
await expect(element(by.label('201'))).toExist();
await expect(element(by.label('202'))).toExist();
await expect(element(by[textMatcher]('Load More'))).toNotExist();
await expect(element(by[textMatcher]('201'))).toExist();
await expect(element(by[textMatcher]('202'))).toExist();
await tapBack();
});
});
const expectThreadMessages = async message => {
await waitFor(element(by.id('room-view-title-jumping-thread')))
await waitFor(element(by.id('room-view-title-thread 1')))
.toExist()
.withTimeout(5000);
await expect(element(by.label(message))).toExist();
await waitForLoading();
await expect(element(by[textMatcher](message)).atIndex(0)).toExist();
await element(by[textMatcher](message)).atIndex(0).tap();
};
describe('Threads', () => {
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true });
});
it('should navigate to a thread from another room', async () => {
await navigateToRoom('jumping');
await waitFor(element(by.label("Go to jumping-thread's thread")).atIndex(0))
await waitFor(element(by[textMatcher]("Go to jumping-thread's thread")).atIndex(0))
.toExist()
.withTimeout(5000);
await element(by.label("Go to jumping-thread's thread")).atIndex(0).tap();
await waitForLoading();
await element(by[textMatcher]("Go to jumping-thread's thread")).atIndex(0).tap();
await expectThreadMessages("Go to jumping-thread's thread");
await tapBack();
});
it('should tap on thread message from main room', async () => {
await waitFor(element(by.label('thread message sent to main room')).atIndex(0))
await waitFor(element(by.id('room-view-title-jumping-thread')))
.toExist()
.withTimeout(5000);
await element(by.label('thread message sent to main room')).atIndex(0).tap();
await waitFor(element(by[textMatcher]('thread message sent to main room')))
.toExist()
.withTimeout(10000);
await element(by[textMatcher]('thread message sent to main room')).atIndex(0).tap();
await expectThreadMessages('thread message sent to main room');
await tapBack();
});
it('should tap on quote', async () => {
await waitFor(element(by.label('quoted')))
await waitFor(element(by.id('room-view-title-jumping-thread')))
.toExist()
.withTimeout(5000);
await element(by.label('quoted')).atIndex(0).tap();
await waitFor(element(by[textMatcher]('quoted')))
.toExist()
.withTimeout(5000);
await element(by[textMatcher]('quoted')).atIndex(0).tap();
await expectThreadMessages('quoted');
await tapBack();
});
@ -214,11 +249,11 @@ describe('Threads', () => {
await waitFor(element(by.id('search-messages-view')))
.toExist()
.withTimeout(5000);
await element(by.id('search-message-view-input')).typeText('to be searched\n');
await waitFor(element(by.label('to be searched')))
await element(by.id('search-message-view-input')).replaceText('to be searched');
await waitFor(element(by[textMatcher]('to be searched')).atIndex(1))
.toExist()
.withTimeout(5000);
await element(by.label('to be searched')).atIndex(1).tap();
.withTimeout(30000);
await element(by[textMatcher]('to be searched')).atIndex(1).tap();
await expectThreadMessages('to be searched');
});

View File

@ -1,11 +1,14 @@
const data = require('../../data');
const { navigateToLogin, login } = require('../../helpers/app');
const { navigateToLogin, login, platformTypes } = require('../../helpers/app');
const teamName = `team-${data.random}`;
describe('Create team screen', () => {
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
});
@ -41,17 +44,23 @@ describe('Create team screen', () => {
describe('Create Team', () => {
describe('Usage', () => {
it('should get invalid team name', async () => {
await element(by.id('create-channel-name')).typeText(`${data.teams.private.name}`);
await element(by.id('create-channel-name')).replaceText(`${data.teams.private.name}`);
await waitFor(element(by.id('create-channel-submit')))
.toExist()
.withTimeout(2000);
await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.text('OK')))
await waitFor(element(by[textMatcher]('OK').and(by.type(alertButtonType))))
.toBeVisible()
.withTimeout(5000);
await element(by.text('OK')).tap();
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
});
it('should create private team', async () => {
await element(by.id('create-channel-name')).replaceText('');
await element(by.id('create-channel-name')).typeText(teamName);
await element(by.id('create-channel-name')).replaceText(teamName);
await waitFor(element(by.id('create-channel-submit')))
.toExist()
.withTimeout(2000);
await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view')))
.toExist()
@ -81,10 +90,10 @@ describe('Create team screen', () => {
await element(by.id('room-info-view-edit-button')).tap();
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-delete')).tap();
await waitFor(element(by.text('Yes, delete it!')))
await waitFor(element(by[textMatcher]('Yes, delete it!')))
.toExist()
.withTimeout(5000);
await element(by.text('Yes, delete it!')).tap();
await element(by[textMatcher]('Yes, delete it!').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('rooms-list-view')))
.toExist()
.withTimeout(10000);

View File

@ -1,5 +1,5 @@
const data = require('../../data');
const { navigateToLogin, login, tapBack, sleep, searchRoom } = require('../../helpers/app');
const { navigateToLogin, login, tapBack, sleep, searchRoom, platformTypes } = require('../../helpers/app');
async function navigateToRoom(roomName) {
await searchRoom(`${roomName}`);
@ -17,6 +17,7 @@ async function openActionSheet(username) {
await sleep(300);
await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up');
}
async function navigateToRoomActions() {
@ -37,20 +38,41 @@ async function backToActions() {
}
async function closeActionSheet() {
await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.6);
await waitFor(element(by.id('action-sheet-handle')))
.toBeNotVisible()
.withTimeout(3000);
await sleep(200);
}
async function waitForToast() {
await sleep(1000);
}
async function swipeTillVisible(container, find, direction = 'up', delta = 0.3, speed = 'slow') {
let found = false;
while (!found) {
try {
await element(container).swipe(direction, speed, delta);
await sleep(200);
await expect(element(find)).toBeVisible();
found = true;
} catch (e) {
//
}
}
}
describe('Team', () => {
const team = data.teams.private.name;
const user = data.users.alternate;
const room = `private${data.random}-channel-team`;
const existingRoom = data.groups.alternate.name;
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
await navigateToRoom(team);
@ -86,7 +108,7 @@ describe('Team', () => {
describe('Team Channels Header', () => {
it('should have actions button ', async () => {
await expect(element(by.id('room-header'))).toExist();
await expect(element(by.id('room-header')).atIndex(0)).toExist();
});
it('should have team channels button ', async () => {
@ -124,6 +146,9 @@ describe('Team', () => {
await element(by.id('add-channel-team-view-create-channel')).tap();
await element(by.id('select-users-view-search')).replaceText('rocket.cat');
await waitFor(element(by.id('select-users-view-item-rocket.cat')))
.toBeVisible()
.withTimeout(5000);
await element(by.id('select-users-view-item-rocket.cat')).tap();
await waitFor(element(by.id('selected-user-rocket.cat')))
.toBeVisible()
@ -134,7 +159,10 @@ describe('Team', () => {
.toExist()
.withTimeout(10000);
await element(by.id('create-channel-name')).replaceText('');
await element(by.id('create-channel-name')).typeText(room);
await element(by.id('create-channel-name')).replaceText(room);
await waitFor(element(by.id('create-channel-submit')))
.toExist()
.withTimeout(10000);
await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view')))
@ -156,9 +184,9 @@ describe('Team', () => {
.toExist()
.withTimeout(60000);
await expect(element(by.id(`room-view-title-${room}`))).toExist();
await expect(element(by.id('room-view-header-team-channels'))).toExist();
await expect(element(by.id('room-view-header-threads'))).toExist();
await expect(element(by.id('room-view-search'))).toExist();
await expect(element(by.id('room-view-header-team-channels')).atIndex(0)).toExist();
await expect(element(by.id('room-view-header-threads')).atIndex(0)).toExist();
await expect(element(by.id('room-view-search')).atIndex(0)).toExist();
await tapBack();
});
@ -186,7 +214,7 @@ describe('Team', () => {
await expect(element(by.id('room-view-header-team-channels'))).toExist();
await element(by.id('room-view-header-team-channels')).tap();
await waitFor(element(by.id(`rooms-list-view-item-${existingRoom}`)))
await waitFor(element(by.id(`rooms-list-view-item-${existingRoom}`)).atIndex(0))
.toExist()
.withTimeout(10000);
});
@ -195,7 +223,8 @@ describe('Team', () => {
await element(by.id(`rooms-list-view-item-${existingRoom}`))
.atIndex(0)
.longPress();
await sleep(500);
await swipeTillVisible(by.id('action-sheet-remove-from-team'), by.id('action-sheet-delete'));
await waitFor(element(by.id('action-sheet-auto-join')))
.toBeVisible()
.withTimeout(5000);
@ -224,7 +253,7 @@ describe('Team', () => {
await waitFor(element(by.id('auto-join-tag')))
.toBeNotVisible()
.withTimeout(5000);
await waitFor(element(by.id(`rooms-list-view-item-${existingRoom}`)))
await waitFor(element(by.id(`rooms-list-view-item-${existingRoom}`)).atIndex(0))
.toExist()
.withTimeout(6000);
});
@ -298,22 +327,22 @@ describe('Team', () => {
await waitFor(
element(
by.label(
by[textMatcher](
'You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.'
)
)
)
.toExist()
.withTimeout(2000);
await element(by.text('OK')).tap();
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('select-list-view-submit')))
.toExist()
.withTimeout(2000);
await element(by.id('select-list-view-submit')).tap();
await waitFor(element(by.text('Last owner cannot be removed')))
await waitFor(element(by[textMatcher]('Last owner cannot be removed')))
.toExist()
.withTimeout(8000);
await element(by.text('OK')).tap();
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
await tapBack();
await waitFor(element(by.id('room-actions-view')))
.toExist()
@ -352,6 +381,9 @@ describe('Team', () => {
it('should remove member from team', async () => {
await openActionSheet('rocket.cat');
await waitFor(element(by.id('action-sheet-remove-from-team')))
.toBeVisible()
.withTimeout(2000);
await element(by.id('action-sheet-remove-from-team')).tap();
await waitFor(element(by.id('select-list-view')))
.toExist()
@ -406,14 +438,14 @@ describe('Team', () => {
await waitFor(
element(
by.label(
by[textMatcher](
'You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.'
)
)
)
.toExist()
.withTimeout(2000);
await element(by.text('OK')).tap();
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('select-list-view-submit')))
.toExist()
.withTimeout(2000);

View File

@ -1,5 +1,5 @@
const data = require('../../data');
const { navigateToLogin, login, tapBack, searchRoom, sleep } = require('../../helpers/app');
const { navigateToLogin, login, tapBack, searchRoom, sleep, platformTypes } = require('../../helpers/app');
const toBeConverted = `to-be-converted-${data.random}`;
const toBeMoved = `to-be-moved-${data.random}`;
@ -17,7 +17,10 @@ const createChannel = async room => {
await waitFor(element(by.id('create-channel-view')))
.toExist()
.withTimeout(10000);
await element(by.id('create-channel-name')).typeText(room);
await element(by.id('create-channel-name')).replaceText(room);
await waitFor(element(by.id('create-channel-submit')))
.toExist()
.withTimeout(10000);
await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view')))
.toExist()
@ -51,8 +54,11 @@ async function navigateToRoomActions(room) {
}
describe('Move/Convert Team', () => {
let alertButtonType;
let textMatcher;
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
});
@ -69,10 +75,10 @@ describe('Move/Convert Team', () => {
.toExist()
.withTimeout(2000);
await element(by.id('room-actions-convert-to-team')).tap();
await waitFor(element(by.label('You are converting this Channel to a Team. All Members will be kept.')))
await waitFor(element(by[textMatcher]('You are converting this Channel to a Team. All Members will be kept.')))
.toExist()
.withTimeout(2000);
await element(by.text('Convert')).tap();
await element(by[textMatcher]('Convert').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('room-view')))
.toExist()
.withTimeout(20000);
@ -101,12 +107,14 @@ describe('Move/Convert Team', () => {
.toExist()
.withTimeout(2000);
await element(by.id('room-actions-move-to-team')).tap();
await waitFor(element(by.id('select-list-view')))
await waitFor(element(by[textMatcher]('Move to Team')).atIndex(0))
.toExist()
.withTimeout(2000);
await waitFor(element(by.id('select-list-view-submit')))
.toExist()
.withTimeout(2000);
await element(by.id('select-list-view-submit')).tap();
await sleep(2000);
await waitFor(element(by.id('select-list-view')))
await waitFor(element(by[textMatcher]('Select Team')))
.toExist()
.withTimeout(2000);
await waitFor(element(by.id(`select-list-view-item-${toBeConverted}`)))
@ -116,14 +124,14 @@ describe('Move/Convert Team', () => {
await element(by.id('select-list-view-submit')).atIndex(0).tap();
await waitFor(
element(
by.label(
by[textMatcher](
'After reading the previous intructions about this behavior, do you still want to move this channel to the selected team?'
)
)
)
.toExist()
.withTimeout(2000);
await element(by.text('Yes, move it!')).tap();
await element(by[textMatcher]('Yes, move it!').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('room-view-header-team-channels')))
.toExist()
.withTimeout(10000);
@ -141,12 +149,11 @@ describe('Move/Convert Team', () => {
it('should convert a team to a channel', async () => {
await navigateToRoomActions(toBeConverted);
await element(by.id('room-actions-scrollview')).scrollTo('bottom');
await waitFor(element(by.id('room-actions-convert-channel-to-team')))
await waitFor(element(by[textMatcher]('Convert to Channel')))
.toExist()
.withTimeout(2000);
await element(by.id('room-actions-convert-channel-to-team')).tap();
await sleep(2000);
await waitFor(element(by.id('select-list-view')))
await element(by[textMatcher]('Convert to Channel')).atIndex(0).tap();
await waitFor(element(by[textMatcher]('Converting Team to Channel')))
.toExist()
.withTimeout(2000);
await waitFor(element(by.id(`select-list-view-item-${toBeMoved}`)))
@ -157,10 +164,10 @@ describe('Move/Convert Team', () => {
.toExist()
.withTimeout(2000);
await element(by.id('select-list-view-submit')).tap();
await waitFor(element(by.label('You are converting this Team to a Channel')))
await waitFor(element(by[textMatcher]('You are converting this Team to a Channel')))
.toExist()
.withTimeout(2000);
await element(by.text('Convert')).tap();
await element(by[textMatcher]('Convert').and(by.type(alertButtonType))).tap();
await waitFor(element(by.id('room-view')))
.toExist()
.withTimeout(20000);

View File

@ -239,6 +239,18 @@
}
}
}
},
"and.emu.debug": {
"device": "Pixel_API_28_AOSP",
"type": "android.emulator",
"binaryPath": "android/app/build/outputs/apk/e2ePlay/debug/app-e2e-play-debug.apk",
"build": "cd android && ./gradlew app:assembleE2ePlayDebug app:assembleE2ePlayDebugAndroidTest -DtestBuildType=debug && cd .."
},
"and.emu.release": {
"device": "Pixel_API_28_AOSP",
"type": "android.emulator",
"binaryPath": "android/app/build/outputs/apk/e2ePlay/release/app-e2e-play-release.apk",
"build": "cd android && ./gradlew app:assembleE2ePlayRelease app:assembleE2ePlayReleaseAndroidTest -DtestBuildType=release && cd .."
}
}
}