Initial commit
This commit is contained in:
parent
afe50aed7e
commit
4bb088d413
|
@ -75,6 +75,11 @@ restore_cache: &restore-gradle-cache
|
|||
name: Restore gradle cache
|
||||
key: android-{{ checksum "android/build.gradle" }}-{{ checksum "android/app/build.gradle" }}
|
||||
|
||||
install-maestro-cli: &install-maestro-cli
|
||||
name: Install Maestro CLI
|
||||
command: |
|
||||
curl -Ls "https://get.maestro.mobile.dev" | bash
|
||||
|
||||
# COMMANDS
|
||||
commands:
|
||||
|
||||
|
@ -362,13 +367,6 @@ commands:
|
|||
working_directory: ios
|
||||
- save_cache: *save-gems-cache
|
||||
|
||||
create-e2e-account-file:
|
||||
description: "Create e2e account file"
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
echo $E2E_ACCOUNT | base64 --decode > ./e2e_account.ts
|
||||
working_directory: e2e
|
||||
|
||||
version: 2.1
|
||||
|
||||
|
@ -516,8 +514,7 @@ jobs:
|
|||
- run:
|
||||
name: Build Android
|
||||
command: |
|
||||
export RUNNING_E2E_TESTS=true
|
||||
yarn e2e:android-build
|
||||
yarn android
|
||||
- save_cache: *save-gradle-cache
|
||||
- store_artifacts:
|
||||
path: android/app/build/outputs/apk/experimentalPlay/release/app-experimental-play-release.apk
|
||||
|
@ -534,7 +531,6 @@ jobs:
|
|||
name: android/android-machine
|
||||
resource-class: large
|
||||
tag: 2022.12.1
|
||||
parallelism: 4
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
|
@ -542,8 +538,8 @@ jobs:
|
|||
- restore_cache: *restore-npm-cache-linux
|
||||
- run: *install-npm-modules
|
||||
- save_cache: *save-npm-cache-linux
|
||||
- run: *install-maestro-cli
|
||||
- run: mkdir ~/junit
|
||||
- create-e2e-account-file
|
||||
- android/create-avd:
|
||||
avd-name: Pixel_API_31_AOSP
|
||||
install: true
|
||||
|
@ -555,14 +551,13 @@ jobs:
|
|||
echo "hw.lcd.height = 2280" >> ~/.android/avd/Pixel_API_31_AOSP.avd/config.ini
|
||||
echo "hw.lcd.width = 1080" >> ~/.android/avd/Pixel_API_31_AOSP.avd/config.ini
|
||||
- run:
|
||||
name: Run Detox Tests
|
||||
name: Run Maestro Tests
|
||||
command: |
|
||||
TEST=$(circleci tests glob "e2e/tests/**/*.ts" | circleci tests split --split-by=timings)
|
||||
yarn e2e:android-test $TEST
|
||||
maestro test -e APP_ID=chat.rocket.reactnative -e PLATFORM=Android e2e/ --format junit
|
||||
- store_artifacts:
|
||||
path: artifacts
|
||||
- run:
|
||||
command: cp junit.xml ~/junit/
|
||||
command: cp report.xml ~/junit/
|
||||
when: always
|
||||
- store_test_results:
|
||||
path: ~/junit
|
||||
|
@ -604,19 +599,12 @@ jobs:
|
|||
- save_cache: *save-npm-cache-mac
|
||||
- save_cache: *save-gems-cache
|
||||
- manage-pods
|
||||
- run:
|
||||
name: Configure Detox
|
||||
command: |
|
||||
brew tap wix/brew
|
||||
brew install applesimutils
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
/usr/libexec/PlistBuddy -c "Set :bugsnag:apiKey $BUGSNAG_KEY" ./ios/RocketChatRN/Info.plist
|
||||
/usr/libexec/PlistBuddy -c "Set :bugsnag:apiKey $BUGSNAG_KEY" ./ios/ShareRocketChatRN/Info.plist
|
||||
yarn detox clean-framework-cache && yarn detox build-framework-cache
|
||||
export RUNNING_E2E_TESTS=true
|
||||
yarn e2e:ios-build
|
||||
yarn ios
|
||||
- persist_to_workspace:
|
||||
root: /Users/distiller/project
|
||||
paths:
|
||||
|
@ -624,7 +612,6 @@ jobs:
|
|||
|
||||
e2e-test-ios:
|
||||
executor: mac-env
|
||||
parallelism: 5
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
|
@ -632,23 +619,21 @@ jobs:
|
|||
- restore_cache: *restore-npm-cache-mac
|
||||
- run: *install-npm-modules
|
||||
- save_cache: *save-npm-cache-mac
|
||||
- run: *install-maestro-cli
|
||||
- run:
|
||||
name: Configure Facebook IDB
|
||||
command: |
|
||||
brew tap facebook/fb
|
||||
brew install facebook/fb/idb-companion
|
||||
- run: mkdir ~/junit
|
||||
- run:
|
||||
name: Configure Detox
|
||||
name: Run Maestro Tests
|
||||
command: |
|
||||
brew tap wix/brew
|
||||
brew install applesimutils
|
||||
yarn detox clean-framework-cache && yarn detox build-framework-cache
|
||||
- create-e2e-account-file
|
||||
- run:
|
||||
name: Run tests
|
||||
command: |
|
||||
TEST=$(circleci tests glob "e2e/tests/**/*.ts" | circleci tests split --split-by=timings)
|
||||
yarn e2e:ios-test $TEST
|
||||
maestro test -e APP_ID=chat.rocket.reactnative -e PLATFORM=iOS e2e/ --format junit
|
||||
- store_artifacts:
|
||||
path: artifacts
|
||||
- run:
|
||||
command: cp junit.xml ~/junit/
|
||||
command: cp report.xml ~/junit/
|
||||
when: always
|
||||
- store_test_results:
|
||||
path: ~/junit
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import { RectButton, RectButtonProps } from 'react-native-gesture-handler';
|
||||
import { View } from 'react-native';
|
||||
|
||||
import { useTheme } from '../theme';
|
||||
|
||||
|
@ -9,20 +10,22 @@ export interface ITouchProps extends RectButtonProps {
|
|||
testID?: string;
|
||||
}
|
||||
|
||||
const Touch = React.forwardRef<RectButton, ITouchProps>(({ children, onPress, underlayColor, ...props }, ref) => {
|
||||
const Touch = React.forwardRef<RectButton, ITouchProps>(({ children, onPress, underlayColor, testID, ...props }, ref) => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<RectButton
|
||||
ref={ref}
|
||||
onPress={onPress}
|
||||
activeOpacity={1}
|
||||
underlayColor={underlayColor || colors.bannerBackground}
|
||||
rippleColor={colors.bannerBackground}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</RectButton>
|
||||
<View testID={testID}>
|
||||
<RectButton
|
||||
ref={ref}
|
||||
onPress={onPress}
|
||||
activeOpacity={1}
|
||||
underlayColor={underlayColor || colors.bannerBackground}
|
||||
rippleColor={colors.bannerBackground}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</RectButton>
|
||||
</View>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useContext } from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { Alert, View } from 'react-native';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
|
||||
import MessageContext from './Context';
|
||||
|
@ -153,7 +153,7 @@ const MessageTouchable = React.memo((props: IMessageTouchable & IMessage) => {
|
|||
disabled={(props.isInfo && !props.isThreadReply) || props.archived || props.isTemp || props.type === 'jitsi_call_started'}
|
||||
style={{ backgroundColor }}
|
||||
>
|
||||
<View>
|
||||
<View testID='message-container'>
|
||||
<Message {...props} />
|
||||
</View>
|
||||
</Touchable>
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/* eslint-disable no-undef */
|
||||
|
||||
const data = {
|
||||
server: 'https://mobile.rocket.chat',
|
||||
alternateServer: 'https://stable.rocket.chat',
|
||||
adminUser: MAESTRO_ADMIN_USER,
|
||||
adminPassword: MAESTRO_ADMIN_PASSWORD,
|
||||
channels: {
|
||||
detoxpublic: {
|
||||
name: 'detox-public'
|
||||
},
|
||||
detoxpublicprotected: {
|
||||
name: 'detox-public-protected',
|
||||
joinCode: '123'
|
||||
}
|
||||
},
|
||||
randomUser: () => {
|
||||
const randomVal = output.helpers_random();
|
||||
return {
|
||||
username: `user${randomVal}`,
|
||||
name: `user${randomVal}`, // FIXME: apply a different name
|
||||
password: `Password1@${randomVal}`,
|
||||
email: `mobile+${randomVal}@rocket.chat`
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
output.data = data;
|
|
@ -0,0 +1,7 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: ${'room-view-title-' + room}
|
||||
optional: true
|
||||
timeout: 60000
|
|
@ -0,0 +1,18 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: 'login-view'
|
||||
timeout: 2000
|
||||
- tapOn:
|
||||
id: 'login-view-email'
|
||||
- inputText: ${username}
|
||||
- pressKey: enter
|
||||
- tapOn:
|
||||
id: 'login-view-password'
|
||||
- inputText: ${password}
|
||||
- pressKey: enter
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: 'rooms-list-view'
|
||||
timeout: 30000
|
|
@ -0,0 +1,10 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- runFlow:
|
||||
file: navigateToWorkspace.yaml
|
||||
- tapOn:
|
||||
id: 'workspace-view-login'
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: 'login-view'
|
||||
timeout: 2000
|
|
@ -0,0 +1,13 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- runFlow:
|
||||
file: searchRoom.yaml
|
||||
env:
|
||||
room: ${room}
|
||||
- tapOn:
|
||||
text: ${room}
|
||||
index: 1
|
||||
- runFlow:
|
||||
file: checkRoomTitle.yaml
|
||||
env:
|
||||
room: ${room}
|
|
@ -0,0 +1,18 @@
|
|||
appId: ${APP_ID}
|
||||
env:
|
||||
server: ${server || output.data.server}
|
||||
---
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: 'new-server-view'
|
||||
timeout: 60000
|
||||
- tapOn:
|
||||
id: 'new-server-view-input'
|
||||
- inputText: ${server}
|
||||
- pressKey: enter
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: 'workspace-view'
|
||||
timeout: 60000
|
||||
- assertVisible:
|
||||
id: 'workspace-view'
|
|
@ -0,0 +1,30 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: 'rooms-list-view'
|
||||
timeout: 30000
|
||||
- tapOn:
|
||||
id: 'rooms-list-view-search'
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: 'rooms-list-view-search-input'
|
||||
timeout: 1000
|
||||
- waitForAnimationToEnd:
|
||||
timeout: 500
|
||||
- runFlow:
|
||||
when:
|
||||
true: ${nativeElementAction === 'replaceText'}
|
||||
commands:
|
||||
- tapOn:
|
||||
id: 'rooms-list-view-search-input'
|
||||
- inputText: ''
|
||||
- tapOn:
|
||||
id: 'rooms-list-view-search-input'
|
||||
- inputText: ${room}
|
||||
- evalScript: ${output.helpers_sleep(500)}
|
||||
- evalScript: ${output.helpers_sleep(500)}
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: ${roomTestId || 'rooms-list-view-item-' + room}
|
||||
timeout: 60000
|
|
@ -0,0 +1,70 @@
|
|||
/* eslint-disable no-undef */
|
||||
const { server } = output.data;
|
||||
|
||||
const baseURL = `${server}/api/v1/`;
|
||||
|
||||
let headers = {
|
||||
'Content-Type': 'application/json;charset=UTF-8'
|
||||
};
|
||||
|
||||
const login = (username, password) => {
|
||||
console.log(`Logging in as user ${username}`);
|
||||
const response = http.post(`${baseURL}login`, {
|
||||
headers: { ...headers },
|
||||
body: JSON.stringify({
|
||||
user: username,
|
||||
password
|
||||
})
|
||||
});
|
||||
|
||||
const { authToken, userId } = json(response.body).data;
|
||||
headers = { ...headers, 'X-User-Id': userId, 'X-Auth-Token': authToken };
|
||||
return { authToken, userId };
|
||||
};
|
||||
|
||||
const createRandomUser = () => {
|
||||
try {
|
||||
login(output.data.adminUser, output.data.adminPassword);
|
||||
const user = output.data.randomUser();
|
||||
console.log(`Creating user ${user.username}`);
|
||||
|
||||
http.post(`${baseURL}users.create`, {
|
||||
headers: { ...headers },
|
||||
body: JSON.stringify({
|
||||
username: user.username,
|
||||
name: user.name,
|
||||
password: user.password,
|
||||
email: user.email
|
||||
})
|
||||
});
|
||||
return user;
|
||||
} catch (error) {
|
||||
console.log(JSON.stringify(error));
|
||||
throw new Error('Failed to create user');
|
||||
}
|
||||
};
|
||||
|
||||
const sendMessage = (user, channel, msg, tmid) => {
|
||||
console.log(`Sending message to ${channel}`);
|
||||
try {
|
||||
login(user.username, user.password);
|
||||
const response = http.post(`${baseURL}chat.postMessage`, {
|
||||
headers: { ...headers },
|
||||
body: JSON.stringify({
|
||||
channel,
|
||||
msg,
|
||||
tmid
|
||||
})
|
||||
});
|
||||
return json(response.body).data;
|
||||
} catch (infoError) {
|
||||
console.log(JSON.stringify(infoError));
|
||||
throw new Error('Failed to find or create private group');
|
||||
}
|
||||
};
|
||||
|
||||
output.helpers_data_setup = {
|
||||
login,
|
||||
createRandomUser,
|
||||
sendMessage
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
/* eslint-disable no-undef */
|
||||
const random = (length = 10) => {
|
||||
let text = '';
|
||||
const possible = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
|
||||
for (let i = 0; i < length; i += 1) {
|
||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
output.helpers_random = random;
|
|
@ -0,0 +1,9 @@
|
|||
/* eslint-disable no-undef */
|
||||
const sleep = (time) => {
|
||||
const t = new Date().getTime() + time;
|
||||
while (new Date().getTime() <= t) {
|
||||
// do nothing
|
||||
}
|
||||
};
|
||||
|
||||
output.helpers_sleep = sleep;
|
|
@ -0,0 +1,6 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- runScript: data.js
|
||||
- runScript: helpers/random.js
|
||||
- runScript: helpers/sleep.js
|
||||
- runScript: helpers/data_setup.js
|
|
@ -0,0 +1,48 @@
|
|||
appId: ${APP_ID}
|
||||
name: Onboarding
|
||||
onFlowStart:
|
||||
- runFlow: ../../init.yaml
|
||||
---
|
||||
- launchApp:
|
||||
clearState: true
|
||||
clearKeychain: true
|
||||
permissions:
|
||||
android.permission.POST_NOTIFICATIONS: allow
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: 'new-server-view'
|
||||
timeout: 20000
|
||||
|
||||
# should have onboarding screen
|
||||
- assertVisible:
|
||||
id: 'new-server-view'
|
||||
|
||||
# should enter an invalid server and get error
|
||||
- tapOn:
|
||||
id: 'new-server-view-input'
|
||||
- inputText: 'invalidtest'
|
||||
- pressKey: enter
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
text: 'Oops!'
|
||||
optional: true
|
||||
timeout: 10000
|
||||
- tapOn:
|
||||
text: 'OK'
|
||||
optional: true
|
||||
|
||||
# should enter a valid server without login services and navigate to login
|
||||
- launchApp:
|
||||
stopApp: true
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: 'new-server-view'
|
||||
timeout: 5000
|
||||
- tapOn:
|
||||
id: 'new-server-view-input'
|
||||
- inputText: ${output.data.server}
|
||||
- pressKey: enter
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: 'new-server-view'
|
||||
timeout: 60000
|
|
@ -0,0 +1,54 @@
|
|||
appId: ${APP_ID}
|
||||
name: Mark as unread
|
||||
env:
|
||||
name: 'markasunread'
|
||||
message: 'message-mark-as-unread'
|
||||
onFlowStart:
|
||||
- runFlow: ../../init.yaml
|
||||
- runScript: helpers/07-markasunread/init.js
|
||||
---
|
||||
- evalScript: ${output.helpers_sleep(5000)}
|
||||
- evalScript: ${output[name].user = output.helpers_data_setup.createRandomUser()}
|
||||
- evalScript: ${output[name].otherUser = output.helpers_data_setup.createRandomUser()}
|
||||
- launchApp:
|
||||
clearState: true
|
||||
clearKeychain: true
|
||||
permissions:
|
||||
android.permission.POST_NOTIFICATIONS: allow
|
||||
- runFlow:
|
||||
file: ../../helpers/app/navigateToLogin.yaml
|
||||
- runFlow:
|
||||
file: ../../helpers/app/login.yaml
|
||||
env:
|
||||
username: ${output[name].user.username}
|
||||
password: ${output[name].user.password}
|
||||
- runFlow:
|
||||
file: ../../helpers/app/navigateToRoom.yaml
|
||||
env:
|
||||
room: ${output[name].otherUser.username}
|
||||
|
||||
# should mark message as unread
|
||||
- evalScript: ${output.helpers_data_setup.sendMessage(output[name].otherUser,'@' + output[name].user.username, message)}
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
text: ${message}
|
||||
timeout: 30000
|
||||
- evalScript: ${output.helpers_sleep(300)}
|
||||
- longPressOn:
|
||||
text: ${message}
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: action-sheet-handle
|
||||
timeout: 3000
|
||||
- swipe:
|
||||
direction: UP
|
||||
duration: 100
|
||||
- tapOn:
|
||||
text: 'Mark unread'
|
||||
index: 0
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: rooms-list-view
|
||||
timeout: 5000
|
||||
- assertVisible:
|
||||
id: ${ 'rooms-list-view-item-' + output[name].otherUser.username }
|
|
@ -0,0 +1,5 @@
|
|||
/* eslint-disable no-undef */
|
||||
output.markasunread = {
|
||||
user: null,
|
||||
otherUser: null
|
||||
};
|
Loading…
Reference in New Issue