Merge branch 'develop' into chore.circleci_caching

This commit is contained in:
Dan Caseley 2020-07-22 22:10:14 +01:00
commit 8c072c3b82
37 changed files with 473 additions and 389 deletions

View File

@ -36,6 +36,9 @@ commands:
name: Test
command: |
npx detox test << parameters.folder >> --configuration ios.sim.release --cleanup
when: always
- store_artifacts:
path: ./artifacts
install-npm-modules:
description: Install NPM modules

1
.gitignore vendored
View File

@ -58,6 +58,7 @@ buck-out/
coverage
artifacts
.vscode/
e2e/docker/rc_test_env/docker-compose.yml
e2e/docker/data/db

View File

@ -15,6 +15,7 @@ import OrSeparator from './OrSeparator';
import Touch from '../utils/touch';
import I18n from '../i18n';
import random from '../utils/random';
import { logEvent, events } from '../utils/log';
import RocketChat from '../lib/rocketchat';
const BUTTON_HEIGHT = 48;
@ -77,6 +78,7 @@ class LoginServices extends React.PureComponent {
}
onPressFacebook = () => {
logEvent(events.LOGIN_WITH_FACEBOOK);
const { services, server } = this.props;
const { clientId } = services.facebook;
const endpoint = 'https://m.facebook.com/v2.9/dialog/oauth';
@ -88,6 +90,7 @@ class LoginServices extends React.PureComponent {
}
onPressGithub = () => {
logEvent(events.LOGIN_WITH_GITHUB);
const { services, server } = this.props;
const { clientId } = services.github;
const endpoint = `https://github.com/login?client_id=${ clientId }&return_to=${ encodeURIComponent('/login/oauth/authorize') }`;
@ -99,6 +102,7 @@ class LoginServices extends React.PureComponent {
}
onPressGitlab = () => {
logEvent(events.LOGIN_WITH_GITLAB);
const { services, server, Gitlab_URL } = this.props;
const { clientId } = services.gitlab;
const baseURL = Gitlab_URL ? Gitlab_URL.trim().replace(/\/*$/, '') : 'https://gitlab.com';
@ -111,6 +115,7 @@ class LoginServices extends React.PureComponent {
}
onPressGoogle = () => {
logEvent(events.LOGIN_WITH_GOOGLE);
const { services, server } = this.props;
const { clientId } = services.google;
const endpoint = 'https://accounts.google.com/o/oauth2/auth';
@ -122,6 +127,7 @@ class LoginServices extends React.PureComponent {
}
onPressLinkedin = () => {
logEvent(events.LOGIN_WITH_LINKEDIN);
const { services, server } = this.props;
const { clientId } = services.linkedin;
const endpoint = 'https://www.linkedin.com/oauth/v2/authorization';
@ -133,6 +139,7 @@ class LoginServices extends React.PureComponent {
}
onPressMeteor = () => {
logEvent(events.LOGIN_WITH_METEOR);
const { services, server } = this.props;
const { clientId } = services['meteor-developer'];
const endpoint = 'https://www.meteor.com/oauth2/authorize';
@ -143,6 +150,7 @@ class LoginServices extends React.PureComponent {
}
onPressTwitter = () => {
logEvent(events.LOGIN_WITH_TWITTER);
const { server } = this.props;
const state = this.getOAuthState();
const url = `${ server }/_oauth/twitter/?requestTokenAndRedirect=true&state=${ state }`;
@ -150,6 +158,7 @@ class LoginServices extends React.PureComponent {
}
onPressWordpress = () => {
logEvent(events.LOGIN_WITH_WORDPRESS);
const { services, server } = this.props;
const { clientId, serverURL } = services.wordpress;
const endpoint = `${ serverURL }/oauth/authorize`;
@ -161,6 +170,7 @@ class LoginServices extends React.PureComponent {
}
onPressCustomOAuth = (loginService) => {
logEvent(events.LOGIN_WITH_CUSTOM_OAUTH);
const { server } = this.props;
const {
serverURL, authorizePath, clientId, scope, service
@ -175,6 +185,7 @@ class LoginServices extends React.PureComponent {
}
onPressSaml = (loginService) => {
logEvent(events.LOGIN_WITH_SAML);
const { server } = this.props;
const { clientConfig } = loginService;
const { provider } = clientConfig;
@ -184,6 +195,7 @@ class LoginServices extends React.PureComponent {
}
onPressCas = () => {
logEvent(events.LOGIN_WITH_CAS);
const { server, CAS_login_url } = this.props;
const ssoToken = random(17);
const url = `${ CAS_login_url }?service=${ server }/_cas/${ ssoToken }`;

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { View, Text } from 'react-native';
import { View, Text, InteractionManager } from 'react-native';
import _ from 'lodash';
import PropTypes from 'prop-types';
import { sha256 } from 'js-sha256';
@ -99,6 +99,7 @@ const TwoFactor = React.memo(({ theme, isMasterDetail }) => {
<TextInput
value={code}
theme={theme}
inputRef={e => InteractionManager.runAfterInteractions(() => e?.getNativeRef()?.focus())}
returnKeyType='send'
autoCapitalize='none'
onChangeText={setCode}

View File

@ -14,9 +14,10 @@ export default StyleSheet.create({
borderRadius: 4
},
title: {
fontSize: 14,
fontSize: 16,
paddingBottom: 8,
...sharedStyles.textBold
...sharedStyles.textBold,
...sharedStyles.textAlignCenter
},
subtitle: {
fontSize: 14,

View File

@ -17,7 +17,7 @@ import {
import { roomsRequest } from '../actions/rooms';
import { toMomentLocale } from '../utils/moment';
import RocketChat from '../lib/rocketchat';
import log from '../utils/log';
import log, { logEvent, events } from '../utils/log';
import I18n from '../i18n';
import database from '../lib/database';
import EventEmitter from '../utils/events';
@ -32,6 +32,7 @@ const loginCall = args => RocketChat.login(args);
const logoutCall = args => RocketChat.logout(args);
const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnError = false }) {
logEvent(events.DEFAULT_LOGIN);
try {
let result;
if (credentials.resume) {
@ -52,6 +53,7 @@ const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnE
if (logoutOnError && (e.data && e.data.message && /you've been logged out by the server/i.test(e.data.message))) {
yield put(logout(true));
} else {
logEvent(events.DEFAULT_LOGIN_FAIL);
yield put(loginFailure(e));
}
}

24
app/utils/log/events.js Normal file
View File

@ -0,0 +1,24 @@
export default {
JOIN_A_WORKSPACE: 'join_a_workspace',
CREATE_NEW_WORKSPACE: 'create_new_workspace',
CREATE_NEW_WORKSPACE_FAIL: 'create_new_workspace_fail',
CONNECT_TO_WORKSPACE: 'connect_to_workspace',
CONNECT_TO_WORKSPACE_FAIL: 'connect_to_workspace_fail',
JOIN_OPEN_WORKSPACE: 'join_open_workspace',
DEFAULT_LOGIN: 'default_login',
DEFAULT_LOGIN_FAIL: 'default_login_fail',
DEFAULT_SIGN_UP: 'default_sign_up',
DEFAULT_SIGN_UP_FAIL: 'default_sign_up_fail',
FORGOT_PASSWORD: 'forgot_password',
LOGIN_WITH_FACEBOOK: 'login_with_facebook',
LOGIN_WITH_GITHUB: 'login_with_github',
LOGIN_WITH_GITLAB: 'login_with_gitlab',
LOGIN_WITH_LINKEDIN: 'login_with_linkedin',
LOGIN_WITH_GOOGLE: 'login_with_google',
LOGIN_WITH_METEOR: 'login_with_meteor',
LOGIN_WITH_TWITTER: 'login_with_twitter',
LOGIN_WITH_WORDPRESS: 'login_with_wordpress',
LOGIN_WITH_CUSTOM_OAUTH: 'login_with_custom_oauth',
LOGIN_WITH_SAML: 'login_with_saml',
LOGIN_WITH_CAS: 'login_with_cas'
};

View File

@ -1,12 +1,14 @@
import { Client } from 'bugsnag-react-native';
import firebase from 'react-native-firebase';
import config from '../../config';
import config from '../../../config';
import events from './events';
const bugsnag = new Client(config.BUGSNAG_API_KEY);
export const { analytics } = firebase;
export const loggerConfig = bugsnag.config;
export const { leaveBreadcrumb } = bugsnag;
export { events };
let metadata = {};
@ -16,6 +18,11 @@ export const logServerVersion = (serverVersion) => {
};
};
export const logEvent = (eventName, payload) => {
analytics().logEvent(eventName, payload);
leaveBreadcrumb(eventName, payload);
};
export const setCurrentScreen = (currentScreen) => {
analytics().setCurrentScreen(currentScreen);
leaveBreadcrumb(currentScreen, { type: 'navigation' });

View File

@ -31,6 +31,8 @@ class AdminPanelView extends React.Component {
<SafeAreaView theme={theme}>
<StatusBar theme={theme} />
<WebView
// https://github.com/react-native-community/react-native-webview/issues/1311
onMessage={() => {}}
source={{ uri: `${ baseUrl }/admin/info?layout=embedded` }}
injectedJavaScript={`Meteor.loginWithToken('${ token }', function() { })`}
/>

View File

@ -6,7 +6,7 @@ import {
import { connect } from 'react-redux';
import equal from 'deep-equal';
import { analytics } from '../utils/log';
import { logEvent, events } from '../utils/log';
import sharedStyles from './Styles';
import Button from '../containers/Button';
import I18n from '../i18n';
@ -103,6 +103,7 @@ class LoginView extends React.Component {
}
forgotPassword = () => {
logEvent(events.FORGOT_PASSWORD);
const { navigation, Site_Name } = this.props;
navigation.navigate('ForgotPasswordView', { title: Site_Name });
}
@ -121,7 +122,6 @@ class LoginView extends React.Component {
const { loginRequest } = this.props;
Keyboard.dismiss();
loginRequest({ user, password });
analytics().logEvent('login');
}
renderUserForm = () => {

View File

@ -20,7 +20,7 @@ import FormContainer, { FormContainerInner } from '../containers/FormContainer';
import I18n from '../i18n';
import { isIOS } from '../utils/deviceInfo';
import { themes } from '../constants/colors';
import log from '../utils/log';
import log, { logEvent, events } from '../utils/log';
import { animateNextTransition } from '../utils/layoutAnimation';
import { withTheme } from '../theme';
import { setBasicAuth, BASIC_AUTH_KEY } from '../utils/fetch';
@ -124,6 +124,7 @@ class NewServerView extends React.Component {
}
submit = async() => {
logEvent(events.CONNECT_TO_WORKSPACE);
const { text, certificate } = this.state;
const { connectServer } = this.props;
let cert = null;
@ -135,6 +136,7 @@ class NewServerView extends React.Component {
try {
await FileSystem.copyAsync({ from: certificate.path, to: certificatePath });
} catch (e) {
logEvent(events.CONNECT_TO_WORKSPACE_FAIL);
log(e);
}
cert = {
@ -152,6 +154,7 @@ class NewServerView extends React.Component {
}
connectOpen = () => {
logEvent(events.JOIN_OPEN_WORKSPACE);
this.setState({ connectingOpen: true });
const { connectServer } = this.props;
connectServer('https://open.rocket.chat');

View File

@ -14,6 +14,7 @@ import { isTablet } from '../../utils/deviceInfo';
import { themes } from '../../constants/colors';
import { withTheme } from '../../theme';
import FormContainer, { FormContainerInner } from '../../containers/FormContainer';
import { logEvent, events } from '../../utils/log';
class OnboardingView extends React.Component {
static navigationOptions = {
@ -69,15 +70,17 @@ class OnboardingView extends React.Component {
}
connectServer = () => {
logEvent(events.JOIN_A_WORKSPACE);
const { navigation } = this.props;
navigation.navigate('NewServerView');
}
createWorkspace = async() => {
logEvent(events.CREATE_NEW_WORKSPACE);
try {
await Linking.openURL('https://cloud.rocket.chat/trial');
} catch {
// do nothing
logEvent(events.CREATE_NEW_WORKSPACE_FAIL);
}
}

View File

@ -6,7 +6,7 @@ import {
import { connect } from 'react-redux';
import RNPickerSelect from 'react-native-picker-select';
import log from '../utils/log';
import log, { logEvent, events } from '../utils/log';
import sharedStyles from './Styles';
import Button from '../containers/Button';
import I18n from '../i18n';
@ -114,6 +114,7 @@ class RegisterView extends React.Component {
}
submit = async() => {
logEvent(events.DEFAULT_SIGN_UP);
if (!this.valid()) {
return;
}
@ -149,6 +150,7 @@ class RegisterView extends React.Component {
return loginRequest({ user: email, password });
}
if (e.data?.error) {
logEvent(events.DEFAULT_SIGN_UP_FAIL);
showErrorAlert(e.data.error, I18n.t('Oops'));
}
}

View File

@ -29,10 +29,15 @@ const data = {
}
},
channels: {
public: {
detoxpublic: {
name: 'detox-public'
}
},
groups: {
private: {
name: `detox-private-${ value }`
}
},
registeringUser: {
username: `newuser${ value }`,
password: `password${ value }`,

View File

@ -29,10 +29,15 @@ const data = {
}
},
channels: {
public: {
detoxpublic: {
name: 'detox-public'
}
},
groups: {
private: {
name: `detox-private-${ value }`
}
},
registeringUser: {
username: `newuser${ value }`,
password: `password${ value }`,

View File

@ -29,10 +29,15 @@ const data = {
}
},
channels: {
public: {
detoxpublic: {
name: 'detox-public'
}
},
groups: {
private: {
name: `detox-private-${ value }`
}
},
registeringUser: {
username: `newuser${ value }`,
password: `password${ value }`,

View File

@ -31,7 +31,6 @@ async function login(username, password) {
await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(2000);
await element(by.id('login-view-email')).replaceText(username);
await element(by.id('login-view-password')).replaceText(password);
await sleep(300);
await element(by.id('login-view-submit')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
}
@ -61,6 +60,33 @@ async function mockMessage(message) {
await element(by.label(`${ data.random }${ message }`)).atIndex(0).tap();
};
async function starMessage(message){
const messageLabel = `${ data.random }${ message }`
await waitFor(element(by.label(messageLabel))).toBeVisible().withTimeout(5000);
await element(by.label(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')).tap();
await waitFor(element(by.id('action-sheet'))).toNotExist().withTimeout(5000);
};
async function pinMessage(message){
const messageLabel = `${ data.random }${ message }`
await waitFor(element(by.label(messageLabel)).atIndex(0)).toExist();
await element(by.label(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')).tap();
await waitFor(element(by.id('action-sheet'))).toNotExist().withTimeout(5000);
}
async function dismissReviewNag(){
await waitFor(element(by.text('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
}
async function tapBack() {
await element(by.id('header-back')).atIndex(0).tap();
}
@ -74,7 +100,22 @@ async function searchRoom(room) {
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(2000);
}
async function tryTapping(theElement, timeout, longtap = false){
try {
if(longtap){
await theElement.longPress()
} else {
await theElement.tap()
}
} catch(e) {
if(timeout <= 0){ //TODO: Maths. How closely has the timeout been honoured here?
throw e
}
await sleep(100)
await tryTapping(theElement, timeout - 100)
}
}
module.exports = {
@ -84,7 +125,11 @@ module.exports = {
login,
logout,
mockMessage,
starMessage,
pinMessage,
dismissReviewNag,
tapBack,
sleep,
searchRoom
searchRoom,
tryTapping
};

View File

@ -38,7 +38,7 @@ const createUser = async (username, password, name, email) => {
}
const createChannelIfNotExists = async (channelname) => {
console.log(`Creating channel ${channelname}`)
console.log(`Creating public channel ${channelname}`)
try {
await rocketchat.post('channels.create', {
"name": channelname
@ -49,7 +49,24 @@ const createChannelIfNotExists = async (channelname) => {
} catch (infoError) {
console.log(JSON.stringify(createError))
console.log(JSON.stringify(infoError))
throw "Failed to find or create channel"
throw "Failed to find or create public channel"
}
}
}
const createGroupIfNotExists = async (groupname) => {
console.log(`Creating private group ${groupname}`)
try {
await rocketchat.post('groups.create', {
"name": groupname
})
} catch (createError) {
try { //Maybe it exists already?
await rocketchat.get(`group.info?roomName=${groupname}`)
} catch (infoError) {
console.log(JSON.stringify(createError))
console.log(JSON.stringify(infoError))
throw "Failed to find or create private group"
}
}
}
@ -71,6 +88,15 @@ const setup = async () => {
}
}
await login(data.users.regular.username, data.users.regular.password)
for (var groupKey in data.groups) {
if (data.groups.hasOwnProperty(groupKey)) {
const group = data.groups[groupKey]
await createGroupIfNotExists(group.name)
}
}
return
}

View File

@ -9,12 +9,12 @@ const checkServer = async(server) => {
await element(by.id('rooms-list-view-sidebar')).tap();
await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000);
await waitFor(element(by.label(label))).toBeVisible().withTimeout(60000);
await expect(element(by.label(label))).toBeVisible();
await element(by.id('sidebar-close-drawer')).tap();
}
describe('Change server', () => {
before(async() => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
@ -28,8 +28,6 @@ describe('Change server', () => {
await sleep(5000);
await element(by.id('rooms-list-header-server-dropdown-button')).tap();
await waitFor(element(by.id('rooms-list-header-server-dropdown'))).toBeVisible().withTimeout(5000);
await expect(element(by.id('rooms-list-header-server-dropdown'))).toExist();
await sleep(1000);
await element(by.id('rooms-list-header-server-add')).tap();
// TODO: refactor
@ -37,19 +35,16 @@ describe('Change server', () => {
await element(by.id('new-server-view-input')).replaceText(data.alternateServer);
await element(by.id('new-server-view-button')).tap();
await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('workspace-view'))).toBeVisible();
await element(by.id('workspace-view-register')).tap();
await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000);
await expect(element(by.id('register-view'))).toBeVisible();
// Register new user
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')).replaceText(data.registeringUser.password);
await sleep(1000);
await element(by.id('register-view-submit')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('rooms-list-view'))).toBeVisible();
// For a sanity test, to make sure roomslist is showing correct rooms
// app CANNOT show public room created on previous tests
@ -59,11 +54,8 @@ describe('Change server', () => {
});
it('should change back', async() => {
await sleep(5000);
await element(by.id('rooms-list-header-server-dropdown-button')).tap();
await waitFor(element(by.id('rooms-list-header-server-dropdown'))).toBeVisible().withTimeout(5000);
await expect(element(by.id('rooms-list-header-server-dropdown'))).toExist();
await sleep(1000);
await element(by.id(`rooms-list-header-server-${ data.server }`)).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
await checkServer(data.server);

View File

@ -23,28 +23,16 @@ describe('Broadcast room', () => {
await waitFor(element(by.id('select-users-view'))).toBeVisible().withTimeout(2000);
await element(by.id('select-users-view-search')).replaceText(otheruser.username);
await waitFor(element(by.id(`select-users-view-item-${ otheruser.username }`))).toBeVisible().withTimeout(60000);
await expect(element(by.id(`select-users-view-item-${ otheruser.username }`))).toBeVisible();
await element(by.id(`select-users-view-item-${ otheruser.username }`)).tap();
await waitFor(element(by.id(`selected-user-${ otheruser.username }`))).toBeVisible().withTimeout(5000);
await sleep(1000);
await element(by.id('selected-users-view-submit')).tap();
await sleep(1000);
await waitFor(element(by.id('create-channel-view'))).toExist().withTimeout(5000);
await element(by.id('create-channel-name')).replaceText(`broadcast${ data.random }`);
await sleep(2000);
await element(by.id('create-channel-broadcast')).tap();
if (device.getPlatform() === 'ios') { //Because this tap is FLAKY on iOS
await expect(element(by.id('create-channel-broadcast'))).toHaveValue('1')
}
await sleep(500);
await element(by.id('create-channel-broadcast')).longPress(); //https://github.com/facebook/react-native/issues/28032
await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('room-view'))).toBeVisible();
await waitFor(element(by.id(`room-view-title-broadcast${ data.random }`))).toBeVisible().withTimeout(60000);
await expect(element(by.id(`room-view-title-broadcast${ data.random }`))).toBeVisible();
await sleep(1000);
await element(by.id('room-view-header-actions')).tap();
await sleep(1000);
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(5000);
await element(by.id('room-actions-info')).tap();
await waitFor(element(by.id('room-info-view'))).toBeVisible().withTimeout(2000);
@ -64,25 +52,19 @@ describe('Broadcast room', () => {
it('should login as user without write message authorization and enter room', async() => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin();
await element(by.id('login-view-email')).replaceText(otheruser.username);
await element(by.id('login-view-password')).replaceText(otheruser.password);
await sleep(1000);
await element(by.id('login-view-submit')).tap();
await login(otheruser.username, otheruser.password);
//await waitFor(element(by.id('two-factor'))).toBeVisible().withTimeout(5000);
//await expect(element(by.id('two-factor'))).toBeVisible();
//const code = GA.gen(data.alternateUserTOTPSecret);
//await element(by.id('two-factor-input')).replaceText(code);
//await sleep(1000);
//await element(by.id('two-factor-send')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
await searchRoom(`broadcast${ data.random }`);
await waitFor(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toExist().withTimeout(60000);
await expect(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toExist();
await element(by.id(`rooms-list-view-item-broadcast${ data.random }`)).tap();
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
await waitFor(element(by.id(`room-view-title-broadcast${ data.random }`))).toBeVisible().withTimeout(60000);
await expect(element(by.id(`room-view-title-broadcast${ data.random }`))).toBeVisible();
await sleep(1000);
});
it('should not have messagebox', async() => {
@ -95,7 +77,6 @@ describe('Broadcast room', () => {
it('should have the message created earlier', async() => {
await waitFor(element(by.label(`${ data.random }message`)).atIndex(0)).toBeVisible().withTimeout(60000);
await expect(element(by.label(`${ data.random }message`)).atIndex(0)).toBeVisible();
});
it('should have reply button', async() => {
@ -104,9 +85,7 @@ describe('Broadcast room', () => {
it('should tap on reply button and navigate to direct room', async() => {
await element(by.id('message-broadcast-reply')).tap();
await sleep(1000);
await waitFor(element(by.id(`room-view-title-${ testuser.username }`))).toBeVisible().withTimeout(5000);
await expect(element(by.id(`room-view-title-${ testuser.username }`))).toBeVisible();
});
it('should reply broadcasted message', async() => {

View File

@ -13,7 +13,7 @@ async function waitForToast() {
// await expect(element(by.id('toast'))).toBeVisible();
// await waitFor(element(by.id('toast'))).toBeNotVisible().withTimeout(10000);
// await expect(element(by.id('toast'))).toBeNotVisible();
await sleep(5000);
await sleep(1);
}
describe('Profile screen', () => {
@ -24,7 +24,6 @@ describe('Profile screen', () => {
await element(by.id('rooms-list-view-sidebar')).tap();
await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000);
await waitFor(element(by.id('sidebar-profile'))).toBeVisible().withTimeout(2000);
await expect(element(by.id('sidebar-profile'))).toBeVisible();
await element(by.id('sidebar-profile')).tap();
await waitFor(element(by.id('profile-view'))).toBeVisible().withTimeout(2000);
});
@ -60,22 +59,18 @@ describe('Profile screen', () => {
it('should have reset avatar button', async() => {
await waitFor(element(by.id('profile-view-reset-avatar'))).toExist().whileElement(by.id('profile-view-list')).scroll(scrollDown, 'down');
await expect(element(by.id('profile-view-reset-avatar'))).toExist();
});
it('should have upload avatar button', async() => {
await waitFor(element(by.id('profile-view-upload-avatar'))).toExist().whileElement(by.id('profile-view-list')).scroll(scrollDown, 'down');
await expect(element(by.id('profile-view-upload-avatar'))).toExist();
});
it('should have avatar url button', async() => {
await waitFor(element(by.id('profile-view-avatar-url-button'))).toExist().whileElement(by.id('profile-view-list')).scroll(scrollDown, 'down');
await expect(element(by.id('profile-view-avatar-url-button'))).toExist();
});
it('should have submit button', async() => {
await waitFor(element(by.id('profile-view-submit'))).toExist().whileElement(by.id('profile-view-list')).scroll(scrollDown, 'down');
await expect(element(by.id('profile-view-submit'))).toExist();
});
});
@ -84,9 +79,7 @@ describe('Profile screen', () => {
await element(by.type('UIScrollView')).atIndex(1).swipe('down');
await element(by.id('profile-view-name')).replaceText(`${ profileChangeUser.username }new`);
await element(by.id('profile-view-username')).replaceText(`${ profileChangeUser.username }new`);
await sleep(1000);
await element(by.type('UIScrollView')).atIndex(1).swipe('up');
await sleep(1000);
await element(by.id('profile-view-submit')).tap();
await waitForToast();
});
@ -103,7 +96,6 @@ describe('Profile screen', () => {
it('should reset avatar', async() => {
await element(by.type('UIScrollView')).atIndex(1).swipe('up');
await sleep(1000);
await element(by.id('profile-view-reset-avatar')).tap();
await waitForToast();
});

View File

@ -1,12 +1,18 @@
const {
device, expect, element, by, waitFor
} = require('detox');
const { navigateToLogin, login } = require('../../helpers/app');
const data = require('../../data');
const testuser = data.users.regular
describe('Settings screen', () => {
before(async() => {
await device.launchApp({ newInstance: true });
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin();
await login(testuser.username, testuser.password);
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
await expect(element(by.id('rooms-list-view'))).toBeVisible();
await element(by.id('rooms-list-view-sidebar')).tap();
await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000);
await waitFor(element(by.id('sidebar-settings'))).toBeVisible().withTimeout(2000);

View File

@ -2,12 +2,12 @@ const {
device, expect, element, by, waitFor
} = require('detox');
const data = require('../../data');
const { mockMessage, tapBack, sleep, searchRoom } = require('../../helpers/app');
const { navigateToLogin, login, mockMessage, tapBack, sleep, searchRoom } = require('../../helpers/app');
const room = 'detox-public';
const testuser = data.users.regular
const room = data.channels.detoxpublic.name;
async function navigateToRoom() {
await sleep(2000);
await searchRoom(room);
await waitFor(element(by.id(`rooms-list-view-item-${ room }`)).atIndex(0)).toBeVisible().withTimeout(60000);
await element(by.id(`rooms-list-view-item-${ room }`)).atIndex(0).tap();
@ -15,15 +15,15 @@ async function navigateToRoom() {
}
async function navigateToRoomActions() {
await sleep(2000);
await element(by.id('room-view-header-actions')).tap();
await sleep(2000);
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(5000);
}
describe('Join public room', () => {
before(async() => {
await device.launchApp({ newInstance: true });
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin();
await login(testuser.username, testuser.password);
await navigateToRoom();
});
@ -167,9 +167,7 @@ describe('Join public room', () => {
await element(by.text('Yes, leave it!')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
// await element(by.id('rooms-list-view-search')).typeText('');
await sleep(2000);
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible().withTimeout(60000);
await expect(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible();
});
});
});

View File

@ -1,14 +1,21 @@
const {
expect, element, by, waitFor
} = require('detox');
const { sleep } = require('../../helpers/app');
const { navigateToLogin, login, sleep } = require('../../helpers/app');
const data = require('../../data');
const testuser = data.users.regular
async function waitForToast() {
await sleep(5000);
await sleep(1);
}
describe('Status screen', () => {
before(async() => {
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin();
await login(testuser.username, testuser.password);
await element(by.id('rooms-list-view-sidebar')).tap();
await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000);
await waitFor(element(by.id('sidebar-custom-status'))).toBeVisible().withTimeout(2000);
@ -17,30 +24,27 @@ describe('Status screen', () => {
await waitFor(element(by.id('status-view'))).toBeVisible().withTimeout(2000);
});
describe('Render', async() => {
it('should have status input', async() => {
describe('Render', async () => {
it('should have status input', async () => {
await expect(element(by.id('status-view-input'))).toBeVisible();
await expect(element(by.id('status-view-online'))).toExist();
await expect(element(by.id('status-view-busy'))).toExist();
await expect(element(by.id('status-view-away'))).toExist();
await expect(element(by.id('status-view-offline'))).toExist();
});
});
});
});
describe('Usage', async() => {
it('should change status', async() => {
await sleep(1000);
describe('Usage', async () => {
it('should change status', async () => {
await element(by.id('status-view-busy')).tap();
await sleep(1000);
await expect(element(by.id('status-view-current-busy'))).toExist();
});
});
it('should change status text', async() => {
it('should change status text', async () => {
await element(by.id('status-view-input')).replaceText('status-text-new');
await sleep(1000);
await element(by.id('status-view-submit')).tap();
await waitForToast();
await waitFor(element(by.label('status-text-new').withAncestor(by.id('sidebar-custom-status')))).toBeVisible().withTimeout(2000);
});
});
});
});
});

View File

@ -1,11 +1,21 @@
const detox = require('detox');
const config = require('../../package.json').detox;
const dataSetup = require('../helpers/data_setup')
const adapter = require('detox/runners/mocha/adapter');
before(async() => {
await dataSetup()
await detox.init(config, { launchApp: false });
await device.launchApp({ permissions: { notifications: 'YES' } });
await Promise.all([dataSetup(), detox.init(config, { launchApp: false })])
//await dataSetup()
//await detox.init(config, { launchApp: false });
//await device.launchApp({ permissions: { notifications: 'YES' } });
});
beforeEach(async function() {
await adapter.beforeEach(this);
});
afterEach(async function() {
await adapter.afterEach(this);
});
after(async() => {

View File

@ -31,7 +31,6 @@ describe('Onboarding', () => {
it('should navigate to join a workspace', async() => {
await element(by.id('join-workspace')).tap();
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('new-server-view'))).toBeVisible();
});
it('should enter an invalid server and get error', async() => {
@ -39,14 +38,12 @@ describe('Onboarding', () => {
await element(by.id('new-server-view-button')).tap();
const errorText = 'Oops!';
await waitFor(element(by.text(errorText))).toBeVisible().withTimeout(60000);
await expect(element(by.text(errorText))).toBeVisible();
await element(by.text('OK')).tap();
});
it('should tap on "Join our open workspace" and navigate', async() => {
await element(by.id('new-server-view-open')).tap();
await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('workspace-view'))).toBeVisible();
});
it('should enter a valid server without login services and navigate to login', async() => {
@ -57,7 +54,6 @@ describe('Onboarding', () => {
await element(by.id('new-server-view-input')).replaceText(data.server);
await element(by.id('new-server-view-button')).tap();
await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('workspace-view'))).toBeVisible();
});
});
});

View File

@ -4,54 +4,62 @@ const {
const { navigateToRegister, navigateToLogin } = require('../../helpers/app');
describe('Legal screen', () => {
it('should have legal button on login', async() => {
await device.launchApp({ newInstance: true });
await navigateToLogin();
await waitFor(element(by.id('login-view-more'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('login-view-more'))).toBeVisible();
describe('From Login', () => {
before(async() => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin();
});
it('should have legal button on login', async() => {
await waitFor(element(by.id('login-view-more'))).toBeVisible().withTimeout(60000);
});
it('should navigate to legal from login', async() => {
await expect(element(by.id('login-view-more'))).toBeVisible();
await element(by.id('login-view-more')).tap();
await waitFor(element(by.id('legal-view'))).toBeVisible().withTimeout(4000)
});
});
it('should navigate to legal from login', async() => {
await waitFor(element(by.id('login-view-more'))).toBeVisible().withTimeout(60000);
await element(by.id('login-view-more')).tap();
describe('From Register', () => {
before(async() => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToRegister();
});
it('should have legal button on register', async() => {
await waitFor(element(by.id('register-view-more'))).toBeVisible().withTimeout(60000);
});
it('should navigate to legal from register', async() => {
await expect(element(by.id('register-view-more'))).toBeVisible();
await element(by.id('register-view-more')).tap();
await waitFor(element(by.id('legal-view'))).toBeVisible().withTimeout(4000);
});
it('should have terms of service button', async() => {
await expect(element(by.id('legal-terms-button'))).toBeVisible();
});
it('should have privacy policy button', async() => {
await expect(element(by.id('legal-privacy-button'))).toBeVisible();
});
// We can't simulate how webview behaves, so I had to disable :(
/*
it('should navigate to terms', async() => {
await element(by.id('legal-terms-button')).tap();
await waitFor(element(by.id('terms-view'))).toBeVisible().withTimeout(2000);
await expect(element(by.id('terms-view'))).toBeVisible();
});
it('should navigate to privacy', async() => {
await tapBack();
await element(by.id('legal-privacy-button')).tap();
await waitFor(element(by.id('privacy-view'))).toBeVisible().withTimeout(2000);
await expect(element(by.id('privacy-view'))).toBeVisible();
});
*/
});
it('should have legal button on register', async() => {
await device.launchApp({ newInstance: true });
await navigateToRegister();
await waitFor(element(by.id('register-view-more'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('register-view-more'))).toBeVisible();
});
it('should navigate to legal from register', async() => {
await waitFor(element(by.id('register-view-more'))).toBeVisible().withTimeout(60000);
await element(by.id('register-view-more')).tap();
});
it('should have legal screen', async() => {
await expect(element(by.id('legal-view'))).toBeVisible();
});
it('should have terms of service button', async() => {
await expect(element(by.id('legal-terms-button'))).toBeVisible();
});
it('should have privacy policy button', async() => {
await expect(element(by.id('legal-privacy-button'))).toBeVisible();
});
// We can't simulate how webview behaves, so I had to disable :(
// it('should navigate to terms', async() => {
// await element(by.id('legal-terms-button')).tap();
// await waitFor(element(by.id('terms-view'))).toBeVisible().withTimeout(2000);
// await expect(element(by.id('terms-view'))).toBeVisible();
// });
// it('should navigate to privacy', async() => {
// await tapBack();
// await element(by.id('legal-privacy-button')).tap();
// await waitFor(element(by.id('privacy-view'))).toBeVisible().withTimeout(2000);
// await expect(element(by.id('privacy-view'))).toBeVisible();
// });
});

View File

@ -32,7 +32,6 @@ describe('Forgot password screen', () => {
await element(by.id('forgot-password-view-submit')).tap();
await element(by.text('OK')).tap();
await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('login-view'))).toBeVisible();
});
});
});

View File

@ -53,10 +53,8 @@ describe('Create user screen', () => {
await element(by.id('register-view-username')).replaceText(data.registeringUser.username);
await element(by.id('register-view-email')).replaceText(data.users.existing.email);
await element(by.id('register-view-password')).replaceText(data.registeringUser.password);
await sleep(300);
await element(by.id('register-view-submit')).tap();
await waitFor(element(by.text('Email already exists. [403]')).atIndex(0)).toExist().withTimeout(10000);
await expect(element(by.text('Email already exists. [403]')).atIndex(0)).toExist();
await element(by.text('OK')).tap();
});
@ -65,10 +63,8 @@ describe('Create user screen', () => {
await element(by.id('register-view-username')).replaceText(data.users.existing.username);
await element(by.id('register-view-email')).replaceText(data.registeringUser.email);
await element(by.id('register-view-password')).replaceText(data.registeringUser.password);
await sleep(300);
await element(by.id('register-view-submit')).tap();
await waitFor(element(by.text('Username is already in use')).atIndex(0)).toExist().withTimeout(10000);
await expect(element(by.text('Username is already in use')).atIndex(0)).toExist();
await element(by.text('OK')).tap();
});
@ -77,10 +73,8 @@ describe('Create user screen', () => {
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')).replaceText(data.registeringUser.password);
await sleep(300);
await element(by.id('register-view-submit')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('rooms-list-view'))).toBeVisible();
});
});
});

View File

@ -44,33 +44,27 @@ describe('Login screen', () => {
it('should navigate to register', async() => {
await element(by.id('login-view-register')).tap();
await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000);
await expect(element(by.id('register-view'))).toBeVisible();
await tapBack();
});
it('should navigate to forgot password', async() => {
await element(by.id('login-view-forgot-password')).tap();
await waitFor(element(by.id('forgot-password-view'))).toExist().withTimeout(2000);
await expect(element(by.id('forgot-password-view'))).toExist();
await tapBack();
});
it('should insert wrong password and get error', async() => {
await element(by.id('login-view-email')).replaceText(data.users.regular.username);
await element(by.id('login-view-password')).replaceText('NotMyActualPassword');
await sleep(300);
await element(by.id('login-view-submit')).tap();
await waitFor(element(by.text('Your credentials were rejected! Please try again.'))).toBeVisible().withTimeout(10000);
await expect(element(by.text('Your credentials were rejected! Please try again.'))).toBeVisible();
await element(by.text('OK')).tap();
});
it('should login with success', async() => {
await element(by.id('login-view-password')).replaceText(data.users.regular.password);
await sleep(300);
await element(by.id('login-view-submit')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('rooms-list-view'))).toBeVisible();
});
});
});

View File

@ -1,9 +1,17 @@
const {
device, expect, element, by, waitFor
} = require('detox');
const { logout, tapBack, sleep, searchRoom } = require('../../helpers/app');
const { login, navigateToLogin, logout, tapBack, sleep, searchRoom } = require('../../helpers/app');
const data = require('../../data');
describe('Rooms list screen', () => {
before(async() => {
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true, delete: true });
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password)
});
describe('Render', () => {
it('should have rooms list screen', async() => {
await expect(element(by.id('rooms-list-view'))).toBeVisible();
@ -29,18 +37,12 @@ describe('Rooms list screen', () => {
it('should search room and navigate', async() => {
await searchRoom('rocket.cat');
await waitFor(element(by.id('rooms-list-view-item-rocket.cat'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('rooms-list-view-item-rocket.cat'))).toBeVisible();
await element(by.id('rooms-list-view-item-rocket.cat')).tap();
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(10000);
await expect(element(by.id('room-view'))).toBeVisible();
await waitFor(element(by.id('room-view-title-rocket.cat'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('room-view-title-rocket.cat'))).toBeVisible();
await tapBack();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
await expect(element(by.id('rooms-list-view'))).toBeVisible();
await sleep(2000);
await waitFor(element(by.id('rooms-list-view-item-rocket.cat'))).toExist().withTimeout(60000);
await expect(element(by.id('rooms-list-view-item-rocket.cat'))).toExist();
});
it('should logout', async() => {

View File

@ -2,48 +2,50 @@ const {
device, expect, element, by, waitFor
} = require('detox');
const data = require('../../data');
const { tapBack, sleep, navigateToLogin, login } = require('../../helpers/app');
const { tapBack, sleep, navigateToLogin, login, tryTapping } = require('../../helpers/app');
describe('Create room screen', () => {
before(async() => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
await element(by.id('rooms-list-view-create-channel')).tap();
await waitFor(element(by.id('new-message-view'))).toExist().withTimeout(2000);
});
describe('New Message', async() => {
before(async() => {
await element(by.id('rooms-list-view-create-channel')).tap();
});
describe('Render', async() => {
it('should have new message screen', async() => {
await expect(element(by.id('new-message-view'))).toExist();
await waitFor(element(by.id('new-message-view'))).toBeVisible().withTimeout(2000);
});
it('should have search input', async() => {
await waitFor(element(by.id('new-message-view-search'))).toExist().withTimeout(2000);
await expect(element(by.id('new-message-view-search'))).toExist();
await waitFor(element(by.id('new-message-view-search'))).toBeVisible().withTimeout(2000);
});
})
describe('Usage', async() => {
it('should back to rooms list', async() => {
await sleep(1000);
await waitFor(element(by.id('new-message-view-close'))).toBeVisible().withTimeout(2000);
await element(by.id('new-message-view-close')).tap();
await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(2000);
await expect(element(by.id('rooms-list-view'))).toExist();
await element(by.id('rooms-list-view-create-channel')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
await tryTapping(element(by.id('rooms-list-view-create-channel')), 3000);
//await element(by.id('rooms-list-view-create-channel')).tap();
await waitFor(element(by.id('new-message-view'))).toExist().withTimeout(2000);
await expect(element(by.id('new-message-view'))).toExist();
});
it('should search user and navigate', async() => {
await element(by.id('new-message-view-search')).replaceText('rocket.cat');
await waitFor(element(by.id('new-message-view-item-rocket.cat'))).toExist().withTimeout(60000);
await expect(element(by.id('new-message-view-item-rocket.cat'))).toExist();
await element(by.id('new-message-view-item-rocket.cat')).tap();
await waitFor(element(by.id('room-view'))).toExist().withTimeout(10000);
await expect(element(by.id('room-view'))).toExist();
await waitFor(element(by.id('room-view-title-rocket.cat'))).toExist().withTimeout(60000);
await expect(element(by.id('room-view-title-rocket.cat'))).toExist();
await tapBack();
await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(2000);
});
@ -51,11 +53,8 @@ describe('Create room screen', () => {
it('should navigate to select users', async() => {
await element(by.id('rooms-list-view-create-channel')).tap();
await waitFor(element(by.id('new-message-view'))).toExist().withTimeout(2000);
await expect(element(by.id('new-message-view'))).toExist();
await sleep(1000);
await element(by.id('new-message-view-create-channel')).tap();
await waitFor(element(by.id('select-users-view'))).toExist().withTimeout(2000);
await expect(element(by.id('select-users-view'))).toExist();
});
})
});
@ -108,7 +107,6 @@ describe('Create room screen', () => {
const room = `public${ data.random }`;
await element(by.id('create-channel-name')).replaceText(room);
await element(by.id('create-channel-type')).tap();
await sleep(1000);
await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view'))).toExist().withTimeout(60000);
await expect(element(by.id('room-view'))).toExist();
@ -123,20 +121,15 @@ describe('Create room screen', () => {
it('should create private room', async() => {
const room = `private${ data.random }`;
await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(2000);
// await device.launchApp({ newInstance: true });
await sleep(1000);
await element(by.id('rooms-list-view-create-channel')).tap();
await waitFor(element(by.id('new-message-view'))).toExist().withTimeout(2000);
await sleep(1000);
await element(by.id('new-message-view-create-channel')).tap();
await waitFor(element(by.id('select-users-view'))).toExist().withTimeout(2000);
await sleep(1000);
await element(by.id('select-users-view-item-rocket.cat')).tap();
await waitFor(element(by.id('selected-user-rocket.cat'))).toExist().withTimeout(5000);
await element(by.id('selected-users-view-submit')).tap();
await waitFor(element(by.id('create-channel-view'))).toExist().withTimeout(5000);
await element(by.id('create-channel-name')).replaceText(room);
await sleep(1000);
await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view'))).toExist().withTimeout(60000);
await expect(element(by.id('room-view'))).toExist();
@ -152,17 +145,13 @@ describe('Create room screen', () => {
const room = `empty${ data.random }`;
await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(2000);
// await device.launchApp({ newInstance: true });
await sleep(1000);
await element(by.id('rooms-list-view-create-channel')).tap();
await waitFor(element(by.id('new-message-view'))).toExist().withTimeout(2000);
await sleep(1000);
await element(by.id('new-message-view-create-channel')).tap();
await waitFor(element(by.id('select-users-view'))).toExist().withTimeout(2000);
await sleep(1000);
await element(by.id('selected-users-view-submit')).tap();
await waitFor(element(by.id('create-channel-view'))).toExist().withTimeout(5000);
await element(by.id('create-channel-name')).replaceText(room);
await sleep(1000);
await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view'))).toExist().withTimeout(60000);
await expect(element(by.id('room-view'))).toExist();

View File

@ -2,27 +2,29 @@ const {
device, expect, element, by, waitFor
} = require('detox');
const data = require('../../data');
const { mockMessage, tapBack, sleep, searchRoom } = require('../../helpers/app');
const { navigateToLogin, login, mockMessage, tapBack, sleep, searchRoom, starMessage, pinMessage, dismissReviewNag, tryTapping } = require('../../helpers/app');
async function navigateToRoom() {
await searchRoom(`private${ data.random }`);
await waitFor(element(by.id(`rooms-list-view-item-private${ data.random }`))).toExist().withTimeout(60000);
await element(by.id(`rooms-list-view-item-private${ data.random }`)).tap();
async function navigateToRoom(roomName) {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
await searchRoom(`${ roomName }`);
await waitFor(element(by.id(`rooms-list-view-item-${ roomName }`))).toExist().withTimeout(60000);
await element(by.id(`rooms-list-view-item-${ roomName }`)).tap();
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
}
describe('Room screen', () => {
const mainRoom = `private${ data.random }`;
const mainRoom = data.groups.private.name;
before(async() => {
await navigateToRoom();
await navigateToRoom(mainRoom);
});
describe('Render', async() => {
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);
await expect(element(by.id(`room-view-title-${ mainRoom }`))).toExist();
});
// Render - Header
@ -69,22 +71,15 @@ describe('Room screen', () => {
await expect(element(by.label(`${ data.random }message`)).atIndex(0)).toExist();
});
it('should ask for review', async() => {
await waitFor(element(by.text('Are you enjoying this app?'))).toExist().withTimeout(60000);
await expect(element(by.text('Are you enjoying this app?')).atIndex(0)).toExist();
await element(by.label('No').and(by.type('_UIAlertControllerActionView'))).tap(); // Tap `no` on ask for review alert
})
it('should show/hide emoji keyboard', async () => {
if (device.getPlatform() === 'android') {
await element(by.id('messagebox-open-emoji')).tap();
await waitFor(element(by.id('messagebox-keyboard-emoji'))).toExist().withTimeout(10000);
await expect(element(by.id('messagebox-keyboard-emoji'))).toExist();
await expect(element(by.id('messagebox-close-emoji'))).toExist();
await expect(element(by.id('messagebox-open-emoji'))).toBeNotVisible();
await element(by.id('messagebox-close-emoji')).tap();
await waitFor(element(by.id('messagebox-keyboard-emoji'))).toBeNotVisible().withTimeout(10000);
await expect(element(by.id('messagebox-keyboard-emoji'))).toBeNotVisible();
await expect(element(by.id('messagebox-close-emoji'))).toBeNotVisible();
await expect(element(by.id('messagebox-open-emoji'))).toExist();
}
@ -94,10 +89,8 @@ describe('Room screen', () => {
await element(by.id('messagebox-input')).tap();
await element(by.id('messagebox-input')).typeText(':joy');
await waitFor(element(by.id('messagebox-container'))).toExist().withTimeout(10000);
await expect(element(by.id('messagebox-container'))).toExist();
await element(by.id('messagebox-input')).clearText();
await waitFor(element(by.id('messagebox-container'))).toBeNotVisible().withTimeout(10000);
await expect(element(by.id('messagebox-container'))).toBeNotVisible();
});
it('should show and tap on emoji autocomplete', async() => {
@ -105,8 +98,6 @@ describe('Room screen', () => {
await element(by.id('messagebox-input')).replaceText(':');
await element(by.id('messagebox-input')).typeText('joy'); // workaround for number keyboard
await waitFor(element(by.id('messagebox-container'))).toExist().withTimeout(10000);
await expect(element(by.id('messagebox-container'))).toExist();
await sleep(1000);
await element(by.id('mention-item-joy')).tap();
await expect(element(by.id('messagebox-input'))).toHaveText(':joy: ');
await element(by.id('messagebox-input')).clearText();
@ -116,25 +107,22 @@ describe('Room screen', () => {
const username = data.users.regular.username
await element(by.id('messagebox-input')).tap();
await element(by.id('messagebox-input')).typeText(`@${ username }`);
await waitFor(element(by.id('messagebox-container'))).toExist().withTimeout(60000);
await expect(element(by.id('messagebox-container'))).toExist();
await sleep(1000);
await element(by.id(`mention-item-${ username }`)).tap();
await waitFor(element(by.id('messagebox-container'))).toExist().withTimeout(4000);
await waitFor(element(by.id(`mention-item-${ username }`))).toBeVisible().withTimeout(4000)
await tryTapping(element(by.id(`mention-item-${ username }`)), 2000, true);
await expect(element(by.id('messagebox-input'))).toHaveText(`@${ username } `);
await element(by.id('messagebox-input')).tap();
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);
await sleep(2000);
});
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(60000);
await expect(element(by.id('messagebox-container'))).toExist();
await sleep(1000);
await element(by.id('mention-item-general')).tap();
//await waitFor(element(by.id('messagebox-container'))).toExist().withTimeout(4000);
await waitFor(element(by.id('mention-item-general'))).toBeVisible().withTimeout(4000);
await tryTapping(element(by.id('mention-item-general')), 2000, true)
await expect(element(by.id('messagebox-input'))).toHaveText('#general ');
await element(by.id('messagebox-input')).clearText();
});
@ -147,7 +135,6 @@ describe('Room screen', () => {
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')).tap();
await sleep(1000);
// TODO: test clipboard
});
@ -158,28 +145,20 @@ describe('Room screen', () => {
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')).tap();
await sleep(1000);
// TODO: test clipboard
});
it('should star message', async() => {
await element(by.label(`${ data.random }message`)).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')).tap();
await sleep(1000);
await waitFor(element(by.id('action-sheet'))).toNotExist().withTimeout(5000);
await starMessage('message')
await sleep(1000) //https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/2324
await element(by.label(`${ data.random }message`)).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 waitFor(element(by.label('Unstar'))).toBeVisible().withTimeout(2000);
await expect(element(by.label('Unstar'))).toBeVisible();
await element(by.id('action-sheet-backdrop')).tap();
await sleep(1000);
});
it('should react to message', async() => {
@ -189,14 +168,10 @@ describe('Room screen', () => {
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await element(by.id('add-reaction')).tap();
await waitFor(element(by.id('reaction-picker'))).toBeVisible().withTimeout(2000);
await expect(element(by.id('reaction-picker'))).toBeVisible();
await element(by.id('reaction-picker-😃')).tap();
await waitFor(element(by.id('reaction-picker-grinning'))).toExist().withTimeout(2000);
await expect(element(by.id('reaction-picker-grinning'))).toExist();
await element(by.id('reaction-picker-grinning')).tap();
await waitFor(element(by.id('message-reaction-:grinning:'))).toExist().withTimeout(60000);
await expect(element(by.id('message-reaction-:grinning:'))).toExist();
await sleep(1000);
});
it('should react to message with frequently used emoji', async() => {
@ -205,30 +180,27 @@ describe('Room screen', () => {
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'))).toBeVisible().withTimeout(2000);
await expect(element(by.id('message-actions-emoji-+1'))).toBeVisible();
await element(by.id('message-actions-emoji-+1')).tap();
await waitFor(element(by.id('message-reaction-:+1:'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('message-reaction-:+1:'))).toBeVisible();
await sleep(1000);
});
it('should show reaction picker on add reaction button pressed and have frequently used emoji', async() => {
await element(by.id('message-add-reaction')).tap();
await waitFor(element(by.id('reaction-picker'))).toExist().withTimeout(2000);
await expect(element(by.id('reaction-picker'))).toExist();
await waitFor(element(by.id('reaction-picker-grinning'))).toExist().withTimeout(2000);
await expect(element(by.id('reaction-picker-grinning'))).toExist();
await element(by.id('reaction-picker-😃')).tap();
await waitFor(element(by.id('reaction-picker-grimacing'))).toExist().withTimeout(2000);
await element(by.id('reaction-picker-grimacing')).tap();
await waitFor(element(by.id('message-reaction-:grimacing:'))).toExist().withTimeout(60000);
await sleep(1000);
});
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:'))).toBeNotVisible().withTimeout(60000);
await expect(element(by.id('message-reaction-:grinning:'))).toBeNotVisible();
});
it('should edit message', async() => {
@ -241,7 +213,6 @@ describe('Room screen', () => {
await element(by.id('messagebox-input')).typeText('ed');
await element(by.id('messagebox-send-message')).tap();
await waitFor(element(by.label(`${ data.random }edited (edited)`)).atIndex(0)).toExist().withTimeout(60000);
await expect(element(by.label(`${ data.random }edited (edited)`)).atIndex(0)).toExist();
});
it('should quote message', async() => {
@ -253,46 +224,39 @@ describe('Room screen', () => {
await element(by.label('Quote')).tap();
await element(by.id('messagebox-input')).typeText(`${ data.random }quoted`);
await element(by.id('messagebox-send-message')).tap();
await sleep(1000);
// TODO: test if quote was sent
});
it('should pin message', async() => {
await waitFor(element(by.label(`${ data.random }edited (edited)`)).atIndex(0)).toExist();
await element(by.label(`${ data.random }edited (edited)`)).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')).tap();
await waitFor(element(by.id('action-sheet'))).toNotExist().withTimeout(5000);
await sleep(1500);
await mockMessage('pin')
await pinMessage('pin')
await waitFor(element(by.label(`${ data.random }edited (edited)`)).atIndex(0)).toBeVisible();
await element(by.label(`${ data.random }edited (edited)`)).atIndex(0).longPress();
await expect(element(by.id('action-sheet'))).toExist();
await waitFor(element(by.label(`${ data.random }pin`)).atIndex(0)).toBeVisible().withTimeout(2000);
await waitFor(element(by.label('Message pinned')).atIndex(0)).toBeVisible().withTimeout(2000);
await element(by.label(`${ data.random }pin`)).atIndex(0).longPress();
await waitFor(element(by.id('action-sheet'))).toExist().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'))).toBeVisible().withTimeout(2000);
await expect(element(by.label('Unpin'))).toBeVisible();
await element(by.id('action-sheet-backdrop')).tap();
});
it('should delete message', async() => {
await waitFor(element(by.label(`${ data.random }quoted`)).atIndex(0)).toBeVisible();
await element(by.label(`${ data.random }quoted`)).atIndex(0).longPress();
await mockMessage('delete')
await waitFor(element(by.label(`${ data.random }delete`)).atIndex(0)).toBeVisible();
await element(by.label(`${ data.random }delete`)).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('Delete')).tap();
const deleteAlertMessage = 'You will not be able to recover this message!';
await waitFor(element(by.text(deleteAlertMessage)).atIndex(0)).toExist().withTimeout(10000);
await expect(element(by.text(deleteAlertMessage)).atIndex(0)).toExist();
await waitFor(element(by.text(deleteAlertMessage)).atIndex(0)).toExist().withTimeout(10000);
await element(by.text('Delete')).tap();
await sleep(1000);
await expect(element(by.label(`${ data.random }quoted`)).atIndex(0)).toNotExist();
await waitFor(element(by.label(`${ data.random }delete`)).atIndex(0)).toNotExist().withTimeout(2000);
});
});
@ -317,7 +281,6 @@ describe('Room screen', () => {
await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000);
await expect(element(by.id(`room-view-title-${ thread }`))).toExist();
await tapBack();
await sleep(1000);
});
it('should toggle follow thread', async() => {
@ -332,10 +295,13 @@ describe('Room screen', () => {
await waitFor(element(by.id('room-view-header-unfollow'))).toExist().withTimeout(60000);
await expect(element(by.id('room-view-header-unfollow'))).toExist();
await tapBack();
await sleep(1000);
});
it('should navigate to thread from thread name', async() => {
await waitFor(element(by.id('room-view-header-actions').and(by.label(`${ mainRoom }`)))).toBeVisible().withTimeout(2000);
await waitFor(element(by.id('room-view-header-actions').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 mockMessage('dummymessagebetweenthethread');
await element(by.label(thread)).atIndex(0).longPress();
await expect(element(by.id('action-sheet'))).toExist();
@ -352,10 +318,10 @@ describe('Room screen', () => {
await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000);
await expect(element(by.id(`room-view-title-${ thread }`))).toExist();
await tapBack();
await sleep(1000);
});
it('should navigate to thread from threads view', async() => {
await waitFor(element(by.id('room-view-header-threads'))).toExist().withTimeout(1000);
await element(by.id('room-view-header-threads')).tap();
await waitFor(element(by.id('thread-messages-view'))).toExist().withTimeout(5000);
await expect(element(by.id('thread-messages-view'))).toExist();

View File

@ -2,7 +2,7 @@ const {
device, expect, element, by, waitFor
} = require('detox');
const data = require('../../data');
const { tapBack, sleep, searchRoom } = require('../../helpers/app');
const { navigateToLogin, login, tapBack, sleep, searchRoom, mockMessage, starMessage, pinMessage } = require('../../helpers/app');
const scrollDown = 200;
@ -11,13 +11,12 @@ async function navigateToRoomActions(type) {
if (type === 'd') {
room = 'rocket.cat';
} else {
room = `private${ data.random }`;
room = data.groups.private.name;
}
await searchRoom(room);
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(60000);
await element(by.id(`rooms-list-view-item-${ room }`)).tap();
await waitFor(element(by.id('room-view'))).toExist().withTimeout(2000);
await sleep(1000);
await element(by.id('room-view-header-actions')).tap();
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
}
@ -25,7 +24,6 @@ async function navigateToRoomActions(type) {
async function backToActions() {
await tapBack();
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(2000);
await expect(element(by.id('room-actions-view'))).toExist();
}
async function backToRoomsList() {
@ -36,10 +34,16 @@ async function backToRoomsList() {
}
describe('Room actions screen', () => {
before(async() => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
});
describe('Render', async() => {
describe('Direct', async() => {
before(async() => {
await device.launchApp({ newInstance: true });
await navigateToRoomActions('d');
});
@ -197,65 +201,89 @@ describe('Room actions screen', () => {
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 expect(element(by.id('mentioned-messages-view'))).toExist();
// await waitFor(element(by.text(` ${ data.random }mention`))).toExist().withTimeout(60000);
// await expect(element(by.text(` ${ data.random }mention`))).toExist();
await backToActions();
});
it('should show starred message and unstar it', async() => {
//Go back to room and send a message
await tapBack();
await mockMessage('messageToStar');
//Star the message
await starMessage('messageToStar')
//Back into Room Actions
await element(by.id('room-view-header-actions')).tap();
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
//Go to starred messages
await element(by.id('room-actions-starred')).tap();
await waitFor(element(by.id('starred-messages-view'))).toExist().withTimeout(2000);
await sleep(1000);
await waitFor(element(by.label(`${ data.random }message`).withAncestor(by.id('starred-messages-view')))).toBeVisible().withTimeout(60000);
await expect(element(by.label(`${ data.random }message`).withAncestor(by.id('starred-messages-view')))).toBeVisible();
await element(by.label(`${ data.random }message`).withAncestor(by.id('starred-messages-view'))).longPress();
await waitFor(element(by.label(`${ data.random }messageToStar`).withAncestor(by.id('starred-messages-view')))).toBeVisible().withTimeout(60000);
//Unstar message
await element(by.label(`${ data.random }messageToStar`).withAncestor(by.id('starred-messages-view'))).longPress();
await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.label('Unstar')).tap();
await waitFor(element(by.label(`${ data.random }message`).withAncestor(by.id('starred-messages-view')))).toBeNotVisible().withTimeout(60000);
await expect(element(by.label(`${ data.random }message`).withAncestor(by.id('starred-messages-view')))).toBeNotVisible();
await waitFor(element(by.label(`${ data.random }messageToStar`).withAncestor(by.id('starred-messages-view')))).toBeNotVisible().withTimeout(60000);
await backToActions();
});
it('should show pinned message and unpin it', async() => {
//Go back to room and send a message
await tapBack();
await mockMessage('messageToPin');
//Pin the message
await pinMessage('messageToPin')
//Back into Room Actions
await element(by.id('room-view-header-actions')).tap();
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
await waitFor(element(by.id('room-actions-pinned'))).toExist();
await element(by.id('room-actions-pinned')).tap();
await waitFor(element(by.id('pinned-messages-view'))).toExist().withTimeout(2000);
await sleep(1000);
await waitFor(element(by.label(`${ data.random }edited (edited)`).withAncestor(by.id('pinned-messages-view')))).toBeVisible().withTimeout(60000);
await expect(element(by.label(`${ data.random }edited (edited)`).withAncestor(by.id('pinned-messages-view')))).toBeVisible();
await element(by.label(`${ data.random }edited (edited)`).withAncestor(by.id('pinned-messages-view'))).longPress();
await waitFor(element(by.label(`${ data.random }messageToPin`).withAncestor(by.id('pinned-messages-view')))).toBeVisible().withTimeout(60000);
await element(by.label(`${ data.random }messageToPin`).withAncestor(by.id('pinned-messages-view'))).longPress();
await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.label('Unpin')).tap();
await waitFor(element(by.label(`${ data.random }edited (edited)`).withAncestor(by.id('pinned-messages-view')))).toBeNotVisible().withTimeout(60000);
await expect(element(by.label(`${ data.random }edited (edited)`).withAncestor(by.id('pinned-messages-view')))).toBeNotVisible();
await waitFor(element(by.label(`${ data.random }messageToPin`).withAncestor(by.id('pinned-messages-view')))).toBeNotVisible().withTimeout(60000);
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-view-header-actions')).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 }message/`);
await waitFor(element(by.label(`${ data.random }message`).withAncestor(by.id('search-messages-view')))).toExist().withTimeout(60000);
await expect(element(by.label(`${ data.random }message`).withAncestor(by.id('search-messages-view')))).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', async() => {
it('should navigate to notification preference view', async() => {
await waitFor(element(by.id('room-actions-notifications'))).toExist();
await expect(element(by.id('room-actions-notifications'))).toExist();
await waitFor(element(by.id('room-actions-notifications'))).toExist().withTimeout(2000);
await element(by.id('room-actions-notifications')).tap();
await waitFor(element(by.id('notification-preference-view'))).toExist().withTimeout(2000);
await expect(element(by.id('notification-preference-view'))).toExist();
});
it('should have receive notification option', async() => {
@ -271,30 +299,25 @@ describe('Room actions screen', () => {
});
it('should have push notification option', async() => {
await waitFor(element(by.id('notification-preference-view-push-notification'))).toExist();
await expect(element(by.id('notification-preference-view-push-notification'))).toExist();
await waitFor(element(by.id('notification-preference-view-push-notification'))).toExist().withTimeout(4000);
});
it('should have notification audio option', async() => {
await waitFor(element(by.id('notification-preference-view-audio'))).toExist();
await expect(element(by.id('notification-preference-view-audio'))).toExist();
await waitFor(element(by.id('notification-preference-view-audio'))).toExist().withTimeout(4000);
});
it('should have notification sound option', async() => {
// Ugly hack to scroll on detox
await element(by.type('UIScrollView')).atIndex(1).scrollTo('bottom');
await waitFor(element(by.id('notification-preference-view-sound'))).toExist();
await expect(element(by.id('notification-preference-view-sound'))).toExist();
await waitFor(element(by.id('notification-preference-view-sound'))).toExist().withTimeout(4000);
});
it('should have notification duration option', async() => {
await waitFor(element(by.id('notification-preference-view-notification-duration'))).toExist();
await expect(element(by.id('notification-preference-view-notification-duration'))).toExist();
await waitFor(element(by.id('notification-preference-view-notification-duration'))).toExist().withTimeout(4000);
});
it('should have email alert option', async() => {
await waitFor(element(by.id('notification-preference-view-email-alert'))).toExist();
await expect(element(by.id('notification-preference-view-email-alert'))).toExist();
await waitFor(element(by.id('notification-preference-view-email-alert'))).toExist().withTimeout(4000);
});
after(async() => {
@ -309,34 +332,28 @@ describe('Room actions screen', () => {
const user = data.users.alternate
it('should tap on leave channel and raise alert', async() => {
await waitFor(element(by.id('room-actions-leave-channel'))).toExist();
await expect(element(by.id('room-actions-leave-channel'))).toExist();
await waitFor(element(by.id('room-actions-leave-channel'))).toExist().withTimeout(2000);
await element(by.id('room-actions-leave-channel')).tap();
await waitFor(element(by.text('Yes, leave it!'))).toExist().withTimeout(2000);
await expect(element(by.text('Yes, leave it!'))).toExist();
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.'))).toExist().withTimeout(60000);
await expect(element(by.text('You are the last owner. Please set new owner before leaving the room.'))).toExist();
await waitFor(element(by.text('You are the last owner. Please set new owner before leaving the room.'))).toExist().withTimeout(8000);
await element(by.text('OK')).tap();
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(2000);
});
it('should add user to the room', async() => {
await waitFor(element(by.id('room-actions-add-user'))).toExist();
await waitFor(element(by.id('room-actions-add-user'))).toExist().withTimeout(4000);
await element(by.id('room-actions-add-user')).tap();
await element(by.id('select-users-view-search')).tap();
await element(by.id('select-users-view-search')).replaceText(user.username);
await waitFor(element(by.id(`select-users-view-item-${ user.username }`))).toExist().withTimeout(60000);
await expect(element(by.id(`select-users-view-item-${ user.username }`))).toExist();
await waitFor(element(by.id(`select-users-view-item-${ user.username }`))).toExist().withTimeout(10000);
await element(by.id(`select-users-view-item-${ user.username }`)).tap();
await waitFor(element(by.id(`selected-user-${ user.username }`))).toExist().withTimeout(5000);
await expect(element(by.id(`selected-user-${ user.username }`))).toExist();
await element(by.id('selected-users-view-submit')).tap();
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(2000);
await element(by.id('room-actions-members')).tap();
await element(by.id('room-members-view-toggle-status')).tap();
await waitFor(element(by.id(`room-members-view-item-${ user.username }`))).toExist().withTimeout(60000);
await expect(element(by.id(`room-members-view-item-${ user.username }`))).toExist();
await backToActions(1);
});
@ -344,26 +361,20 @@ describe('Room actions screen', () => {
before(async() => {
await element(by.id('room-actions-members')).tap();
await waitFor(element(by.id('room-members-view'))).toExist().withTimeout(2000);
await expect(element(by.id('room-members-view'))).toExist();
});
it('should show all users', async() => {
await sleep(1000);
await element(by.id('room-members-view-toggle-status')).tap();
await waitFor(element(by.id(`room-members-view-item-${ user.username }`))).toExist().withTimeout(60000);
await expect(element(by.id(`room-members-view-item-${ user.username }`))).toExist();
});
it('should filter user', async() => {
await waitFor(element(by.id(`room-members-view-item-${ user.username }`))).toExist().withTimeout(60000);
await expect(element(by.id(`room-members-view-item-${ user.username }`))).toExist();
await element(by.id('room-members-view-search')).replaceText('rocket');
await waitFor(element(by.id(`room-members-view-item-${ user.username }`))).toBeNotVisible().withTimeout(60000);
await expect(element(by.id(`room-members-view-item-${ user.username }`))).toBeNotVisible();
await element(by.id('room-members-view-search')).tap();
await element(by.id('room-members-view-search')).clearText('');
await waitFor(element(by.id(`room-members-view-item-${ user.username }`))).toExist().withTimeout(60000);
await expect(element(by.id(`room-members-view-item-${ user.username }`))).toExist();
});
// FIXME: mute/unmute isn't working
@ -391,9 +402,7 @@ describe('Room actions screen', () => {
await waitFor(element(by.id(`room-members-view-item-${ user.username }`))).toExist().withTimeout(5000);
await element(by.id(`room-members-view-item-${ user.username }`)).tap();
await waitFor(element(by.id('room-view'))).toExist().withTimeout(60000);
await expect(element(by.id('room-view'))).toExist();
await waitFor(element(by.id(`room-view-title-${ user.username }`))).toExist().withTimeout(60000);
await expect(element(by.id(`room-view-title-${ user.username }`))).toExist();
await tapBack();
await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(2000);
});
@ -407,13 +416,10 @@ describe('Room actions screen', () => {
it('should block/unblock user', async() => {
await waitFor(element(by.id('room-actions-block-user'))).toExist();
await sleep(1000);
await element(by.id('room-actions-block-user')).tap();
await waitFor(element(by.label('Unblock user'))).toExist().withTimeout(60000);
await expect(element(by.label('Unblock user'))).toExist();
await element(by.id('room-actions-block-user')).tap();
await waitFor(element(by.label('Block user'))).toExist().withTimeout(60000);
await expect(element(by.label('Block user'))).toExist();
});
});
});

View File

@ -2,23 +2,23 @@ const {
device, expect, element, by, waitFor
} = require('detox');
const data = require('../../data');
const { tapBack, sleep, searchRoom } = require('../../helpers/app');
const { navigateToLogin, login, tapBack, sleep, searchRoom } = require('../../helpers/app');
const privateRoomName = data.groups.private.name
async function navigateToRoomInfo(type) {
let room;
if (type === 'd') {
room = 'rocket.cat';
} else {
room = `private${ data.random }`;
room = privateRoomName;
}
await searchRoom(room);
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(60000);
await element(by.id(`rooms-list-view-item-${ room }`)).tap();
await waitFor(element(by.id('room-view'))).toExist().withTimeout(2000);
await sleep(1000);
await element(by.id('room-view-header-actions')).tap();
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
await sleep(1000);
await element(by.id('room-actions-info')).tap();
await waitFor(element(by.id('room-info-view'))).toExist().withTimeout(2000);
}
@ -28,13 +28,19 @@ async function waitForToast() {
// 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(5000);
await sleep(1);
}
describe('Room info screen', () => {
before(async() => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
});
describe('Direct', async() => {
before(async() => {
await device.launchApp({ newInstance: true });
await navigateToRoomInfo('d');
});
@ -42,11 +48,16 @@ describe('Room info screen', () => {
await expect(element(by.id('room-info-view'))).toExist();
await expect(element(by.id('room-info-view-name'))).toExist();
});
after(async() => {
await tapBack()
await tapBack()
await tapBack()
})
});
describe('Channel/Group', async() => {
before(async() => {
await device.launchApp({ newInstance: true });
await navigateToRoomInfo('c');
});
@ -78,7 +89,6 @@ describe('Room info screen', () => {
describe('Render Edit', async() => {
before(async() => {
await sleep(1000);
await waitFor(element(by.id('room-info-view-edit-button'))).toExist().withTimeout(10000);
await element(by.id('room-info-view-edit-button')).tap();
await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000);
@ -141,7 +151,6 @@ describe('Room info screen', () => {
});
describe('Usage', async() => {
const room = `private${ data.random }`;
// 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');
@ -155,22 +164,17 @@ describe('Room info screen', () => {
// });
it('should change room name', async() => {
await element(by.id('room-info-edit-view-name')).replaceText(`${ room }new`);
await element(by.id('room-info-edit-view-name')).replaceText(`${ privateRoomName }new`);
await element(by.type('UIScrollView')).atIndex(1).swipe('up');
await element(by.id('room-info-edit-view-submit')).tap();
await sleep(5000);
await tapBack();
await waitFor(element(by.id('room-info-view'))).toExist().withTimeout(2000);
await sleep(1000);
await expect(element(by.id('room-info-view-name'))).toHaveLabel(`${ room }new`);
await expect(element(by.id('room-info-view-name'))).toHaveLabel(`${ privateRoomName }new`);
// change name to original
await element(by.id('room-info-view-edit-button')).tap();
await sleep(1000);
await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000);
await sleep(1000);
await element(by.id('room-info-edit-view-name')).replaceText(`${ room }`);
await element(by.id('room-info-edit-view-name')).replaceText(`${ privateRoomName }`);
await element(by.type('UIScrollView')).atIndex(1).swipe('up');
await sleep(1000);
await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast();
await element(by.type('UIScrollView')).atIndex(1).swipe('down');
@ -184,14 +188,11 @@ describe('Room info screen', () => {
await element(by.id('room-info-edit-view-password')).replaceText('abc');
await element(by.type('UIScrollView')).atIndex(1).swipe('up');
await element(by.id('room-info-edit-view-t')).tap();
await sleep(1000);
await element(by.id('room-info-edit-view-ro')).tap();
await sleep(1000);
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 sleep(1000);
await element(by.id('room-info-edit-view-reset')).tap();
// after reset
await expect(element(by.id('room-info-edit-view-name'))).toHaveText(room);
await expect(element(by.id('room-info-edit-view-name'))).toHaveText(privateRoomName);
await expect(element(by.id('room-info-edit-view-description'))).toHaveText('');
await expect(element(by.id('room-info-edit-view-topic'))).toHaveText('');
await expect(element(by.id('room-info-edit-view-announcement'))).toHaveText('');
@ -203,55 +204,45 @@ describe('Room info screen', () => {
});
it('should change room description', async() => {
await sleep(1000);
await element(by.id('room-info-edit-view-description')).replaceText('new description');
await element(by.type('UIScrollView')).atIndex(1).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 sleep(1000);
await expect(element(by.label('new description').withAncestor(by.id('room-info-view-description')))).toExist();
});
it('should change room topic', async() => {
await sleep(1000);
await waitFor(element(by.id('room-info-view-edit-button'))).toExist().withTimeout(10000);
await element(by.id('room-info-view-edit-button')).tap();
await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000);
await sleep(1000);
await element(by.id('room-info-edit-view-topic')).replaceText('new topic');
await element(by.type('UIScrollView')).atIndex(1).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 sleep(1000);
await expect(element(by.label('new topic').withAncestor(by.id('room-info-view-topic')))).toExist();
});
it('should change room announcement', async() => {
await sleep(1000);
await waitFor(element(by.id('room-info-view-edit-button'))).toExist().withTimeout(10000);
await element(by.id('room-info-view-edit-button')).tap();
await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000);
await sleep(1000);
await element(by.id('room-info-edit-view-announcement')).replaceText('new announcement');
await element(by.type('UIScrollView')).atIndex(1).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 sleep(1000);
await expect(element(by.label('new announcement').withAncestor(by.id('room-info-view-announcement')))).toExist();
});
it('should change room password', async() => {
await sleep(1000);
await waitFor(element(by.id('room-info-view-edit-button'))).toExist().withTimeout(10000);
await element(by.id('room-info-view-edit-button')).tap();
await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000);
await sleep(1000);
await element(by.type('UIScrollView')).atIndex(1).swipe('up');
await element(by.id('room-info-edit-view-password')).replaceText('password');
await element(by.id('room-info-edit-view-submit')).tap();
@ -259,7 +250,6 @@ describe('Room info screen', () => {
});
it('should change room type', async() => {
await sleep(1000);
await element(by.type('UIScrollView')).atIndex(1).swipe('up');
await element(by.id('room-info-edit-view-t')).tap();
await element(by.id('room-info-edit-view-submit')).tap();
@ -282,14 +272,11 @@ describe('Room info screen', () => {
// });
it('should archive room', async() => {
await sleep(1000);
await element(by.type('UIScrollView')).atIndex(1).swipe('up');
await element(by.id('room-info-edit-view-archive')).tap();
await waitFor(element(by.text('Yes, archive it!'))).toExist().withTimeout(5000);
await expect(element(by.text('Yes, archive it!'))).toExist();
await element(by.text('Yes, archive it!')).tap();
await waitFor(element(by.id('room-info-edit-view-unarchive'))).toExist().withTimeout(60000);
await expect(element(by.id('room-info-edit-view-unarchive'))).toExist();
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();
@ -301,16 +288,12 @@ describe('Room info screen', () => {
});
it('should delete room', async() => {
await sleep(1000);
await element(by.type('UIScrollView')).atIndex(1).swipe('up');
await element(by.id('room-info-edit-view-delete')).tap();
await waitFor(element(by.text('Yes, delete it!'))).toExist().withTimeout(5000);
await expect(element(by.text('Yes, delete it!'))).toExist();
await element(by.text('Yes, delete it!')).tap();
await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(10000);
await sleep(2000);
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible().withTimeout(60000);
await expect(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible();
await waitFor(element(by.id(`rooms-list-view-item-${ privateRoomName }`))).toBeNotVisible().withTimeout(60000);
});
});
});

View File

@ -136,7 +136,7 @@
"babel-plugin-transform-remove-console": "^6.9.4",
"babel-runtime": "^6.26.0",
"bugsnag-sourcemaps": "1.3.0",
"codecov": "3.6.5",
"codecov": "3.7.1",
"detox": "^16.9.0",
"emotion-theming": "10.0.27",
"eslint": "6.8.0",
@ -196,6 +196,20 @@
"type": "ios.simulator",
"device": {
"type": "iPhone 11 Pro"
},
"artifacts": {
"plugins": {
"screenshot": {
"enabled": true,
"shouldTakeAutomaticSnapshots": true,
"keepOnlyFailedTestsArtifacts": true,
"takeWhen": {
"testStart": true,
"testDone": true,
"appNotReady": true
}
}
}
}
}
}

View File

@ -5004,10 +5004,10 @@ code-point-at@^1.0.0:
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
codecov@3.6.5:
version "3.6.5"
resolved "https://registry.yarnpkg.com/codecov/-/codecov-3.6.5.tgz#d73ce62e8a021f5249f54b073e6f2d6a513f172a"
integrity sha512-v48WuDMUug6JXwmmfsMzhCHRnhUf8O3duqXvltaYJKrO1OekZWpB/eH6iIoaxMl8Qli0+u3OxptdsBOYiD7VAQ==
codecov@3.7.1:
version "3.7.1"
resolved "https://registry.yarnpkg.com/codecov/-/codecov-3.7.1.tgz#434cb8d55f18ef01672e5739d3d266696bebc202"
integrity sha512-JHWxyPTkMLLJn9SmKJnwAnvY09kg2Os2+Ux+GG7LwZ9g8gzDDISpIN5wAsH1UBaafA/yGcd3KofMaorE8qd6Lw==
dependencies:
argv "0.0.2"
ignore-walk "3.0.3"
@ -5121,8 +5121,8 @@ commondir@^1.0.1:
integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
"commonmark-react-renderer@git+https://github.com/RocketChat/commonmark-react-renderer.git":
version "4.3.5"
resolved "git+https://github.com/RocketChat/commonmark-react-renderer.git#996553c27ab6457775ba1f4b6a5a6a20ce7ddfbc"
version "4.3.4"
resolved "git+https://github.com/RocketChat/commonmark-react-renderer.git#1264ac7b1c13d9be3e2f67eec6702a3132f4fac2"
dependencies:
lodash.assign "^4.2.0"
lodash.isplainobject "^4.0.6"
@ -5130,14 +5130,14 @@ commondir@^1.0.1:
xss-filters "^1.2.6"
"commonmark@git+https://github.com/RocketChat/commonmark.js.git":
version "0.29.2"
resolved "git+https://github.com/RocketChat/commonmark.js.git#020b5af060459ac2010e382e9ae431d48ed39777"
version "0.29.0"
resolved "git+https://github.com/RocketChat/commonmark.js.git#5d293fe9ba83a3e6f842d5d3f41a9b57c35bea1f"
dependencies:
entities "~2.0"
mdurl "~1.0.1"
minimist ">=1.2.2"
entities "~ 1.1.1"
mdurl "~ 1.0.1"
minimist "~ 1.2.0"
string.prototype.repeat "^0.2.0"
xregexp "^4.3.0"
xregexp "4.1.1"
compare-urls@^2.0.0:
version "2.0.0"
@ -6127,7 +6127,7 @@ enhanced-resolve@^4.1.0:
memory-fs "^0.5.0"
tapable "^1.0.0"
entities@^1.1.1, entities@^1.1.2:
entities@^1.1.1, entities@^1.1.2, "entities@~ 1.1.1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
@ -6137,16 +6137,16 @@ entities@^2.0.0:
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.2.tgz#ac74db0bba8d33808bbf36809c3a5c3683531436"
integrity sha512-dmD3AvJQBUjKpcNkoqr+x+IF0SdRtPz9Vk0uTy4yWqga9ibB6s4v++QFWNohjiUGoMlF552ZvNyXDxz5iW0qmw==
entities@~2.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f"
integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==
envinfo@^7.1.0, envinfo@^7.5.0:
envinfo@^7.1.0:
version "7.5.1"
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.5.1.tgz#93c26897225a00457c75e734d354ea9106a72236"
integrity sha512-hQBkDf2iO4Nv0CNHpCuSBeaSrveU6nThVxFGTrq/eDlV716UQk09zChaJae4mZRsos1x4YLY2TaH3LHUae3ZmQ==
envinfo@^7.5.0:
version "7.7.0"
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.7.0.tgz#fbfa46d739dec0554ef40220cd91fb20f64c9698"
integrity sha512-XX0+kACx7HcIFhar/JjsDtDIVcC8hnzQO1Asehq+abs+v9MtzpUuujFb6eBTT4lF9j2Bh6d2XFngbFRryjUAeQ==
errno@^0.1.3, errno@~0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
@ -10348,7 +10348,7 @@ md5.js@^1.3.4:
inherits "^2.0.1"
safe-buffer "^5.1.2"
mdurl@~1.0.1:
"mdurl@~ 1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
@ -10892,7 +10892,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
dependencies:
brace-expansion "^1.1.7"
minimist@>=1.2.2, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, "minimist@~ 1.2.0":
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
@ -15957,7 +15957,12 @@ xpipe@^1.0.5:
resolved "https://registry.yarnpkg.com/xpipe/-/xpipe-1.0.5.tgz#8dd8bf45fc3f7f55f0e054b878f43a62614dafdf"
integrity sha1-jdi/Rfw/f1Xw4FS4ePQ6YmFNr98=
xregexp@^4.2.4, xregexp@^4.3.0:
xregexp@4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.1.1.tgz#eb8a032aa028d403f7b1b22c47a5f16c24b21d8d"
integrity sha512-QJ1gfSUV7kEOLfpKFCjBJRnfPErUzkNKFMso4kDSmGpp3x6ZgkyKf74inxI7PnnQCFYq5TqYJCd7DrgDN8Q05A==
xregexp@^4.2.4:
version "4.3.0"
resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.3.0.tgz#7e92e73d9174a99a59743f67a4ce879a04b5ae50"
integrity sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==