Merge branch 'develop' into chore/ts-RoomView
This commit is contained in:
commit
b1d1e29d41
|
@ -1419,6 +1419,7 @@ Array [
|
|||
</Text>
|
||||
</View>
|
||||
<View
|
||||
accessibilityLabel="Use"
|
||||
accessible={true}
|
||||
focusable={true}
|
||||
onClick={[Function]}
|
||||
|
@ -1581,6 +1582,7 @@ Array [
|
|||
</Text>
|
||||
</View>
|
||||
<View
|
||||
accessibilityLabel="Use"
|
||||
accessible={true}
|
||||
focusable={true}
|
||||
onClick={[Function]}
|
||||
|
@ -41244,6 +41246,7 @@ exports[`Storyshots Message Show a button as attachment 1`] = `
|
|||
Test Button
|
||||
</Text>
|
||||
<View
|
||||
accessibilityLabel="Text button"
|
||||
accessible={true}
|
||||
focusable={true}
|
||||
onClick={[Function]}
|
||||
|
|
|
@ -151,6 +151,8 @@ android {
|
|||
missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60" // See note below!
|
||||
}
|
||||
resValue "string", "rn_config_reader_custom_package", "chat.rocket.reactnative"
|
||||
testBuildType System.getProperty('testBuildType', 'debug')
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
|
@ -203,6 +205,10 @@ android {
|
|||
dimension = "app"
|
||||
buildConfigField "boolean", "IS_OFFICIAL", "false"
|
||||
}
|
||||
e2e {
|
||||
dimension = "app"
|
||||
buildConfigField "boolean", "IS_OFFICIAL", "false"
|
||||
}
|
||||
foss {
|
||||
dimension = "type"
|
||||
buildConfigField "boolean", "FDROID_BUILD", "true"
|
||||
|
@ -230,6 +236,16 @@ android {
|
|||
java.srcDirs = ['src/main/java', 'src/play/java']
|
||||
manifest.srcFile 'src/play/AndroidManifest.xml'
|
||||
}
|
||||
e2ePlayDebug {
|
||||
java.srcDirs = ['src/main/java', 'src/play/java']
|
||||
res.srcDirs = ['src/experimental/res']
|
||||
manifest.srcFile 'src/play/AndroidManifest.xml'
|
||||
}
|
||||
e2ePlayRelease {
|
||||
java.srcDirs = ['src/main/java', 'src/play/java']
|
||||
res.srcDirs = ['src/experimental/res']
|
||||
manifest.srcFile 'src/play/AndroidManifest.xml'
|
||||
}
|
||||
}
|
||||
|
||||
applicationVariants.all { variant ->
|
||||
|
@ -294,6 +310,8 @@ dependencies {
|
|||
implementation "com.tencent:mmkv-static:1.2.1"
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
|
||||
implementation "com.squareup.okhttp3:okhttp-urlconnection:4.9.0"
|
||||
androidTestImplementation('com.wix:detox:+') { transitive = true }
|
||||
androidTestImplementation 'junit:junit:4.12'
|
||||
}
|
||||
|
||||
// Run this once to be able to run the application with BUCK
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
// Replace "com.example" here and below with your app's package name from the top of MainActivity.java
|
||||
package chat.rocket.reactnative;
|
||||
|
||||
import com.wix.detox.Detox;
|
||||
import com.wix.detox.config.DetoxConfig;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
public class DetoxTest {
|
||||
@Rule
|
||||
// Replace 'MainActivity' with the value of android:name entry in
|
||||
// <activity> in AndroidManifest.xml
|
||||
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class, false, false);
|
||||
|
||||
@Test
|
||||
public void runDetoxTests() {
|
||||
DetoxConfig detoxConfig = new DetoxConfig();
|
||||
detoxConfig.idlePolicyConfig.masterTimeoutSec = 90;
|
||||
detoxConfig.idlePolicyConfig.idleResourceTimeoutSec = 60;
|
||||
detoxConfig.rnContextLoadTimeoutSec = (chat.rocket.reactnative.BuildConfig.DEBUG ? 180 : 60);
|
||||
|
||||
Detox.runTests(mActivityRule, detoxConfig);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config xmlns:tools="http://schemas.android.com/tools">
|
||||
<base-config cleartextTrafficPermitted="true">
|
||||
<trust-anchors>
|
||||
<certificates src="system" />
|
||||
<certificates src="user"
|
||||
tools:ignore="AcceptsUserCertificates" />
|
||||
</trust-anchors>
|
||||
</base-config>
|
||||
</network-security-config>
|
|
@ -53,6 +53,10 @@ allprojects {
|
|||
url("$rootDir/../node_modules/jsc-android/dist")
|
||||
}
|
||||
|
||||
maven {
|
||||
url "$rootDir/../node_modules/detox/Detox-android"
|
||||
}
|
||||
|
||||
maven {
|
||||
url jitsi_url
|
||||
}
|
||||
|
|
|
@ -124,7 +124,11 @@ const ActionSheet = React.memo(
|
|||
|
||||
const renderFooter = () =>
|
||||
data?.hasCancel ? (
|
||||
<Button onPress={hide} style={[styles.button, { backgroundColor: themes[theme].auxiliaryBackground }]} theme={theme}>
|
||||
<Button
|
||||
onPress={hide}
|
||||
style={[styles.button, { backgroundColor: themes[theme].auxiliaryBackground }]}
|
||||
theme={theme}
|
||||
accessibilityLabel={I18n.t('Cancel')}>
|
||||
<Text style={[styles.text, { color: themes[theme].bodyText }]}>{I18n.t('Cancel')}</Text>
|
||||
</Button>
|
||||
) : null;
|
||||
|
|
|
@ -70,6 +70,7 @@ export default class Button extends React.PureComponent<Partial<IButtonProps>, a
|
|||
disabled && styles.disabled,
|
||||
style
|
||||
]}
|
||||
accessibilityLabel={title}
|
||||
{...otherProps}>
|
||||
{loading ? (
|
||||
<ActivityIndicator color={textColor} />
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
interface IHeaderButtonContainer {
|
||||
children: JSX.Element;
|
||||
children: React.ReactNode;
|
||||
left?: boolean;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ interface IPasscodeBase {
|
|||
previousPasscode?: string;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
showBiometry?: string;
|
||||
showBiometry?: boolean;
|
||||
onEndProcess: Function;
|
||||
onError?: Function;
|
||||
onBiometryPress?(): void;
|
||||
|
|
|
@ -15,7 +15,7 @@ import I18n from '../../i18n';
|
|||
|
||||
interface IPasscodePasscodeEnter {
|
||||
theme: string;
|
||||
hasBiometry: string;
|
||||
hasBiometry: boolean;
|
||||
finishProcess: Function;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ interface IStatus {
|
|||
status: string;
|
||||
size: number;
|
||||
style?: StyleProp<TextStyle>;
|
||||
testID?: string;
|
||||
}
|
||||
|
||||
const Status = React.memo(({ style, status = 'offline', size = 32, ...props }: IStatus) => {
|
||||
|
|
|
@ -43,7 +43,11 @@ const Content = React.memo(
|
|||
content = <Text style={[styles.text, { color: themes[props.theme].bodyText }]}>{I18n.t('Sent_an_attachment')}</Text>;
|
||||
} else if (props.isEncrypted) {
|
||||
content = (
|
||||
<Text style={[styles.textInfo, { color: themes[props.theme].auxiliaryText }]}>{I18n.t('Encrypted_message')}</Text>
|
||||
<Text
|
||||
style={[styles.textInfo, { color: themes[props.theme].auxiliaryText }]}
|
||||
accessibilityLabel={I18n.t('Encrypted_message')}>
|
||||
{I18n.t('Encrypted_message')}
|
||||
</Text>
|
||||
);
|
||||
} else {
|
||||
const { baseUrl, user, onLinkPress } = useContext(MessageContext);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// https://github.com/RocketChat/Rocket.Chat/blob/develop/definition/ITeam.ts
|
||||
export const TEAM_TYPE = {
|
||||
exports.TEAM_TYPE = {
|
||||
PUBLIC: 0,
|
||||
PRIVATE: 1
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import { Text, View, ViewStyle } from 'react-native';
|
||||
|
||||
import Touch from '../../utils/touch';
|
||||
import Avatar from '../../containers/Avatar';
|
||||
|
@ -10,7 +10,7 @@ import { themes } from '../../constants/colors';
|
|||
export { ROW_HEIGHT };
|
||||
|
||||
interface IDirectoryItemLabel {
|
||||
text: string;
|
||||
text?: string;
|
||||
theme: string;
|
||||
}
|
||||
|
||||
|
@ -21,9 +21,9 @@ interface IDirectoryItem {
|
|||
type: string;
|
||||
onPress(): void;
|
||||
testID: string;
|
||||
style: any;
|
||||
rightLabel: string;
|
||||
rid: string;
|
||||
style?: ViewStyle;
|
||||
rightLabel?: string;
|
||||
rid?: string;
|
||||
theme: string;
|
||||
teamMain?: boolean;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ const DirectoryItemLabel = React.memo(({ text, theme }: IDirectoryItemLabel) =>
|
|||
if (!text) {
|
||||
return null;
|
||||
}
|
||||
return <Text style={[styles.directoryItemLabel, { color: themes[theme!].auxiliaryText }]}>{text}</Text>;
|
||||
return <Text style={[styles.directoryItemLabel, { color: themes[theme].auxiliaryText }]}>{text}</Text>;
|
||||
});
|
||||
|
||||
const DirectoryItem = ({
|
||||
|
|
|
@ -4,7 +4,7 @@ import { KeyboardAwareScrollView, KeyboardAwareScrollViewProps } from '@codler/r
|
|||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
|
||||
interface IKeyboardViewProps extends KeyboardAwareScrollViewProps {
|
||||
keyboardVerticalOffset: number;
|
||||
keyboardVerticalOffset?: number;
|
||||
scrollEnabled?: boolean;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ interface IUserItem {
|
|||
testID: string;
|
||||
onLongPress?: () => void;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
icon: string;
|
||||
icon?: string;
|
||||
theme: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,11 @@ export default class DirectoryOptions extends PureComponent<IDirectoryOptionsPro
|
|||
}
|
||||
|
||||
return (
|
||||
<Touch onPress={() => changeType(itemType)} style={styles.dropdownItemButton} theme={theme}>
|
||||
<Touch
|
||||
onPress={() => changeType(itemType)}
|
||||
style={styles.dropdownItemButton}
|
||||
theme={theme}
|
||||
accessibilityLabel={I18n.t(text)}>
|
||||
<View style={styles.dropdownItemContainer}>
|
||||
<CustomIcon style={[styles.dropdownItemIcon, { color: themes[theme].bodyText }]} size={22} name={icon} />
|
||||
<Text style={[styles.dropdownItemText, { color: themes[theme].bodyText }]}>{I18n.t(text)}</Text>
|
||||
|
@ -90,7 +94,7 @@ export default class DirectoryOptions extends PureComponent<IDirectoryOptionsPro
|
|||
</TouchableWithoutFeedback>
|
||||
<Animated.View
|
||||
style={[styles.dropdownContainer, { transform: [{ translateY }], backgroundColor: themes[theme].backgroundColor }]}>
|
||||
<Touch onPress={this.close} theme={theme}>
|
||||
<Touch onPress={this.close} theme={theme} accessibilityLabel={I18n.t('Search_by')}>
|
||||
<View
|
||||
style={[
|
||||
styles.dropdownContainerHeader,
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
import { FlatList, StyleSheet, Text, View } from 'react-native';
|
||||
import { Dispatch } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import { dequal } from 'dequal';
|
||||
import * as List from '../containers/List';
|
||||
|
||||
import * as List from '../containers/List';
|
||||
import Touch from '../utils/touch';
|
||||
import database from '../lib/database';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
|
@ -18,7 +19,6 @@ import * as HeaderButton from '../containers/HeaderButton';
|
|||
import StatusBar from '../containers/StatusBar';
|
||||
import { themes } from '../constants/colors';
|
||||
import { withTheme } from '../theme';
|
||||
import { getUserSelector } from '../selectors/login';
|
||||
import Navigation from '../lib/Navigation';
|
||||
import { createChannelRequest } from '../actions/createChannel';
|
||||
import { goRoom } from '../utils/goRoom';
|
||||
|
@ -47,33 +47,54 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
class NewMessageView extends React.Component {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
interface IButton {
|
||||
onPress: () => void;
|
||||
testID: string;
|
||||
title: string;
|
||||
icon: string;
|
||||
first?: boolean;
|
||||
}
|
||||
|
||||
interface ISearch {
|
||||
_id: string;
|
||||
status: string;
|
||||
username: string;
|
||||
avatarETag: string;
|
||||
outside: boolean;
|
||||
rid: string;
|
||||
name: string;
|
||||
t: string;
|
||||
search: boolean;
|
||||
}
|
||||
|
||||
interface INewMessageViewState {
|
||||
search: ISearch[];
|
||||
// TODO: Refactor when migrate room
|
||||
chats: any[];
|
||||
permissions: boolean[];
|
||||
}
|
||||
|
||||
interface INewMessageViewProps {
|
||||
navigation: StackNavigationProp<any, 'NewMessageView'>;
|
||||
create: (params: { group: boolean }) => void;
|
||||
maxUsers: number;
|
||||
theme: string;
|
||||
isMasterDetail: boolean;
|
||||
serverVersion: string;
|
||||
createTeamPermission: string[];
|
||||
createDirectMessagePermission: string[];
|
||||
createPublicChannelPermission: string[];
|
||||
createPrivateChannelPermission: string[];
|
||||
createDiscussionPermission: string[];
|
||||
}
|
||||
|
||||
class NewMessageView extends React.Component<INewMessageViewProps, INewMessageViewState> {
|
||||
static navigationOptions = ({ navigation }: INewMessageViewProps): StackNavigationOptions => ({
|
||||
headerLeft: () => <HeaderButton.CloseModal navigation={navigation} testID='new-message-view-close' />,
|
||||
title: I18n.t('New_Message')
|
||||
});
|
||||
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
user: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
token: PropTypes.string,
|
||||
roles: PropTypes.array
|
||||
}),
|
||||
create: PropTypes.func,
|
||||
maxUsers: PropTypes.number,
|
||||
theme: PropTypes.string,
|
||||
isMasterDetail: PropTypes.bool,
|
||||
serverVersion: PropTypes.string,
|
||||
createTeamPermission: PropTypes.array,
|
||||
createDirectMessagePermission: PropTypes.array,
|
||||
createPublicChannelPermission: PropTypes.array,
|
||||
createPrivateChannelPermission: PropTypes.array,
|
||||
createDiscussionPermission: PropTypes.array
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: INewMessageViewProps) {
|
||||
super(props);
|
||||
this.init();
|
||||
this.state = {
|
||||
|
@ -102,7 +123,7 @@ class NewMessageView extends React.Component {
|
|||
this.handleHasPermission();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
componentDidUpdate(prevProps: INewMessageViewProps) {
|
||||
const {
|
||||
createTeamPermission,
|
||||
createPublicChannelPermission,
|
||||
|
@ -122,7 +143,7 @@ class NewMessageView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
onSearchChangeText(text) {
|
||||
onSearchChangeText(text: string) {
|
||||
this.search(text);
|
||||
}
|
||||
|
||||
|
@ -131,7 +152,7 @@ class NewMessageView extends React.Component {
|
|||
return navigation.pop();
|
||||
};
|
||||
|
||||
search = async text => {
|
||||
search = async (text: string) => {
|
||||
const result = await RocketChat.search({ text, filterRooms: false });
|
||||
this.setState({
|
||||
search: result
|
||||
|
@ -162,7 +183,8 @@ class NewMessageView extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
goRoom = item => {
|
||||
// TODO: Refactor when migrate room
|
||||
goRoom = (item: any) => {
|
||||
logEvent(events.NEW_MSG_CHAT_WITH_USER);
|
||||
const { isMasterDetail, navigation } = this.props;
|
||||
if (isMasterDetail) {
|
||||
|
@ -171,7 +193,7 @@ class NewMessageView extends React.Component {
|
|||
goRoom({ item, isMasterDetail });
|
||||
};
|
||||
|
||||
renderButton = ({ onPress, testID, title, icon, first }) => {
|
||||
renderButton = ({ onPress, testID, title, icon, first }: IButton) => {
|
||||
const { theme } = this.props;
|
||||
return (
|
||||
<Touch onPress={onPress} style={{ backgroundColor: themes[theme].backgroundColor }} testID={testID} theme={theme}>
|
||||
|
@ -218,7 +240,7 @@ class NewMessageView extends React.Component {
|
|||
|
||||
return (
|
||||
<View style={{ backgroundColor: themes[theme].auxiliaryBackground }}>
|
||||
<SearchBox onChangeText={text => this.onSearchChangeText(text)} testID='new-message-view-search' />
|
||||
<SearchBox onChangeText={(text: string) => this.onSearchChangeText(text)} testID='new-message-view-search' />
|
||||
<View style={styles.buttonContainer}>
|
||||
{permissions[0] || permissions[1]
|
||||
? this.renderButton({
|
||||
|
@ -258,9 +280,10 @@ class NewMessageView extends React.Component {
|
|||
);
|
||||
};
|
||||
|
||||
renderItem = ({ item, index }) => {
|
||||
// TODO: Refactor when migrate room
|
||||
renderItem = ({ item, index }: { item: ISearch | any; index: number }) => {
|
||||
const { search, chats } = this.state;
|
||||
const { baseUrl, user, theme } = this.props;
|
||||
const { theme } = this.props;
|
||||
|
||||
let style = { borderColor: themes[theme].separatorColor };
|
||||
if (index === 0) {
|
||||
|
@ -277,10 +300,8 @@ class NewMessageView extends React.Component {
|
|||
name={item.search ? item.name : item.fname}
|
||||
username={item.search ? item.username : item.name}
|
||||
onPress={() => this.goRoom(item)}
|
||||
baseUrl={baseUrl}
|
||||
testID={`new-message-view-item-${item.name}`}
|
||||
style={style}
|
||||
user={user}
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
|
@ -313,12 +334,10 @@ class NewMessageView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state: any) => ({
|
||||
serverVersion: state.server.version,
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
baseUrl: state.server.server,
|
||||
maxUsers: state.settings.DirectMesssage_maxUsers || 1,
|
||||
user: getUserSelector(state),
|
||||
createTeamPermission: state.permissions['create-team'],
|
||||
createDirectMessagePermission: state.permissions['create-d'],
|
||||
createPublicChannelPermission: state.permissions['create-c'],
|
||||
|
@ -326,8 +345,8 @@ const mapStateToProps = state => ({
|
|||
createDiscussionPermission: state.permissions['start-discussion']
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
create: params => dispatch(createChannelRequest(params))
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
create: (params: { group: boolean }) => dispatch(createChannelRequest(params))
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(NewMessageView));
|
|
@ -918,7 +918,6 @@ class RoomActionsView extends React.Component {
|
|||
event: this.convertTeamToChannel
|
||||
})
|
||||
}
|
||||
testID='room-actions-convert-channel-to-team'
|
||||
left={() => <List.Icon name='channel-public' />}
|
||||
showActionIndicator
|
||||
/>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Switch } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { StackNavigationOptions } from '@react-navigation/stack';
|
||||
import Model from '@nozbe/watermelondb/Model';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import I18n from '../i18n';
|
||||
import { withTheme } from '../theme';
|
||||
|
@ -16,19 +18,42 @@ import { events, logEvent } from '../utils/log';
|
|||
|
||||
const DEFAULT_BIOMETRY = false;
|
||||
|
||||
class ScreenLockConfigView extends React.Component {
|
||||
static navigationOptions = () => ({
|
||||
interface IServerRecords extends Model {
|
||||
autoLock?: boolean;
|
||||
autoLockTime?: number;
|
||||
biometry?: boolean;
|
||||
}
|
||||
|
||||
interface IItem {
|
||||
title: string;
|
||||
value: number;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
interface IScreenLockConfigViewProps {
|
||||
theme: string;
|
||||
server: string;
|
||||
Force_Screen_Lock: boolean;
|
||||
Force_Screen_Lock_After: number;
|
||||
}
|
||||
|
||||
interface IScreenLockConfigViewState {
|
||||
autoLock?: boolean;
|
||||
autoLockTime?: number | null;
|
||||
biometry?: boolean;
|
||||
biometryLabel: null;
|
||||
}
|
||||
|
||||
class ScreenLockConfigView extends React.Component<IScreenLockConfigViewProps, IScreenLockConfigViewState> {
|
||||
private serverRecord?: IServerRecords;
|
||||
|
||||
private observable?: Subscription;
|
||||
|
||||
static navigationOptions = (): StackNavigationOptions => ({
|
||||
title: I18n.t('Screen_lock')
|
||||
});
|
||||
|
||||
static propTypes = {
|
||||
theme: PropTypes.string,
|
||||
server: PropTypes.string,
|
||||
Force_Screen_Lock: PropTypes.string,
|
||||
Force_Screen_Lock_After: PropTypes.string
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: IScreenLockConfigViewProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
autoLock: false,
|
||||
|
@ -104,7 +129,7 @@ class ScreenLockConfigView extends React.Component {
|
|||
logEvent(events.SLC_SAVE_SCREEN_LOCK);
|
||||
const { autoLock, autoLockTime, biometry } = this.state;
|
||||
const serversDB = database.servers;
|
||||
await serversDB.action(async () => {
|
||||
await serversDB.write(async () => {
|
||||
await this.serverRecord?.update(record => {
|
||||
record.autoLock = autoLock;
|
||||
record.autoLockTime = autoLockTime === null ? DEFAULT_AUTO_LOCK : autoLockTime;
|
||||
|
@ -113,7 +138,7 @@ class ScreenLockConfigView extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
changePasscode = async ({ force }) => {
|
||||
changePasscode = async ({ force }: { force: boolean }) => {
|
||||
logEvent(events.SLC_CHANGE_PASSCODE);
|
||||
await changePasscode({ force });
|
||||
};
|
||||
|
@ -144,12 +169,12 @@ class ScreenLockConfigView extends React.Component {
|
|||
);
|
||||
};
|
||||
|
||||
isSelected = value => {
|
||||
isSelected = (value: number) => {
|
||||
const { autoLockTime } = this.state;
|
||||
return autoLockTime === value;
|
||||
};
|
||||
|
||||
changeAutoLockTime = autoLockTime => {
|
||||
changeAutoLockTime = (autoLockTime: number) => {
|
||||
logEvent(events.SLC_CHANGE_AUTOLOCK_TIME);
|
||||
this.setState({ autoLockTime }, () => this.save());
|
||||
};
|
||||
|
@ -159,7 +184,7 @@ class ScreenLockConfigView extends React.Component {
|
|||
return <List.Icon name='check' color={themes[theme].tintColor} />;
|
||||
};
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
renderItem = ({ item }: { item: IItem }) => {
|
||||
const { title, value, disabled } = item;
|
||||
return (
|
||||
<>
|
||||
|
@ -194,7 +219,7 @@ class ScreenLockConfigView extends React.Component {
|
|||
if (!autoLock) {
|
||||
return null;
|
||||
}
|
||||
let items = this.defaultAutoLockOptions;
|
||||
let items: IItem[] = this.defaultAutoLockOptions;
|
||||
if (Force_Screen_Lock && Force_Screen_Lock_After > 0) {
|
||||
items = [
|
||||
{
|
||||
|
@ -262,7 +287,7 @@ class ScreenLockConfigView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state: any) => ({
|
||||
server: state.server.server,
|
||||
Force_Screen_Lock: state.settings.Force_Screen_Lock,
|
||||
Force_Screen_Lock_After: state.settings.Force_Screen_Lock_After
|
|
@ -1,19 +1,25 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Modal from 'react-native-modal';
|
||||
import useDeepCompareEffect from 'use-deep-compare-effect';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import Orientation from 'react-native-orientation-locker';
|
||||
|
||||
import { withTheme } from '../theme';
|
||||
import { useTheme } from '../theme';
|
||||
import EventEmitter from '../utils/events';
|
||||
import { LOCAL_AUTHENTICATE_EMITTER } from '../constants/localAuthentication';
|
||||
import { isTablet } from '../utils/deviceInfo';
|
||||
import { PasscodeEnter } from '../containers/Passcode';
|
||||
|
||||
const ScreenLockedView = ({ theme }) => {
|
||||
interface IData {
|
||||
submit?: () => void;
|
||||
hasBiometry?: boolean;
|
||||
}
|
||||
|
||||
const ScreenLockedView = (): JSX.Element => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [data, setData] = useState({});
|
||||
const [data, setData] = useState<IData>({});
|
||||
|
||||
const { theme } = useTheme();
|
||||
|
||||
useDeepCompareEffect(() => {
|
||||
if (!isEmpty(data)) {
|
||||
|
@ -23,7 +29,7 @@ const ScreenLockedView = ({ theme }) => {
|
|||
}
|
||||
}, [data]);
|
||||
|
||||
const showScreenLock = args => {
|
||||
const showScreenLock = (args: IData) => {
|
||||
setData(args);
|
||||
};
|
||||
|
||||
|
@ -56,13 +62,9 @@ const ScreenLockedView = ({ theme }) => {
|
|||
style={{ margin: 0 }}
|
||||
animationIn='fadeIn'
|
||||
animationOut='fadeOut'>
|
||||
<PasscodeEnter theme={theme} hasBiometry={data?.hasBiometry} finishProcess={onSubmit} />
|
||||
<PasscodeEnter theme={theme} hasBiometry={!!data?.hasBiometry} finishProcess={onSubmit} />
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
ScreenLockedView.propTypes = {
|
||||
theme: PropTypes.string
|
||||
};
|
||||
|
||||
export default withTheme(ScreenLockedView);
|
||||
export default ScreenLockedView;
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Switch } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
|
@ -20,11 +20,15 @@ import {
|
|||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import { isFDroidBuild } from '../constants/environment';
|
||||
|
||||
const SecurityPrivacyView = ({ navigation }) => {
|
||||
interface ISecurityPrivacyViewProps {
|
||||
navigation: StackNavigationProp<any, 'SecurityPrivacyView'>;
|
||||
}
|
||||
|
||||
const SecurityPrivacyView = ({ navigation }: ISecurityPrivacyViewProps): JSX.Element => {
|
||||
const [crashReportState, setCrashReportState] = useState(getReportCrashErrorsValue());
|
||||
const [analyticsEventsState, setAnalyticsEventsState] = useState(getReportAnalyticsEventsValue());
|
||||
|
||||
const e2eEnabled = useSelector(state => state.settings.E2E_Enable);
|
||||
const e2eEnabled = useSelector((state: any) => state.settings.E2E_Enable);
|
||||
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
|
@ -32,21 +36,22 @@ const SecurityPrivacyView = ({ navigation }) => {
|
|||
});
|
||||
}, []);
|
||||
|
||||
const toggleCrashReport = value => {
|
||||
logEvent(events.SE_TOGGLE_CRASH_REPORT);
|
||||
const toggleCrashReport = (value: boolean) => {
|
||||
logEvent(events.SP_TOGGLE_CRASH_REPORT);
|
||||
AsyncStorage.setItem(CRASH_REPORT_KEY, JSON.stringify(value));
|
||||
setCrashReportState(value);
|
||||
toggleCrashErrorsReport(value);
|
||||
};
|
||||
|
||||
const toggleAnalyticsEvents = value => {
|
||||
logEvent(events.SE_TOGGLE_ANALYTICS_EVENTS);
|
||||
const toggleAnalyticsEvents = (value: boolean) => {
|
||||
logEvent(events.SP_TOGGLE_ANALYTICS_EVENTS);
|
||||
AsyncStorage.setItem(ANALYTICS_EVENTS_KEY, JSON.stringify(value));
|
||||
setAnalyticsEventsState(value);
|
||||
toggleAnalyticsEventsReport(value);
|
||||
};
|
||||
|
||||
const navigateToScreen = screen => {
|
||||
const navigateToScreen = (screen: 'E2EEncryptionSecurityView' | 'ScreenLockConfigView') => {
|
||||
// @ts-ignore
|
||||
logEvent(events[`SP_GO_${screen.replace('View', '').toUpperCase()}`]);
|
||||
navigation.navigate(screen);
|
||||
};
|
||||
|
@ -106,8 +111,4 @@ const SecurityPrivacyView = ({ navigation }) => {
|
|||
);
|
||||
};
|
||||
|
||||
SecurityPrivacyView.propTypes = {
|
||||
navigation: PropTypes.object
|
||||
};
|
||||
|
||||
export default SecurityPrivacyView;
|
|
@ -1,8 +1,9 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
import { FlatList, StyleSheet, Text, View } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { RadioButton } from 'react-native-ui-lib';
|
||||
import { RouteProp } from '@react-navigation/native';
|
||||
|
||||
import log from '../utils/log';
|
||||
import * as List from '../containers/List';
|
||||
|
@ -25,15 +26,58 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
class SelectListView extends React.Component {
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object,
|
||||
route: PropTypes.object,
|
||||
theme: PropTypes.string,
|
||||
isMasterDetail: PropTypes.bool
|
||||
};
|
||||
interface IData {
|
||||
rid: string;
|
||||
name: string;
|
||||
t?: string;
|
||||
teamMain?: boolean;
|
||||
alert?: boolean;
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
interface ISelectListViewState {
|
||||
data: IData[];
|
||||
dataFiltered: IData[];
|
||||
isSearching: boolean;
|
||||
selected: string[];
|
||||
}
|
||||
|
||||
interface ISelectListViewProps {
|
||||
navigation: StackNavigationProp<any, 'SelectListView'>;
|
||||
route: RouteProp<
|
||||
{
|
||||
SelectView: {
|
||||
data: IData[];
|
||||
title: string;
|
||||
infoText: string;
|
||||
nextAction(selected: string[]): void;
|
||||
showAlert(): void;
|
||||
isSearch: boolean;
|
||||
onSearch(text: string): IData[];
|
||||
isRadio: boolean;
|
||||
};
|
||||
},
|
||||
'SelectView'
|
||||
>;
|
||||
theme: string;
|
||||
isMasterDetail: boolean;
|
||||
}
|
||||
|
||||
class SelectListView extends React.Component<ISelectListViewProps, ISelectListViewState> {
|
||||
private title: string;
|
||||
|
||||
private infoText: string;
|
||||
|
||||
private nextAction: (selected: string[]) => void;
|
||||
|
||||
private showAlert: () => void;
|
||||
|
||||
private isSearch: boolean;
|
||||
|
||||
private onSearch: (text: string) => IData[];
|
||||
|
||||
private isRadio: boolean;
|
||||
|
||||
constructor(props: ISelectListViewProps) {
|
||||
super(props);
|
||||
const data = props.route?.params?.data;
|
||||
this.title = props.route?.params?.title;
|
||||
|
@ -56,7 +100,7 @@ class SelectListView extends React.Component {
|
|||
const { navigation, isMasterDetail } = this.props;
|
||||
const { selected } = this.state;
|
||||
|
||||
const options = {
|
||||
const options: StackNavigationOptions = {
|
||||
headerTitle: I18n.t(this.title)
|
||||
};
|
||||
|
||||
|
@ -87,7 +131,7 @@ class SelectListView extends React.Component {
|
|||
return (
|
||||
<View style={{ backgroundColor: themes[theme].auxiliaryBackground }}>
|
||||
<SearchBox
|
||||
onChangeText={text => this.search(text)}
|
||||
onChangeText={(text: string) => this.search(text)}
|
||||
testID='select-list-view-search'
|
||||
onCancelPress={() => this.setState({ isSearching: false })}
|
||||
/>
|
||||
|
@ -95,7 +139,7 @@ class SelectListView extends React.Component {
|
|||
);
|
||||
};
|
||||
|
||||
search = async text => {
|
||||
search = async (text: string) => {
|
||||
try {
|
||||
this.setState({ isSearching: true });
|
||||
const result = await this.onSearch(text);
|
||||
|
@ -105,12 +149,12 @@ class SelectListView extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
isChecked = rid => {
|
||||
isChecked = (rid: string) => {
|
||||
const { selected } = this.state;
|
||||
return selected.includes(rid);
|
||||
};
|
||||
|
||||
toggleItem = rid => {
|
||||
toggleItem = (rid: string) => {
|
||||
const { selected } = this.state;
|
||||
|
||||
animateNextTransition();
|
||||
|
@ -126,7 +170,7 @@ class SelectListView extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
renderItem = ({ item }: { item: IData }) => {
|
||||
const { theme } = this.props;
|
||||
const { selected } = this.state;
|
||||
|
||||
|
@ -187,7 +231,7 @@ class SelectListView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state: any) => ({
|
||||
isMasterDetail: state.app.isMasterDetail
|
||||
});
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react';
|
||||
import { FlatList } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
import { connect } from 'react-redux';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import { Q, Model } from '@nozbe/watermelondb';
|
||||
|
||||
import I18n from '../i18n';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
|
@ -12,29 +12,39 @@ import database from '../lib/database';
|
|||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import * as List from '../containers/List';
|
||||
|
||||
const getItemLayout = (data, index) => ({ length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index });
|
||||
const keyExtractor = item => item.id;
|
||||
const getItemLayout = (data: any, index: number) => ({ length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index });
|
||||
const keyExtractor = (item: IServer) => item.id;
|
||||
|
||||
class SelectServerView extends React.Component {
|
||||
static navigationOptions = () => ({
|
||||
interface IServer extends Model {
|
||||
id: string;
|
||||
iconURL?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
interface ISelectServerViewState {
|
||||
servers: IServer[];
|
||||
}
|
||||
|
||||
interface ISelectServerViewProps {
|
||||
navigation: StackNavigationProp<any, 'SelectServerView'>;
|
||||
server: string;
|
||||
}
|
||||
|
||||
class SelectServerView extends React.Component<ISelectServerViewProps, ISelectServerViewState> {
|
||||
static navigationOptions = (): StackNavigationOptions => ({
|
||||
title: I18n.t('Select_Server')
|
||||
});
|
||||
|
||||
static propTypes = {
|
||||
server: PropTypes.string,
|
||||
navigation: PropTypes.object
|
||||
};
|
||||
|
||||
state = { servers: [] };
|
||||
state = { servers: [] as IServer[] };
|
||||
|
||||
async componentDidMount() {
|
||||
const serversDB = database.servers;
|
||||
const serversCollection = serversDB.get('servers');
|
||||
const servers = await serversCollection.query(Q.where('rooms_updated_at', Q.notEq(null))).fetch();
|
||||
const servers: IServer[] = await serversCollection.query(Q.where('rooms_updated_at', Q.notEq(null))).fetch();
|
||||
this.setState({ servers });
|
||||
}
|
||||
|
||||
select = async server => {
|
||||
select = async (server: string) => {
|
||||
const { server: currentServer, navigation } = this.props;
|
||||
|
||||
navigation.navigate('ShareListView');
|
||||
|
@ -43,7 +53,7 @@ class SelectServerView extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
renderItem = ({ item }: { item: IServer }) => {
|
||||
const { server } = this.props;
|
||||
return <ServerItem onPress={() => this.select(item.id)} item={item} hasCheck={item.id === server} />;
|
||||
};
|
||||
|
@ -62,7 +72,6 @@ class SelectServerView extends React.Component {
|
|||
ItemSeparatorComponent={List.Separator}
|
||||
ListHeaderComponent={List.Separator}
|
||||
ListFooterComponent={List.Separator}
|
||||
enableEmptySections
|
||||
removeClippedSubviews
|
||||
keyboardShouldPersistTaps='always'
|
||||
/>
|
||||
|
@ -71,7 +80,7 @@ class SelectServerView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({ share }) => ({
|
||||
const mapStateToProps = ({ share }: any) => ({
|
||||
server: share.server.server
|
||||
});
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
import { Dispatch } from 'redux';
|
||||
import { ScrollView, StyleSheet, Text } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import Orientation from 'react-native-orientation-locker';
|
||||
import { RouteProp } from '@react-navigation/native';
|
||||
|
||||
import { loginRequest as loginRequestAction } from '../actions/login';
|
||||
import TextInput from '../containers/TextInput';
|
||||
|
@ -27,21 +29,27 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
class SetUsernameView extends React.Component {
|
||||
static navigationOptions = ({ route }) => ({
|
||||
interface ISetUsernameViewState {
|
||||
username: string;
|
||||
saving: boolean;
|
||||
}
|
||||
|
||||
interface ISetUsernameViewProps {
|
||||
navigation: StackNavigationProp<any, 'SetUsernameView'>;
|
||||
route: RouteProp<{ SetUsernameView: { title: string } }, 'SetUsernameView'>;
|
||||
server: string;
|
||||
userId: string;
|
||||
loginRequest: ({ resume }: { resume: string }) => void;
|
||||
token: string;
|
||||
theme: string;
|
||||
}
|
||||
|
||||
class SetUsernameView extends React.Component<ISetUsernameViewProps, ISetUsernameViewState> {
|
||||
static navigationOptions = ({ route }: Pick<ISetUsernameViewProps, 'route'>): StackNavigationOptions => ({
|
||||
title: route.params?.title
|
||||
});
|
||||
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object,
|
||||
server: PropTypes.string,
|
||||
userId: PropTypes.string,
|
||||
loginRequest: PropTypes.func,
|
||||
token: PropTypes.string,
|
||||
theme: PropTypes.string
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: ISetUsernameViewProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
username: '',
|
||||
|
@ -61,7 +69,7 @@ class SetUsernameView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
shouldComponentUpdate(nextProps: ISetUsernameViewProps, nextState: ISetUsernameViewState) {
|
||||
const { username, saving } = this.state;
|
||||
const { theme } = this.props;
|
||||
if (nextProps.theme !== theme) {
|
||||
|
@ -88,7 +96,7 @@ class SetUsernameView extends React.Component {
|
|||
try {
|
||||
await RocketChat.saveUserProfile({ username });
|
||||
await loginRequest({ resume: token });
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
showErrorAlert(e.message, I18n.t('Oops'));
|
||||
}
|
||||
this.setState({ saving: false });
|
||||
|
@ -136,13 +144,13 @@ class SetUsernameView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state: any) => ({
|
||||
server: state.server.server,
|
||||
token: getUserSelector(state).token
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
loginRequest: params => dispatch(loginRequestAction(params))
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
loginRequest: (params: { resume: string }) => dispatch(loginRequestAction(params))
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(SetUsernameView));
|
|
@ -1,5 +1,4 @@
|
|||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Keyboard, StyleSheet, View } from 'react-native';
|
||||
import ShareExtension from 'rn-extensions-share';
|
||||
|
||||
|
@ -8,6 +7,7 @@ import * as HeaderButton from '../../../containers/HeaderButton';
|
|||
import { themes } from '../../../constants/colors';
|
||||
import sharedStyles from '../../Styles';
|
||||
import { animateNextTransition } from '../../../utils/layoutAnimation';
|
||||
import { IShareListHeaderIos } from './interface';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -16,10 +16,10 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
const Header = React.memo(({ searching, onChangeSearchText, initSearch, cancelSearch, theme }) => {
|
||||
const Header = React.memo(({ searching, onChangeSearchText, initSearch, cancelSearch, theme }: IShareListHeaderIos) => {
|
||||
const [text, setText] = useState('');
|
||||
|
||||
const onChangeText = searchText => {
|
||||
const onChangeText = (searchText: string) => {
|
||||
onChangeSearchText(searchText);
|
||||
setText(searchText);
|
||||
};
|
||||
|
@ -59,12 +59,4 @@ const Header = React.memo(({ searching, onChangeSearchText, initSearch, cancelSe
|
|||
);
|
||||
});
|
||||
|
||||
Header.propTypes = {
|
||||
searching: PropTypes.bool,
|
||||
onChangeSearchText: PropTypes.func,
|
||||
initSearch: PropTypes.func,
|
||||
cancelSearch: PropTypes.func,
|
||||
theme: PropTypes.string
|
||||
};
|
||||
|
||||
export default Header;
|
|
@ -1,11 +1,11 @@
|
|||
import React from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import TextInput from '../../../presentation/TextInput';
|
||||
import I18n from '../../../i18n';
|
||||
import { themes } from '../../../constants/colors';
|
||||
import sharedStyles from '../../Styles';
|
||||
import { IShareListHeader } from './interface';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -24,7 +24,7 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
const Header = React.memo(({ searching, onChangeSearchText, theme }) => {
|
||||
const Header = React.memo(({ searching, onChangeSearchText, theme }: IShareListHeader) => {
|
||||
const titleColorStyle = { color: themes[theme].headerTintColor };
|
||||
const isLight = theme === 'light';
|
||||
if (searching) {
|
||||
|
@ -43,10 +43,4 @@ const Header = React.memo(({ searching, onChangeSearchText, theme }) => {
|
|||
return <Text style={[styles.title, titleColorStyle]}>{I18n.t('Send_to')}</Text>;
|
||||
});
|
||||
|
||||
Header.propTypes = {
|
||||
searching: PropTypes.bool,
|
||||
onChangeSearchText: PropTypes.func,
|
||||
theme: PropTypes.string
|
||||
};
|
||||
|
||||
export default Header;
|
|
@ -1,11 +1,11 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Header from './Header';
|
||||
import { IShareListHeader } from './interface';
|
||||
|
||||
const ShareListHeader = React.memo(({ searching, initSearch, cancelSearch, search, theme }) => {
|
||||
const onSearchChangeText = text => {
|
||||
search(text.trim());
|
||||
const ShareListHeader = React.memo(({ searching, initSearch, cancelSearch, onChangeSearchText, theme }: IShareListHeader) => {
|
||||
const onSearchChangeText = (text: string) => {
|
||||
onChangeSearchText(text.trim());
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -19,12 +19,4 @@ const ShareListHeader = React.memo(({ searching, initSearch, cancelSearch, searc
|
|||
);
|
||||
});
|
||||
|
||||
ShareListHeader.propTypes = {
|
||||
searching: PropTypes.bool,
|
||||
initSearch: PropTypes.func,
|
||||
cancelSearch: PropTypes.func,
|
||||
search: PropTypes.func,
|
||||
theme: PropTypes.string
|
||||
};
|
||||
|
||||
export default ShareListHeader;
|
|
@ -0,0 +1,13 @@
|
|||
import { TextInputProps } from 'react-native';
|
||||
|
||||
type RequiredOnChangeText = Required<Pick<TextInputProps, 'onChangeText'>>;
|
||||
|
||||
export interface IShareListHeader {
|
||||
searching: boolean;
|
||||
onChangeSearchText: RequiredOnChangeText['onChangeText'];
|
||||
theme: string;
|
||||
initSearch?: () => void;
|
||||
cancelSearch?: () => void;
|
||||
}
|
||||
|
||||
export type IShareListHeaderIos = Required<IShareListHeader>;
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { BackHandler, FlatList, Keyboard, PermissionsAndroid, ScrollView, Text, View } from 'react-native';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import { BackHandler, FlatList, Keyboard, PermissionsAndroid, ScrollView, Text, View, Rationale } from 'react-native';
|
||||
import ShareExtension from 'rn-extensions-share';
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import { connect } from 'react-redux';
|
||||
|
@ -25,24 +25,75 @@ import { sanitizeLikeString } from '../../lib/database/utils';
|
|||
import styles from './styles';
|
||||
import ShareListHeader from './Header';
|
||||
|
||||
const permission = {
|
||||
interface IFile {
|
||||
value: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface IAttachment {
|
||||
filename: string;
|
||||
description: string;
|
||||
size: number;
|
||||
mime: any;
|
||||
path: string;
|
||||
}
|
||||
|
||||
interface IChat {
|
||||
rid: string;
|
||||
t: string;
|
||||
name: string;
|
||||
fname: string;
|
||||
blocked: boolean;
|
||||
blocker: boolean;
|
||||
prid: string;
|
||||
uids: string[];
|
||||
usernames: string[];
|
||||
topic: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
interface IServerInfo {
|
||||
useRealName: boolean;
|
||||
}
|
||||
interface IState {
|
||||
searching: boolean;
|
||||
searchText: string;
|
||||
searchResults: IChat[];
|
||||
chats: IChat[];
|
||||
serversCount: number;
|
||||
attachments: IAttachment[];
|
||||
text: string;
|
||||
loading: boolean;
|
||||
serverInfo: IServerInfo;
|
||||
needsPermission: boolean;
|
||||
}
|
||||
|
||||
interface INavigationOption {
|
||||
navigation: StackNavigationProp<any, 'ShareListView'>;
|
||||
}
|
||||
|
||||
interface IShareListViewProps extends INavigationOption {
|
||||
server: string;
|
||||
token: string;
|
||||
userId: string;
|
||||
theme: string;
|
||||
}
|
||||
|
||||
const permission: Rationale = {
|
||||
title: I18n.t('Read_External_Permission'),
|
||||
message: I18n.t('Read_External_Permission_Message')
|
||||
message: I18n.t('Read_External_Permission_Message'),
|
||||
buttonPositive: 'Ok'
|
||||
};
|
||||
|
||||
const getItemLayout = (data, index) => ({ length: data.length, offset: ROW_HEIGHT * index, index });
|
||||
const keyExtractor = item => item.rid;
|
||||
const getItemLayout = (data: any, index: number) => ({ length: data.length, offset: ROW_HEIGHT * index, index });
|
||||
const keyExtractor = (item: IChat) => item.rid;
|
||||
|
||||
class ShareListView extends React.Component {
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object,
|
||||
server: PropTypes.string,
|
||||
token: PropTypes.string,
|
||||
userId: PropTypes.string,
|
||||
theme: PropTypes.string
|
||||
};
|
||||
class ShareListView extends React.Component<IShareListViewProps, IState> {
|
||||
private unsubscribeFocus: (() => void) | undefined;
|
||||
|
||||
constructor(props) {
|
||||
private unsubscribeBlur: (() => void) | undefined;
|
||||
|
||||
constructor(props: IShareListViewProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
searching: false,
|
||||
|
@ -53,7 +104,7 @@ class ShareListView extends React.Component {
|
|||
attachments: [],
|
||||
text: '',
|
||||
loading: true,
|
||||
serverInfo: null,
|
||||
serverInfo: {} as IServerInfo,
|
||||
needsPermission: isAndroid || false
|
||||
};
|
||||
this.setHeader();
|
||||
|
@ -70,7 +121,7 @@ class ShareListView extends React.Component {
|
|||
async componentDidMount() {
|
||||
const { server } = this.props;
|
||||
try {
|
||||
const data = await ShareExtension.data();
|
||||
const data = (await ShareExtension.data()) as IFile[];
|
||||
if (isAndroid) {
|
||||
await this.askForPermission(data);
|
||||
}
|
||||
|
@ -85,7 +136,7 @@ class ShareListView extends React.Component {
|
|||
size: file.size,
|
||||
mime: mime.lookup(file.uri),
|
||||
path: file.uri
|
||||
}));
|
||||
})) as IAttachment[];
|
||||
const text = data.filter(item => item.type === 'text').reduce((acc, item) => `${item.value}\n${acc}`, '');
|
||||
this.setState({
|
||||
text,
|
||||
|
@ -98,14 +149,14 @@ class ShareListView extends React.Component {
|
|||
this.getSubscriptions(server);
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
UNSAFE_componentWillReceiveProps(nextProps: IShareListViewProps) {
|
||||
const { server } = this.props;
|
||||
if (nextProps.server !== server) {
|
||||
this.getSubscriptions(nextProps.server);
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
shouldComponentUpdate(nextProps: IShareListViewProps, nextState: IState) {
|
||||
const { searching, needsPermission } = this.state;
|
||||
if (nextState.searching !== searching) {
|
||||
return true;
|
||||
|
@ -151,7 +202,7 @@ class ShareListView extends React.Component {
|
|||
searching={searching}
|
||||
initSearch={this.initSearch}
|
||||
cancelSearch={this.cancelSearch}
|
||||
search={this.search}
|
||||
onChangeSearchText={this.search}
|
||||
theme={theme}
|
||||
/>
|
||||
)
|
||||
|
@ -168,7 +219,7 @@ class ShareListView extends React.Component {
|
|||
) : (
|
||||
<HeaderButton.CancelModal onPress={ShareExtension.close} testID='share-extension-close' />
|
||||
),
|
||||
headerTitle: () => <ShareListHeader searching={searching} search={this.search} theme={theme} />,
|
||||
headerTitle: () => <ShareListHeader searching={searching} onChangeSearchText={this.search} theme={theme} />,
|
||||
headerRight: () =>
|
||||
searching ? null : (
|
||||
<HeaderButton.Container>
|
||||
|
@ -178,16 +229,16 @@ class ShareListView extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
internalSetState = (...args) => {
|
||||
internalSetState = (...args: object[]) => {
|
||||
const { navigation } = this.props;
|
||||
if (navigation.isFocused()) {
|
||||
animateNextTransition();
|
||||
}
|
||||
// @ts-ignore
|
||||
this.setState(...args);
|
||||
};
|
||||
|
||||
query = async text => {
|
||||
query = async (text?: string) => {
|
||||
const db = database.active;
|
||||
const defaultWhereClause = [
|
||||
Q.where('archived', false),
|
||||
|
@ -195,15 +246,16 @@ class ShareListView extends React.Component {
|
|||
Q.experimentalSkip(0),
|
||||
Q.experimentalTake(20),
|
||||
Q.experimentalSortBy('room_updated_at', Q.desc)
|
||||
];
|
||||
] as (Q.WhereDescription | Q.Skip | Q.Take | Q.SortBy | Q.Or)[];
|
||||
if (text) {
|
||||
const likeString = sanitizeLikeString(text);
|
||||
defaultWhereClause.push(Q.or(Q.where('name', Q.like(`%${likeString}%`)), Q.where('fname', Q.like(`%${likeString}%`))));
|
||||
}
|
||||
const data = await db
|
||||
const data = (await db
|
||||
.get('subscriptions')
|
||||
.query(...defaultWhereClause)
|
||||
.fetch();
|
||||
.fetch()) as IChat[];
|
||||
|
||||
return data.map(item => ({
|
||||
rid: item.rid,
|
||||
t: item.t,
|
||||
|
@ -218,7 +270,7 @@ class ShareListView extends React.Component {
|
|||
}));
|
||||
};
|
||||
|
||||
getSubscriptions = async server => {
|
||||
getSubscriptions = async (server: string) => {
|
||||
const serversDB = database.servers;
|
||||
|
||||
if (server) {
|
||||
|
@ -242,7 +294,7 @@ class ShareListView extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
askForPermission = async data => {
|
||||
askForPermission = async (data: IFile[]) => {
|
||||
const mediaIndex = data.findIndex(item => item.type === 'media');
|
||||
if (mediaIndex !== -1) {
|
||||
const result = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE, permission);
|
||||
|
@ -255,15 +307,14 @@ class ShareListView extends React.Component {
|
|||
return Promise.resolve();
|
||||
};
|
||||
|
||||
uriToPath = uri => decodeURIComponent(isIOS ? uri.replace(/^file:\/\//, '') : uri);
|
||||
uriToPath = (uri: string) => decodeURIComponent(isIOS ? uri.replace(/^file:\/\//, '') : uri);
|
||||
|
||||
getRoomTitle = item => {
|
||||
getRoomTitle = (item: IChat) => {
|
||||
const { serverInfo } = this.state;
|
||||
const { useRealName } = serverInfo;
|
||||
return ((item.prid || useRealName) && item.fname) || item.name;
|
||||
return ((item.prid || serverInfo?.useRealName) && item.fname) || item.name;
|
||||
};
|
||||
|
||||
shareMessage = room => {
|
||||
shareMessage = (room: IChat) => {
|
||||
const { attachments, text, serverInfo } = this.state;
|
||||
const { navigation } = this.props;
|
||||
|
||||
|
@ -276,7 +327,7 @@ class ShareListView extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
search = async text => {
|
||||
search = async (text: string) => {
|
||||
const result = await this.query(text);
|
||||
this.internalSetState({
|
||||
searchResults: result,
|
||||
|
@ -303,7 +354,7 @@ class ShareListView extends React.Component {
|
|||
return false;
|
||||
};
|
||||
|
||||
renderSectionHeader = header => {
|
||||
renderSectionHeader = (header: string) => {
|
||||
const { searching } = this.state;
|
||||
const { theme } = this.props;
|
||||
if (searching) {
|
||||
|
@ -320,10 +371,9 @@ class ShareListView extends React.Component {
|
|||
);
|
||||
};
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
renderItem = ({ item }: { item: IChat }) => {
|
||||
const { serverInfo } = this.state;
|
||||
const { useRealName } = serverInfo;
|
||||
const { userId, token, server, theme } = this.props;
|
||||
const { theme } = this.props;
|
||||
let description;
|
||||
switch (item.t) {
|
||||
case 'c':
|
||||
|
@ -333,7 +383,7 @@ class ShareListView extends React.Component {
|
|||
description = item.topic || item.description;
|
||||
break;
|
||||
case 'd':
|
||||
description = useRealName ? item.name : item.fname;
|
||||
description = serverInfo?.useRealName ? item.name : item.fname;
|
||||
break;
|
||||
default:
|
||||
description = item.fname;
|
||||
|
@ -341,12 +391,7 @@ class ShareListView extends React.Component {
|
|||
}
|
||||
return (
|
||||
<DirectoryItem
|
||||
user={{
|
||||
id: userId,
|
||||
token
|
||||
}}
|
||||
title={this.getRoomTitle(item)}
|
||||
baseUrl={server}
|
||||
avatar={RocketChat.getRoomAvatar(item)}
|
||||
description={description}
|
||||
type={item.prid ? 'discussion' : item.t}
|
||||
|
@ -439,7 +484,7 @@ class ShareListView extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
const mapStateToProps = ({ share }) => ({
|
||||
const mapStateToProps = ({ share }: any) => ({
|
||||
userId: share.user && share.user.id,
|
||||
token: share.user && share.user.token,
|
||||
server: share.server.server
|
|
@ -25,7 +25,7 @@ const Item = React.memo(({ left, right, text, onPress, testID, current, theme }:
|
|||
style={[styles.item, current && { backgroundColor: themes[theme].borderColor }]}>
|
||||
<View style={styles.itemHorizontal}>{left}</View>
|
||||
<View style={styles.itemCenter}>
|
||||
<Text style={[styles.itemText, { color: themes[theme].titleText }]} numberOfLines={1}>
|
||||
<Text style={[styles.itemText, { color: themes[theme].titleText }]} numberOfLines={1} accessibilityLabel={text}>
|
||||
{text}
|
||||
</Text>
|
||||
</View>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import { FlatList, StyleSheet } from 'react-native';
|
||||
import { Dispatch } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import I18n from '../i18n';
|
||||
|
@ -53,23 +54,29 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
class StatusView extends React.Component {
|
||||
static propTypes = {
|
||||
user: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
status: PropTypes.string,
|
||||
statusText: PropTypes.string
|
||||
}),
|
||||
theme: PropTypes.string,
|
||||
navigation: PropTypes.object,
|
||||
isMasterDetail: PropTypes.bool,
|
||||
setUser: PropTypes.func,
|
||||
Accounts_AllowInvisibleStatusOption: PropTypes.bool
|
||||
};
|
||||
interface IUser {
|
||||
id: string;
|
||||
status: string;
|
||||
statusText: string;
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
interface IStatusViewState {
|
||||
statusText: string;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
interface IStatusViewProps {
|
||||
navigation: StackNavigationProp<any, 'StatusView'>;
|
||||
user: IUser;
|
||||
theme: string;
|
||||
isMasterDetail: boolean;
|
||||
setUser: (user: Partial<IUser>) => void;
|
||||
Accounts_AllowInvisibleStatusOption: boolean;
|
||||
}
|
||||
|
||||
class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
||||
constructor(props: IStatusViewProps) {
|
||||
super(props);
|
||||
|
||||
const { statusText } = props.user;
|
||||
this.state = { statusText: statusText || '', loading: false };
|
||||
this.setHeader();
|
||||
|
@ -103,7 +110,7 @@ class StatusView extends React.Component {
|
|||
navigation.goBack();
|
||||
};
|
||||
|
||||
setCustomStatus = async statusText => {
|
||||
setCustomStatus = async (statusText: string) => {
|
||||
const { user, setUser } = this.props;
|
||||
|
||||
this.setState({ loading: true });
|
||||
|
@ -147,7 +154,7 @@ class StatusView extends React.Component {
|
|||
);
|
||||
};
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
renderItem = ({ item }: { item: { id: string; name: string } }) => {
|
||||
const { statusText } = this.state;
|
||||
const { user, setUser } = this.props;
|
||||
const { id, name } = item;
|
||||
|
@ -155,6 +162,7 @@ class StatusView extends React.Component {
|
|||
<List.Item
|
||||
title={name}
|
||||
onPress={async () => {
|
||||
// @ts-ignore
|
||||
logEvent(events[`STATUS_${item.id.toUpperCase()}`]);
|
||||
if (user.status !== item.id) {
|
||||
try {
|
||||
|
@ -162,7 +170,7 @@ class StatusView extends React.Component {
|
|||
if (result.success) {
|
||||
setUser({ status: item.id });
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
showErrorAlert(I18n.t(e.data.errorType));
|
||||
logEvent(events.SET_STATUS_FAIL);
|
||||
log(e);
|
||||
|
@ -197,14 +205,14 @@ class StatusView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state: any) => ({
|
||||
user: getUserSelector(state),
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
Accounts_AllowInvisibleStatusOption: state.settings.Accounts_AllowInvisibleStatusOption ?? true
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
setUser: user => dispatch(setUserAction(user))
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
setUser: (user: IUser) => dispatch(setUserAction(user))
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(StatusView));
|
|
@ -1,10 +1,11 @@
|
|||
import React from 'react';
|
||||
import { Alert, FlatList, Keyboard } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import { RouteProp } from '@react-navigation/native';
|
||||
import { Dispatch } from 'redux';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { EdgeInsets, withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { connect } from 'react-redux';
|
||||
import { HeaderBackButton } from '@react-navigation/stack';
|
||||
import { HeaderBackButton, StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import RoomHeader from '../containers/RoomHeader';
|
||||
|
@ -38,35 +39,74 @@ const PERMISSION_EDIT_TEAM_CHANNEL = 'edit-team-channel';
|
|||
const PERMISSION_REMOVE_TEAM_CHANNEL = 'remove-team-channel';
|
||||
const PERMISSION_ADD_TEAM_CHANNEL = 'add-team-channel';
|
||||
|
||||
const getItemLayout = (data, index) => ({
|
||||
length: data.length,
|
||||
const getItemLayout = (data: IItem[] | null | undefined, index: number) => ({
|
||||
length: data?.length || 0,
|
||||
offset: ROW_HEIGHT * index,
|
||||
index
|
||||
});
|
||||
const keyExtractor = item => item._id;
|
||||
const keyExtractor = (item: IItem) => item._id;
|
||||
|
||||
class TeamChannelsView extends React.Component {
|
||||
static propTypes = {
|
||||
route: PropTypes.object,
|
||||
navigation: PropTypes.object,
|
||||
isMasterDetail: PropTypes.bool,
|
||||
insets: PropTypes.object,
|
||||
theme: PropTypes.string,
|
||||
useRealName: PropTypes.bool,
|
||||
width: PropTypes.number,
|
||||
StoreLastMessage: PropTypes.bool,
|
||||
addTeamChannelPermission: PropTypes.array,
|
||||
editTeamChannelPermission: PropTypes.array,
|
||||
removeTeamChannelPermission: PropTypes.array,
|
||||
deleteCPermission: PropTypes.array,
|
||||
deletePPermission: PropTypes.array,
|
||||
showActionSheet: PropTypes.func,
|
||||
deleteRoom: PropTypes.func,
|
||||
showAvatar: PropTypes.bool,
|
||||
displayMode: PropTypes.string
|
||||
};
|
||||
// This interface comes from request RocketChat.getTeamListRoom
|
||||
interface IItem {
|
||||
_id: string;
|
||||
fname: string;
|
||||
customFields: object;
|
||||
broadcast: boolean;
|
||||
encrypted: boolean;
|
||||
name: string;
|
||||
t: string;
|
||||
msgs: number;
|
||||
usersCount: number;
|
||||
u: { _id: string; name: string };
|
||||
ts: string;
|
||||
ro: boolean;
|
||||
teamId: string;
|
||||
default: boolean;
|
||||
sysMes: boolean;
|
||||
_updatedAt: string;
|
||||
teamDefault: boolean;
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
interface ITeamChannelsViewState {
|
||||
loading: boolean;
|
||||
loadingMore: boolean;
|
||||
data: IItem[];
|
||||
isSearching: boolean;
|
||||
searchText: string | null;
|
||||
search: IItem[];
|
||||
end: boolean;
|
||||
showCreate: boolean;
|
||||
}
|
||||
|
||||
interface ITeamChannelsViewProps {
|
||||
route: RouteProp<{ TeamChannelsView: { teamId: string } }, 'TeamChannelsView'>;
|
||||
navigation: StackNavigationProp<any, 'TeamChannelsView'>;
|
||||
isMasterDetail: boolean;
|
||||
insets: EdgeInsets;
|
||||
theme: string;
|
||||
useRealName: boolean;
|
||||
width: number;
|
||||
StoreLastMessage: boolean;
|
||||
addTeamChannelPermission: string[];
|
||||
editTeamChannelPermission: string[];
|
||||
removeTeamChannelPermission: string[];
|
||||
deleteCPermission: string[];
|
||||
deletePPermission: string[];
|
||||
showActionSheet: (options: any) => void;
|
||||
deleteRoom: (rid: string, t: string) => void;
|
||||
showAvatar: boolean;
|
||||
displayMode: string;
|
||||
}
|
||||
class TeamChannelsView extends React.Component<ITeamChannelsViewProps, ITeamChannelsViewState> {
|
||||
private teamId: string;
|
||||
|
||||
// TODO: Refactor when migrate room
|
||||
private teamChannels: any;
|
||||
|
||||
// TODO: Refactor when migrate room
|
||||
private team: any;
|
||||
|
||||
constructor(props: ITeamChannelsViewProps) {
|
||||
super(props);
|
||||
this.teamId = props.route.params?.teamId;
|
||||
this.state = {
|
||||
|
@ -95,7 +135,7 @@ class TeamChannelsView extends React.Component {
|
|||
try {
|
||||
const subCollection = db.get('subscriptions');
|
||||
this.teamChannels = await subCollection.query(Q.where('team_id', Q.eq(this.teamId)));
|
||||
this.team = this.teamChannels?.find(channel => channel.teamMain);
|
||||
this.team = this.teamChannels?.find((channel: any) => channel.teamMain);
|
||||
this.setHeader();
|
||||
|
||||
if (!this.team) {
|
||||
|
@ -140,7 +180,7 @@ class TeamChannelsView extends React.Component {
|
|||
loading: false,
|
||||
loadingMore: false,
|
||||
end: result.rooms.length < API_FETCH_COUNT
|
||||
};
|
||||
} as ITeamChannelsViewState;
|
||||
|
||||
if (isSearching) {
|
||||
newState.search = [...search, ...result.rooms];
|
||||
|
@ -170,7 +210,7 @@ class TeamChannelsView extends React.Component {
|
|||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: 2 });
|
||||
|
||||
if (isSearching) {
|
||||
const options = {
|
||||
const options: StackNavigationOptions = {
|
||||
headerTitleAlign: 'left',
|
||||
headerLeft: () => (
|
||||
<HeaderButton.Container left>
|
||||
|
@ -187,7 +227,7 @@ class TeamChannelsView extends React.Component {
|
|||
return navigation.setOptions(options);
|
||||
}
|
||||
|
||||
const options = {
|
||||
const options: StackNavigationOptions = {
|
||||
headerShown: true,
|
||||
headerTitleAlign: 'left',
|
||||
headerTitleContainerStyle: {
|
||||
|
@ -232,7 +272,7 @@ class TeamChannelsView extends React.Component {
|
|||
this.setState({ isSearching: true }, () => this.setHeader());
|
||||
};
|
||||
|
||||
onSearchChangeText = debounce(searchText => {
|
||||
onSearchChangeText = debounce((searchText: string) => {
|
||||
this.setState(
|
||||
{
|
||||
searchText,
|
||||
|
@ -270,7 +310,7 @@ class TeamChannelsView extends React.Component {
|
|||
);
|
||||
};
|
||||
|
||||
goRoomActionsView = screen => {
|
||||
goRoomActionsView = (screen: string) => {
|
||||
logEvent(events.TC_GO_ACTIONS);
|
||||
const { team } = this;
|
||||
const { navigation, isMasterDetail } = this.props;
|
||||
|
@ -293,12 +333,12 @@ class TeamChannelsView extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
getRoomTitle = item => RocketChat.getRoomTitle(item);
|
||||
getRoomTitle = (item: IItem) => RocketChat.getRoomTitle(item);
|
||||
|
||||
getRoomAvatar = item => RocketChat.getRoomAvatar(item);
|
||||
getRoomAvatar = (item: IItem) => RocketChat.getRoomAvatar(item);
|
||||
|
||||
onPressItem = debounce(
|
||||
async item => {
|
||||
async (item: IItem) => {
|
||||
logEvent(events.TC_GO_ROOM);
|
||||
const { navigation, isMasterDetail } = this.props;
|
||||
try {
|
||||
|
@ -314,7 +354,7 @@ class TeamChannelsView extends React.Component {
|
|||
navigation.pop();
|
||||
}
|
||||
goRoom({ item: params, isMasterDetail, navigationMethod: navigation.push });
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
if (e.data.error === 'not-allowed') {
|
||||
showErrorAlert(I18n.t('error-not-allowed'));
|
||||
} else {
|
||||
|
@ -326,7 +366,7 @@ class TeamChannelsView extends React.Component {
|
|||
true
|
||||
);
|
||||
|
||||
toggleAutoJoin = async item => {
|
||||
toggleAutoJoin = async (item: IItem) => {
|
||||
logEvent(events.TC_TOGGLE_AUTOJOIN);
|
||||
try {
|
||||
const { data } = this.state;
|
||||
|
@ -346,7 +386,7 @@ class TeamChannelsView extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
remove = item => {
|
||||
remove = (item: IItem) => {
|
||||
Alert.alert(
|
||||
I18n.t('Confirmation'),
|
||||
I18n.t('Remove_Team_Room_Warning'),
|
||||
|
@ -365,7 +405,7 @@ class TeamChannelsView extends React.Component {
|
|||
);
|
||||
};
|
||||
|
||||
removeRoom = async item => {
|
||||
removeRoom = async (item: IItem) => {
|
||||
logEvent(events.TC_DELETE_ROOM);
|
||||
try {
|
||||
const { data } = this.state;
|
||||
|
@ -380,7 +420,7 @@ class TeamChannelsView extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
delete = item => {
|
||||
delete = (item: IItem) => {
|
||||
logEvent(events.TC_DELETE_ROOM);
|
||||
const { deleteRoom } = this.props;
|
||||
|
||||
|
@ -402,7 +442,7 @@ class TeamChannelsView extends React.Component {
|
|||
);
|
||||
};
|
||||
|
||||
showChannelActions = async item => {
|
||||
showChannelActions = async (item: IItem) => {
|
||||
logEvent(events.ROOM_SHOW_BOX_ACTIONS);
|
||||
const {
|
||||
showActionSheet,
|
||||
|
@ -464,7 +504,7 @@ class TeamChannelsView extends React.Component {
|
|||
showActionSheet({ options });
|
||||
};
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
renderItem = ({ item }: { item: IItem }) => {
|
||||
const { StoreLastMessage, useRealName, theme, width, showAvatar, displayMode } = this.props;
|
||||
return (
|
||||
<RoomItem
|
||||
|
@ -534,7 +574,7 @@ class TeamChannelsView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state: any) => ({
|
||||
baseUrl: state.server.server,
|
||||
user: getUserSelector(state),
|
||||
useRealName: state.settings.UI_Use_Real_Name,
|
||||
|
@ -549,8 +589,8 @@ const mapStateToProps = state => ({
|
|||
displayMode: state.sortPreferences.displayMode
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
deleteRoom: (rid, t) => dispatch(deleteRoomAction(rid, t))
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
deleteRoom: (rid: string, t: string) => dispatch(deleteRoomAction(rid, t))
|
||||
});
|
||||
|
||||
export default connect(
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StackNavigationOptions } from '@react-navigation/stack';
|
||||
|
||||
import I18n from '../i18n';
|
||||
import { withTheme } from '../theme';
|
||||
|
@ -51,18 +51,29 @@ if (supportSystemTheme()) {
|
|||
const themeGroup = THEMES.filter(item => item.group === THEME_GROUP);
|
||||
const darkGroup = THEMES.filter(item => item.group === DARK_GROUP);
|
||||
|
||||
class ThemeView extends React.Component {
|
||||
static navigationOptions = () => ({
|
||||
interface ITheme {
|
||||
label: string;
|
||||
value: string;
|
||||
group: string;
|
||||
}
|
||||
|
||||
interface IThemePreference {
|
||||
currentTheme?: string;
|
||||
darkLevel?: string;
|
||||
}
|
||||
|
||||
interface IThemeViewProps {
|
||||
theme: string;
|
||||
themePreferences: IThemePreference;
|
||||
setTheme(newTheme?: IThemePreference): void;
|
||||
}
|
||||
|
||||
class ThemeView extends React.Component<IThemeViewProps> {
|
||||
static navigationOptions = (): StackNavigationOptions => ({
|
||||
title: I18n.t('Theme')
|
||||
});
|
||||
|
||||
static propTypes = {
|
||||
theme: PropTypes.string,
|
||||
themePreferences: PropTypes.object,
|
||||
setTheme: PropTypes.func
|
||||
};
|
||||
|
||||
isSelected = item => {
|
||||
isSelected = (item: ITheme) => {
|
||||
const { themePreferences } = this.props;
|
||||
const { group } = item;
|
||||
const { darkLevel, currentTheme } = themePreferences;
|
||||
|
@ -74,11 +85,11 @@ class ThemeView extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
onClick = item => {
|
||||
onClick = (item: ITheme) => {
|
||||
const { themePreferences } = this.props;
|
||||
const { darkLevel, currentTheme } = themePreferences;
|
||||
const { value, group } = item;
|
||||
let changes = {};
|
||||
let changes: IThemePreference = {};
|
||||
if (group === THEME_GROUP && currentTheme !== value) {
|
||||
logEvent(events.THEME_SET_THEME_GROUP, { theme_group: value });
|
||||
changes = { currentTheme: value };
|
||||
|
@ -90,7 +101,7 @@ class ThemeView extends React.Component {
|
|||
this.setTheme(changes);
|
||||
};
|
||||
|
||||
setTheme = async theme => {
|
||||
setTheme = async (theme: IThemePreference) => {
|
||||
const { setTheme, themePreferences } = this.props;
|
||||
const newTheme = { ...themePreferences, ...theme };
|
||||
setTheme(newTheme);
|
||||
|
@ -102,7 +113,7 @@ class ThemeView extends React.Component {
|
|||
return <List.Icon name='check' color={themes[theme].tintColor} />;
|
||||
};
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
renderItem = ({ item }: { item: ITheme }) => {
|
||||
const { label, value } = item;
|
||||
return (
|
||||
<>
|
|
@ -1,10 +1,33 @@
|
|||
const { exec } = require('child_process');
|
||||
const data = require('../data');
|
||||
|
||||
const platformTypes = {
|
||||
android: {
|
||||
// Android types
|
||||
alertButtonType: 'android.widget.Button',
|
||||
scrollViewType: 'android.widget.ScrollView',
|
||||
textInputType: 'android.widget.EditText',
|
||||
textMatcher: 'text'
|
||||
},
|
||||
ios: {
|
||||
// iOS types
|
||||
alertButtonType: '_UIAlertControllerActionView',
|
||||
scrollViewType: 'UIScrollView',
|
||||
textInputType: '_UIAlertControllerTextField',
|
||||
textMatcher: 'label'
|
||||
}
|
||||
};
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(res => setTimeout(res, ms));
|
||||
}
|
||||
|
||||
async function navigateToWorkspace(server = data.server) {
|
||||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(60000);
|
||||
await element(by.id('new-server-view-input')).typeText(`${server}\n`);
|
||||
await element(by.id('new-server-view-input')).replaceText(`${server}`);
|
||||
await element(by.id('new-server-view-input')).tapReturnKey();
|
||||
await waitFor(element(by.id('workspace-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(60000);
|
||||
|
@ -41,6 +64,8 @@ async function login(username, password) {
|
|||
}
|
||||
|
||||
async function logout() {
|
||||
const deviceType = device.getPlatform();
|
||||
const { scrollViewType, textMatcher } = platformTypes[deviceType];
|
||||
await element(by.id('rooms-list-view-sidebar')).tap();
|
||||
await waitFor(element(by.id('sidebar-view')))
|
||||
.toBeVisible()
|
||||
|
@ -52,14 +77,14 @@ async function logout() {
|
|||
await waitFor(element(by.id('settings-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await element(by.type('UIScrollView')).atIndex(1).scrollTo('bottom');
|
||||
await element(by.type(scrollViewType)).atIndex(1).scrollTo('bottom');
|
||||
await element(by.id('settings-logout')).tap();
|
||||
const logoutAlertMessage = 'You will be logged out of this application.';
|
||||
await waitFor(element(by.text(logoutAlertMessage)).atIndex(0))
|
||||
await waitFor(element(by[textMatcher](logoutAlertMessage)).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await expect(element(by.text(logoutAlertMessage)).atIndex(0)).toExist();
|
||||
await element(by.text('Logout')).tap();
|
||||
await expect(element(by[textMatcher](logoutAlertMessage)).atIndex(0)).toExist();
|
||||
await element(by[textMatcher]('Logout')).atIndex(0).tap();
|
||||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(10000);
|
||||
|
@ -67,66 +92,73 @@ async function logout() {
|
|||
}
|
||||
|
||||
async function mockMessage(message, isThread = false) {
|
||||
const deviceType = device.getPlatform();
|
||||
const { textMatcher } = platformTypes[deviceType];
|
||||
const input = isThread ? 'messagebox-input-thread' : 'messagebox-input';
|
||||
await element(by.id(input)).tap();
|
||||
await element(by.id(input)).typeText(`${data.random}${message}`);
|
||||
await element(by.id(input)).replaceText(`${data.random}${message}`);
|
||||
await sleep(300);
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
await waitFor(element(by.label(`${data.random}${message}`)))
|
||||
await waitFor(element(by[textMatcher](`${data.random}${message}`)))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await expect(element(by.label(`${data.random}${message}`))).toExist();
|
||||
await element(by.label(`${data.random}${message}`))
|
||||
await element(by[textMatcher](`${data.random}${message}`))
|
||||
.atIndex(0)
|
||||
.tap();
|
||||
}
|
||||
|
||||
async function starMessage(message) {
|
||||
const deviceType = device.getPlatform();
|
||||
const { textMatcher } = platformTypes[deviceType];
|
||||
const messageLabel = `${data.random}${message}`;
|
||||
await element(by.label(messageLabel)).atIndex(0).longPress();
|
||||
await element(by[textMatcher](messageLabel)).atIndex(0).longPress();
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
|
||||
await element(by.label('Star')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('Star')).atIndex(0).tap();
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
.not.toExist()
|
||||
.withTimeout(5000);
|
||||
}
|
||||
|
||||
async function pinMessage(message) {
|
||||
const deviceType = device.getPlatform();
|
||||
const { textMatcher } = platformTypes[deviceType];
|
||||
const messageLabel = `${data.random}${message}`;
|
||||
await waitFor(element(by.label(messageLabel)).atIndex(0)).toExist();
|
||||
await element(by.label(messageLabel)).atIndex(0).longPress();
|
||||
await waitFor(element(by[textMatcher](messageLabel)).atIndex(0)).toExist();
|
||||
await element(by[textMatcher](messageLabel)).atIndex(0).longPress();
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
|
||||
await element(by.label('Pin')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('Pin')).atIndex(0).tap();
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
.not.toExist()
|
||||
.withTimeout(5000);
|
||||
}
|
||||
|
||||
async function dismissReviewNag() {
|
||||
await waitFor(element(by.text('Are you enjoying this app?')))
|
||||
const deviceType = device.getPlatform();
|
||||
const { textMatcher } = platformTypes[deviceType];
|
||||
await waitFor(element(by[textMatcher]('Are you enjoying this app?')))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await element(by.label('No').and(by.type('_UIAlertControllerActionView'))).tap(); // Tap `no` on ask for review alert
|
||||
await element(by[textMatcher]('No')).atIndex(0).tap(); // Tap `no` on ask for review alert
|
||||
}
|
||||
|
||||
async function tapBack() {
|
||||
await element(by.id('header-back')).atIndex(0).tap();
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(res => setTimeout(res, ms));
|
||||
}
|
||||
|
||||
async function searchRoom(room) {
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(30000);
|
||||
await element(by.id('rooms-list-view-search')).tap();
|
||||
await expect(element(by.id('rooms-list-view-search-input'))).toExist();
|
||||
await waitFor(element(by.id('rooms-list-view-search-input')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('rooms-list-view-search-input')).typeText(room);
|
||||
await sleep(300);
|
||||
await element(by.id('rooms-list-view-search-input')).replaceText(room);
|
||||
await sleep(300);
|
||||
await waitFor(element(by.id(`rooms-list-view-item-${room}`)))
|
||||
.toBeVisible()
|
||||
|
@ -162,6 +194,29 @@ const checkServer = async server => {
|
|||
await element(by.id('sidebar-close-drawer')).tap();
|
||||
};
|
||||
|
||||
function runCommand(command) {
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(command, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(new Error(`exec error: ${stderr}`));
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function prepareAndroid() {
|
||||
if (device.getPlatform() !== 'android') {
|
||||
return;
|
||||
}
|
||||
await runCommand('adb shell settings put secure spell_checker_enabled 0');
|
||||
await runCommand('adb shell settings put secure autofill_service null');
|
||||
await runCommand('adb shell settings put global window_animation_scale 0.0');
|
||||
await runCommand('adb shell settings put global transition_animation_scale 0.0');
|
||||
await runCommand('adb shell settings put global animator_duration_scale 0.0');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
navigateToWorkspace,
|
||||
navigateToLogin,
|
||||
|
@ -176,5 +231,7 @@ module.exports = {
|
|||
sleep,
|
||||
searchRoom,
|
||||
tryTapping,
|
||||
checkServer
|
||||
checkServer,
|
||||
platformTypes,
|
||||
prepareAndroid
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const { navigateToLogin, login, sleep, tapBack, mockMessage, searchRoom, logout } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, sleep, tapBack, mockMessage, searchRoom, logout, platformTypes } = require('../../helpers/app');
|
||||
|
||||
const data = require('../../data');
|
||||
|
||||
const testuser = data.users.regular;
|
||||
|
@ -17,8 +18,9 @@ const checkServer = async server => {
|
|||
};
|
||||
|
||||
const checkBanner = async () => {
|
||||
await waitFor(element(by.id('listheader-encryption').withDescendant(by.label('Save Your Encryption Password'))))
|
||||
.toBeVisible()
|
||||
// TODO: Assert 'Save Your Encryption Password'
|
||||
await waitFor(element(by.id('listheader-encryption')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
};
|
||||
|
||||
|
@ -58,9 +60,13 @@ async function navigateSecurityPrivacy() {
|
|||
describe('E2E Encryption', () => {
|
||||
const room = `encrypted${data.random}`;
|
||||
const newPassword = 'abc';
|
||||
let alertButtonType;
|
||||
let scrollViewType;
|
||||
let textMatcher;
|
||||
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, scrollViewType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(testuser.username, testuser.password);
|
||||
});
|
||||
|
@ -187,11 +193,11 @@ describe('E2E Encryption', () => {
|
|||
it('should change password', async () => {
|
||||
await element(by.id('e2e-encryption-security-view-password')).typeText(newPassword);
|
||||
await element(by.id('e2e-encryption-security-view-change-password')).tap();
|
||||
await waitFor(element(by.text('Are you sure?')))
|
||||
await waitFor(element(by[textMatcher]('Are you sure?')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.text("Make sure you've saved it carefully somewhere else."))).toExist();
|
||||
await element(by.label('Yes, change it').and(by.type('_UIAlertControllerActionView'))).tap();
|
||||
await expect(element(by[textMatcher]("Make sure you've saved it carefully somewhere else."))).toExist();
|
||||
await element(by[textMatcher]('Yes, change it')).atIndex(0).tap();
|
||||
await waitForToast();
|
||||
});
|
||||
|
||||
|
@ -216,7 +222,7 @@ describe('E2E Encryption', () => {
|
|||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await navigateToRoom(room);
|
||||
await waitFor(element(by.label(`${data.random}message`)).atIndex(0))
|
||||
await waitFor(element(by[textMatcher](`${data.random}message`)).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
});
|
||||
|
@ -230,7 +236,7 @@ describe('E2E Encryption', () => {
|
|||
await navigateToLogin();
|
||||
await login(testuser.username, testuser.password);
|
||||
await navigateToRoom(room);
|
||||
await waitFor(element(by.label(`${data.random}message`)).atIndex(0))
|
||||
await waitFor(element(by[textMatcher](`${data.random}message`)).atIndex(0))
|
||||
.not.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.label('Encrypted message')).atIndex(0)).toExist();
|
||||
|
@ -241,10 +247,11 @@ describe('E2E Encryption', () => {
|
|||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await waitFor(element(by.id('listheader-encryption').withDescendant(by.label('Enter Your E2E Password'))))
|
||||
// TODO: assert 'Enter Your E2E Password'
|
||||
await waitFor(element(by.id('listheader-encryption')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('listheader-encryption').withDescendant(by.label('Enter Your E2E Password'))).tap();
|
||||
await element(by.id('listheader-encryption')).tap();
|
||||
await waitFor(element(by.id('e2e-enter-your-password-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
|
@ -254,43 +261,52 @@ describe('E2E Encryption', () => {
|
|||
.not.toExist()
|
||||
.withTimeout(10000);
|
||||
await navigateToRoom(room);
|
||||
await waitFor(element(by.label(`${data.random}message`)).atIndex(0))
|
||||
await waitFor(element(by[textMatcher](`${data.random}message`)).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Reset E2E key', () => {
|
||||
it('should reset e2e key', async () => {
|
||||
before(async () => {
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
});
|
||||
it('should reset e2e key', async () => {
|
||||
// FIXME: too flaky on Android for now... let's fix it later
|
||||
// It's also flaky on iOS, but it works from time to time
|
||||
if (device.getPlatform() === 'android') {
|
||||
return;
|
||||
}
|
||||
await navigateSecurityPrivacy();
|
||||
await element(by.id('security-privacy-view-e2e-encryption')).tap();
|
||||
await waitFor(element(by.id('e2e-encryption-security-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('e2e-encryption-security-view-reset-key').and(by.label('Reset E2E Key'))).tap();
|
||||
await waitFor(element(by.text('Are you sure?')))
|
||||
await waitFor(element(by[textMatcher]('Are you sure?')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.text("You're going to be logged out."))).toExist();
|
||||
await element(by.label('Yes, reset it').and(by.type('UILabel'))).tap();
|
||||
await expect(element(by[textMatcher]("You're going to be logged out."))).toExist();
|
||||
await element(by[textMatcher]('Yes, reset it').and(by.type(alertButtonType))).tap();
|
||||
await sleep(2000);
|
||||
|
||||
await waitFor(element(by[textMatcher]("You've been logged out by the server. Please log in again.")))
|
||||
.toExist()
|
||||
.withTimeout(20000);
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('workspace-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(10000);
|
||||
await waitFor(element(by.text("You've been logged out by the server. Please log in again.")))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.label('OK').and(by.type('_UIAlertControllerActionView'))).tap();
|
||||
await element(by.id('workspace-view-login')).tap();
|
||||
await waitFor(element(by.id('login-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await login(testuser.username, testuser.password);
|
||||
await waitFor(element(by.id('listheader-encryption').withDescendant(by.label('Save Your Encryption Password'))))
|
||||
// TODO: assert 'Save Your Encryption Password'
|
||||
await waitFor(element(by.id('listheader-encryption')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
});
|
||||
|
@ -298,6 +314,14 @@ describe('E2E Encryption', () => {
|
|||
});
|
||||
|
||||
describe('Persist Banner', () => {
|
||||
before(async () => {
|
||||
// reinstall the app because of one flaky test above
|
||||
if (device.getPlatform() === 'android') {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
await navigateToLogin();
|
||||
await login(testuser.username, testuser.password);
|
||||
}
|
||||
});
|
||||
it('check save banner', async () => {
|
||||
await checkServer(data.server);
|
||||
await checkBanner();
|
||||
|
@ -315,7 +339,8 @@ describe('E2E Encryption', () => {
|
|||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(60000);
|
||||
await element(by.id('new-server-view-input')).typeText(`${data.alternateServer}\n`);
|
||||
await element(by.id('new-server-view-input')).typeText(`${data.alternateServer}`);
|
||||
await element(by.id('new-server-view-input')).tapReturnKey();
|
||||
await waitFor(element(by.id('workspace-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(60000);
|
||||
|
@ -328,7 +353,7 @@ describe('E2E Encryption', () => {
|
|||
await element(by.id('register-view-name')).replaceText(data.registeringUser.username);
|
||||
await element(by.id('register-view-username')).replaceText(data.registeringUser.username);
|
||||
await element(by.id('register-view-email')).replaceText(data.registeringUser.email);
|
||||
await element(by.id('register-view-password')).typeText(data.registeringUser.password);
|
||||
await element(by.id('register-view-password')).replaceText(data.registeringUser.password);
|
||||
await element(by.id('register-view-submit')).tap();
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
// const OTP = require('otp.js');
|
||||
// const GA = OTP.googleAuthenticator;
|
||||
|
||||
const { navigateToLogin, login, mockMessage, tapBack, searchRoom } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, mockMessage, tapBack, searchRoom, platformTypes } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
|
||||
const testuser = data.users.regular;
|
||||
const otheruser = data.users.alternate;
|
||||
|
||||
describe('Broadcast room', () => {
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(testuser.username, testuser.password);
|
||||
});
|
||||
|
@ -101,7 +103,7 @@ describe('Broadcast room', () => {
|
|||
});
|
||||
|
||||
it('should have the message created earlier', async () => {
|
||||
await waitFor(element(by.label(`${data.random}message`)))
|
||||
await waitFor(element(by[textMatcher](`${data.random}message`)))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { navigateToLogin, login, sleep } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, sleep, platformTypes } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
|
||||
const profileChangeUser = data.users.profileChanges;
|
||||
|
@ -14,8 +14,14 @@ async function waitForToast() {
|
|||
}
|
||||
|
||||
describe('Profile screen', () => {
|
||||
let textInputType;
|
||||
let scrollViewType;
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ textInputType, scrollViewType, alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(profileChangeUser.username, profileChangeUser.password);
|
||||
await element(by.id('rooms-list-view-sidebar')).tap();
|
||||
|
@ -92,8 +98,8 @@ describe('Profile screen', () => {
|
|||
describe('Usage', () => {
|
||||
it('should change name and username', async () => {
|
||||
await element(by.id('profile-view-name')).replaceText(`${profileChangeUser.username}new`);
|
||||
await element(by.id('profile-view-username')).typeText(`${profileChangeUser.username}new`);
|
||||
await element(by.type('UIScrollView')).atIndex(1).swipe('up');
|
||||
await element(by.id('profile-view-username')).replaceText(`${profileChangeUser.username}new`);
|
||||
await element(by.type(scrollViewType)).atIndex(1).swipe('up');
|
||||
await element(by.id('profile-view-submit')).tap();
|
||||
await waitForToast();
|
||||
});
|
||||
|
@ -102,12 +108,13 @@ describe('Profile screen', () => {
|
|||
await element(by.id('profile-view-email')).replaceText(`mobile+profileChangesNew${data.random}@rocket.chat`);
|
||||
await element(by.id('profile-view-new-password')).replaceText(`${profileChangeUser.password}new`);
|
||||
await element(by.id('profile-view-submit')).tap();
|
||||
await element(by.type('_UIAlertControllerTextField')).typeText(`${profileChangeUser.password}\n`);
|
||||
await element(by.type(textInputType)).replaceText(`${profileChangeUser.password}`);
|
||||
await element(by[textMatcher]('Save').and(by.type(alertButtonType))).tap();
|
||||
await waitForToast();
|
||||
});
|
||||
|
||||
it('should reset avatar', async () => {
|
||||
await element(by.type('UIScrollView')).atIndex(1).swipe('up');
|
||||
await element(by.type(scrollViewType)).atIndex(1).swipe('up');
|
||||
await element(by.id('profile-view-reset-avatar')).tap();
|
||||
await waitForToast();
|
||||
});
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
const { navigateToLogin, login } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, platformTypes } = require('../../helpers/app');
|
||||
|
||||
const data = require('../../data');
|
||||
|
||||
const testuser = data.users.regular;
|
||||
|
||||
describe('Settings screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(testuser.username, testuser.password);
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
|
@ -72,10 +76,10 @@ describe('Settings screen', () => {
|
|||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('settings-view-clear-cache')).tap();
|
||||
await waitFor(element(by.text('This will clear all your offline data.')))
|
||||
await waitFor(element(by[textMatcher]('This will clear all your offline data.')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.label('Clear').and(by.type('_UIAlertControllerActionView'))).tap();
|
||||
await element(by[textMatcher]('Clear').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, mockMessage, tapBack, searchRoom } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, mockMessage, tapBack, searchRoom, platformTypes } = require('../../helpers/app');
|
||||
|
||||
const testuser = data.users.regular;
|
||||
const room = data.channels.detoxpublic.name;
|
||||
|
@ -7,21 +7,24 @@ const room = data.channels.detoxpublic.name;
|
|||
async function navigateToRoom() {
|
||||
await searchRoom(room);
|
||||
await element(by.id(`rooms-list-view-item-${room}`)).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toBeVisible()
|
||||
await waitFor(element(by.id('room-view')).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
}
|
||||
|
||||
async function navigateToRoomActions() {
|
||||
await element(by.id('room-header')).tap();
|
||||
await element(by.id(`room-view-title-${room}`)).tap();
|
||||
await waitFor(element(by.id('room-actions-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
}
|
||||
|
||||
describe('Join public room', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(testuser.username, testuser.password);
|
||||
await navigateToRoom();
|
||||
|
@ -32,10 +35,6 @@ describe('Join public room', () => {
|
|||
await expect(element(by.id('room-view'))).toBeVisible();
|
||||
});
|
||||
|
||||
// it('should have messages list', async() => {
|
||||
// await expect(element(by.id('room-view-messages'))).toBeVisible();
|
||||
// });
|
||||
|
||||
// Render - Header
|
||||
describe('Header', () => {
|
||||
it('should have actions button ', async () => {
|
||||
|
@ -75,16 +74,10 @@ describe('Join public room', () => {
|
|||
await expect(element(by.id('room-actions-info'))).toBeVisible();
|
||||
});
|
||||
|
||||
// it('should have voice', async() => {
|
||||
// await expect(element(by.id('room-actions-voice'))).toBeVisible();
|
||||
// });
|
||||
|
||||
// it('should have video', async() => {
|
||||
// await expect(element(by.id('room-actions-video'))).toBeVisible();
|
||||
// });
|
||||
|
||||
it('should have members', async () => {
|
||||
await expect(element(by.id('room-actions-members'))).toBeVisible();
|
||||
await waitFor(element(by.id('room-actions-members')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
});
|
||||
|
||||
it('should have files', async () => {
|
||||
|
@ -147,32 +140,29 @@ describe('Join public room', () => {
|
|||
await navigateToRoomActions();
|
||||
await expect(element(by.id('room-actions-view'))).toBeVisible();
|
||||
await expect(element(by.id('room-actions-info'))).toBeVisible();
|
||||
// await expect(element(by.id('room-actions-voice'))).toBeVisible();
|
||||
// await expect(element(by.id('room-actions-video'))).toBeVisible();
|
||||
await expect(element(by.id('room-actions-members'))).toBeVisible();
|
||||
await expect(element(by.id('room-actions-files'))).toBeVisible();
|
||||
await expect(element(by.id('room-actions-mentioned'))).toBeVisible();
|
||||
await expect(element(by.id('room-actions-starred'))).toBeVisible();
|
||||
await element(by.id('room-actions-scrollview')).swipe('down');
|
||||
await expect(element(by.id('room-actions-share'))).toBeVisible();
|
||||
await expect(element(by.id('room-actions-pinned'))).toBeVisible();
|
||||
await expect(element(by.id('room-actions-notifications'))).toBeVisible();
|
||||
await element(by.id('room-actions-scrollview')).scrollTo('bottom');
|
||||
await expect(element(by.id('room-actions-leave-channel'))).toBeVisible();
|
||||
});
|
||||
|
||||
it('should leave room', async () => {
|
||||
await element(by.id('room-actions-leave-channel')).tap();
|
||||
await waitFor(element(by.text('Yes, leave it!')))
|
||||
await waitFor(element(by[textMatcher]('Yes, leave it!').and(by.type(alertButtonType))))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
await expect(element(by.text('Yes, leave it!'))).toBeVisible();
|
||||
await element(by.text('Yes, leave it!')).tap();
|
||||
await element(by[textMatcher]('Yes, leave it!').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(10000);
|
||||
await waitFor(element(by.id(`rooms-list-view-item-${room}`)))
|
||||
.toBeNotVisible()
|
||||
.withTimeout(60000);
|
||||
.withTimeout(60000); // flaky on Android
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -45,8 +45,9 @@ describe('Status screen', () => {
|
|||
.withTimeout(2000);
|
||||
});
|
||||
|
||||
// TODO: flaky
|
||||
it('should change status text', async () => {
|
||||
await element(by.id('status-view-input')).typeText('status-text-new');
|
||||
await element(by.id('status-view-input')).replaceText('status-text-new');
|
||||
await element(by.id('status-view-submit')).tap();
|
||||
await waitForToast();
|
||||
await waitFor(element(by.label('status-text-new').withAncestor(by.id('sidebar-custom-status'))))
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, checkServer } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, checkServer, platformTypes } = require('../../helpers/app');
|
||||
|
||||
const reopenAndCheckServer = async server => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' } });
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true });
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(10000);
|
||||
|
@ -37,7 +37,8 @@ describe('Change server', () => {
|
|||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(6000);
|
||||
await element(by.id('new-server-view-input')).typeText(`${data.alternateServer}\n`);
|
||||
await element(by.id('new-server-view-input')).replaceText(`${data.alternateServer}`);
|
||||
await element(by.id('new-server-view-input')).tapReturnKey();
|
||||
await waitFor(element(by.id('workspace-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(10000);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, mockMessage, searchRoom } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, mockMessage, searchRoom, sleep } = require('../../helpers/app');
|
||||
|
||||
const testuser = data.users.regular;
|
||||
const room = data.channels.detoxpublicprotected.name;
|
||||
|
@ -9,15 +9,25 @@ async function navigateToRoom() {
|
|||
await searchRoom(room);
|
||||
await element(by.id(`rooms-list-view-item-${room}`)).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toBeVisible()
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
}
|
||||
|
||||
async function openJoinCode() {
|
||||
await element(by.id('room-view-join-button')).tap();
|
||||
await waitFor(element(by.id('join-code')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.id('room-view-join-button')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
let n = 0;
|
||||
while (n < 3) {
|
||||
try {
|
||||
await element(by.id('room-view-join-button')).tap();
|
||||
await waitFor(element(by.id('join-code')))
|
||||
.toBeVisible()
|
||||
.withTimeout(500);
|
||||
} catch (error) {
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe('Join protected room', () => {
|
||||
|
|
|
@ -10,7 +10,7 @@ async function navigateToRoom(search) {
|
|||
.withTimeout(10000);
|
||||
await sleep(300); // app takes some time to animate
|
||||
await element(by.id(`directory-view-item-${search}`)).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
await waitFor(element(by.id('room-view')).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.id(`room-view-title-${search}`)))
|
||||
|
@ -44,20 +44,20 @@ describe('Join room from directory', () => {
|
|||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('directory-view-dropdown')).tap();
|
||||
await element(by.label('Users')).tap();
|
||||
await element(by.label('Search by')).tap();
|
||||
await element(by.label('Users')).atIndex(0).tap();
|
||||
await element(by.label('Search by')).atIndex(0).tap();
|
||||
await navigateToRoom(data.users.alternate.username);
|
||||
});
|
||||
|
||||
it('should search user and navigate', async () => {
|
||||
it('should search team and navigate', async () => {
|
||||
await tapBack();
|
||||
await element(by.id('rooms-list-view-directory')).tap();
|
||||
await waitFor(element(by.id('directory-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('directory-view-dropdown')).tap();
|
||||
await element(by.label('Teams')).tap();
|
||||
await element(by.label('Search by')).tap();
|
||||
await element(by.label('Teams')).atIndex(0).tap();
|
||||
await element(by.label('Search by')).atIndex(0).tap();
|
||||
await navigateToRoom(data.teams.private.name);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
const data = require('../../data');
|
||||
const { sleep, navigateToLogin, login, checkServer } = require('../../helpers/app');
|
||||
const { sleep, navigateToLogin, login, checkServer, platformTypes } = require('../../helpers/app');
|
||||
|
||||
describe('Delete server', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(data.users.regular.username, data.users.regular.password);
|
||||
});
|
||||
|
@ -23,7 +26,8 @@ describe('Delete server', () => {
|
|||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(10000);
|
||||
await element(by.id('new-server-view-input')).typeText(`${data.alternateServer}\n`);
|
||||
await element(by.id('new-server-view-input')).replaceText(`${data.alternateServer}`);
|
||||
await element(by.id('new-server-view-input')).tapReturnKey();
|
||||
await waitFor(element(by.id('workspace-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(10000);
|
||||
|
@ -36,7 +40,7 @@ describe('Delete server', () => {
|
|||
await element(by.id('register-view-name')).replaceText(data.registeringUser3.username);
|
||||
await element(by.id('register-view-username')).replaceText(data.registeringUser3.username);
|
||||
await element(by.id('register-view-email')).replaceText(data.registeringUser3.email);
|
||||
await element(by.id('register-view-password')).typeText(data.registeringUser3.password);
|
||||
await element(by.id('register-view-password')).replaceText(data.registeringUser3.password);
|
||||
await element(by.id('register-view-submit')).tap();
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
|
@ -51,7 +55,7 @@ describe('Delete server', () => {
|
|||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
await element(by.id(`rooms-list-header-server-${data.server}`)).longPress(1500);
|
||||
await element(by.label('Delete').and(by.type('_UIAlertControllerActionView'))).tap();
|
||||
await element(by[textMatcher]('Delete').and(by.type(alertButtonType))).tap();
|
||||
await element(by.id('rooms-list-header-server-dropdown-button')).tap();
|
||||
await waitFor(element(by.id('rooms-list-header-server-dropdown')))
|
||||
.toBeVisible()
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
const data = require('../../data');
|
||||
const { tapBack, checkServer, navigateToRegister } = require('../../helpers/app');
|
||||
const { tapBack, checkServer, navigateToRegister, platformTypes } = require('../../helpers/app');
|
||||
const { get, login, sendMessage } = require('../../helpers/data_setup');
|
||||
|
||||
const DEEPLINK_METHODS = { AUTH: 'auth', ROOM: 'room' };
|
||||
|
||||
let amp = '&';
|
||||
|
||||
const getDeepLink = (method, server, params) => {
|
||||
const deeplink = `rocketchat://${method}?host=${server.replace(/^(http:\/\/|https:\/\/)/, '')}&${params}`;
|
||||
const deeplink = `rocketchat://${method}?host=${server.replace(/^(http:\/\/|https:\/\/)/, '')}${amp}${params}`;
|
||||
console.log(`Deeplinking to: ${deeplink}`);
|
||||
return deeplink;
|
||||
};
|
||||
|
@ -12,11 +15,17 @@ const getDeepLink = (method, server, params) => {
|
|||
describe('Deep linking', () => {
|
||||
let userId;
|
||||
let authToken;
|
||||
let scrollViewType;
|
||||
let threadId;
|
||||
let textMatcher;
|
||||
let alertButtonType;
|
||||
const threadMessage = `to-thread-${data.random}`;
|
||||
before(async () => {
|
||||
const loginResult = await login(data.users.regular.username, data.users.regular.password);
|
||||
({ userId, authToken } = loginResult);
|
||||
const deviceType = device.getPlatform();
|
||||
amp = deviceType === 'android' ? '\\&' : '&';
|
||||
({ scrollViewType, textMatcher, alertButtonType } = platformTypes[deviceType]);
|
||||
// create a thread with api
|
||||
const result = await sendMessage(data.users.regular, data.groups.alternate2.name, threadMessage);
|
||||
threadId = result.message._id;
|
||||
|
@ -28,10 +37,9 @@ describe('Deep linking', () => {
|
|||
await device.launchApp({
|
||||
permissions: { notifications: 'YES' },
|
||||
delete: true,
|
||||
url: getDeepLink(DEEPLINK_METHODS.AUTH, data.server, 'userId=123&token=abc'),
|
||||
sourceApp: 'com.apple.mobilesafari'
|
||||
url: getDeepLink(DEEPLINK_METHODS.AUTH, data.server, `userId=123${amp}token=abc`)
|
||||
});
|
||||
await waitFor(element(by.text("You've been logged out by the server. Please log in again.")))
|
||||
await waitFor(element(by[textMatcher]("You've been logged out by the server. Please log in again.")))
|
||||
.toExist()
|
||||
.withTimeout(10000); // TODO: we need to improve this message
|
||||
});
|
||||
|
@ -43,9 +51,8 @@ describe('Deep linking', () => {
|
|||
url: getDeepLink(
|
||||
DEEPLINK_METHODS.AUTH,
|
||||
data.server,
|
||||
`userId=${userId}&token=${authToken}&path=group/${data.groups.private.name}`
|
||||
),
|
||||
sourceApp: 'com.apple.mobilesafari'
|
||||
`userId=${userId}${amp}token=${authToken}${amp}path=group/${data.groups.private.name}`
|
||||
)
|
||||
});
|
||||
await waitFor(element(by.id(`room-view-title-${data.groups.private.name}`)))
|
||||
.toExist()
|
||||
|
@ -56,7 +63,7 @@ describe('Deep linking', () => {
|
|||
.withTimeout(10000);
|
||||
await checkServer(data.server);
|
||||
await waitFor(element(by.id(`rooms-list-view-item-${data.groups.private.name}`)))
|
||||
.toBeVisible()
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
};
|
||||
|
||||
|
@ -70,7 +77,8 @@ describe('Deep linking', () => {
|
|||
await element(by.id('register-view-name')).replaceText(data.registeringUser4.username);
|
||||
await element(by.id('register-view-username')).replaceText(data.registeringUser4.username);
|
||||
await element(by.id('register-view-email')).replaceText(data.registeringUser4.email);
|
||||
await element(by.id('register-view-password')).typeText(data.registeringUser4.password);
|
||||
await element(by.id('register-view-password')).replaceText(data.registeringUser4.password);
|
||||
await element(by.type(scrollViewType)).atIndex(0).scrollTo('bottom');
|
||||
await element(by.id('register-view-submit')).tap();
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
|
@ -85,8 +93,7 @@ describe('Deep linking', () => {
|
|||
await device.launchApp({
|
||||
permissions: { notifications: 'YES' },
|
||||
newInstance: true,
|
||||
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `path=group/${data.groups.private.name}`),
|
||||
sourceApp: 'com.apple.mobilesafari'
|
||||
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `path=group/${data.groups.private.name}`)
|
||||
});
|
||||
await waitFor(element(by.id(`room-view-title-${data.groups.private.name}`)))
|
||||
.toExist()
|
||||
|
@ -97,8 +104,7 @@ describe('Deep linking', () => {
|
|||
await device.launchApp({
|
||||
permissions: { notifications: 'YES' },
|
||||
newInstance: true,
|
||||
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `path=group/${data.groups.alternate2.name}/thread/${threadId}`),
|
||||
sourceApp: 'com.apple.mobilesafari'
|
||||
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `path=group/${data.groups.alternate2.name}/thread/${threadId}`)
|
||||
});
|
||||
await waitFor(element(by.id(`room-view-title-${threadMessage}`)))
|
||||
.toExist()
|
||||
|
@ -110,8 +116,7 @@ describe('Deep linking', () => {
|
|||
await device.launchApp({
|
||||
permissions: { notifications: 'YES' },
|
||||
newInstance: true,
|
||||
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `rid=${roomResult.data.group._id}`),
|
||||
sourceApp: 'com.apple.mobilesafari'
|
||||
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `rid=${roomResult.data.group._id}`)
|
||||
});
|
||||
await waitFor(element(by.id(`room-view-title-${data.groups.private.name}`)))
|
||||
.toExist()
|
||||
|
@ -135,8 +140,7 @@ describe('Deep linking', () => {
|
|||
await device.launchApp({
|
||||
permissions: { notifications: 'YES' },
|
||||
newInstance: true,
|
||||
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `path=group/${data.groups.private.name}`),
|
||||
sourceApp: 'com.apple.mobilesafari'
|
||||
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `path=group/${data.groups.private.name}`)
|
||||
});
|
||||
await waitFor(element(by.id(`room-view-title-${data.groups.private.name}`)))
|
||||
.toExist()
|
||||
|
@ -147,8 +151,7 @@ describe('Deep linking', () => {
|
|||
await device.launchApp({
|
||||
permissions: { notifications: 'YES' },
|
||||
newInstance: true,
|
||||
url: getDeepLink(DEEPLINK_METHODS.ROOM, 'https://google.com'),
|
||||
sourceApp: 'com.apple.mobilesafari'
|
||||
url: getDeepLink(DEEPLINK_METHODS.ROOM, 'https://google.com')
|
||||
});
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
|
|
|
@ -29,6 +29,9 @@ const navToLanguage = async () => {
|
|||
describe('i18n', () => {
|
||||
describe('OS language', () => {
|
||||
it("OS set to 'en' and proper translate to 'en'", async () => {
|
||||
if (device.getPlatform() === 'android') {
|
||||
return; // FIXME: Passing language with launch parameters doesn't work with Android
|
||||
}
|
||||
await device.launchApp({
|
||||
...defaultLaunchArgs,
|
||||
languageAndLocale: {
|
||||
|
@ -44,6 +47,9 @@ describe('i18n', () => {
|
|||
});
|
||||
|
||||
it("OS set to unavailable language and fallback to 'en'", async () => {
|
||||
if (device.getPlatform() === 'android') {
|
||||
return; // FIXME: Passing language with launch parameters doesn't work with Android
|
||||
}
|
||||
await device.launchApp({
|
||||
...defaultLaunchArgs,
|
||||
languageAndLocale: {
|
||||
|
@ -74,7 +80,7 @@ describe('i18n', () => {
|
|||
|
||||
describe('Rocket.Chat language', () => {
|
||||
before(async () => {
|
||||
await device.launchApp(defaultLaunchArgs);
|
||||
await device.launchApp({ ...defaultLaunchArgs, delete: true });
|
||||
await navigateToLogin();
|
||||
await login(testuser.username, testuser.password);
|
||||
});
|
||||
|
@ -113,7 +119,7 @@ describe('i18n', () => {
|
|||
|
||||
it("should set unsupported language and fallback to 'en'", async () => {
|
||||
await post('users.setPreferences', { data: { language: 'eo' } }); // Set language to Esperanto
|
||||
await device.launchApp(defaultLaunchArgs);
|
||||
await device.launchApp({ ...defaultLaunchArgs, newInstance: true });
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(10000);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { login, navigateToLogin } = require('../../helpers/app');
|
||||
const { login, navigateToLogin, sleep } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
|
||||
const goToDisplayPref = async () => {
|
||||
|
@ -14,7 +14,7 @@ const goToRoomList = async () => {
|
|||
await element(by.id('sidebar-chats')).tap();
|
||||
};
|
||||
|
||||
describe('Rooms list screen', () => {
|
||||
describe('Display prefs', () => {
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true, delete: true });
|
||||
await navigateToLogin();
|
||||
|
@ -89,7 +89,9 @@ describe('Rooms list screen', () => {
|
|||
await expect(element(by.id('display-pref-view-avatar-switch'))).toBeVisible();
|
||||
await element(by.id('display-pref-view-avatar-switch')).tap();
|
||||
await goToRoomList();
|
||||
await expect(element(by.id('avatar'))).not.toBeVisible();
|
||||
await waitFor(element(by.id('avatar').withAncestor(by.id('rooms-list-view-item-general'))))
|
||||
.not.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,9 +3,11 @@ const adapter = require('detox/runners/mocha/adapter');
|
|||
|
||||
const config = require('../../package.json').detox;
|
||||
const { setup } = require('../helpers/data_setup');
|
||||
const { prepareAndroid } = require('../helpers/app');
|
||||
|
||||
before(async () => {
|
||||
await Promise.all([setup(), detox.init(config, { launchApp: false })]);
|
||||
await prepareAndroid(); // Make Android less flaky
|
||||
// await dataSetup()
|
||||
// await detox.init(config, { launchApp: false });
|
||||
// await device.launchApp({ permissions: { notifications: 'YES' } });
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
const data = require('../../data');
|
||||
const { platformTypes } = require('../../helpers/app');
|
||||
|
||||
describe('Onboarding', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(20000);
|
||||
|
@ -19,17 +23,13 @@ describe('Onboarding', () => {
|
|||
});
|
||||
|
||||
describe('Usage', () => {
|
||||
// it('should navigate to create new workspace', async() => {
|
||||
// // webviews are not supported by detox: https://github.com/wix/detox/issues/136#issuecomment-306591554
|
||||
// });
|
||||
|
||||
it('should enter an invalid server and get error', async () => {
|
||||
await element(by.id('new-server-view-input')).typeText('invalidtest\n');
|
||||
const errorText = 'Oops!';
|
||||
await waitFor(element(by.text(errorText)))
|
||||
.toBeVisible()
|
||||
.withTimeout(60000);
|
||||
await element(by.text('OK')).tap();
|
||||
await element(by.id('new-server-view-input')).replaceText('invalidtest');
|
||||
await element(by.id('new-server-view-input')).tapReturnKey();
|
||||
await waitFor(element(by[textMatcher]('Oops!')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
});
|
||||
|
||||
it('should tap on "Join our open workspace" and navigate', async () => {
|
||||
|
@ -44,7 +44,8 @@ describe('Onboarding', () => {
|
|||
await waitFor(element(by.id('new-server-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('new-server-view-input')).typeText(`${data.server}\n`);
|
||||
await element(by.id('new-server-view-input')).replaceText(data.server);
|
||||
await element(by.id('new-server-view-input')).tapReturnKey();
|
||||
await waitFor(element(by.id('workspace-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(60000);
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin } = require('../../helpers/app');
|
||||
const { navigateToLogin, platformTypes } = require('../../helpers/app');
|
||||
|
||||
describe('Forgot password screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await element(by.id('login-view-forgot-password')).tap();
|
||||
await waitFor(element(by.id('forgot-password-view')))
|
||||
|
@ -29,10 +32,10 @@ describe('Forgot password screen', () => {
|
|||
it('should reset password and navigate to login', async () => {
|
||||
await element(by.id('forgot-password-view-email')).replaceText(data.users.existing.email);
|
||||
await element(by.id('forgot-password-view-submit')).tap();
|
||||
await waitFor(element(by.text('OK')))
|
||||
await waitFor(element(by[textMatcher]('OK')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by.text('OK')).tap();
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('login-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(60000);
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
const { navigateToRegister } = require('../../helpers/app');
|
||||
const { navigateToRegister, platformTypes } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
|
||||
describe('Create user screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToRegister();
|
||||
});
|
||||
|
||||
|
@ -50,10 +53,10 @@ describe('Create user screen', () => {
|
|||
await element(by.id('register-view-email')).replaceText(data.users.existing.email);
|
||||
await element(by.id('register-view-password')).replaceText(data.registeringUser.password);
|
||||
await element(by.id('register-view-submit')).tap();
|
||||
await waitFor(element(by.text('Email already exists. [403]')).atIndex(0))
|
||||
await waitFor(element(by[textMatcher]('Email already exists. [403]')).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by.text('OK')).tap();
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
});
|
||||
|
||||
it('should submit username already taken and raise error', async () => {
|
||||
|
@ -62,10 +65,10 @@ describe('Create user screen', () => {
|
|||
await element(by.id('register-view-email')).replaceText(data.registeringUser.email);
|
||||
await element(by.id('register-view-password')).replaceText(data.registeringUser.password);
|
||||
await element(by.id('register-view-submit')).tap();
|
||||
await waitFor(element(by.text('Username is already in use')).atIndex(0))
|
||||
await waitFor(element(by[textMatcher]('Username is already in use')).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by.text('OK')).tap();
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
});
|
||||
|
||||
it('should register', async () => {
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
const { navigateToLogin, tapBack } = require('../../helpers/app');
|
||||
const { navigateToLogin, tapBack, platformTypes } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
|
||||
describe('Login screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
});
|
||||
|
||||
|
@ -58,10 +61,10 @@ describe('Login screen', () => {
|
|||
await element(by.id('login-view-email')).replaceText(data.users.regular.username);
|
||||
await element(by.id('login-view-password')).replaceText('NotMyActualPassword');
|
||||
await element(by.id('login-view-submit')).tap();
|
||||
await waitFor(element(by.text('Your credentials were rejected! Please try again.')))
|
||||
await waitFor(element(by[textMatcher]('Your credentials were rejected! Please try again.')))
|
||||
.toBeVisible()
|
||||
.withTimeout(10000);
|
||||
await element(by.text('OK')).tap();
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
});
|
||||
|
||||
it('should login with success', async () => {
|
||||
|
|
|
@ -14,7 +14,9 @@ describe('Rooms list screen', () => {
|
|||
});
|
||||
|
||||
it('should have room item', async () => {
|
||||
await expect(element(by.id('rooms-list-view-item-general'))).toExist();
|
||||
await waitFor(element(by.id('rooms-list-view-item-general')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
});
|
||||
|
||||
// Render - Header
|
||||
|
|
|
@ -25,10 +25,10 @@ describe('Server history', () => {
|
|||
|
||||
it('should tap on a server history and navigate to login', async () => {
|
||||
await element(by.id(`server-history-${data.server}`)).tap();
|
||||
await waitFor(element(by.id('login-view')))
|
||||
await waitFor(element(by.id('login-view-email')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
await expect(element(by.id('login-view-email'))).toHaveText(data.users.regular.username);
|
||||
await expect(element(by.label(data.users.regular.username).withAncestor(by.id('login-view-email'))));
|
||||
});
|
||||
|
||||
it('should delete server from history', async () => {
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
const data = require('../../data');
|
||||
const { tapBack, navigateToLogin, login, tryTapping } = require('../../helpers/app');
|
||||
const { tapBack, navigateToLogin, login, tryTapping, platformTypes } = require('../../helpers/app');
|
||||
|
||||
describe('Create room screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(data.users.regular.username, data.users.regular.password);
|
||||
});
|
||||
|
@ -121,20 +124,26 @@ describe('Create room screen', () => {
|
|||
|
||||
describe('Usage', () => {
|
||||
it('should get invalid room', async () => {
|
||||
await element(by.id('create-channel-name')).typeText('general');
|
||||
await element(by.id('create-channel-name')).replaceText('general');
|
||||
await waitFor(element(by.id('create-channel-submit')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('create-channel-submit')).tap();
|
||||
await waitFor(element(by.text('A channel with name general exists')))
|
||||
await waitFor(element(by[textMatcher]('A channel with name general exists')))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await expect(element(by.text('A channel with name general exists'))).toExist();
|
||||
await element(by.text('OK')).tap();
|
||||
await expect(element(by[textMatcher]('A channel with name general exists'))).toExist();
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
});
|
||||
|
||||
it('should create public room', async () => {
|
||||
const room = `public${data.random}`;
|
||||
await element(by.id('create-channel-name')).replaceText('');
|
||||
await element(by.id('create-channel-name')).typeText(room);
|
||||
await element(by.id('create-channel-name')).replaceText(room);
|
||||
await element(by.id('create-channel-type')).tap();
|
||||
await waitFor(element(by.id('create-channel-submit')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('create-channel-submit')).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toExist()
|
||||
|
@ -175,7 +184,10 @@ describe('Create room screen', () => {
|
|||
await waitFor(element(by.id('create-channel-view')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('create-channel-name')).typeText(room);
|
||||
await element(by.id('create-channel-name')).replaceText(room);
|
||||
await waitFor(element(by.id('create-channel-submit')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('create-channel-submit')).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toExist()
|
||||
|
@ -213,7 +225,10 @@ describe('Create room screen', () => {
|
|||
await waitFor(element(by.id('create-channel-view')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by.id('create-channel-name')).typeText(room);
|
||||
await element(by.id('create-channel-name')).replaceText(room);
|
||||
await waitFor(element(by.id('create-channel-submit')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('create-channel-submit')).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toExist()
|
||||
|
|
|
@ -9,7 +9,8 @@ const {
|
|||
starMessage,
|
||||
pinMessage,
|
||||
dismissReviewNag,
|
||||
tryTapping
|
||||
tryTapping,
|
||||
platformTypes
|
||||
} = require('../../helpers/app');
|
||||
|
||||
async function navigateToRoom(roomName) {
|
||||
|
@ -22,9 +23,12 @@ async function navigateToRoom(roomName) {
|
|||
|
||||
describe('Room screen', () => {
|
||||
const mainRoom = data.groups.private.name;
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(data.users.regular.username, data.users.regular.password);
|
||||
await navigateToRoom(mainRoom);
|
||||
|
@ -79,7 +83,7 @@ describe('Room screen', () => {
|
|||
describe('Messagebox', () => {
|
||||
it('should send message', async () => {
|
||||
await mockMessage('message');
|
||||
await expect(element(by.label(`${data.random}message`)).atIndex(0)).toExist();
|
||||
await expect(element(by[textMatcher](`${data.random}message`)).atIndex(0)).toExist();
|
||||
});
|
||||
|
||||
it('should show/hide emoji keyboard', async () => {
|
||||
|
@ -100,8 +104,8 @@ describe('Room screen', () => {
|
|||
});
|
||||
|
||||
it('should show/hide emoji autocomplete', async () => {
|
||||
await element(by.id('messagebox-input')).tap();
|
||||
await element(by.id('messagebox-input')).typeText(':joy');
|
||||
await sleep(300);
|
||||
await waitFor(element(by.id('messagebox-container')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
|
@ -112,9 +116,8 @@ describe('Room screen', () => {
|
|||
});
|
||||
|
||||
it('should show and tap on emoji autocomplete', async () => {
|
||||
await element(by.id('messagebox-input')).tap();
|
||||
await element(by.id('messagebox-input')).replaceText(':');
|
||||
await element(by.id('messagebox-input')).typeText('joy'); // workaround for number keyboard
|
||||
await element(by.id('messagebox-input')).typeText(':joy');
|
||||
await sleep(300);
|
||||
await waitFor(element(by.id('messagebox-container')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
|
@ -124,9 +127,8 @@ describe('Room screen', () => {
|
|||
});
|
||||
|
||||
it('should not show emoji autocomplete on semicolon in middle of a string', async () => {
|
||||
await element(by.id('messagebox-input')).tap();
|
||||
// await element(by.id('messagebox-input')).replaceText(':');
|
||||
await element(by.id('messagebox-input')).typeText('name:is');
|
||||
await sleep(300);
|
||||
await waitFor(element(by.id('messagebox-container')))
|
||||
.toNotExist()
|
||||
.withTimeout(20000);
|
||||
|
@ -135,8 +137,11 @@ describe('Room screen', () => {
|
|||
|
||||
it('should show and tap on user autocomplete and send mention', async () => {
|
||||
const { username } = data.users.regular;
|
||||
await element(by.id('messagebox-input')).tap();
|
||||
const messageMention = `@${username}`;
|
||||
const message = `${data.random}mention`;
|
||||
const fullMessage = `${messageMention} ${message}`;
|
||||
await element(by.id('messagebox-input')).typeText(`@${username}`);
|
||||
await sleep(300);
|
||||
await waitFor(element(by.id('messagebox-container')))
|
||||
.toExist()
|
||||
.withTimeout(4000);
|
||||
|
@ -144,15 +149,24 @@ describe('Room screen', () => {
|
|||
.toBeVisible()
|
||||
.withTimeout(4000);
|
||||
await tryTapping(element(by.id(`mention-item-${username}`)), 2000, true);
|
||||
await expect(element(by.id('messagebox-input'))).toHaveText(`@${username} `);
|
||||
await expect(element(by.id('messagebox-input'))).toHaveText(`${messageMention} `);
|
||||
await tryTapping(element(by.id('messagebox-input')), 2000);
|
||||
await element(by.id('messagebox-input')).typeText(`${data.random}mention`);
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
// await waitFor(element(by.label(`@${ data.user } ${ data.random }mention`)).atIndex(0)).toExist().withTimeout(60000);
|
||||
if (device.getPlatform() === 'ios') {
|
||||
await element(by.id('messagebox-input')).typeText(message);
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
const fullMessageMatcher = fullMessage.substr(1); // removes `@`
|
||||
await waitFor(element(by[textMatcher](fullMessageMatcher)))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await expect(element(by[textMatcher](fullMessageMatcher))).toExist();
|
||||
await element(by[textMatcher](fullMessageMatcher)).atIndex(0).tap();
|
||||
} else {
|
||||
await element(by.id('messagebox-input')).replaceText(fullMessage);
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
}
|
||||
});
|
||||
|
||||
it('should not show user autocomplete on @ in the middle of a string', async () => {
|
||||
await element(by.id('messagebox-input')).tap();
|
||||
await element(by.id('messagebox-input')).typeText('email@gmail');
|
||||
await waitFor(element(by.id('messagebox-container')))
|
||||
.toNotExist()
|
||||
|
@ -161,9 +175,7 @@ describe('Room screen', () => {
|
|||
});
|
||||
|
||||
it('should show and tap on room autocomplete', async () => {
|
||||
await element(by.id('messagebox-input')).tap();
|
||||
await element(by.id('messagebox-input')).typeText('#general');
|
||||
// await waitFor(element(by.id('messagebox-container'))).toExist().withTimeout(4000);
|
||||
await waitFor(element(by.id('mention-item-general')))
|
||||
.toBeVisible()
|
||||
.withTimeout(4000);
|
||||
|
@ -181,7 +193,6 @@ describe('Room screen', () => {
|
|||
await element(by.id('messagebox-input')).clearText();
|
||||
});
|
||||
it('should draft message', async () => {
|
||||
await element(by.id('messagebox-input')).tap();
|
||||
await element(by.id('messagebox-input')).typeText(`${data.random}draft`);
|
||||
await tapBack();
|
||||
|
||||
|
@ -197,25 +208,29 @@ describe('Room screen', () => {
|
|||
|
||||
describe('Message', () => {
|
||||
it('should copy permalink', async () => {
|
||||
await element(by.label(`${data.random}message`))
|
||||
await element(by[textMatcher](`${data.random}message`))
|
||||
.atIndex(0)
|
||||
.longPress();
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
|
||||
await element(by.label('Permalink')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('Permalink')).atIndex(0).tap();
|
||||
|
||||
// TODO: test clipboard
|
||||
});
|
||||
|
||||
it('should copy message', async () => {
|
||||
await element(by.label(`${data.random}message`))
|
||||
await element(by[textMatcher](`${data.random}message`))
|
||||
.atIndex(0)
|
||||
.longPress();
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
|
||||
await element(by.label('Copy')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('Copy')).atIndex(0).tap();
|
||||
|
||||
// TODO: test clipboard
|
||||
});
|
||||
|
@ -224,23 +239,33 @@ describe('Room screen', () => {
|
|||
await starMessage('message');
|
||||
|
||||
await sleep(1000); // https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/2324
|
||||
await element(by.label(`${data.random}message`))
|
||||
await element(by[textMatcher](`${data.random}message`))
|
||||
.atIndex(0)
|
||||
.longPress();
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up', 'slow', 0.5);
|
||||
await waitFor(element(by.label('Unstar')).atIndex(0))
|
||||
await waitFor(element(by[textMatcher]('Unstar')).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(6000);
|
||||
await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.8);
|
||||
});
|
||||
|
||||
it('should react to message', async () => {
|
||||
await element(by.label(`${data.random}message`))
|
||||
await waitFor(element(by[textMatcher](`${data.random}message`)))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await element(by[textMatcher](`${data.random}message`))
|
||||
.atIndex(0)
|
||||
.tap();
|
||||
await element(by[textMatcher](`${data.random}message`))
|
||||
.atIndex(0)
|
||||
.longPress();
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
|
||||
await element(by.id('add-reaction')).tap();
|
||||
|
@ -258,10 +283,12 @@ describe('Room screen', () => {
|
|||
});
|
||||
|
||||
it('should react to message with frequently used emoji', async () => {
|
||||
await element(by.label(`${data.random}message`))
|
||||
await element(by[textMatcher](`${data.random}message`))
|
||||
.atIndex(0)
|
||||
.longPress();
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
|
||||
await waitFor(element(by.id('message-actions-emoji-+1')))
|
||||
|
@ -273,7 +300,7 @@ describe('Room screen', () => {
|
|||
.withTimeout(60000);
|
||||
});
|
||||
|
||||
it('should show reaction picker on add reaction button pressed and have frequently used emoji', async () => {
|
||||
it('should show reaction picker on add reaction button pressed and have frequently used emoji, and dismiss review nag', async () => {
|
||||
await element(by.id('message-add-reaction')).tap();
|
||||
await waitFor(element(by.id('reaction-picker')))
|
||||
.toExist()
|
||||
|
@ -291,10 +318,6 @@ describe('Room screen', () => {
|
|||
.withTimeout(60000);
|
||||
});
|
||||
|
||||
it('should ask for review', async () => {
|
||||
await dismissReviewNag(); // TODO: Create a proper test for this elsewhere.
|
||||
});
|
||||
|
||||
it('should remove reaction', async () => {
|
||||
await element(by.id('message-reaction-:grinning:')).tap();
|
||||
await waitFor(element(by.id('message-reaction-:grinning:')))
|
||||
|
@ -302,32 +325,43 @@ describe('Room screen', () => {
|
|||
.withTimeout(60000);
|
||||
});
|
||||
|
||||
it('should ask for review', async () => {
|
||||
await dismissReviewNag(); // TODO: Create a proper test for this elsewhere.
|
||||
});
|
||||
|
||||
it('should edit message', async () => {
|
||||
await mockMessage('edit');
|
||||
await element(by.label(`${data.random}edit`))
|
||||
await element(by[textMatcher](`${data.random}edit`))
|
||||
.atIndex(0)
|
||||
.longPress();
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
|
||||
await element(by.label('Edit')).atIndex(0).tap();
|
||||
await element(by.id('messagebox-input')).typeText('ed');
|
||||
await element(by[textMatcher]('Edit')).atIndex(0).tap();
|
||||
await element(by.id('messagebox-input')).replaceText(`${data.random}edited`);
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
await waitFor(element(by.label(`${data.random}edited (edited)`)).atIndex(0))
|
||||
await waitFor(element(by[textMatcher](`${data.random}edited (edited)`)).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
});
|
||||
|
||||
it('should quote message', async () => {
|
||||
await mockMessage('quote');
|
||||
await element(by.label(`${data.random}quote`))
|
||||
await element(by[textMatcher](`${data.random}quote`))
|
||||
.atIndex(0)
|
||||
.longPress();
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
|
||||
await element(by.label('Quote')).atIndex(0).tap();
|
||||
await element(by.id('messagebox-input')).typeText(`${data.random}quoted`);
|
||||
await element(by[textMatcher]('Quote')).atIndex(0).tap();
|
||||
await element(by.id('messagebox-input')).replaceText(`${data.random}quoted`);
|
||||
await waitFor(element(by.id('messagebox-send-message')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
|
||||
// TODO: test if quote was sent
|
||||
|
@ -337,13 +371,13 @@ describe('Room screen', () => {
|
|||
await mockMessage('pin');
|
||||
await pinMessage('pin');
|
||||
|
||||
await waitFor(element(by.label(`${data.random}pin`)).atIndex(0))
|
||||
await waitFor(element(by[textMatcher](`${data.random}pin`)).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.label(`${data.users.regular.username} Message pinned`)).atIndex(0))
|
||||
await waitFor(element(by[textMatcher](`${data.users.regular.username} Message pinned`)).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label(`${data.random}pin`))
|
||||
await element(by[textMatcher](`${data.random}pin`))
|
||||
.atIndex(0)
|
||||
.longPress();
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
|
@ -351,7 +385,7 @@ describe('Room screen', () => {
|
|||
.withTimeout(1000);
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
|
||||
await waitFor(element(by.label('Unpin')).atIndex(0))
|
||||
await waitFor(element(by[textMatcher]('Unpin')).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.8);
|
||||
|
@ -359,26 +393,26 @@ describe('Room screen', () => {
|
|||
|
||||
it('should delete message', async () => {
|
||||
await mockMessage('delete');
|
||||
|
||||
await waitFor(element(by.label(`${data.random}delete`)).atIndex(0)).toBeVisible();
|
||||
await element(by.label(`${data.random}delete`))
|
||||
await waitFor(element(by[textMatcher](`${data.random}delete`)).atIndex(0)).toBeVisible();
|
||||
await element(by[textMatcher](`${data.random}delete`))
|
||||
.atIndex(0)
|
||||
.longPress();
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
|
||||
await waitFor(element(by.label('Delete')))
|
||||
await waitFor(element(by[textMatcher]('Delete')))
|
||||
.toExist()
|
||||
.withTimeout(1000);
|
||||
await element(by.label('Delete')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('Delete')).atIndex(0).tap();
|
||||
|
||||
const deleteAlertMessage = 'You will not be able to recover this message!';
|
||||
await waitFor(element(by.text(deleteAlertMessage)).atIndex(0))
|
||||
await waitFor(element(by[textMatcher](deleteAlertMessage)).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by.text('Delete')).tap();
|
||||
|
||||
await waitFor(element(by.label(`${data.random}delete`)).atIndex(0))
|
||||
await element(by[textMatcher]('Delete').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by[textMatcher](`${data.random}delete`)).atIndex(0))
|
||||
.toNotExist()
|
||||
.withTimeout(2000);
|
||||
});
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, tapBack, sleep, searchRoom, mockMessage, starMessage, pinMessage } = require('../../helpers/app');
|
||||
const {
|
||||
navigateToLogin,
|
||||
login,
|
||||
tapBack,
|
||||
sleep,
|
||||
searchRoom,
|
||||
mockMessage,
|
||||
starMessage,
|
||||
pinMessage,
|
||||
platformTypes
|
||||
} = require('../../helpers/app');
|
||||
const { sendMessage } = require('../../helpers/data_setup');
|
||||
|
||||
async function navigateToRoomActions(type) {
|
||||
|
@ -43,10 +53,13 @@ async function waitForToast() {
|
|||
}
|
||||
|
||||
describe('Room actions screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
await navigateToLogin();
|
||||
await login(data.users.regular.username, data.users.regular.password);
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
});
|
||||
|
||||
describe('Render', () => {
|
||||
|
@ -172,36 +185,12 @@ describe('Room actions screen', () => {
|
|||
});
|
||||
|
||||
describe('Usage', () => {
|
||||
describe('TDB', async () => {
|
||||
// TODO: test into a jitsi call
|
||||
// it('should NOT navigate to voice call', async() => {
|
||||
// await waitFor(element(by.id('room-actions-voice'))).toExist();
|
||||
// await element(by.id('room-actions-voice')).tap();
|
||||
// await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(2000);
|
||||
// await expect(element(by.id('room-actions-view'))).toExist();
|
||||
// });
|
||||
// TODO: test into a jitsi call
|
||||
// it('should NOT navigate to video call', async() => {
|
||||
// await element(by.id('room-actions-video')).tap();
|
||||
// await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(2000);
|
||||
// await expect(element(by.id('room-actions-view'))).toExist();
|
||||
// });
|
||||
// TODO: test share room link
|
||||
// it('should NOT navigate to share room', async() => {
|
||||
// await waitFor(element(by.id('room-actions-share'))).toExist();
|
||||
// await element(by.id('room-actions-share')).tap();
|
||||
// await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(2000);
|
||||
// await expect(element(by.id('room-actions-view'))).toExist();
|
||||
// });
|
||||
});
|
||||
|
||||
describe('Common', () => {
|
||||
it('should show mentioned messages', async () => {
|
||||
await element(by.id('room-actions-mentioned')).tap();
|
||||
await waitFor(element(by.id('mentioned-messages-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
// await waitFor(element(by.text(` ${ data.random }mention`))).toExist().withTimeout(60000);
|
||||
await backToActions();
|
||||
});
|
||||
|
||||
|
@ -220,23 +209,25 @@ describe('Room actions screen', () => {
|
|||
.withTimeout(5000);
|
||||
|
||||
// Go to starred messages
|
||||
await element(by.id('room-actions-view')).swipe('up');
|
||||
await waitFor(element(by.id('room-actions-starred'))).toExist();
|
||||
await element(by.id('room-actions-starred')).tap();
|
||||
await waitFor(element(by.id('starred-messages-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await waitFor(element(by.label(`${data.random}messageToStar`).withAncestor(by.id('starred-messages-view'))))
|
||||
await waitFor(element(by[textMatcher](`${data.random}messageToStar`).withAncestor(by.id('starred-messages-view'))))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
|
||||
// Unstar message
|
||||
await element(by.label(`${data.random}messageToStar`))
|
||||
await element(by[textMatcher](`${data.random}messageToStar`))
|
||||
.atIndex(0)
|
||||
.longPress();
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.label('Unstar')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('Unstar')).atIndex(0).tap();
|
||||
|
||||
await waitFor(element(by.label(`${data.random}messageToStar`).withAncestor(by.id('starred-messages-view'))))
|
||||
await waitFor(element(by[textMatcher](`${data.random}messageToStar`).withAncestor(by.id('starred-messages-view'))))
|
||||
.toBeNotVisible()
|
||||
.withTimeout(60000);
|
||||
await backToActions();
|
||||
|
@ -261,40 +252,22 @@ describe('Room actions screen', () => {
|
|||
await waitFor(element(by.id('pinned-messages-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await waitFor(element(by.label(`${data.random}messageToPin`).withAncestor(by.id('pinned-messages-view'))))
|
||||
await waitFor(element(by[textMatcher](`${data.random}messageToPin`).withAncestor(by.id('pinned-messages-view'))))
|
||||
.toExist()
|
||||
.withTimeout(6000);
|
||||
await element(by.label(`${data.random}messageToPin`).withAncestor(by.id('pinned-messages-view')))
|
||||
await element(by[textMatcher](`${data.random}messageToPin`).withAncestor(by.id('pinned-messages-view')))
|
||||
.atIndex(0)
|
||||
.longPress();
|
||||
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.label('Unpin')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('Unpin')).atIndex(0).tap();
|
||||
|
||||
await waitFor(element(by.label(`${data.random}messageToPin`).withAncestor(by.id('pinned-messages-view'))))
|
||||
await waitFor(element(by[textMatcher](`${data.random}messageToPin`).withAncestor(by.id('pinned-messages-view'))))
|
||||
.not.toExist()
|
||||
.withTimeout(6000);
|
||||
await backToActions();
|
||||
});
|
||||
|
||||
// it('should search and find a message', async() => {
|
||||
|
||||
// //Go back to room and send a message
|
||||
// await tapBack();
|
||||
// await mockMessage('messageToFind');
|
||||
|
||||
// //Back into Room Actions
|
||||
// await element(by.id('room-header')).tap();
|
||||
// await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
|
||||
|
||||
// await element(by.id('room-actions-search')).tap();
|
||||
// await waitFor(element(by.id('search-messages-view'))).toExist().withTimeout(2000);
|
||||
// await expect(element(by.id('search-message-view-input'))).toExist();
|
||||
// await element(by.id('search-message-view-input')).replaceText(`/${ data.random }messageToFind/`);
|
||||
// await waitFor(element(by.label(`${ data.random }messageToFind`).withAncestor(by.id('search-messages-view')))).toExist().withTimeout(60000);
|
||||
// await backToActions();
|
||||
// });
|
||||
});
|
||||
|
||||
describe('Notification', () => {
|
||||
|
@ -370,14 +343,14 @@ describe('Room actions screen', () => {
|
|||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-actions-leave-channel')).tap();
|
||||
await waitFor(element(by.text('Yes, leave it!')))
|
||||
await waitFor(element(by[textMatcher]('Yes, leave it!')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.text('Yes, leave it!')).tap();
|
||||
await waitFor(element(by.text('You are the last owner. Please set new owner before leaving the room.')))
|
||||
await element(by[textMatcher]('Yes, leave it!').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by[textMatcher]('You are the last owner. Please set new owner before leaving the room.')))
|
||||
.toExist()
|
||||
.withTimeout(8000);
|
||||
await element(by.text('OK')).tap();
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('room-actions-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
|
@ -404,6 +377,7 @@ describe('Room actions screen', () => {
|
|||
.withTimeout(4000);
|
||||
await element(by.id('select-users-view-search')).tap();
|
||||
await element(by.id('select-users-view-search')).replaceText(user.username);
|
||||
await sleep(300);
|
||||
await waitFor(element(by.id(`select-users-view-item-${user.username}`)))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
|
@ -437,14 +411,30 @@ describe('Room actions screen', () => {
|
|||
await waitFor(element(by.id(`room-members-view-item-${username}`)))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.id(`room-members-view-item-${username}`)).tap();
|
||||
await sleep(300);
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
let n = 0;
|
||||
while (n < 3) {
|
||||
// Max tries three times, in case it does not register the click
|
||||
try {
|
||||
await element(by.id(`room-members-view-item-${username}`)).tap();
|
||||
await sleep(300);
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up');
|
||||
return;
|
||||
} catch (e) {
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const closeActionSheet = async () => {
|
||||
await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.6);
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
.toBeNotVisible()
|
||||
.withTimeout(1000);
|
||||
await sleep(100);
|
||||
};
|
||||
|
||||
it('should show all users', async () => {
|
||||
|
@ -471,11 +461,14 @@ describe('Room actions screen', () => {
|
|||
|
||||
it('should remove user from room', async () => {
|
||||
await openActionSheet('rocket.cat');
|
||||
await element(by.label('Remove from room')).atIndex(0).tap();
|
||||
await waitFor(element(by.label('Are you sure?')))
|
||||
await waitFor(element(by[textMatcher]('Remove from room')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by[textMatcher]('Remove from room')).atIndex(0).tap();
|
||||
await waitFor(element(by[textMatcher]('Are you sure?')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label('Yes, remove user!').and(by.type('_UIAlertControllerActionView'))).tap();
|
||||
await element(by[textMatcher]('Yes, remove user!').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('room-members-view-item-rocket.cat')))
|
||||
.toBeNotVisible()
|
||||
.withTimeout(60000);
|
||||
|
@ -548,24 +541,24 @@ describe('Room actions screen', () => {
|
|||
|
||||
it('should set/remove as mute', async () => {
|
||||
await openActionSheet(user.username);
|
||||
await element(by.label('Mute')).atIndex(0).tap();
|
||||
await waitFor(element(by.label('Are you sure?')))
|
||||
await element(by[textMatcher]('Mute')).atIndex(0).tap();
|
||||
await waitFor(element(by[textMatcher]('Are you sure?')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label('Mute').and(by.type('_UIAlertControllerActionView'))).tap();
|
||||
await element(by[textMatcher]('Mute').and(by.type(alertButtonType))).tap();
|
||||
await waitForToast();
|
||||
|
||||
await openActionSheet(user.username);
|
||||
await element(by.label('Unmute')).atIndex(0).tap();
|
||||
await waitFor(element(by.label('Are you sure?')))
|
||||
await element(by[textMatcher]('Unmute')).atIndex(0).tap();
|
||||
await waitFor(element(by[textMatcher]('Are you sure?')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label('Unmute').and(by.type('_UIAlertControllerActionView'))).tap();
|
||||
await element(by[textMatcher]('Unmute').and(by.type(alertButtonType))).tap();
|
||||
await waitForToast();
|
||||
|
||||
await openActionSheet(user.username);
|
||||
// Tests if Remove as mute worked
|
||||
await waitFor(element(by.label('Mute')))
|
||||
await waitFor(element(by[textMatcher]('Mute')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await closeActionSheet();
|
||||
|
@ -576,21 +569,21 @@ describe('Room actions screen', () => {
|
|||
const channelName = `#${data.groups.private.name}`;
|
||||
await sendMessage(user, channelName, message);
|
||||
await openActionSheet(user.username);
|
||||
await element(by.label('Ignore')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('Ignore')).atIndex(0).tap();
|
||||
await waitForToast();
|
||||
await backToActions();
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await waitFor(element(by.label('Message ignored. Tap to display it.')).atIndex(0))
|
||||
await waitFor(element(by[textMatcher]('Message ignored. Tap to display it.')).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await element(by.label('Message ignored. Tap to display it.')).atIndex(0).tap();
|
||||
await waitFor(element(by.label(message)).atIndex(0))
|
||||
await element(by[textMatcher]('Message ignored. Tap to display it.')).atIndex(0).tap();
|
||||
await waitFor(element(by[textMatcher](message)).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await element(by.label(message)).atIndex(0).tap();
|
||||
await element(by[textMatcher](message)).atIndex(0).tap();
|
||||
});
|
||||
|
||||
it('should navigate to direct message', async () => {
|
||||
|
@ -607,7 +600,7 @@ describe('Room actions screen', () => {
|
|||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await openActionSheet(user.username);
|
||||
await element(by.label('Direct message')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('Direct message')).atIndex(0).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
|
@ -630,11 +623,11 @@ describe('Room actions screen', () => {
|
|||
it('should block/unblock user', async () => {
|
||||
await waitFor(element(by.id('room-actions-block-user'))).toExist();
|
||||
await element(by.id('room-actions-block-user')).tap();
|
||||
await waitFor(element(by.label('Unblock user')))
|
||||
await waitFor(element(by[textMatcher]('Unblock user')))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await element(by.id('room-actions-block-user')).tap();
|
||||
await waitFor(element(by.label('Block user')))
|
||||
await waitFor(element(by[textMatcher]('Block user')))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { navigateToLogin, login, mockMessage, tapBack, searchRoom } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, mockMessage, tapBack, searchRoom, platformTypes } = require('../../helpers/app');
|
||||
const data = require('../../data');
|
||||
|
||||
const channel = data.groups.private.name;
|
||||
|
@ -12,8 +12,10 @@ const navigateToRoom = async () => {
|
|||
};
|
||||
|
||||
describe('Discussion', () => {
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true, delete: true });
|
||||
({ textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(data.users.regular.username, data.users.regular.password);
|
||||
});
|
||||
|
@ -24,12 +26,12 @@ describe('Discussion', () => {
|
|||
await waitFor(element(by.id('new-message-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.label('Create Discussion')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('Create Discussion')).atIndex(0).tap();
|
||||
await waitFor(element(by.id('create-discussion-view')))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await expect(element(by.id('create-discussion-view'))).toExist();
|
||||
await element(by.label('Select a Channel...')).tap();
|
||||
await element(by[textMatcher]('Select a Channel...')).tap();
|
||||
await element(by.id('multi-select-search')).replaceText(`${channel}`);
|
||||
await waitFor(element(by.id(`multi-select-item-${channel}`)))
|
||||
.toExist()
|
||||
|
@ -59,7 +61,7 @@ describe('Discussion', () => {
|
|||
await waitFor(element(by.id('action-sheet')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.label('Create Discussion')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('Create Discussion')).atIndex(0).tap();
|
||||
await waitFor(element(by.id('create-discussion-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
|
@ -86,11 +88,11 @@ describe('Discussion', () => {
|
|||
|
||||
it('should create discussion', async () => {
|
||||
const discussionName = `${data.random}message`;
|
||||
await element(by.label(discussionName)).atIndex(0).longPress();
|
||||
await element(by[textMatcher](discussionName)).atIndex(0).longPress();
|
||||
await waitFor(element(by.id('action-sheet')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.label('Start a Discussion')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('Start a Discussion')).atIndex(0).tap();
|
||||
await waitFor(element(by.id('create-discussion-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
|
@ -136,6 +138,7 @@ describe('Discussion', () => {
|
|||
});
|
||||
|
||||
it('should have starred', async () => {
|
||||
await element(by.id('room-actions-scrollview')).swipe('up', 'slow', 0.5);
|
||||
await expect(element(by.id('room-actions-starred'))).toBeVisible();
|
||||
});
|
||||
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, mockMessage, tapBack, sleep, searchRoom, dismissReviewNag } = require('../../helpers/app');
|
||||
const {
|
||||
navigateToLogin,
|
||||
login,
|
||||
mockMessage,
|
||||
tapBack,
|
||||
sleep,
|
||||
searchRoom,
|
||||
platformTypes,
|
||||
dismissReviewNag
|
||||
} = require('../../helpers/app');
|
||||
|
||||
async function navigateToRoom(roomName) {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
|
@ -7,21 +16,22 @@ async function navigateToRoom(roomName) {
|
|||
await login(data.users.regular.username, data.users.regular.password);
|
||||
await searchRoom(`${roomName}`);
|
||||
await element(by.id(`rooms-list-view-item-${roomName}`)).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toBeVisible()
|
||||
await waitFor(element(by.id(`room-view-title-${roomName}`)))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
}
|
||||
|
||||
describe('Threads', () => {
|
||||
const mainRoom = data.groups.private.name;
|
||||
let textMatcher;
|
||||
|
||||
before(async () => {
|
||||
({ textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToRoom(mainRoom);
|
||||
});
|
||||
|
||||
describe('Render', () => {
|
||||
it('should have room screen', async () => {
|
||||
await expect(element(by.id('room-view'))).toExist();
|
||||
await waitFor(element(by.id(`room-view-title-${mainRoom}`)))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
|
@ -69,12 +79,15 @@ describe('Threads', () => {
|
|||
const thread = `${data.random}thread`;
|
||||
it('should create thread', async () => {
|
||||
await mockMessage('thread');
|
||||
await element(by.label(thread)).atIndex(0).longPress();
|
||||
await element(by[textMatcher](thread)).atIndex(0).longPress();
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
|
||||
await element(by.label('Reply in Thread')).atIndex(0).tap();
|
||||
await element(by.id('messagebox-input')).typeText('replied');
|
||||
await element(by[textMatcher]('Reply in Thread')).atIndex(0).tap();
|
||||
await element(by.id('messagebox-input')).replaceText('replied');
|
||||
await waitFor(element(by.id('messagebox-send-message')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
await waitFor(element(by.id(`message-thread-button-${thread}`)))
|
||||
.toExist()
|
||||
|
@ -84,9 +97,6 @@ describe('Threads', () => {
|
|||
|
||||
it('should navigate to thread from button', async () => {
|
||||
await element(by.id(`message-thread-button-${thread}`)).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.id(`room-view-title-${thread}`)))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
|
@ -96,13 +106,9 @@ describe('Threads', () => {
|
|||
|
||||
it('should toggle follow thread', async () => {
|
||||
await element(by.id(`message-thread-button-${thread}`)).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.id(`room-view-title-${thread}`)))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await expect(element(by.id(`room-view-title-${thread}`))).toExist();
|
||||
await element(by.id('room-view-header-unfollow')).tap();
|
||||
await waitFor(element(by.id('room-view-header-follow')))
|
||||
.toExist()
|
||||
|
@ -119,14 +125,13 @@ describe('Threads', () => {
|
|||
const messageText = 'threadonly';
|
||||
await mockMessage(messageText, true);
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('room-header').and(by.label(`${mainRoom}`))))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await waitFor(element(by.id('room-header').and(by.label(`${data.random}thread`))))
|
||||
.toBeNotVisible()
|
||||
.withTimeout(2000);
|
||||
await sleep(500); // TODO: Find a better way to wait for the animation to finish and the messagebox-input to be available and usable :(
|
||||
await waitFor(element(by.label(`${data.random}${messageText}`)).atIndex(0))
|
||||
await waitFor(element(by.id(`room-view-title-${data.random}thread`)))
|
||||
.not.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.id(`room-view-title-${mainRoom}`)))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by[textMatcher](`${data.random}${messageText}`)).atIndex(0))
|
||||
.toNotExist()
|
||||
.withTimeout(2000);
|
||||
});
|
||||
|
@ -137,40 +142,39 @@ describe('Threads', () => {
|
|||
await waitFor(element(by.id('messagebox-input-thread')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('messagebox-input-thread')).typeText(messageText);
|
||||
await element(by.id('messagebox-input-thread')).replaceText(messageText);
|
||||
await element(by.id('messagebox-send-to-channel')).tap();
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('room-header').and(by.label(`${mainRoom}`))))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await waitFor(element(by.id('room-header').and(by.label(`${data.random}thread`))))
|
||||
.toBeNotVisible()
|
||||
.withTimeout(2000);
|
||||
await sleep(500); // TODO: Find a better way to wait for the animation to finish and the messagebox-input to be available and usable :(
|
||||
await waitFor(element(by.label(messageText)).atIndex(0))
|
||||
await waitFor(element(by.id(`room-view-title-${data.random}thread`)))
|
||||
.not.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.id(`room-view-title-${mainRoom}`)))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by[textMatcher](messageText)).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
});
|
||||
|
||||
it('should navigate to thread from thread name', async () => {
|
||||
const messageText = 'navthreadname';
|
||||
await mockMessage('dummymessagebetweenthethread');
|
||||
await dismissReviewNag(); // TODO: Create a proper test for this elsewhere.
|
||||
await mockMessage('dummymessagebetweenthethread'); // TODO: Create a proper test for this elsewhere.
|
||||
await dismissReviewNag();
|
||||
await element(by.id(`message-thread-button-${thread}`)).tap();
|
||||
await waitFor(element(by.id('messagebox-input-thread')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('messagebox-input-thread')).typeText(messageText);
|
||||
await element(by.id('messagebox-input-thread')).replaceText(messageText);
|
||||
await element(by.id('messagebox-send-to-channel')).tap();
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('room-header').and(by.label(`${mainRoom}`))))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await waitFor(element(by.id('room-header').and(by.label(`${data.random}thread`))))
|
||||
.toBeNotVisible()
|
||||
.withTimeout(2000);
|
||||
await waitFor(element(by.id(`room-view-title-${data.random}thread`)))
|
||||
.not.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.id(`room-view-title-${mainRoom}`)))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.id(`message-thread-replied-on-${thread}`)))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
|
@ -211,7 +215,7 @@ describe('Threads', () => {
|
|||
await waitFor(element(by.id(`room-view-title-${thread}`)))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('messagebox-input-thread')).typeText(`${thread}draft`);
|
||||
await element(by.id('messagebox-input-thread')).replaceText(`${thread}draft`);
|
||||
await tapBack();
|
||||
|
||||
await element(by.id(`message-thread-button-${thread}`)).tap();
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, platformTypes } = require('../../helpers/app');
|
||||
|
||||
describe('Group DM', () => {
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(data.users.regular.username, data.users.regular.password);
|
||||
});
|
||||
|
@ -29,7 +31,7 @@ describe('Group DM', () => {
|
|||
|
||||
describe('Usage', () => {
|
||||
it('should navigate to create DM', async () => {
|
||||
await element(by.label('Create Direct Messages')).tap();
|
||||
await element(by[textMatcher]('Create Direct Messages')).tap();
|
||||
});
|
||||
|
||||
it('should add users', async () => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, searchRoom, sleep } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, searchRoom, sleep, platformTypes } = require('../../helpers/app');
|
||||
const { sendMessage } = require('../../helpers/data_setup');
|
||||
|
||||
async function navigateToRoom(user) {
|
||||
|
@ -12,9 +12,11 @@ async function navigateToRoom(user) {
|
|||
|
||||
describe('Mark as unread', () => {
|
||||
const user = data.users.alternate.username;
|
||||
let textMatcher;
|
||||
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(data.users.regular.username, data.users.regular.password);
|
||||
await navigateToRoom(user);
|
||||
|
@ -26,16 +28,16 @@ describe('Mark as unread', () => {
|
|||
const message = `${data.random}message-mark-as-unread`;
|
||||
const channelName = `@${data.users.regular.username}`;
|
||||
await sendMessage(data.users.alternate, channelName, message);
|
||||
await waitFor(element(by.label(message)).atIndex(0))
|
||||
await waitFor(element(by[textMatcher](message)).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(30000);
|
||||
await sleep(300);
|
||||
await element(by.label(message)).atIndex(0).longPress();
|
||||
await element(by[textMatcher](message)).atIndex(0).longPress();
|
||||
await waitFor(element(by.id('action-sheet-handle')))
|
||||
.toBeVisible()
|
||||
.withTimeout(3000);
|
||||
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
|
||||
await element(by.label('Mark Unread')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('Mark Unread')).atIndex(0).tap();
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, tapBack, sleep, searchRoom } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, tapBack, sleep, searchRoom, platformTypes } = require('../../helpers/app');
|
||||
|
||||
const privateRoomName = data.groups.private.name;
|
||||
|
||||
|
@ -25,17 +25,20 @@ async function navigateToRoomInfo(type) {
|
|||
.withTimeout(2000);
|
||||
}
|
||||
|
||||
async function swipe(direction) {
|
||||
await element(by.id('room-info-edit-view-list')).swipe(direction, 'fast', 0.8);
|
||||
}
|
||||
|
||||
async function waitForToast() {
|
||||
// await waitFor(element(by.id('toast'))).toExist().withTimeout(10000);
|
||||
// await expect(element(by.id('toast'))).toExist();
|
||||
// await waitFor(element(by.id('toast'))).toBeNotVisible().withTimeout(10000);
|
||||
// await expect(element(by.id('toast'))).toBeNotVisible();
|
||||
await sleep(300);
|
||||
}
|
||||
|
||||
describe('Room info screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(data.users.regular.username, data.users.regular.password);
|
||||
});
|
||||
|
@ -72,15 +75,15 @@ describe('Room info screen', () => {
|
|||
});
|
||||
|
||||
it('should have description', async () => {
|
||||
await expect(element(by.label('Description'))).toExist();
|
||||
await expect(element(by[textMatcher]('Description'))).toExist();
|
||||
});
|
||||
|
||||
it('should have topic', async () => {
|
||||
await expect(element(by.label('Topic'))).toExist();
|
||||
await expect(element(by[textMatcher]('Topic'))).toExist();
|
||||
});
|
||||
|
||||
it('should have announcement', async () => {
|
||||
await expect(element(by.label('Announcement'))).toExist();
|
||||
await expect(element(by[textMatcher]('Announcement'))).toExist();
|
||||
});
|
||||
|
||||
it('should have edit button', async () => {
|
||||
|
@ -124,8 +127,7 @@ describe('Room info screen', () => {
|
|||
});
|
||||
|
||||
it('should have type switch', async () => {
|
||||
// Ugly hack to scroll on detox
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.8);
|
||||
await swipe('up');
|
||||
await expect(element(by.id('room-info-edit-view-t'))).toExist();
|
||||
});
|
||||
|
||||
|
@ -150,44 +152,33 @@ describe('Room info screen', () => {
|
|||
});
|
||||
|
||||
after(async () => {
|
||||
// Ugly hack to scroll on detox
|
||||
await element(by.id('room-info-edit-view-list')).swipe('down', 'fast', 0.8);
|
||||
await swipe('down');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Usage', () => {
|
||||
// it('should enter "invalid name" and get error', async() => {
|
||||
// await element(by.type('UIScrollView')).atIndex(1).swipe('down');
|
||||
// await element(by.id('room-info-edit-view-name')).replaceText('invalid name');
|
||||
// await element(by.type('UIScrollView')).atIndex(1).swipe('up');
|
||||
// await element(by.id('room-info-edit-view-submit')).tap();
|
||||
// await waitFor(element(by.text('There was an error while saving settings!'))).toExist().withTimeout(60000);
|
||||
// await expect(element(by.text('There was an error while saving settings!'))).toExist();
|
||||
// await element(by.text('OK')).tap();
|
||||
// await waitFor(element(by.text('There was an error while saving settings!'))).toBeNotVisible().withTimeout(10000);
|
||||
// await element(by.type('UIScrollView')).atIndex(1).swipe('down');
|
||||
// });
|
||||
|
||||
it('should change room name', async () => {
|
||||
await element(by.id('room-info-edit-view-name')).replaceText(`${privateRoomName}new`);
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await swipe('up');
|
||||
await element(by.id('room-info-edit-view-submit')).tap();
|
||||
await waitForToast();
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('room-info-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.id('room-info-view-name'))).toHaveLabel(`${privateRoomName}new`);
|
||||
const matcher = device.getPlatform() === 'android' ? 'toHaveText' : 'toHaveLabel';
|
||||
await expect(element(by.id('room-info-view-name')))[matcher](`${privateRoomName}new`);
|
||||
// change name to original
|
||||
await element(by.id('room-info-view-edit-button')).tap();
|
||||
await waitFor(element(by.id('room-info-edit-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-info-edit-view-name')).replaceText(`${privateRoomName}`);
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await swipe('up');
|
||||
await element(by.id('room-info-edit-view-submit')).tap();
|
||||
await waitForToast();
|
||||
await element(by.id('room-info-edit-view-list')).swipe('down', 'fast', 0.8);
|
||||
await swipe('down');
|
||||
});
|
||||
|
||||
it('should reset form', async () => {
|
||||
|
@ -196,10 +187,11 @@ describe('Room info screen', () => {
|
|||
await element(by.id('room-info-edit-view-topic')).replaceText('abc');
|
||||
await element(by.id('room-info-edit-view-announcement')).replaceText('abc');
|
||||
await element(by.id('room-info-edit-view-password')).replaceText('abc');
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await element(by.id('room-info-edit-view-t')).tap();
|
||||
await swipe('up');
|
||||
await element(by.id('room-info-edit-view-ro')).longPress(); // https://github.com/facebook/react-native/issues/28032
|
||||
await element(by.id('room-info-edit-view-react-when-ro')).tap();
|
||||
await swipe('up');
|
||||
await element(by.id('room-info-edit-view-reset')).tap();
|
||||
// after reset
|
||||
await expect(element(by.id('room-info-edit-view-name'))).toHaveText(privateRoomName);
|
||||
|
@ -207,22 +199,23 @@ describe('Room info screen', () => {
|
|||
await expect(element(by.id('room-info-edit-view-topic'))).toHaveText('');
|
||||
await expect(element(by.id('room-info-edit-view-announcement'))).toHaveText('');
|
||||
await expect(element(by.id('room-info-edit-view-password'))).toHaveText('');
|
||||
await expect(element(by.id('room-info-edit-view-t'))).toHaveValue('1');
|
||||
await expect(element(by.id('room-info-edit-view-ro'))).toHaveValue('0');
|
||||
// await swipe('down');
|
||||
await expect(element(by.id('room-info-edit-view-t'))).toHaveToggleValue(true);
|
||||
await expect(element(by.id('room-info-edit-view-ro'))).toHaveToggleValue(false);
|
||||
await expect(element(by.id('room-info-edit-view-react-when-ro'))).toBeNotVisible();
|
||||
await element(by.id('room-info-edit-view-list')).swipe('down', 'fast', 0.8);
|
||||
await swipe('down');
|
||||
});
|
||||
|
||||
it('should change room description', async () => {
|
||||
await element(by.id('room-info-edit-view-description')).replaceText('new description');
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await swipe('up');
|
||||
await element(by.id('room-info-edit-view-submit')).tap();
|
||||
await waitForToast();
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('room-info-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.label('new description').withAncestor(by.id('room-info-view-description')))).toExist();
|
||||
await expect(element(by[textMatcher]('new description').withAncestor(by.id('room-info-view-description')))).toExist();
|
||||
});
|
||||
|
||||
it('should change room topic', async () => {
|
||||
|
@ -234,14 +227,14 @@ describe('Room info screen', () => {
|
|||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-info-edit-view-topic')).replaceText('new topic');
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await swipe('up');
|
||||
await element(by.id('room-info-edit-view-submit')).tap();
|
||||
await waitForToast();
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('room-info-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.label('new topic').withAncestor(by.id('room-info-view-topic')))).toExist();
|
||||
await expect(element(by[textMatcher]('new topic').withAncestor(by.id('room-info-view-topic')))).toExist();
|
||||
});
|
||||
|
||||
it('should change room announcement', async () => {
|
||||
|
@ -253,14 +246,14 @@ describe('Room info screen', () => {
|
|||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-info-edit-view-announcement')).replaceText('new announcement');
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await swipe('up');
|
||||
await element(by.id('room-info-edit-view-submit')).tap();
|
||||
await waitForToast();
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('room-info-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await expect(element(by.label('new announcement').withAncestor(by.id('room-info-view-announcement')))).toExist();
|
||||
await expect(element(by[textMatcher]('new announcement').withAncestor(by.id('room-info-view-announcement')))).toExist();
|
||||
});
|
||||
|
||||
it('should change room password', async () => {
|
||||
|
@ -271,61 +264,45 @@ describe('Room info screen', () => {
|
|||
await waitFor(element(by.id('room-info-edit-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await element(by.id('room-info-edit-view-password')).replaceText('password');
|
||||
await swipe('up');
|
||||
await element(by.id('room-info-edit-view-submit')).tap();
|
||||
await waitForToast();
|
||||
});
|
||||
|
||||
it('should change room type', async () => {
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await swipe('down');
|
||||
await element(by.id('room-info-edit-view-t')).tap();
|
||||
await swipe('up');
|
||||
await element(by.id('room-info-edit-view-submit')).tap();
|
||||
await waitForToast();
|
||||
await swipe('down');
|
||||
await element(by.id('room-info-edit-view-t')).tap();
|
||||
await swipe('up');
|
||||
await element(by.id('room-info-edit-view-submit')).tap();
|
||||
await waitForToast();
|
||||
});
|
||||
|
||||
// it('should change room read only and allow reactions', async() => {
|
||||
// await sleep(1000);
|
||||
// await element(by.type('UIScrollView')).atIndex(1).swipe('up');
|
||||
// await element(by.id('room-info-edit-view-ro')).tap();
|
||||
// await waitFor(element(by.id('room-info-edit-view-react-when-ro'))).toExist().withTimeout(2000);
|
||||
// await expect(element(by.id('room-info-edit-view-react-when-ro'))).toExist();
|
||||
// await element(by.id('room-info-edit-view-react-when-ro')).tap();
|
||||
// await element(by.id('room-info-edit-view-submit')).tap();
|
||||
// await waitForToast();
|
||||
// // TODO: test if it's possible to react
|
||||
// });
|
||||
|
||||
it('should archive room', async () => {
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await element(by.id('room-info-edit-view-archive')).tap();
|
||||
await waitFor(element(by.text('Yes, archive it!')))
|
||||
await waitFor(element(by[textMatcher]('Yes, archive it!')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.text('Yes, archive it!')).tap();
|
||||
await element(by[textMatcher]('Yes, archive it!').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('room-info-edit-view-unarchive')))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await expect(element(by.id('room-info-edit-view-archive'))).toBeNotVisible();
|
||||
// TODO: needs permission to unarchive
|
||||
// await element(by.id('room-info-edit-view-archive')).tap();
|
||||
// await waitFor(element(by.text('Yes, unarchive it!'))).toExist().withTimeout(5000);
|
||||
// await expect(element(by.text('Yes, unarchive it!'))).toExist();
|
||||
// await element(by.text('Yes, unarchive it!')).tap();
|
||||
// await waitFor(element(by.text('ARCHIVE'))).toExist().withTimeout(60000);
|
||||
// await expect(element(by.text('ARCHIVE'))).toExist();
|
||||
});
|
||||
|
||||
it('should delete room', async () => {
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await swipe('up');
|
||||
await element(by.id('room-info-edit-view-delete')).tap();
|
||||
await waitFor(element(by.text('Yes, delete it!')))
|
||||
await waitFor(element(by[textMatcher]('Yes, delete it!')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.text('Yes, delete it!')).tap();
|
||||
await element(by[textMatcher]('Yes, delete it!').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, tapBack, login, searchRoom } = require('../../helpers/app');
|
||||
const { navigateToLogin, tapBack, login, searchRoom, sleep, platformTypes } = require('../../helpers/app');
|
||||
|
||||
async function navigateToRoom(roomName) {
|
||||
await searchRoom(`${roomName}`);
|
||||
|
@ -7,8 +7,14 @@ async function navigateToRoom(roomName) {
|
|||
await waitFor(element(by.id('room-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.id(`room-view-title-${roomName}`)))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
}
|
||||
|
||||
let textMatcher;
|
||||
let alertButtonType;
|
||||
|
||||
async function clearCache() {
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toBeVisible()
|
||||
|
@ -26,10 +32,10 @@ async function clearCache() {
|
|||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('settings-view-clear-cache')).tap();
|
||||
await waitFor(element(by.text('This will clear all your offline data.')))
|
||||
await waitFor(element(by[textMatcher]('This will clear all your offline data.')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.label('Clear').and(by.type('_UIAlertControllerActionView'))).tap();
|
||||
await element(by[textMatcher]('Clear').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
|
@ -39,6 +45,10 @@ async function clearCache() {
|
|||
}
|
||||
|
||||
async function waitForLoading() {
|
||||
if (device.getPlatform() === 'android') {
|
||||
await sleep(10000);
|
||||
return; // FIXME: Loading indicator doesn't animate properly on android
|
||||
}
|
||||
await waitFor(element(by.id('loading')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
|
@ -50,21 +60,22 @@ async function waitForLoading() {
|
|||
describe('Room', () => {
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(data.adminUser, data.adminPassword);
|
||||
});
|
||||
|
||||
it('should jump to an old message and load its surroundings', async () => {
|
||||
await navigateToRoom('jumping');
|
||||
await waitFor(element(by.label('Quote first message')))
|
||||
await waitFor(element(by[textMatcher]('300')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label('1')).atIndex(0).tap();
|
||||
await element(by[textMatcher]('1')).atIndex(0).tap();
|
||||
await waitForLoading();
|
||||
await waitFor(element(by.label('1')).atIndex(0))
|
||||
await waitFor(element(by[textMatcher]('1')).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await expect(element(by.label('2'))).toExist();
|
||||
await expect(element(by[textMatcher]('2'))).toExist();
|
||||
});
|
||||
|
||||
it('should tap FAB and scroll to bottom', async () => {
|
||||
|
@ -72,7 +83,7 @@ describe('Room', () => {
|
|||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('nav-jump-to-bottom')).tap();
|
||||
await waitFor(element(by.label('Quote first message')))
|
||||
await waitFor(element(by[textMatcher]('Quote first message')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await clearCache();
|
||||
|
@ -83,14 +94,15 @@ describe('Room', () => {
|
|||
await waitFor(element(by.id('room-view-messages')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.label('300')))
|
||||
await waitFor(element(by[textMatcher]('300')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
let found = false;
|
||||
while (!found) {
|
||||
await element(by.id('room-view-messages')).atIndex(0).scroll(500, 'up');
|
||||
try {
|
||||
await expect(element(by.label('249'))).toExist();
|
||||
const direction = device.getPlatform() === 'android' ? 'down' : 'up';
|
||||
await element(by.id('room-view-messages')).scroll(500, direction);
|
||||
await expect(element(by[textMatcher]('249'))).toExist();
|
||||
found = true;
|
||||
} catch {
|
||||
//
|
||||
|
@ -101,107 +113,130 @@ describe('Room', () => {
|
|||
|
||||
it('should search for old message and load its surroundings', async () => {
|
||||
await navigateToRoom('jumping');
|
||||
await sleep(1000); // wait for proper load the room
|
||||
await element(by.id('room-view-search')).tap();
|
||||
await waitFor(element(by.id('search-messages-view')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('search-message-view-input')).typeText('30\n');
|
||||
await waitFor(element(by.label('30')).atIndex(0))
|
||||
await element(by.id('search-message-view-input')).replaceText('30');
|
||||
await waitFor(element(by[textMatcher]('30')).atIndex(1))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label('30')).atIndex(0).tap();
|
||||
.withTimeout(30000);
|
||||
await element(by[textMatcher]('30')).atIndex(1).tap();
|
||||
await waitForLoading();
|
||||
await expect(element(by.label('30'))).toExist();
|
||||
await expect(element(by.label('31'))).toExist();
|
||||
await expect(element(by.label('32'))).toExist();
|
||||
await waitFor(element(by[textMatcher]('30')).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(30000);
|
||||
await expect(element(by[textMatcher]('31'))).toExist();
|
||||
await expect(element(by[textMatcher]('32'))).toExist();
|
||||
});
|
||||
|
||||
it('should load newer and older messages', async () => {
|
||||
await element(by.id('room-view-messages')).atIndex(0).swipe('down', 'fast', 0.8);
|
||||
await waitFor(element(by.label('5')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await waitFor(element(by.label('Load Older')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label('Load Older')).atIndex(0).tap();
|
||||
await waitFor(element(by.label('4')))
|
||||
// TODO: couldn't make it work on Android :(
|
||||
if (device.getPlatform() === 'android') {
|
||||
return;
|
||||
}
|
||||
let found = false;
|
||||
while (!found) {
|
||||
try {
|
||||
// it doesn't recognize this list
|
||||
await element(by.id('room-view-messages')).scroll(500, 'up');
|
||||
await expect(element(by[textMatcher]('Load Older'))).toBeVisible();
|
||||
await expect(element(by[textMatcher]('5'))).toExist();
|
||||
found = true;
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
}
|
||||
await element(by[textMatcher]('Load Older')).atIndex(0).tap();
|
||||
await waitFor(element(by[textMatcher]('4')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('room-view-messages')).atIndex(0).swipe('down', 'fast', 0.5);
|
||||
await waitFor(element(by.label('1')))
|
||||
await waitFor(element(by[textMatcher]('1')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('room-view-messages')).atIndex(0).swipe('up', 'fast', 0.5);
|
||||
await waitFor(element(by.label('25')))
|
||||
await waitFor(element(by[textMatcher]('25')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('room-view-messages')).atIndex(0).swipe('up', 'fast', 0.5);
|
||||
await waitFor(element(by.label('50')))
|
||||
await waitFor(element(by[textMatcher]('50')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('room-view-messages')).atIndex(0).swipe('up', 'slow', 0.5);
|
||||
await waitFor(element(by.label('Load Newer')))
|
||||
await waitFor(element(by[textMatcher]('Load Newer')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label('Load Newer')).atIndex(0).tap();
|
||||
await waitFor(element(by.label('104')))
|
||||
await element(by[textMatcher]('Load Newer')).atIndex(0).tap();
|
||||
await waitFor(element(by[textMatcher]('104')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.label('Load Newer')))
|
||||
await waitFor(element(by[textMatcher]('Load Newer')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label('Load Newer')).atIndex(0).tap();
|
||||
await waitFor(element(by.label('154')))
|
||||
await element(by[textMatcher]('Load Newer')).atIndex(0).tap();
|
||||
await waitFor(element(by[textMatcher]('154')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.label('Load Newer')))
|
||||
await waitFor(element(by[textMatcher]('Load Newer')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label('Load Newer')).atIndex(0).tap();
|
||||
await waitFor(element(by.label('Load Newer')))
|
||||
await element(by[textMatcher]('Load Newer')).atIndex(0).tap();
|
||||
await waitFor(element(by[textMatcher]('Load Newer')))
|
||||
.toNotExist()
|
||||
.withTimeout(5000);
|
||||
await expect(element(by.label('Load More'))).toNotExist();
|
||||
await expect(element(by.label('201'))).toExist();
|
||||
await expect(element(by.label('202'))).toExist();
|
||||
await expect(element(by[textMatcher]('Load More'))).toNotExist();
|
||||
await expect(element(by[textMatcher]('201'))).toExist();
|
||||
await expect(element(by[textMatcher]('202'))).toExist();
|
||||
await tapBack();
|
||||
});
|
||||
});
|
||||
|
||||
const expectThreadMessages = async message => {
|
||||
await waitFor(element(by.id('room-view-title-jumping-thread')))
|
||||
await waitFor(element(by.id('room-view-title-thread 1')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await expect(element(by.label(message))).toExist();
|
||||
await waitForLoading();
|
||||
await expect(element(by[textMatcher](message)).atIndex(0)).toExist();
|
||||
await element(by[textMatcher](message)).atIndex(0).tap();
|
||||
};
|
||||
|
||||
describe('Threads', () => {
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true });
|
||||
});
|
||||
|
||||
it('should navigate to a thread from another room', async () => {
|
||||
await navigateToRoom('jumping');
|
||||
await waitFor(element(by.label("Go to jumping-thread's thread")).atIndex(0))
|
||||
await waitFor(element(by[textMatcher]("Go to jumping-thread's thread")).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label("Go to jumping-thread's thread")).atIndex(0).tap();
|
||||
await waitForLoading();
|
||||
await element(by[textMatcher]("Go to jumping-thread's thread")).atIndex(0).tap();
|
||||
await expectThreadMessages("Go to jumping-thread's thread");
|
||||
await tapBack();
|
||||
});
|
||||
|
||||
it('should tap on thread message from main room', async () => {
|
||||
await waitFor(element(by.label('thread message sent to main room')).atIndex(0))
|
||||
await waitFor(element(by.id('room-view-title-jumping-thread')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label('thread message sent to main room')).atIndex(0).tap();
|
||||
await waitFor(element(by[textMatcher]('thread message sent to main room')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by[textMatcher]('thread message sent to main room')).atIndex(0).tap();
|
||||
await expectThreadMessages('thread message sent to main room');
|
||||
await tapBack();
|
||||
});
|
||||
|
||||
it('should tap on quote', async () => {
|
||||
await waitFor(element(by.label('quoted')))
|
||||
await waitFor(element(by.id('room-view-title-jumping-thread')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label('quoted')).atIndex(0).tap();
|
||||
await waitFor(element(by[textMatcher]('quoted')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by[textMatcher]('quoted')).atIndex(0).tap();
|
||||
await expectThreadMessages('quoted');
|
||||
await tapBack();
|
||||
});
|
||||
|
@ -214,11 +249,11 @@ describe('Threads', () => {
|
|||
await waitFor(element(by.id('search-messages-view')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('search-message-view-input')).typeText('to be searched\n');
|
||||
await waitFor(element(by.label('to be searched')))
|
||||
await element(by.id('search-message-view-input')).replaceText('to be searched');
|
||||
await waitFor(element(by[textMatcher]('to be searched')).atIndex(1))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.label('to be searched')).atIndex(1).tap();
|
||||
.withTimeout(30000);
|
||||
await element(by[textMatcher]('to be searched')).atIndex(1).tap();
|
||||
await expectThreadMessages('to be searched');
|
||||
});
|
||||
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, platformTypes } = require('../../helpers/app');
|
||||
|
||||
const teamName = `team-${data.random}`;
|
||||
|
||||
describe('Create team screen', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(data.users.regular.username, data.users.regular.password);
|
||||
});
|
||||
|
@ -41,17 +44,23 @@ describe('Create team screen', () => {
|
|||
describe('Create Team', () => {
|
||||
describe('Usage', () => {
|
||||
it('should get invalid team name', async () => {
|
||||
await element(by.id('create-channel-name')).typeText(`${data.teams.private.name}`);
|
||||
await element(by.id('create-channel-name')).replaceText(`${data.teams.private.name}`);
|
||||
await waitFor(element(by.id('create-channel-submit')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('create-channel-submit')).tap();
|
||||
await waitFor(element(by.text('OK')))
|
||||
await waitFor(element(by[textMatcher]('OK').and(by.type(alertButtonType))))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
await element(by.text('OK')).tap();
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
});
|
||||
|
||||
it('should create private team', async () => {
|
||||
await element(by.id('create-channel-name')).replaceText('');
|
||||
await element(by.id('create-channel-name')).typeText(teamName);
|
||||
await element(by.id('create-channel-name')).replaceText(teamName);
|
||||
await waitFor(element(by.id('create-channel-submit')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('create-channel-submit')).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toExist()
|
||||
|
@ -81,10 +90,10 @@ describe('Create team screen', () => {
|
|||
await element(by.id('room-info-view-edit-button')).tap();
|
||||
await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
|
||||
await element(by.id('room-info-edit-view-delete')).tap();
|
||||
await waitFor(element(by.text('Yes, delete it!')))
|
||||
await waitFor(element(by[textMatcher]('Yes, delete it!')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await element(by.text('Yes, delete it!')).tap();
|
||||
await element(by[textMatcher]('Yes, delete it!').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('rooms-list-view')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, tapBack, sleep, searchRoom } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, tapBack, sleep, searchRoom, platformTypes } = require('../../helpers/app');
|
||||
|
||||
async function navigateToRoom(roomName) {
|
||||
await searchRoom(`${roomName}`);
|
||||
|
@ -17,6 +17,7 @@ async function openActionSheet(username) {
|
|||
await sleep(300);
|
||||
await expect(element(by.id('action-sheet'))).toExist();
|
||||
await expect(element(by.id('action-sheet-handle'))).toBeVisible();
|
||||
await element(by.id('action-sheet-handle')).swipe('up');
|
||||
}
|
||||
|
||||
async function navigateToRoomActions() {
|
||||
|
@ -37,20 +38,41 @@ async function backToActions() {
|
|||
}
|
||||
async function closeActionSheet() {
|
||||
await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.6);
|
||||
await waitFor(element(by.id('action-sheet-handle')))
|
||||
.toBeNotVisible()
|
||||
.withTimeout(3000);
|
||||
await sleep(200);
|
||||
}
|
||||
|
||||
async function waitForToast() {
|
||||
await sleep(1000);
|
||||
}
|
||||
|
||||
async function swipeTillVisible(container, find, direction = 'up', delta = 0.3, speed = 'slow') {
|
||||
let found = false;
|
||||
while (!found) {
|
||||
try {
|
||||
await element(container).swipe(direction, speed, delta);
|
||||
await sleep(200);
|
||||
await expect(element(find)).toBeVisible();
|
||||
found = true;
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe('Team', () => {
|
||||
const team = data.teams.private.name;
|
||||
const user = data.users.alternate;
|
||||
const room = `private${data.random}-channel-team`;
|
||||
const existingRoom = data.groups.alternate.name;
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(data.users.regular.username, data.users.regular.password);
|
||||
await navigateToRoom(team);
|
||||
|
@ -86,7 +108,7 @@ describe('Team', () => {
|
|||
|
||||
describe('Team Channels Header', () => {
|
||||
it('should have actions button ', async () => {
|
||||
await expect(element(by.id('room-header'))).toExist();
|
||||
await expect(element(by.id('room-header')).atIndex(0)).toExist();
|
||||
});
|
||||
|
||||
it('should have team channels button ', async () => {
|
||||
|
@ -124,6 +146,9 @@ describe('Team', () => {
|
|||
await element(by.id('add-channel-team-view-create-channel')).tap();
|
||||
|
||||
await element(by.id('select-users-view-search')).replaceText('rocket.cat');
|
||||
await waitFor(element(by.id('select-users-view-item-rocket.cat')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
await element(by.id('select-users-view-item-rocket.cat')).tap();
|
||||
await waitFor(element(by.id('selected-user-rocket.cat')))
|
||||
.toBeVisible()
|
||||
|
@ -134,7 +159,10 @@ describe('Team', () => {
|
|||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by.id('create-channel-name')).replaceText('');
|
||||
await element(by.id('create-channel-name')).typeText(room);
|
||||
await element(by.id('create-channel-name')).replaceText(room);
|
||||
await waitFor(element(by.id('create-channel-submit')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by.id('create-channel-submit')).tap();
|
||||
|
||||
await waitFor(element(by.id('room-view')))
|
||||
|
@ -156,9 +184,9 @@ describe('Team', () => {
|
|||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await expect(element(by.id(`room-view-title-${room}`))).toExist();
|
||||
await expect(element(by.id('room-view-header-team-channels'))).toExist();
|
||||
await expect(element(by.id('room-view-header-threads'))).toExist();
|
||||
await expect(element(by.id('room-view-search'))).toExist();
|
||||
await expect(element(by.id('room-view-header-team-channels')).atIndex(0)).toExist();
|
||||
await expect(element(by.id('room-view-header-threads')).atIndex(0)).toExist();
|
||||
await expect(element(by.id('room-view-search')).atIndex(0)).toExist();
|
||||
await tapBack();
|
||||
});
|
||||
|
||||
|
@ -186,7 +214,7 @@ describe('Team', () => {
|
|||
await expect(element(by.id('room-view-header-team-channels'))).toExist();
|
||||
await element(by.id('room-view-header-team-channels')).tap();
|
||||
|
||||
await waitFor(element(by.id(`rooms-list-view-item-${existingRoom}`)))
|
||||
await waitFor(element(by.id(`rooms-list-view-item-${existingRoom}`)).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
});
|
||||
|
@ -195,7 +223,8 @@ describe('Team', () => {
|
|||
await element(by.id(`rooms-list-view-item-${existingRoom}`))
|
||||
.atIndex(0)
|
||||
.longPress();
|
||||
|
||||
await sleep(500);
|
||||
await swipeTillVisible(by.id('action-sheet-remove-from-team'), by.id('action-sheet-delete'));
|
||||
await waitFor(element(by.id('action-sheet-auto-join')))
|
||||
.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
|
@ -224,7 +253,7 @@ describe('Team', () => {
|
|||
await waitFor(element(by.id('auto-join-tag')))
|
||||
.toBeNotVisible()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.id(`rooms-list-view-item-${existingRoom}`)))
|
||||
await waitFor(element(by.id(`rooms-list-view-item-${existingRoom}`)).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(6000);
|
||||
});
|
||||
|
@ -298,22 +327,22 @@ describe('Team', () => {
|
|||
|
||||
await waitFor(
|
||||
element(
|
||||
by.label(
|
||||
by[textMatcher](
|
||||
'You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.'
|
||||
)
|
||||
)
|
||||
)
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.text('OK')).tap();
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('select-list-view-submit')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('select-list-view-submit')).tap();
|
||||
await waitFor(element(by.text('Last owner cannot be removed')))
|
||||
await waitFor(element(by[textMatcher]('Last owner cannot be removed')))
|
||||
.toExist()
|
||||
.withTimeout(8000);
|
||||
await element(by.text('OK')).tap();
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('room-actions-view')))
|
||||
.toExist()
|
||||
|
@ -352,6 +381,9 @@ describe('Team', () => {
|
|||
|
||||
it('should remove member from team', async () => {
|
||||
await openActionSheet('rocket.cat');
|
||||
await waitFor(element(by.id('action-sheet-remove-from-team')))
|
||||
.toBeVisible()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('action-sheet-remove-from-team')).tap();
|
||||
await waitFor(element(by.id('select-list-view')))
|
||||
.toExist()
|
||||
|
@ -406,14 +438,14 @@ describe('Team', () => {
|
|||
|
||||
await waitFor(
|
||||
element(
|
||||
by.label(
|
||||
by[textMatcher](
|
||||
'You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.'
|
||||
)
|
||||
)
|
||||
)
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.text('OK')).tap();
|
||||
await element(by[textMatcher]('OK').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('select-list-view-submit')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const data = require('../../data');
|
||||
const { navigateToLogin, login, tapBack, searchRoom, sleep } = require('../../helpers/app');
|
||||
const { navigateToLogin, login, tapBack, searchRoom, sleep, platformTypes } = require('../../helpers/app');
|
||||
|
||||
const toBeConverted = `to-be-converted-${data.random}`;
|
||||
const toBeMoved = `to-be-moved-${data.random}`;
|
||||
|
@ -17,7 +17,10 @@ const createChannel = async room => {
|
|||
await waitFor(element(by.id('create-channel-view')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by.id('create-channel-name')).typeText(room);
|
||||
await element(by.id('create-channel-name')).replaceText(room);
|
||||
await waitFor(element(by.id('create-channel-submit')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by.id('create-channel-submit')).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toExist()
|
||||
|
@ -51,8 +54,11 @@ async function navigateToRoomActions(room) {
|
|||
}
|
||||
|
||||
describe('Move/Convert Team', () => {
|
||||
let alertButtonType;
|
||||
let textMatcher;
|
||||
before(async () => {
|
||||
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
|
||||
({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
|
||||
await navigateToLogin();
|
||||
await login(data.users.regular.username, data.users.regular.password);
|
||||
});
|
||||
|
@ -69,10 +75,10 @@ describe('Move/Convert Team', () => {
|
|||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-actions-convert-to-team')).tap();
|
||||
await waitFor(element(by.label('You are converting this Channel to a Team. All Members will be kept.')))
|
||||
await waitFor(element(by[textMatcher]('You are converting this Channel to a Team. All Members will be kept.')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.text('Convert')).tap();
|
||||
await element(by[textMatcher]('Convert').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toExist()
|
||||
.withTimeout(20000);
|
||||
|
@ -101,12 +107,14 @@ describe('Move/Convert Team', () => {
|
|||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-actions-move-to-team')).tap();
|
||||
await waitFor(element(by.id('select-list-view')))
|
||||
await waitFor(element(by[textMatcher]('Move to Team')).atIndex(0))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await waitFor(element(by.id('select-list-view-submit')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('select-list-view-submit')).tap();
|
||||
await sleep(2000);
|
||||
await waitFor(element(by.id('select-list-view')))
|
||||
await waitFor(element(by[textMatcher]('Select Team')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await waitFor(element(by.id(`select-list-view-item-${toBeConverted}`)))
|
||||
|
@ -116,14 +124,14 @@ describe('Move/Convert Team', () => {
|
|||
await element(by.id('select-list-view-submit')).atIndex(0).tap();
|
||||
await waitFor(
|
||||
element(
|
||||
by.label(
|
||||
by[textMatcher](
|
||||
'After reading the previous intructions about this behavior, do you still want to move this channel to the selected team?'
|
||||
)
|
||||
)
|
||||
)
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.text('Yes, move it!')).tap();
|
||||
await element(by[textMatcher]('Yes, move it!').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('room-view-header-team-channels')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
|
@ -141,12 +149,11 @@ describe('Move/Convert Team', () => {
|
|||
it('should convert a team to a channel', async () => {
|
||||
await navigateToRoomActions(toBeConverted);
|
||||
await element(by.id('room-actions-scrollview')).scrollTo('bottom');
|
||||
await waitFor(element(by.id('room-actions-convert-channel-to-team')))
|
||||
await waitFor(element(by[textMatcher]('Convert to Channel')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-actions-convert-channel-to-team')).tap();
|
||||
await sleep(2000);
|
||||
await waitFor(element(by.id('select-list-view')))
|
||||
await element(by[textMatcher]('Convert to Channel')).atIndex(0).tap();
|
||||
await waitFor(element(by[textMatcher]('Converting Team to Channel')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await waitFor(element(by.id(`select-list-view-item-${toBeMoved}`)))
|
||||
|
@ -157,10 +164,10 @@ describe('Move/Convert Team', () => {
|
|||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('select-list-view-submit')).tap();
|
||||
await waitFor(element(by.label('You are converting this Team to a Channel')))
|
||||
await waitFor(element(by[textMatcher]('You are converting this Team to a Channel')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.text('Convert')).tap();
|
||||
await element(by[textMatcher]('Convert').and(by.type(alertButtonType))).tap();
|
||||
await waitFor(element(by.id('room-view')))
|
||||
.toExist()
|
||||
.withTimeout(20000);
|
||||
|
|
12
package.json
12
package.json
|
@ -239,6 +239,18 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"and.emu.debug": {
|
||||
"device": "Pixel_API_28_AOSP",
|
||||
"type": "android.emulator",
|
||||
"binaryPath": "android/app/build/outputs/apk/e2ePlay/debug/app-e2e-play-debug.apk",
|
||||
"build": "cd android && ./gradlew app:assembleE2ePlayDebug app:assembleE2ePlayDebugAndroidTest -DtestBuildType=debug && cd .."
|
||||
},
|
||||
"and.emu.release": {
|
||||
"device": "Pixel_API_28_AOSP",
|
||||
"type": "android.emulator",
|
||||
"binaryPath": "android/app/build/outputs/apk/e2ePlay/release/app-e2e-play-release.apk",
|
||||
"build": "cd android && ./gradlew app:assembleE2ePlayRelease app:assembleE2ePlayReleaseAndroidTest -DtestBuildType=release && cd .."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue