diff --git a/.eslintignore b/.eslintignore index 398578ec4..9594dcce6 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,6 +1,6 @@ __tests__ node_modules coverage -e2e +e2e/docker android ios \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 31146aefe..409efb70a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -29,7 +29,8 @@ module.exports = { "commonjs": true, "es6": true, "node": true, - "jquery": true + "jquery": true, + "mocha": true }, "rules": { "react/jsx-filename-extension": [1, { @@ -155,5 +156,23 @@ module.exports = { }, "globals": { "__DEV__": true - } + }, + overrides: [ + { + files: ['e2e/**'], + globals: { + by: true, + detox: true, + device: true, + element: true, + expect: true, + waitFor: true + }, + rules: { + 'import/no-extraneous-dependencies': 0, + 'no-await-in-loop': 0, + 'no-restricted-syntax': 0 + } + } + ] }; diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 3e3106d94..f7291f458 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -11490,7 +11490,7 @@ exports[`Storyshots LoadMore black theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -11593,7 +11593,7 @@ exports[`Storyshots LoadMore black theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -11696,7 +11696,7 @@ exports[`Storyshots LoadMore black theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -11973,7 +11973,7 @@ exports[`Storyshots LoadMore black theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -12076,7 +12076,7 @@ exports[`Storyshots LoadMore black theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -12179,7 +12179,7 @@ exports[`Storyshots LoadMore black theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -12420,7 +12420,7 @@ exports[`Storyshots LoadMore black theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -12692,7 +12692,7 @@ exports[`Storyshots LoadMore dark theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -12795,7 +12795,7 @@ exports[`Storyshots LoadMore dark theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -12898,7 +12898,7 @@ exports[`Storyshots LoadMore dark theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -13175,7 +13175,7 @@ exports[`Storyshots LoadMore dark theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -13278,7 +13278,7 @@ exports[`Storyshots LoadMore dark theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -13381,7 +13381,7 @@ exports[`Storyshots LoadMore dark theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -13622,7 +13622,7 @@ exports[`Storyshots LoadMore dark theme 1`] = ` }, undefined, Object { - "color": "#e8ebed", + "color": "#cbced1", }, ] } @@ -67631,7 +67631,7 @@ Array [ "textAlign": "left", }, Object { - "color": "#e8ebed", + "color": "#cbced1", }, Object { "backgroundColor": "transparent", @@ -67791,7 +67791,7 @@ Array [ "textAlign": "left", }, Object { - "color": "#e8ebed", + "color": "#cbced1", }, Object { "backgroundColor": "transparent", @@ -74309,7 +74309,7 @@ exports[`Storyshots Thread Messages.Item themes 1`] = ` "textAlign": "left", }, Object { - "color": "#e8ebed", + "color": "#cbced1", }, Object { "flex": 1, @@ -74661,7 +74661,7 @@ exports[`Storyshots Thread Messages.Item themes 1`] = ` "textAlign": "left", }, Object { - "color": "#e8ebed", + "color": "#cbced1", }, Object { "flex": 1, diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js index 1fd8679bc..0790b7bad 100644 --- a/app/actions/actionsTypes.js +++ b/app/actions/actionsTypes.js @@ -66,9 +66,10 @@ export const INVITE_LINKS = createRequestTypes('INVITE_LINKS', [ 'CLEAR', ...defaultTypes ]); -export const SETTINGS = createRequestTypes('SETTINGS', ['CLEAR', 'ADD']); +export const SETTINGS = createRequestTypes('SETTINGS', ['CLEAR', 'ADD', 'UPDATE']); export const APP_STATE = createRequestTypes('APP_STATE', ['FOREGROUND', 'BACKGROUND']); export const ENTERPRISE_MODULES = createRequestTypes('ENTERPRISE_MODULES', ['CLEAR', 'SET']); export const ENCRYPTION = createRequestTypes('ENCRYPTION', ['INIT', 'STOP', 'DECODE_KEY', 'SET', 'SET_BANNER']); -export const PERMISSIONS = createRequestTypes('PERMISSIONS', ['SET']); +export const PERMISSIONS = createRequestTypes('PERMISSIONS', ['SET', 'UPDATE']); +export const ROLES = createRequestTypes('ROLES', ['SET', 'UPDATE', 'REMOVE']); diff --git a/app/actions/login.js b/app/actions/login.js index daf13d3b4..e0f4c1e28 100644 --- a/app/actions/login.js +++ b/app/actions/login.js @@ -1,10 +1,11 @@ import * as types from './actionsTypes'; -export function loginRequest(credentials, logoutOnError) { +export function loginRequest(credentials, logoutOnError, isFromWebView) { return { type: types.LOGIN.REQUEST, credentials, - logoutOnError + logoutOnError, + isFromWebView }; } diff --git a/app/actions/permissions.js b/app/actions/permissions.js index 88179c34f..444d9f11c 100644 --- a/app/actions/permissions.js +++ b/app/actions/permissions.js @@ -6,3 +6,10 @@ export function setPermissions(permissions) { permissions }; } + +export function updatePermission(id, roles) { + return { + type: types.PERMISSIONS.UPDATE, + payload: { id, roles } + }; +} diff --git a/app/actions/roles.js b/app/actions/roles.js new file mode 100644 index 000000000..8ee30425b --- /dev/null +++ b/app/actions/roles.js @@ -0,0 +1,20 @@ +import * as types from './actionsTypes'; + +export function setRoles(roles) { + return { + type: types.ROLES.SET, + roles + }; +} +export function updateRoles(id, desc) { + return { + type: types.ROLES.UPDATE, + payload: { id, desc } + }; +} +export function removeRoles(id) { + return { + type: types.ROLES.REMOVE, + payload: { id } + }; +} diff --git a/app/actions/room.js b/app/actions/room.js index 4ad7e87f6..2753d7b9a 100644 --- a/app/actions/room.js +++ b/app/actions/room.js @@ -23,11 +23,12 @@ export function leaveRoom(roomType, room, selected) { }; } -export function deleteRoom(rid, t) { +export function deleteRoom(roomType, room, selected) { return { type: types.ROOM.DELETE, - rid, - t + room, + roomType, + selected }; } diff --git a/app/actions/settings.js b/app/actions/settings.js index 381958c54..6fae375bc 100644 --- a/app/actions/settings.js +++ b/app/actions/settings.js @@ -7,6 +7,13 @@ export function addSettings(settings) { }; } +export function updateSettings(id, value) { + return { + type: SETTINGS.UPDATE, + payload: { id, value } + }; +} + export function clearSettings() { return { type: SETTINGS.CLEAR diff --git a/app/constants/colors.js b/app/constants/colors.js index 554d7f8d3..1172b4bc9 100644 --- a/app/constants/colors.js +++ b/app/constants/colors.js @@ -74,7 +74,7 @@ export const themes = { auxiliaryBackground: '#07101e', bannerBackground: '#0e1f38', titleText: '#f9f9f9', - bodyText: '#e8ebed', + bodyText: '#cbced1', backdropColor: '#000000', dangerColor: '#f5455c', successColor: '#2de0a5', @@ -121,7 +121,7 @@ export const themes = { auxiliaryBackground: '#080808', bannerBackground: '#1f2329', titleText: '#f9f9f9', - bodyText: '#e8ebed', + bodyText: '#cbced1', backdropColor: '#000000', dangerColor: '#f5455c', successColor: '#2de0a5', diff --git a/app/constants/settings.js b/app/constants/settings.js index d684a11c1..14ad8fb36 100644 --- a/app/constants/settings.js +++ b/app/constants/settings.js @@ -196,5 +196,11 @@ export default { }, Accounts_AllowInvisibleStatusOption: { type: 'valueAsString' + }, + Jitsi_Enable_Teams: { + type: 'valueAsBoolean' + }, + Jitsi_Enable_Channels: { + type: 'valuesAsBoolean' } }; diff --git a/app/containers/InAppNotification/NotifierComponent.js b/app/containers/InAppNotification/NotifierComponent.js index b69704359..6268cd098 100644 --- a/app/containers/InAppNotification/NotifierComponent.js +++ b/app/containers/InAppNotification/NotifierComponent.js @@ -76,7 +76,7 @@ const NotifierComponent = React.memo(({ notification, isMasterDetail }) => { const { title = name, avatar = name } = notification; const onPress = () => { - const { prid } = payload; + const { prid, _id } = payload; if (!rid) { return; } @@ -89,7 +89,7 @@ const NotifierComponent = React.memo(({ notification, isMasterDetail }) => { } else { Navigation.navigate('RoomsListView'); } - goRoom({ item, isMasterDetail }); + goRoom({ item, isMasterDetail, jumpToMessageId: _id }); hideNotification(); }; diff --git a/app/i18n/locales/de.json b/app/i18n/locales/de.json index 0a7f7e1ff..e734fd164 100644 --- a/app/i18n/locales/de.json +++ b/app/i18n/locales/de.json @@ -685,7 +685,7 @@ "Following": "verfolgte", "Threads_displaying_all": "zeige alle", "Threads_displaying_following": "zeige gefolgte", - "Threads_displaying_unread": "zeige ungelesene", + "Threads_displaying_unread": "Zeige ungelesene", "No_threads": "Es gibt keine Threads", "No_threads_following": "Du folgst keinen Threads", "No_threads_unread": "Es gibt keine ungelesenen Threads", @@ -724,6 +724,7 @@ "creating_team": "Team erstellen", "team-name-already-exists": "Ein Team mit diesem Namen existiert bereits", "Add_Channel_to_Team": "Kanal zum Team hinzufügen", + "Left_The_Team_Successfully": "Das Team erfolgreich verlassen", "Create_New": "Neu erstellen", "Add_Existing": "Vorhandenes hinzufügen", "Add_Existing_Channel": "Vorhandenen Kanal hinzufügen", diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 926b0c674..723b4dd9e 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -762,5 +762,8 @@ "Move_to_Team_Warning": "After reading the previous intructions about this behavior, do you still want to move this channel to the selected team?", "Load_More": "Load More", "Load_Newer": "Load Newer", - "Load_Older": "Load Older" + "Load_Older": "Load Older", + "Left_The_Room_Successfully": "Left the room successfully", + "Deleted_The_Team_Successfully": "Team deleted successfully", + "Deleted_The_Room_Successfully": "Room deleted successfully" } \ No newline at end of file diff --git a/app/i18n/locales/fr.json b/app/i18n/locales/fr.json index 91388e2de..22088b5d1 100644 --- a/app/i18n/locales/fr.json +++ b/app/i18n/locales/fr.json @@ -724,6 +724,7 @@ "creating_team": "création de l'équipe", "team-name-already-exists": "Une équipe portant ce nom existe déjà", "Add_Channel_to_Team": "Ajouter un canal à l'équipe", + "Left_The_Team_Successfully": "A quitté l'équipe avec succès", "Create_New": "Créer un nouveau", "Add_Existing": "Ajouter existant", "Add_Existing_Channel": "Ajouter un canal existant", @@ -761,5 +762,8 @@ "Move_to_Team_Warning": "Après avoir lu les instructions précédentes sur ce comportement, voulez-vous toujours déplacer ce canal vers l'équipe sélectionnée ?", "Load_More": "Charger plus", "Load_Newer": "Charger plus récent", - "Load_Older": "Charger plus ancien" + "Load_Older": "Charger plus ancien", + "Left_The_Room_Successfully": "A quitté le salon avec succès", + "Deleted_The_Team_Successfully": "Equipe supprimée avec succès", + "Deleted_The_Room_Successfully": "Salon supprimé avec succès" } \ No newline at end of file diff --git a/app/i18n/locales/nl.json b/app/i18n/locales/nl.json index 8a48d3c74..5d54bfee7 100644 --- a/app/i18n/locales/nl.json +++ b/app/i18n/locales/nl.json @@ -724,6 +724,7 @@ "creating_team": "team maken", "team-name-already-exists": "Er bestaat al een team met die naam", "Add_Channel_to_Team": "Kanaal toevoegen aan team", + "Left_The_Team_Successfully": "Het team met succes verlaten", "Create_New": "Maak nieuw", "Add_Existing": "Voeg bestaande", "Add_Existing_Channel": "Bestaand kanaal toevoegen", @@ -761,5 +762,8 @@ "Move_to_Team_Warning": "Wil je na het lezen van de vorige instructies over dit gedrag, dit kanaal nog steeds naar het geselecteerde team verplaatsen?", "Load_More": "Meer laden", "Load_Newer": "Nieuwer laden", - "Load_Older": "Ouder laden" + "Load_Older": "Ouder laden", + "Left_The_Room_Successfully": "Heeft kamer met succes verlaten", + "Deleted_The_Team_Successfully": "Team succesvol verwijderd", + "Deleted_The_Room_Successfully": "Kamer succesvol verwijderd" } \ No newline at end of file diff --git a/app/i18n/locales/pt-BR.json b/app/i18n/locales/pt-BR.json index 9b34d87d3..a56f169b8 100644 --- a/app/i18n/locales/pt-BR.json +++ b/app/i18n/locales/pt-BR.json @@ -664,6 +664,10 @@ "No_team_channels_found": "Nenhum canal encontrado", "Team_not_found": "Time não encontrado", "Private_Team": "Equipe Privada", + "Left_The_Team_Successfully": "Saiu do time com sucesso", "Add_Existing_Channel": "Adicionar Canal Existente", - "invalid-room": "Sala inválida" + "invalid-room": "Sala inválida", + "Left_The_Room_Successfully": "Saiu da sala com sucesso", + "Deleted_The_Team_Successfully": "Time deletado com sucesso", + "Deleted_The_Room_Successfully": "Sala deletada com sucesso" } \ No newline at end of file diff --git a/app/i18n/locales/pt-PT.json b/app/i18n/locales/pt-PT.json index ca7d4dc59..3724b0634 100644 --- a/app/i18n/locales/pt-PT.json +++ b/app/i18n/locales/pt-PT.json @@ -10,19 +10,22 @@ "error-could-not-change-email": "Não foi possível alterar o e-mail", "error-could-not-change-name": "Não foi possível alterar o nome", "error-could-not-change-username": "Não foi possível alterar o nome de utilizador", + "error-could-not-change-status": "Impossível mudar estado", "error-delete-protected-role": "Não é possível eliminar uma função protegida", "error-department-not-found": "Departamento não encontrado", "error-direct-message-file-upload-not-allowed": "Partilha de ficheiros não permitido em mensagens diretas", - "error-duplicate-channel-name": "Um canal com o nome {{channel_name}} existe", + "error-duplicate-channel-name": "Existe um canal com o nome {{room_name}}", "error-email-domain-blacklisted": "O domínio de e-mail está na lista negra", "error-email-send-failed": "Erro ao tentar enviar e-mail: {{message}}", + "error-save-image": "Erro ao salvar imagem", + "error-save-video": "Erro ao salvar vídeo", "error-field-unavailable": "{{field}} já está em uso :(", "error-file-too-large": "Ficheiro demasiado grande", "error-importer-not-defined": "O importador não foi definido correctamente, a classe Import está em falta.", "error-input-is-not-a-valid-field": "{{input}} não é um {{field}} válido", "error-invalid-actionlink": "Link de acção inválido", "error-invalid-arguments": "Argumentos inválidos", - "error-invalid-asset": "Ficheiro inválida", + "error-invalid-asset": "Ficheiro inválido", "error-invalid-channel": "Canal inválido.", "error-invalid-channel-start-with-chars": "Canal inválido. Começa por @ ou #", "error-invalid-custom-field": "Campo personalizado inválido", @@ -58,6 +61,7 @@ "error-message-editing-blocked": "A edição de mensagens está bloqueada", "error-message-size-exceeded": "O tamanho da mensagem excede Message_MaxAllowedSize", "error-missing-unsubscribe-link": "Você deve fornecer o link para cancelar a subscrição: [unsubscribe].", + "error-no-owner-channel": "Você não é dono do canal", "error-no-tokens-for-this-user": "Não há tokens para este utilizador", "error-not-allowed": "Não permitido", "error-not-authorized": "Não autorizado", @@ -75,33 +79,46 @@ "error-user-registration-disabled": "O registo de utilizadores está desactivado", "error-user-registration-secret": "O registo de utilizadores só é permitido por meio de um URL secreto", "error-you-are-last-owner": "Você é o último proprietário. Por favor, defina novo proprietário antes de sair da sala.", + "error-status-not-allowed": "O estado invisível está desactivado", "Actions": "Acções", "activity": "actividade", "Activity": "Actividade", "Add_Reaction": "Adicionar Reacção", "Add_Server": "Adicionar Servidor", "Add_users": "Adicionar utilizadores", + "Admin_Panel": "Painel de Administração", + "Agent": "Agente", "Alert": "Alerta", "alert": "alerta", "alerts": "alertas", "All_users_in_the_channel_can_write_new_messages": "Todos os utilizadores no canal podem escrever novas mensagens", + "All_users_in_the_team_can_write_new_messages": "Todos os usuários da equipa podem escrever novas mensagens", + "A_meaningful_name_for_the_discussion_room": "Um nome significativo para a sala de discussão", "All": "Todos", + "All_Messages": "Todas as Mensagens", "Allow_Reactions": "Permitir Reacções", "Alphabetical": "Alfabética", "and_more": "e mais", "and": "e", "announcement": "anúncio", "Announcement": "Anúncio", + "Apply_Your_Certificate": "Aplique o seu Certificado", "ARCHIVE": "ARQUIVAR", "archive": "arquivar", "are_typing": "estão a escrever", "Are_you_sure_question_mark": "Tem a certeza?", "Are_you_sure_you_want_to_leave_the_room": "Tem certeza de que quer sair da sala {{room}}?", + "Audio": "Áudio", "Authenticating": "Autenticando", + "Automatic": "Automático", + "Auto_Translate": "Auto-Tradução", "Avatar_changed_successfully": "Avatar alterado com sucesso!", "Avatar_Url": "URL do Avatar", "Away": "Ausente", + "Back": "Voltar", + "Black": "Preto", "Block_user": "Bloquear utilizador", + "Browser": "Navegador", "Broadcast_channel_Description": "Apenas utilizadores autorizados podem escrever novas mensagens, mas os outros utilizadores poderão responder", "Broadcast_Channel": "Canal de Transmissão", "Busy": "Ocupado", @@ -111,80 +128,187 @@ "Cancel": "Cancelar", "changing_avatar": "a alterar avatar", "creating_channel": "a criar canal", + "creating_invite": "a criar convite", "Channel_Name": "Nome do Canal", "Channels": "Canais", "Chats": "Chats", + "Call_already_ended": "Chamada já terminada!", + "Clear_cookies_alert": "Quer limpar todas as cookies?", + "Clear_cookies_desc": "Esta acção irá limpar todos os cookies de login, permitindo que você faça login em outras contas.", + "Clear_cookies_yes": "Sim, limpar cookies", + "Clear_cookies_no": "Não, guardar cookies", + "Click_to_join": "Clique para Entrar!", "Close": "Fechar", "Close_emoji_selector": "Fechar selector de emoticons", + "Closing_chat": "A fechar o chat", + "Change_language_loading": "Mudança de idioma.", + "Chat_closed_by_agent": "Chat fechado por agente", "Choose": "Escolher", "Choose_from_library": "Escolher da biblioteca", + "Choose_file": "Escolher arquivo", + "Choose_where_you_want_links_be_opened": "Escolha onde você quer que os links sejam abertos", "Code": "Código", + "Code_or_password_invalid": "Código ou senha inválidos", "Collaborative": "Colaborativa", "Confirm": "Confirmar", "Connect": "Ligar", "Connected": "Ligado", + "connecting_server": "conexão ao servidor", "Connecting": "A ligar...", + "Contact_us": "Contacte-nos", + "Contact_your_server_admin": "Contacte o administrador do seu servidor.", "Continue_with": "Continuar com", "Copied_to_clipboard": "Copiado para a área de transferência!", "Copy": "Copiar", + "Conversation": "Conversa", "Permalink": "Link permanente", + "Certificate_password": "Senha do Certificado", + "Clear_cache": "Limpar a cache do servidor local", + "Clear_cache_loading": "A limpar a cache.", + "Whats_the_password_for_your_certificate": "Qual é a senha para o seu certificado?", "Create_account": "Criar uma conta", "Create_Channel": "Criar Canal", + "Create_Direct_Messages": "Criar Mensagens Diretas", + "Create_Discussion": "Criar Discussão", "Created_snippet": "criado um extracto", "Create_a_new_workspace": "Criar um novo espaço de trabalho", "Create": "Criar", + "Custom_Status": "Status Personalizado", + "Dark": "Escuro", + "Dark_level": "Nível Escuro", + "Default": "Predefinição", + "Default_browser": "Navegador predefinido", "Delete_Room_Warning": "Apagar uma sala irá remover todas as mensagens contidas nela. Isto não pode ser desfeito.", + "Department": "Departamento", "delete": "apagar", "Delete": "Apagar", "DELETE": "APAGAR", + "move": "mover", "deleting_room": "apagando sala", "description": "descrição", "Description": "Descrição", + "Desktop_Options": "Opções da área de trabalho", + "Desktop_Notifications": "Notificações da área de trabalho", + "Desktop_Alert_info": "Estas notificações são entregues na área de trabalho", + "Directory": "Directório", "Direct_Messages": "Mensagens Directas", "Disable_notifications": "Desactivar notificações", + "Discussions": "Discussões", + "Discussion_Desc": "Ajude a manter uma visão geral sobre o que está acontecendo! Ao criar uma discussão, é criado um sub-canal do que você selecionou e ambos estão ligados.", + "Discussion_name": "Nome da discussão", + "Done": "Feito", "Dont_Have_An_Account": "Não tem uma conta?", + "Do_you_have_an_account": "Você tem uma conta?", + "Do_you_have_a_certificate": "Você tem um certificado?", "Do_you_really_want_to_key_this_room_question_mark": "Você quer mesmo {{key}} esta sala?", + "E2E_Encryption": "Encriptação E2E", + "E2E_How_It_Works_info1": "Agora você pode criar grupos privados criptografados e mensagens diretas. Você também pode alterar grupos privados existentes ou DMs para criptografados.", + "E2E_How_It_Works_info2": "Isto é *criptografia ponto a ponto* portanto a chave para codificar/descodificar as suas mensagens não será salva no servidor. Por essa razão *você precisa armazenar esta senha em algum lugar seguro* que você posa aceder mais tarde, se precisar.", + "E2E_How_It_Works_info3": "Se você prosseguir, uma senha E2E será gerada automaticamente.", + "E2E_How_It_Works_info4": "Você também pode configurar uma nova senha para sua chave de criptografia a qualquer momento a partir de qualquer navegador que você tenha inserido a senha existente do E2E.", "edit": "editar", + "edited": "editado", "Edit": "Editar", + "Edit_Status": "Editar Status", + "Edit_Invite": "Editar Convite", + "End_to_end_encrypted_room": "Sala encriptada de ponta a ponta", + "end_to_end_encryption": "encriptação de ponta a ponta", + "Email_Notification_Mode_All": "Cada Menção/DM", + "Email_Notification_Mode_Disabled": "Desactivado", "Email_or_password_field_is_empty": "O campo de e-mail ou palavra-passe está vazio", "Email": "E-mail", "email": "e-mail", + "Empty_title": "Título vazio", + "Enable_Auto_Translate": "Activar Auto-Tradução", "Enable_notifications": "Activar notificações", + "Encrypted": "Encriptado", + "Encrypted_message": "Mensagem encriptada", + "Enter_Your_E2E_Password": "Digite a sua senha E2E", + "Enter_Your_Encryption_Password_desc1": "Isto permitir-lhe-á aceder aos seus grupos privados encriptados e às suas mensagens directas.", + "Enter_Your_Encryption_Password_desc2": "Você precisa digitar a senha para codificar/descodificar mensagens em cada lugar que você usar o chat.", + "Encryption_error_title": "A sua senha de encriptação parece errada", + "Encryption_error_desc": "Não foi possível descodificar a sua chave de encriptação para ser importada.", "Everyone_can_access_this_channel": "Todos podem aceder a este canal", + "Everyone_can_access_this_team": "Todos podem aceder a esta equipa", "Error_uploading": "Erro ao fazer o envio", + "Expiration_Days": "Validade (Dias)", + "Favorite": "Favorito", "Favorites": "Favoritos", "Files": "Ficheiros", "File_description": "Descrição do ficheiro", "File_name": "Nome do ficheiro", "Finish_recording": "Terminar a gravação", + "Following_thread": "Seguir discussão", "For_your_security_you_must_enter_your_current_password_to_continue": "Para sua segurança, você deve escrever a sua palavra-passe actual para continuar", "Forgot_password_If_this_email_is_registered": "Se este e-mail estiver registado, enviaremos instruções sobre como repor a sua palavra-passe. Se você não receber um e-mail em breve, volte e tente novamente.", "Forgot_password": "Esquecer palavra-passe", "Forgot_Password": "Esquecer Palavra-passe", + "Forward": "Reencaminhar", + "Forward_Chat": "Reencaminhar Chat", + "Forward_to_department": "Reencaminhar para o departamento", + "Forward_to_user": "Reencaminhar para o utilizador", + "Full_table": "Clique para ver a tabela completa", + "Generate_New_Link": "Gerar Novo Link", "Group_by_favorites": "Agrupar por favoritos", "Group_by_type": "Agrupar por tipo", + "Hide": "Esconder", "Has_joined_the_channel": "entrou no canal", "Has_joined_the_conversation": "entrou na conversa", "Has_left_the_channel": "saiu do canal", + "Hide_System_Messages": "Esconder mensagens do sistema", + "Hide_type_messages": "Esconder mensagens \"{{type}}\"", + "How_It_Works": "Como Funciona", + "Message_HideType_uj": "Utilizador entrou", + "Message_HideType_ul": "Utilizador saiu", + "Message_HideType_ru": "Utilizador removido", + "Message_HideType_au": "Utilizador adicionado", + "Message_HideType_mute_unmute": "Utilizador silenciado/de-silenciado", + "Message_HideType_r": "Nome da sala alterado", + "Message_HideType_ut": "Utilizador entrou na conversação", + "Message_HideType_wm": "Bem-vindo", + "Message_HideType_rm": "Mensagem Removida", + "Message_HideType_subscription_role_added": "Foi definido o estatuto", + "Message_HideType_subscription_role_removed": "Definição de estatuto removida", + "Message_HideType_room_archived": "Sala arquivada", + "Message_HideType_room_unarchived": "Sala desarquivada", + "I_Saved_My_E2E_Password": "Guardei a minha senha E2E", + "IP": "IP", + "In_app": "Na aplicação", + "In_App_And_Desktop": "Na aplicação e área de trabalho", + "In_App_and_Desktop_Alert_info": "Exibe um banner no topo da tela quando a aplicação está aberto, e exibe uma notificação na área de trabalho", "Invisible": "Invisível", "Invite": "Convidar", "is_a_valid_RocketChat_instance": "é uma instância válida do Rocket.Chat", "is_not_a_valid_RocketChat_instance": "is not a valid Rocket.Chat instance", "is_typing": "está a escrever", + "Invalid_or_expired_invite_token": "Token de convite invalido ou expirado", "Invalid_server_version": "O servidor ao qual esta tentando ligar-se, utiliza uma versão que não é suporta pela aplicação: {{currentVersion}}.\n\nA versão mínima requerida é {{minVersion}}", + "Invite_Link": "Link de convite", + "Invite_users": "Convidar utilizadores", "Join": "Entrar", + "Join_Code": "Código de entrada", + "Insert_Join_Code": "Insira o código de entrada", + "Join_our_open_workspace": "Junte-se ao nosso espaço de trabalho aberto", + "Join_your_workspace": "Junte-se ao seu espaço de trabalho", "Just_invited_people_can_access_this_channel": "Apenas utilizadores convidados podem aceder a este canal", + "Just_invited_people_can_access_this_team": "Apenas pessoas convidadas podem aceder a esta equipa", "Language": "Idioma", "last_message": "última mensagem", "Leave_channel": "Sair do canal", "leaving_room": "a sair da sala", + "Leave": "Sair", "leave": "sair", "Legal": "Legal", + "Light": "Luz", + "License": "Licença", "Livechat": "Livechat", "Login": "Entrar", "Login_error": "As suas credenciais foram rejeitadas! Por favor, tente novamente.", "Login_with": "Entrar com", + "Logging_out": "A terminar a sessão.", "Logout": "Sair", + "Max_number_of_uses": "Número máximo de utilizações", + "Max_number_of_users_allowed_is_number": "O número máximo de utilizadores permitido é {{maxUsers}}", "members": "membros", "Members": "Membros", "Mentioned_Messages": "Mensagens Mencionadas", @@ -194,7 +318,13 @@ "Message_actions": "Acções de mensagem", "Message_pinned": "Mensagem afixada", "Message_removed": "Mensagem removida", + "Message_starred": "Mensagem estrelada", + "Message_unstarred": "Mensagem não estrelada", + "message": "mensagem", + "messages": "mensagens", + "Message": "Mensagem", "Messages": "Mensagens", + "Message_Reported": "Mensagem reportada", "Microphone_Permission_Message": "O Rocket.Chat necessita de acesso ao seu microfone para que você possa enviar mensagens de áudio.", "Microphone_Permission": "Permissão de Microfone", "Mute": "Silenciar", @@ -202,52 +332,92 @@ "My_servers": "Meus servidores", "N_people_reacted": "{{n}} pessoas reagiram", "N_users": "{{n}} utilizadores", + "N_channels": "{{n}} canais", "name": "nome", "Name": "Nome", + "Navigation_history": "Histórico de navegação", + "Never": "Nunca", "New_Message": "Nova Mensagem", "New_Password": "Nova Palavra-passe", "New_Server": "Novo Servidor", "Next": "Próximo", "No_files": "Nenhum ficheiro", + "No_limit": "Sem limite", "No_mentioned_messages": "Nenhuma mensagem mencionada", "No_pinned_messages": "Nenhuma mensagem afixada", "No_results_found": "Nenhum resultado encontrado", "No_starred_messages": "Nenhuma mensagem marcada com estrela", + "No_thread_messages": "Sem mensagens de discussão ", + "No_label_provided": "{{label}} não fornecida/o", "No_Message": "Nenhuma mensagem", + "No_messages_yet": "Ainda sem mensagens", "No_Reactions": "Nenhuma reação", + "No_Read_Receipts": "Sem recibos de leitura", "Not_logged": "Não ligado", + "Not_RC_Server": "Isto não é um servidor Rocket.Chat.\n{{contact}}", + "Nothing": "Nada", "Nothing_to_save": "Nada para guardar!", "Notify_active_in_this_room": "Notifica utilizadores activos nesta sala", "Notify_all_in_this_room": "Notifica todos os utilizadores nesta sala", + "Notifications": "Notificações", + "Notification_Duration": "Duração da Notificação", + "Notification_Preferences": "Preferências de Notificação", + "No_available_agents_to_transfer": "Não há agentes disponíveis para transferir", "Offline": "Desligado", "Oops": "Oops!", + "Omnichannel": "Omnichannel", + "Open_Livechats": "Chats em andamento", + "Omnichannel_enable_alert": "Você não está disponível no Omnichannel. Você gostaria de estar disponível?", + "Onboarding_description": "Um espaço de trabalho é o espaço da sua equipa ou organização para colaborar. Peça ao administrador do espaço de trabalho um endereço para se juntar ou criar um para a sua equipa.", + "Onboarding_join_workspace": "Junte-se a um espaço de trabalho", + "Onboarding_subtitle": "Além da Colaboração da Equipe", "Onboarding_title": "Bem vindo(a) ao Rocket.Chat", + "Onboarding_join_open_description": "Junte-se ao nosso espaço de trabalho aberto para conversar com a equipa e comunidade Rocket.Chat.", + "Onboarding_agree_terms": "Ao continuar, você concorda com Rocket.Chat", + "Onboarding_less_options": "Menos opções", + "Onboarding_more_options": "Mais opções", "Online": "Ligado", "Only_authorized_users_can_write_new_messages": "Apenas utilizadores autorizados podem escrever novas mensagens", "Open_emoji_selector": "Abra o selector de emoticons", "Open_Source_Communication": "Comunicação Open Source", + "Open_your_authentication_app_and_enter_the_code": "Abra o seu aplicativo de autenticação e digite o código.", + "OR": "OU", + "OS": "OS", + "Overwrites_the_server_configuration_and_use_room_config": "Sobrescreve a configuração do servidor e a configuração da sala de uso", "Password": "Palavra-passe", + "Parent_channel_or_group": "Canal de origem ou grupo", "Permalink_copied_to_clipboard": "Link permanente copiado para a área de transferência!", + "Phone": "Telefone", "Pin": "Afixar", "Pinned_Messages": "Mensagens Afixadas", "pinned": "afixada", "Pinned": "Afixada", + "Please_add_a_comment": "Por favor, acrescente um comentário", "Please_enter_your_password": "Por favor, introduza a sua palavra-passe", + "Please_wait": "Por favor, espere.", + "Preferences": "Preferências", "Preferences_saved": "Preferências guardadas!", "Privacy_Policy": " Política de Privacidade", "Private_Channel": "Canal Privado", "Private_Groups": "Grupos Privados", "Private": "Privado", + "Processing": "A processar...", "Profile_saved_successfully": "Perfil actualizado com sucesso!", "Profile": "Perfil", "Public_Channel": "Canal Público", "Public": "Público", + "Push_Notifications": "Notificações Push", + "Push_Notifications_Alert_Info": "Estas notificações são entregues quando o aplicativo não está aberto", "Quote": "Citar", "Reactions_are_disabled": "Reacções desactivadas", "Reactions_are_enabled": "Reacções activadas", "Reactions": "Reacções", + "Read": "Ler", + "Read_External_Permission_Message": "Rocket.Chat precisa acessar fotos, média e arquivos em seu dispositivo", + "Read_External_Permission": "Permissão de leitura da média", "Read_Only_Channel": "Canal só de leitura", "Read_Only": "Só de Leitura", + "Read_Receipt": "Recibos de leitura", "Register": "Registar", "Repeat_Password": "Repita a palavra-passe", "Reply": "Responder", diff --git a/app/i18n/locales/ru.json b/app/i18n/locales/ru.json index e5fca9504..5267a4a41 100644 --- a/app/i18n/locales/ru.json +++ b/app/i18n/locales/ru.json @@ -724,6 +724,7 @@ "creating_team": "создание Команды", "team-name-already-exists": "Команда с таким названием уже существует", "Add_Channel_to_Team": "Добавить канал в Команду", + "Left_The_Team_Successfully": "Успешно покинул команду", "Create_New": "Создать", "Add_Existing": "Добавить существующее", "Add_Existing_Channel": "Добавить существующий канал", diff --git a/app/lib/database/model/servers/User.js b/app/lib/database/model/servers/User.js index 5b4d3d65a..6d78c27fa 100644 --- a/app/lib/database/model/servers/User.js +++ b/app/lib/database/model/servers/User.js @@ -22,7 +22,7 @@ export default class User extends Model { @field('avatar_etag') avatarETag; - @field('login_email_password') loginEmailPassword; - @field('show_message_in_main_thread') showMessageInMainThread; + + @field('is_from_webview') isFromWebView; } diff --git a/app/lib/database/model/servers/migrations.js b/app/lib/database/model/servers/migrations.js index 782700a37..80954d475 100644 --- a/app/lib/database/model/servers/migrations.js +++ b/app/lib/database/model/servers/migrations.js @@ -95,6 +95,16 @@ export default schemaMigrations({ ] }) ] + }, { + toVersion: 11, + steps: [ + addColumns({ + table: 'users', + columns: [ + { name: 'is_from_webview', type: 'boolean', isOptional: true } + ] + }) + ] } ] }); diff --git a/app/lib/database/schema/servers.js b/app/lib/database/schema/servers.js index 0c81a72fc..1105cf165 100644 --- a/app/lib/database/schema/servers.js +++ b/app/lib/database/schema/servers.js @@ -1,7 +1,7 @@ import { appSchema, tableSchema } from '@nozbe/watermelondb'; export default appSchema({ - version: 10, + version: 11, tables: [ tableSchema({ name: 'users', @@ -15,7 +15,8 @@ export default appSchema({ { name: 'roles', type: 'string', isOptional: true }, { name: 'login_email_password', type: 'boolean', isOptional: true }, { name: 'show_message_in_main_thread', type: 'boolean', isOptional: true }, - { name: 'avatar_etag', type: 'string', isOptional: true } + { name: 'avatar_etag', type: 'string', isOptional: true }, + { name: 'is_from_webview', type: 'boolean', isOptional: true } ] }), tableSchema({ diff --git a/app/lib/methods/getPermissions.js b/app/lib/methods/getPermissions.js index 2b7da4765..6e68f5c33 100644 --- a/app/lib/methods/getPermissions.js +++ b/app/lib/methods/getPermissions.js @@ -6,6 +6,7 @@ import { compareServerVersion, methods } from '../utils'; import database from '../database'; import log from '../../utils/log'; import reduxStore from '../createStore'; +import RocketChat from '../rocketchat'; import protectedFunction from './helpers/protectedFunction'; import { setPermissions as setPermissionsAction } from '../../actions/permissions'; @@ -128,7 +129,7 @@ export function getPermissions() { const db = database.active; const permissionsCollection = db.get('permissions'); const allRecords = await permissionsCollection.query().fetch(); - + RocketChat.subscribe('stream-notify-logged', 'permissions-changed'); // if server version is lower than 0.73.0, fetches from old api if (compareServerVersion(serverVersion, '0.73.0', methods.lowerThan)) { // RC 0.66.0 diff --git a/app/lib/methods/getRoles.js b/app/lib/methods/getRoles.js index df22d382b..98a3895e3 100644 --- a/app/lib/methods/getRoles.js +++ b/app/lib/methods/getRoles.js @@ -2,9 +2,66 @@ import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; import database from '../database'; import log from '../../utils/log'; +import reduxStore from '../createStore'; import protectedFunction from './helpers/protectedFunction'; +import { + removeRoles, setRoles as setRolesAction, updateRoles +} from '../../actions/roles'; -export default function() { +export async function setRoles() { + const db = database.active; + const rolesCollection = db.collections.get('roles'); + const allRoles = await rolesCollection.query().fetch(); + const parsed = allRoles.reduce((acc, item) => ({ ...acc, [item.id]: item.description || item.id }), {}); + reduxStore.dispatch(setRolesAction(parsed)); +} + +export async function onRolesChanged(ddpMessage) { + const { type, _id, description } = ddpMessage.fields.args[0]; + if (/changed/.test(type)) { + const db = database.active; + const rolesCollection = db.get('roles'); + try { + const rolesRecord = await rolesCollection.find(_id); + try { + await db.action(async() => { + await rolesRecord.update((u) => { + u.description = description; + }); + }); + } catch (e) { + log(e); + } + reduxStore.dispatch(updateRoles(_id, description)); + } catch (err) { + try { + await db.action(async() => { + await rolesCollection.create((post) => { + post._raw = sanitizedRaw({ id: _id, description }, rolesCollection.schema); + }); + }); + } catch (e) { + log(e); + } + reduxStore.dispatch(updateRoles(_id, description || _id)); + } + } + if (/removed/.test(type)) { + const db = database.active; + const rolesCollection = db.get('roles'); + try { + const rolesRecord = await rolesCollection.find(_id); + await db.action(async() => { + await rolesRecord.destroyPermanently(); + }); + reduxStore.dispatch(removeRoles(_id)); + } catch (err) { + console.log(err); + } + } +} + +export function getRoles() { const db = database.active; return new Promise(async(resolve) => { try { @@ -50,6 +107,7 @@ export default function() { } catch (e) { log(e); } + setRoles(); return allRecords.length; }); return resolve(); diff --git a/app/lib/methods/getSettings.js b/app/lib/methods/getSettings.js index 6935631ef..f68995af8 100644 --- a/app/lib/methods/getSettings.js +++ b/app/lib/methods/getSettings.js @@ -146,6 +146,7 @@ export default async function() { const filteredSettingsIds = filteredSettings.map(s => s._id); reduxStore.dispatch(addSettings(this.parseSettings(filteredSettings))); + RocketChat.subscribe('stream-notify-all', 'public-settings-changed'); // filter server info const serverInfo = filteredSettings.filter(i1 => serverInfoKeys.includes(i1._id)); diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 6e7b3bcb2..1cc0d4e0f 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -37,7 +37,7 @@ import { getEnterpriseModules, setEnterpriseModules, hasLicense, isOmnichannelModuleAvailable } from './methods/enterpriseModules'; import getSlashCommands from './methods/getSlashCommands'; -import getRoles from './methods/getRoles'; +import { getRoles, setRoles, onRolesChanged } from './methods/getRoles'; import canOpenRoom from './methods/canOpenRoom'; import triggerBlockAction, { triggerSubmitView, triggerCancel } from './methods/actions'; @@ -63,7 +63,9 @@ import UserPreferences from './userPreferences'; import { Encryption } from './encryption'; import EventEmitter from '../utils/events'; import { sanitizeLikeString } from './database/utils'; +import { updatePermission } from '../actions/permissions'; import { TEAM_TYPE } from '../definition/ITeam'; +import { updateSettings } from '../actions/settings'; const TOKEN_KEY = 'reactnativemeteor_usertoken'; const CURRENT_SERVER = 'currentServer'; @@ -225,6 +227,14 @@ const RocketChat = { this.usersListener.then(this.stopListener); } + if (this.notifyAllListener) { + this.notifyAllListener.then(this.stopListener); + } + + if (this.rolesListener) { + this.rolesListener.then(this.stopListener); + } + if (this.notifyLoggedListener) { this.notifyLoggedListener.then(this.stopListener); } @@ -274,6 +284,31 @@ const RocketChat = { this.usersListener = this.sdk.onStreamData('users', protectedFunction(ddpMessage => RocketChat._setUser(ddpMessage))); + this.notifyAllListener = this.sdk.onStreamData('stream-notify-all', protectedFunction(async(ddpMessage) => { + const { eventName } = ddpMessage.fields; + if (/public-settings-changed/.test(eventName)) { + const { _id, value } = ddpMessage.fields.args[1]; + const db = database.active; + const settingsCollection = db.get('settings'); + try { + const settingsRecord = await settingsCollection.find(_id); + const { type } = defaultSettings[_id]; + if (type) { + await db.action(async() => { + await settingsRecord.update((u) => { + u[type] = value; + }); + }); + } + reduxStore.dispatch(updateSettings(_id, value)); + } catch (e) { + log(e); + } + } + })); + + this.rolesListener = this.sdk.onStreamData('stream-roles', protectedFunction(ddpMessage => onRolesChanged(ddpMessage))); + this.notifyLoggedListener = this.sdk.onStreamData('stream-notify-logged', protectedFunction(async(ddpMessage) => { const { eventName } = ddpMessage.fields; if (/user-status/.test(eventName)) { @@ -310,6 +345,21 @@ const RocketChat = { } catch { // We can't create a new record since we don't receive the user._id } + } else if (/permissions-changed/.test(eventName)) { + const { _id, roles } = ddpMessage.fields.args[1]; + const db = database.active; + const permissionsCollection = db.get('permissions'); + try { + const permissionsRecord = await permissionsCollection.find(_id); + await db.action(async() => { + await permissionsRecord.update((u) => { + u.roles = roles; + }); + }); + reduxStore.dispatch(updatePermission(_id, roles)); + } catch (err) { + // + } } else if (/Users:NameChanged/.test(eventName)) { const userNameChanged = ddpMessage.fields.args[0]; const db = database.active; @@ -476,10 +526,10 @@ const RocketChat = { return this.post('users.forgotPassword', { email }, false); }, - loginTOTP(params, loginEmailPassword) { + loginTOTP(params, loginEmailPassword, isFromWebView = false) { return new Promise(async(resolve, reject) => { try { - const result = await this.login(params, loginEmailPassword); + const result = await this.login(params, isFromWebView); return resolve(result); } catch (e) { if (e.data?.error && (e.data.error === 'totp-required' || e.data.error === 'totp-invalid')) { @@ -542,15 +592,15 @@ const RocketChat = { return this.loginTOTP(params, true); }, - async loginOAuthOrSso(params) { - const result = await this.loginTOTP(params); - reduxStore.dispatch(loginRequest({ resume: result.token })); + async loginOAuthOrSso(params, isFromWebView = true) { + const result = await this.loginTOTP(params, false, isFromWebView); + reduxStore.dispatch(loginRequest({ resume: result.token }, false, isFromWebView)); }, - async login(params, loginEmailPassword) { + async login(credentials, isFromWebView = false) { const sdk = this.shareSDK || this.sdk; // RC 0.64.0 - await sdk.login(params); + await sdk.login(credentials); const { result } = sdk.currentLogin; const user = { id: result.userId, @@ -565,7 +615,7 @@ const RocketChat = { emails: result.me.emails, roles: result.me.roles, avatarETag: result.me.avatarETag, - loginEmailPassword, + isFromWebView, showMessageInMainThread: result.me.settings?.preferences?.showMessageInMainThread ?? true }; return user; @@ -843,6 +893,7 @@ const RocketChat = { isOmnichannelModuleAvailable, getSlashCommands, getRoles, + setRoles, parseSettings: settings => settings.reduce((ret, item) => { ret[item._id] = defaultSettings[item._id] && item[defaultSettings[item._id].type]; if (item._id === 'Hide_System_Messages') { diff --git a/app/reducers/index.js b/app/reducers/index.js index dfee5f3eb..eb8f09d82 100644 --- a/app/reducers/index.js +++ b/app/reducers/index.js @@ -19,6 +19,7 @@ import createDiscussion from './createDiscussion'; import enterpriseModules from './enterpriseModules'; import encryption from './encryption'; import permissions from './permissions'; +import roles from './roles'; import inquiry from '../ee/omnichannel/reducers/inquiry'; @@ -43,5 +44,6 @@ export default combineReducers({ inquiry, enterpriseModules, encryption, - permissions + permissions, + roles }); diff --git a/app/reducers/permissions.js b/app/reducers/permissions.js index 1b3a14ec2..034c51420 100644 --- a/app/reducers/permissions.js +++ b/app/reducers/permissions.js @@ -1,13 +1,16 @@ import { PERMISSIONS } from '../actions/actionsTypes'; -const initialState = { - permissions: {} -}; +const initialState = {}; export default function permissions(state = initialState, action) { switch (action.type) { case PERMISSIONS.SET: return action.permissions; + case PERMISSIONS.UPDATE: + return { + ...state, + [action.payload.id]: action.payload.roles + }; default: return state; } diff --git a/app/reducers/roles.js b/app/reducers/roles.js new file mode 100644 index 000000000..93cbffcb0 --- /dev/null +++ b/app/reducers/roles.js @@ -0,0 +1,22 @@ +import { ROLES } from '../actions/actionsTypes'; + +const initialState = {}; + +export default function permissions(state = initialState, action) { + switch (action.type) { + case ROLES.SET: + return action.roles; + case ROLES.UPDATE: + return { + ...state, + [action.payload.id]: action.payload.desc || action.payload.id + }; + case ROLES.REMOVE: { + const newState = { ...state }; + delete newState[action.payload.id]; + return newState; + } + default: + return state; + } +} diff --git a/app/reducers/room.js b/app/reducers/room.js index de47fcede..980715051 100644 --- a/app/reducers/room.js +++ b/app/reducers/room.js @@ -28,7 +28,7 @@ export default function(state = initialState, action) { case ROOM.DELETE: return { ...state, - rid: action.rid, + rid: action.room.rid, isDeleting: true }; case ROOM.CLOSE: diff --git a/app/reducers/settings.js b/app/reducers/settings.js index 9e037b1d0..6e9ab5005 100644 --- a/app/reducers/settings.js +++ b/app/reducers/settings.js @@ -9,6 +9,11 @@ export default (state = initialState, action) => { ...state, ...action.payload }; + case SETTINGS.UPDATE: + return { + ...state, + [action.payload.id]: action.payload.value + }; case SETTINGS.CLEAR: return initialState; default: diff --git a/app/sagas/deepLinking.js b/app/sagas/deepLinking.js index 556573a54..a406f56a9 100644 --- a/app/sagas/deepLinking.js +++ b/app/sagas/deepLinking.js @@ -97,7 +97,7 @@ const fallbackNavigation = function* fallbackNavigation() { const handleOAuth = function* handleOAuth({ params }) { const { credentialToken, credentialSecret } = params; try { - yield RocketChat.loginOAuthOrSso({ oauth: { credentialToken, credentialSecret } }); + yield RocketChat.loginOAuthOrSso({ oauth: { credentialToken, credentialSecret } }, false); } catch (e) { log(e); } diff --git a/app/sagas/login.js b/app/sagas/login.js index 77eda7611..83eb04dd6 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -30,15 +30,15 @@ import Navigation from '../lib/Navigation'; const getServer = state => state.server.server; const loginWithPasswordCall = args => RocketChat.loginWithPassword(args); -const loginCall = args => RocketChat.login(args); +const loginCall = (credentials, isFromWebView) => RocketChat.login(credentials, isFromWebView); const logoutCall = args => RocketChat.logout(args); -const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnError = false }) { +const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnError = false, isFromWebView = false }) { logEvent(events.LOGIN_DEFAULT_LOGIN); try { let result; if (credentials.resume) { - result = yield call(loginCall, credentials); + result = yield loginCall(credentials, isFromWebView); } else { result = yield call(loginWithPasswordCall, credentials); } @@ -68,7 +68,6 @@ const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnE log(e); } }); - yield put(loginSuccess(result)); } } catch (e) { @@ -90,6 +89,7 @@ const fetchCustomEmojis = function* fetchCustomEmojis() { }; const fetchRoles = function* fetchRoles() { + RocketChat.subscribe('stream-roles', 'roles'); yield RocketChat.getRoles(); }; @@ -147,14 +147,13 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) { status: user.status, statusText: user.statusText, roles: user.roles, - loginEmailPassword: user.loginEmailPassword, + isFromWebView: user.isFromWebView, showMessageInMainThread: user.showMessageInMainThread, avatarETag: user.avatarETag }; yield serversDB.action(async() => { try { const userRecord = await usersCollection.find(user.id); - u.loginEmailPassword = userRecord?.loginEmailPassword; await userRecord.update((record) => { record._raw = sanitizedRaw({ id: user.id, ...record._raw }, usersCollection.schema); Object.assign(record, u); diff --git a/app/sagas/room.js b/app/sagas/room.js index e17a06da9..70a0bc4da 100644 --- a/app/sagas/room.js +++ b/app/sagas/room.js @@ -32,7 +32,7 @@ const watchUserTyping = function* watchUserTyping({ rid, status }) { } }; -const handleRemovedRoom = function* handleRemovedRoom(roomType) { +const handleRemovedRoom = function* handleRemovedRoom(roomType, actionType) { const isMasterDetail = yield select(state => state.app.isMasterDetail); if (isMasterDetail) { yield Navigation.navigate('DrawerNavigator'); @@ -40,9 +40,13 @@ const handleRemovedRoom = function* handleRemovedRoom(roomType) { yield Navigation.navigate('RoomsListView'); } - if (roomType === 'team') { - EventEmitter.emit(LISTENER, { message: I18n.t('Left_The_Team_Successfully') }); + if (actionType === 'leave') { + EventEmitter.emit(LISTENER, { message: roomType === 'team' ? I18n.t('Left_The_Team_Successfully') : I18n.t('Left_The_Room_Successfully') }); } + if (actionType === 'delete') { + EventEmitter.emit(LISTENER, { message: roomType === 'team' ? I18n.t('Deleted_The_Team_Successfully') : I18n.t('Deleted_The_Room_Successfully') }); + } + // types.ROOM.REMOVE is triggered by `subscriptions-changed` with `removed` arg const { timeout } = yield race({ @@ -66,7 +70,7 @@ const handleLeaveRoom = function* handleLeaveRoom({ room, roomType, selected }) } if (result?.success) { - yield handleRemovedRoom(roomType); + yield handleRemovedRoom(roomType, 'leave'); } } catch (e) { logEvent(events.RA_LEAVE_F); @@ -80,16 +84,23 @@ const handleLeaveRoom = function* handleLeaveRoom({ room, roomType, selected }) } }; -const handleDeleteRoom = function* handleDeleteRoom({ rid, t }) { +const handleDeleteRoom = function* handleDeleteRoom({ room, roomType, selected }) { logEvent(events.RI_EDIT_DELETE); try { - const result = yield RocketChat.deleteRoom(rid, t); - if (result.success) { - yield handleRemovedRoom(); + let result = {}; + + if (roomType === 'channel') { + result = yield RocketChat.deleteRoom(room.rid, room.t); + } else if (roomType === 'team') { + result = yield RocketChat.deleteTeam({ teamId: room.teamId, ...(selected && { roomsToRemove: selected }) }); + } + + if (result?.success) { + yield handleRemovedRoom(roomType, 'delete'); } } catch (e) { logEvent(events.RI_EDIT_DELETE_F); - Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('deleting_room') })); + Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: roomType === 'team' ? I18n.t('deleting_team') : I18n.t('deleting_room') })); } }; diff --git a/app/sagas/selectServer.js b/app/sagas/selectServer.js index d367274a3..2abf47061 100644 --- a/app/sagas/selectServer.js +++ b/app/sagas/selectServer.js @@ -125,6 +125,7 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch RocketChat.setSettings(); RocketChat.setCustomEmojis(); RocketChat.setPermissions(); + RocketChat.setRoles(); RocketChat.setEnterpriseModules(); let serverInfo; diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index d16ea5768..75c977a28 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -50,6 +50,8 @@ class RoomActionsView extends React.Component { route: PropTypes.object, leaveRoom: PropTypes.func, jitsiEnabled: PropTypes.bool, + jitsiEnableTeams: PropTypes.bool, + jitsiEnableChannels: PropTypes.bool, encryptionEnabled: PropTypes.bool, setLoadingInvite: PropTypes.func, closeRoom: PropTypes.func, @@ -655,10 +657,15 @@ class RoomActionsView extends React.Component { renderJitsi = () => { const { room } = this.state; - const { jitsiEnabled } = this.props; - if (!jitsiEnabled || room.teamMain) { + const { jitsiEnabled, jitsiEnableTeams, jitsiEnableChannels } = this.props; + + const isJitsiDisabledForTeams = room.teamMain && !jitsiEnableTeams; + const isJitsiDisabledForChannels = !room.teamMain && (room.t === 'p' || room.t === 'c') && !jitsiEnableChannels; + + if (!jitsiEnabled || isJitsiDisabledForTeams || isJitsiDisabledForChannels) { return null; } + return ( @@ -1078,6 +1085,8 @@ class RoomActionsView extends React.Component { const mapStateToProps = state => ({ jitsiEnabled: state.settings.Jitsi_Enabled || false, + jitsiEnableTeams: state.settings.Jitsi_Enable_Teams || false, + jitsiEnableChannels: state.settings.Jitsi_Enable_Channels || false, encryptionEnabled: state.encryption.enabled, serverVersion: state.server.version, isMasterDetail: state.app.isMasterDetail, diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js index d5dd7f0c5..28666b2ca 100644 --- a/app/views/RoomInfoEditView/index.js +++ b/app/views/RoomInfoEditView/index.js @@ -292,34 +292,11 @@ class RoomInfoEditView extends React.Component { }, 100); } - handleDeleteTeam = async(selected) => { - logEvent(events.RI_EDIT_DELETE_TEAM); - const { navigation, isMasterDetail } = this.props; - const { room } = this.state; - try { - const result = await RocketChat.deleteTeam({ teamId: room.teamId, ...(selected && { roomsToRemove: selected }) }); - if (result.success) { - if (isMasterDetail) { - navigation.navigate('DrawerNavigator'); - } else { - navigation.navigate('RoomsListView'); - } - } - } catch (e) { - logEvent(events.RI_EDIT_DELETE_TEAM_F); - log(e); - showErrorAlert( - e.data.error - ? I18n.t(e.data.error) - : I18n.t('There_was_an_error_while_action', { action: I18n.t('deleting_team') }), - I18n.t('Cannot_delete') - ); - } - } - deleteTeam = async() => { const { room } = this.state; - const { navigation } = this.props; + const { + navigation, deleteCPermission, deletePPermission, deleteRoom + } = this.props; try { const db = database.active; @@ -329,16 +306,27 @@ class RoomInfoEditView extends React.Component { Q.where('team_main', Q.notEq(true)) ); - if (teamChannels.length) { + const teamChannelOwner = []; + for (let i = 0; i < teamChannels.length; i += 1) { + const permissionType = teamChannels[i].t === 'c' ? deleteCPermission : deletePPermission; + // eslint-disable-next-line no-await-in-loop + const permissions = await RocketChat.hasPermission([ + permissionType + ], teamChannels[i].rid); + + if (permissions[0]) { teamChannelOwner.push(teamChannels[i]); } + } + + if (teamChannelOwner.length) { navigation.navigate('SelectListView', { title: 'Delete_Team', - data: teamChannels, + data: teamChannelOwner, infoText: 'Select_channels_to_delete', nextAction: (selected) => { showConfirmationAlert({ message: I18n.t('You_are_deleting_the_team', { team: RocketChat.getRoomTitle(room) }), confirmationText: I18n.t('Yes_action_it', { action: I18n.t('delete') }), - onPress: () => this.handleDeleteTeam(selected) + onPress: () => deleteRoom('team', room, selected) }); } }); @@ -346,7 +334,7 @@ class RoomInfoEditView extends React.Component { showConfirmationAlert({ message: I18n.t('You_are_deleting_the_team', { team: RocketChat.getRoomTitle(room) }), confirmationText: I18n.t('Yes_action_it', { action: I18n.t('delete') }), - onPress: () => this.handleDeleteTeam() + onPress: () => deleteRoom('team', room) }); } } catch (e) { @@ -375,7 +363,7 @@ class RoomInfoEditView extends React.Component { { text: I18n.t('Yes_action_it', { action: I18n.t('delete') }), style: 'destructive', - onPress: () => deleteRoom(room.rid, room.t) + onPress: () => deleteRoom('channel', room) } ], { cancelable: false } @@ -767,7 +755,7 @@ const mapStateToProps = state => ({ }); const mapDispatchToProps = dispatch => ({ - deleteRoom: (rid, t) => dispatch(deleteRoomAction(rid, t)) + deleteRoom: (roomType, room, selected) => dispatch(deleteRoomAction(roomType, room, selected)) }); export default connect(mapStateToProps, mapDispatchToProps)(withTheme(RoomInfoEditView)); diff --git a/app/views/RoomInfoView/index.js b/app/views/RoomInfoView/index.js index 93a7e3a16..a966463bf 100644 --- a/app/views/RoomInfoView/index.js +++ b/app/views/RoomInfoView/index.js @@ -6,7 +6,6 @@ import { connect } from 'react-redux'; import UAParser from 'ua-parser-js'; import isEmpty from 'lodash/isEmpty'; -import database from '../../lib/database'; import { CustomIcon } from '../../lib/Icons'; import Status from '../../containers/Status'; import Avatar from '../../containers/Avatar'; @@ -55,7 +54,8 @@ class RoomInfoView extends React.Component { theme: PropTypes.string, isMasterDetail: PropTypes.bool, jitsiEnabled: PropTypes.bool, - editRoomPermission: PropTypes.array + editRoomPermission: PropTypes.array, + roles: PropTypes.array } constructor(props) { @@ -133,18 +133,9 @@ class RoomInfoView extends React.Component { return room.t === 'l'; } - getRoleDescription = async(id) => { - const db = database.active; - try { - const rolesCollection = db.get('roles'); - const role = await rolesCollection.find(id); - if (role) { - return role.description; - } - return null; - } catch (e) { - return null; - } + getRoleDescription = (id) => { + const { roles } = this.props; + return roles[id]; }; loadVisitor = async() => { @@ -378,7 +369,8 @@ const mapStateToProps = state => ({ rooms: state.room.rooms, isMasterDetail: state.app.isMasterDetail, jitsiEnabled: state.settings.Jitsi_Enabled || false, - editRoomPermission: state.permissions['edit-room'] + editRoomPermission: state.permissions['edit-room'], + roles: state.roles }); export default connect(mapStateToProps)(withTheme(RoomInfoView)); diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index 5f0deb326..aaa0c98f9 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -49,7 +49,8 @@ class RoomMembersView extends React.Component { room: PropTypes.object, user: PropTypes.shape({ id: PropTypes.string, - token: PropTypes.string + token: PropTypes.string, + roles: PropTypes.array }), showActionSheet: PropTypes.func, theme: PropTypes.string, diff --git a/app/views/RoomView/List/index.js b/app/views/RoomView/List/index.js index 19a8ccb90..cbf02879b 100644 --- a/app/views/RoomView/List/index.js +++ b/app/views/RoomView/List/index.js @@ -269,7 +269,7 @@ class ListContainer extends React.Component { const { listRef } = this.props; const index = messages.findIndex(item => item.id === messageId); if (index > -1) { - listRef.current.getNode().scrollToIndex({ index, viewPosition: 0.5 }); + listRef.current.getNode().scrollToIndex({ index, viewPosition: 0.5, viewOffset: 100 }); await new Promise(res => setTimeout(res, 300)); if (!this.viewableItems.map(vi => vi.key).includes(messageId)) { if (!this.jumping) { diff --git a/app/views/SettingsView/index.js b/app/views/SettingsView/index.js index 55687cf0f..5e696144b 100644 --- a/app/views/SettingsView/index.js +++ b/app/views/SettingsView/index.js @@ -65,7 +65,7 @@ class SettingsView extends React.Component { const usersCollection = db.get('users'); try { const userRecord = await usersCollection.find(user.id); - if (!userRecord.loginEmailPassword) { + if (userRecord.isFromWebView) { showConfirmationAlert({ title: I18n.t('Clear_cookies_alert'), message: I18n.t('Clear_cookies_desc'), diff --git a/e2e/data.js b/e2e/data.js index 98257f71d..4dc093cc6 100644 --- a/e2e/data.js +++ b/e2e/data.js @@ -1,75 +1,76 @@ const random = require('./helpers/random'); + const value = random(20); const data = { - server: 'https://mobile.rocket.chat', - adminUser: 'e2e_admin', - adminPassword: 'p7mFh4yLwCRXSnMvG', - alternateServer: 'https://stable.rocket.chat', - users: { - regular: { - username: `userone${ value }`, - password: '123', - email: `mobile+regular${ value }@rocket.chat` - }, - alternate: { - username: `usertwo${ value }`, - password: '123', - email: `mobile+alternate${ value }@rocket.chat`, - totpSecret: 'NA4GOMZGHBQSK6KEFRVT62DMGJJGSYZJFZIHO3ZOGVXWCYZ6MMZQ' - }, - profileChanges: { - username: `userthree${ value }`, - password: '123', - email: `mobile+profileChanges${ value }@rocket.chat` - }, - existing: { - username: `existinguser${ value }`, - password: '123', - email: `mobile+existing${ value }@rocket.chat` - } - }, - channels: { - detoxpublic: { - name: 'detox-public' - }, - detoxpublicprotected: { - name: 'detox-public-protected', - joinCode: '123' - } - }, - groups: { - private: { - name: `detox-private-${ value }` - }, - alternate: { - name: `detox-alternate-${ value }` - } - }, - teams: { - private: { - name: `detox-team-${ value }` - } - }, - registeringUser: { - username: `newuser${ value }`, - password: `password${ value }`, - email: `mobile+registering${ value }@rocket.chat` - }, - registeringUser2: { - username: `newusertwo${ value }`, - password: `passwordtwo${ value }`, - email: `mobile+registeringtwo${ value }@rocket.chat` - }, - registeringUser3: { - username: `newuserthree${ value }`, - password: `passwordthree${ value }`, - email: `mobile+registeringthree${ value }@rocket.chat` - }, - registeringUser4: { - username: `newuserfour${ value }`, - password: `passwordfour${ value }`, - email: `mobile+registeringfour${ value }@rocket.chat` - }, - random: value -} + server: 'https://mobile.rocket.chat', + adminUser: 'e2e_admin', + adminPassword: 'p7mFh4yLwCRXSnMvG', + alternateServer: 'https://stable.rocket.chat', + users: { + regular: { + username: `userone${ value }`, + password: '123', + email: `mobile+regular${ value }@rocket.chat` + }, + alternate: { + username: `usertwo${ value }`, + password: '123', + email: `mobile+alternate${ value }@rocket.chat`, + totpSecret: 'NA4GOMZGHBQSK6KEFRVT62DMGJJGSYZJFZIHO3ZOGVXWCYZ6MMZQ' + }, + profileChanges: { + username: `userthree${ value }`, + password: '123', + email: `mobile+profileChanges${ value }@rocket.chat` + }, + existing: { + username: `existinguser${ value }`, + password: '123', + email: `mobile+existing${ value }@rocket.chat` + } + }, + channels: { + detoxpublic: { + name: 'detox-public' + }, + detoxpublicprotected: { + name: 'detox-public-protected', + joinCode: '123' + } + }, + groups: { + private: { + name: `detox-private-${ value }` + }, + alternate: { + name: `detox-alternate-${ value }` + } + }, + teams: { + private: { + name: `detox-team-${ value }` + } + }, + registeringUser: { + username: `newuser${ value }`, + password: `password${ value }`, + email: `mobile+registering${ value }@rocket.chat` + }, + registeringUser2: { + username: `newusertwo${ value }`, + password: `passwordtwo${ value }`, + email: `mobile+registeringtwo${ value }@rocket.chat` + }, + registeringUser3: { + username: `newuserthree${ value }`, + password: `passwordthree${ value }`, + email: `mobile+registeringthree${ value }@rocket.chat` + }, + registeringUser4: { + username: `newuserfour${ value }`, + password: `passwordfour${ value }`, + email: `mobile+registeringfour${ value }@rocket.chat` + }, + random: value +}; module.exports = data; diff --git a/e2e/data/data.cloud.js b/e2e/data/data.cloud.js index c69b72515..df98fdd7a 100644 --- a/e2e/data/data.cloud.js +++ b/e2e/data/data.cloud.js @@ -1,72 +1,74 @@ +// eslint-disable-next-line import/no-unresolved const random = require('./helpers/random'); + const value = random(20); const data = { - server: 'https://mobile.rocket.chat', - adminUser: 'e2e_admin', - adminPassword: 'p7mFh4yLwCRXSnMvG', - alternateServer: 'https://stable.rocket.chat', - users: { - regular: { - username: `userone${ value }`, - password: '123', - email: `mobile+regular${ value }@rocket.chat` - }, - alternate: { - username: `usertwo${ value }`, - password: '123', - email: `mobile+alternate${ value }@rocket.chat`, - totpSecret: 'NA4GOMZGHBQSK6KEFRVT62DMGJJGSYZJFZIHO3ZOGVXWCYZ6MMZQ' - }, - profileChanges: { - username: `userthree${ value }`, - password: '123', - email: `mobile+profileChanges${ value }@rocket.chat` - }, - existing: { - username: `existinguser${ value }`, - password: '123', - email: `mobile+existing${ value }@rocket.chat` - } - }, - channels: { - detoxpublic: { - name: 'detox-public' - }, - detoxpublicprotected: { - name: 'detox-public-protected', - joinCode: '123' - } - }, - groups: { - private: { - name: `detox-private-${ value }` - } - }, - teams: { - private: { - name: `detox-team-${ value }` - } - }, - registeringUser: { - username: `newuser${ value }`, - password: `password${ value }`, - email: `mobile+registering${ value }@rocket.chat` - }, - registeringUser2: { - username: `newusertwo${ value }`, - password: `passwordtwo${ value }`, - email: `mobile+registeringtwo${ value }@rocket.chat` - }, - registeringUser3: { - username: `newuserthree${ value }`, - password: `passwordthree${ value }`, - email: `mobile+registeringthree${ value }@rocket.chat` - }, - registeringUser4: { - username: `newuserfour${ value }`, - password: `passwordfour${ value }`, - email: `mobile+registeringfour${ value }@rocket.chat` - }, - random: value -} + server: 'https://mobile.rocket.chat', + adminUser: 'e2e_admin', + adminPassword: 'p7mFh4yLwCRXSnMvG', + alternateServer: 'https://stable.rocket.chat', + users: { + regular: { + username: `userone${ value }`, + password: '123', + email: `mobile+regular${ value }@rocket.chat` + }, + alternate: { + username: `usertwo${ value }`, + password: '123', + email: `mobile+alternate${ value }@rocket.chat`, + totpSecret: 'NA4GOMZGHBQSK6KEFRVT62DMGJJGSYZJFZIHO3ZOGVXWCYZ6MMZQ' + }, + profileChanges: { + username: `userthree${ value }`, + password: '123', + email: `mobile+profileChanges${ value }@rocket.chat` + }, + existing: { + username: `existinguser${ value }`, + password: '123', + email: `mobile+existing${ value }@rocket.chat` + } + }, + channels: { + detoxpublic: { + name: 'detox-public' + }, + detoxpublicprotected: { + name: 'detox-public-protected', + joinCode: '123' + } + }, + groups: { + private: { + name: `detox-private-${ value }` + } + }, + teams: { + private: { + name: `detox-team-${ value }` + } + }, + registeringUser: { + username: `newuser${ value }`, + password: `password${ value }`, + email: `mobile+registering${ value }@rocket.chat` + }, + registeringUser2: { + username: `newusertwo${ value }`, + password: `passwordtwo${ value }`, + email: `mobile+registeringtwo${ value }@rocket.chat` + }, + registeringUser3: { + username: `newuserthree${ value }`, + password: `passwordthree${ value }`, + email: `mobile+registeringthree${ value }@rocket.chat` + }, + registeringUser4: { + username: `newuserfour${ value }`, + password: `passwordfour${ value }`, + email: `mobile+registeringfour${ value }@rocket.chat` + }, + random: value +}; module.exports = data; diff --git a/e2e/data/data.docker.js b/e2e/data/data.docker.js index 31fb5c8e2..6c3ce1925 100644 --- a/e2e/data/data.docker.js +++ b/e2e/data/data.docker.js @@ -1,75 +1,77 @@ +// eslint-disable-next-line import/no-unresolved const random = require('./helpers/random'); + const value = random(20); const data = { - server: 'http://localhost:3000', - adminUser: 'admin', - adminPassword: 'password', - alternateServer: 'https://stable.rocket.chat', - users: { - regular: { - username: `userone${ value }`, - password: '123', - email: `mobile+regular${ value }@rocket.chat` - }, - alternate: { - username: `usertwo${ value }`, - password: '123', - email: `mobile+alternate${ value }@rocket.chat`, - totpSecret: 'NA4GOMZGHBQSK6KEFRVT62DMGJJGSYZJFZIHO3ZOGVXWCYZ6MMZQ' - }, - profileChanges: { - username: `userthree${ value }`, - password: '123', - email: `mobile+profileChanges${ value }@rocket.chat` - }, - existing: { - username: `existinguser${ value }`, - password: '123', - email: `mobile+existing${ value }@rocket.chat` - } - }, - channels: { - detoxpublic: { - name: 'detox-public' - }, - detoxpublicprotected: { - name: 'detox-public-protected', - joinCode: '123' - } - }, - groups: { - private: { - name: `detox-private-${ value }` - }, - alternate: { - name: `detox-alternate-${ value }` - } - }, - teams: { - private: { - name: `detox-team-${ value }` - } - }, - registeringUser: { - username: `newuser${ value }`, - password: `password${ value }`, - email: `mobile+registering${ value }@rocket.chat` - }, - registeringUser2: { - username: `newusertwo${ value }`, - password: `passwordtwo${ value }`, - email: `mobile+registeringtwo${ value }@rocket.chat` - }, - registeringUser3: { - username: `newuserthree${ value }`, - password: `passwordthree${ value }`, - email: `mobile+registeringthree${ value }@rocket.chat` - }, - registeringUser4: { - username: `newuserfour${ value }`, - password: `passwordfour${ value }`, - email: `mobile+registeringfour${ value }@rocket.chat` - }, - random: value -} + server: 'http://localhost:3000', + adminUser: 'admin', + adminPassword: 'password', + alternateServer: 'https://stable.rocket.chat', + users: { + regular: { + username: `userone${ value }`, + password: '123', + email: `mobile+regular${ value }@rocket.chat` + }, + alternate: { + username: `usertwo${ value }`, + password: '123', + email: `mobile+alternate${ value }@rocket.chat`, + totpSecret: 'NA4GOMZGHBQSK6KEFRVT62DMGJJGSYZJFZIHO3ZOGVXWCYZ6MMZQ' + }, + profileChanges: { + username: `userthree${ value }`, + password: '123', + email: `mobile+profileChanges${ value }@rocket.chat` + }, + existing: { + username: `existinguser${ value }`, + password: '123', + email: `mobile+existing${ value }@rocket.chat` + } + }, + channels: { + detoxpublic: { + name: 'detox-public' + }, + detoxpublicprotected: { + name: 'detox-public-protected', + joinCode: '123' + } + }, + groups: { + private: { + name: `detox-private-${ value }` + }, + alternate: { + name: `detox-alternate-${ value }` + } + }, + teams: { + private: { + name: `detox-team-${ value }` + } + }, + registeringUser: { + username: `newuser${ value }`, + password: `password${ value }`, + email: `mobile+registering${ value }@rocket.chat` + }, + registeringUser2: { + username: `newusertwo${ value }`, + password: `passwordtwo${ value }`, + email: `mobile+registeringtwo${ value }@rocket.chat` + }, + registeringUser3: { + username: `newuserthree${ value }`, + password: `passwordthree${ value }`, + email: `mobile+registeringthree${ value }@rocket.chat` + }, + registeringUser4: { + username: `newuserfour${ value }`, + password: `passwordfour${ value }`, + email: `mobile+registeringfour${ value }@rocket.chat` + }, + random: value +}; module.exports = data; diff --git a/e2e/helpers/app.js b/e2e/helpers/app.js index 7c71c9f3e..45a67df56 100644 --- a/e2e/helpers/app.js +++ b/e2e/helpers/app.js @@ -1,122 +1,119 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../data'); async function navigateToWorkspace(server = data.server) { - await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(10000); + await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(10000); await element(by.id('join-workspace')).tap(); 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')).typeText(`${ server }\n`); await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(60000); await expect(element(by.id('workspace-view'))).toBeVisible(); } async function navigateToLogin(server) { - await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(20000); - await navigateToWorkspace(server); + await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(20000); + await navigateToWorkspace(server); await element(by.id('workspace-view-login')).tap(); - await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(2000); - await expect(element(by.id('login-view'))).toBeVisible(); + await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(2000); + await expect(element(by.id('login-view'))).toBeVisible(); } async function navigateToRegister(server) { - await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(20000); - await navigateToWorkspace(server); + await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(20000); + await navigateToWorkspace(server); await element(by.id('workspace-view-register')).tap(); - await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000); + await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000); } async function login(username, password) { - await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(2000); - await element(by.id('login-view-email')).replaceText(username); - await element(by.id('login-view-password')).replaceText(password); - await element(by.id('login-view-submit')).tap(); - await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(30000); + await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(2000); + await element(by.id('login-view-email')).replaceText(username); + await element(by.id('login-view-password')).replaceText(password); + await element(by.id('login-view-submit')).tap(); + await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(30000); } async function logout() { - await element(by.id('rooms-list-view-sidebar')).tap(); - await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000); + await element(by.id('rooms-list-view-sidebar')).tap(); + await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000); await waitFor(element(by.id('sidebar-settings'))).toBeVisible().withTimeout(2000); - await element(by.id('sidebar-settings')).tap(); - await waitFor(element(by.id('settings-view'))).toBeVisible().withTimeout(2000); - await element(by.type('UIScrollView')).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)).toExist().withTimeout(10000); - await expect(element(by.text(logoutAlertMessage)).atIndex(0)).toExist(); - await element(by.text('Logout')).tap(); - await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(10000); - await expect(element(by.id('onboarding-view'))).toBeVisible(); + await element(by.id('sidebar-settings')).tap(); + await waitFor(element(by.id('settings-view'))).toBeVisible().withTimeout(2000); + await element(by.type('UIScrollView')).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)).toExist().withTimeout(10000); + await expect(element(by.text(logoutAlertMessage)).atIndex(0)).toExist(); + await element(by.text('Logout')).tap(); + await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(10000); + await expect(element(by.id('onboarding-view'))).toBeVisible(); } async function mockMessage(message, isThread = false) { - let input = isThread ? 'messagebox-input-thread' : 'messagebox-input'; + 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('messagebox-send-message')).tap(); await waitFor(element(by.label(`${ data.random }${ message }`))).toExist().withTimeout(60000); - await expect(element(by.label(`${ data.random }${ message }`))).toExist(); - await element(by.label(`${ data.random }${ message }`)).atIndex(0).tap(); -}; - -async function starMessage(message){ - const messageLabel = `${ data.random }${ message }` - await element(by.label(messageLabel)).atIndex(0).longPress(); - await expect(element(by.id('action-sheet'))).toExist(); - await expect(element(by.id('action-sheet-handle'))).toBeVisible(); - await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5); - await element(by.label('Star')).atIndex(0).tap(); - await waitFor(element(by.id('action-sheet'))).not.toExist().withTimeout(5000); -}; - -async function pinMessage(message){ - const messageLabel = `${ data.random }${ message }` - await waitFor(element(by.label(messageLabel)).atIndex(0)).toExist(); - await element(by.label(messageLabel)).atIndex(0).longPress(); - await expect(element(by.id('action-sheet'))).toExist(); - await expect(element(by.id('action-sheet-handle'))).toBeVisible(); - await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5); - await element(by.label('Pin')).atIndex(0).tap(); - await waitFor(element(by.id('action-sheet'))).not.toExist().withTimeout(5000); + await expect(element(by.label(`${ data.random }${ message }`))).toExist(); + await element(by.label(`${ data.random }${ message }`)).atIndex(0).tap(); } -async function dismissReviewNag(){ - await waitFor(element(by.text('Are you enjoying this app?'))).toExist().withTimeout(60000); - await element(by.label('No').and(by.type('_UIAlertControllerActionView'))).tap(); // Tap `no` on ask for review alert +async function starMessage(message) { + const messageLabel = `${ data.random }${ message }`; + await element(by.label(messageLabel)).atIndex(0).longPress(); + await expect(element(by.id('action-sheet'))).toExist(); + await expect(element(by.id('action-sheet-handle'))).toBeVisible(); + await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5); + await element(by.label('Star')).atIndex(0).tap(); + await waitFor(element(by.id('action-sheet'))).not.toExist().withTimeout(5000); +} + +async function pinMessage(message) { + const messageLabel = `${ data.random }${ message }`; + await waitFor(element(by.label(messageLabel)).atIndex(0)).toExist(); + await element(by.label(messageLabel)).atIndex(0).longPress(); + await expect(element(by.id('action-sheet'))).toExist(); + await expect(element(by.id('action-sheet-handle'))).toBeVisible(); + await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5); + await element(by.label('Pin')).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?'))).toExist().withTimeout(60000); + await element(by.label('No').and(by.type('_UIAlertControllerActionView'))).tap(); // Tap `no` on ask for review alert } async function tapBack() { - await element(by.id('header-back')).atIndex(0).tap(); + await element(by.id('header-back')).atIndex(0).tap(); } -async function sleep(ms) { - return new Promise(res => setTimeout(res, ms)); +function sleep(ms) { + return new Promise(res => setTimeout(res, ms)); } async function searchRoom(room) { - await element(by.id('rooms-list-view-search')).tap(); + 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')).typeText(room); + await sleep(300); await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toBeVisible().withTimeout(60000); } -async function tryTapping(theElement, timeout, longtap = false){ +async function tryTapping(theElement, timeout, longtap = false) { try { - if(longtap){ - await theElement.longPress() - } else { - await theElement.tap() - } - } catch(e) { - if(timeout <= 0){ //TODO: Maths. How closely has the timeout been honoured here? - throw e + if (longtap) { + await theElement.longPress(); + } else { + await theElement.tap(); } - await sleep(100) - await tryTapping(theElement, timeout - 100) + } catch (e) { + if (timeout <= 0) { // TODO: Maths. How closely has the timeout been honoured here? + throw e; + } + await sleep(100); + await tryTapping(theElement, timeout - 100); } } @@ -126,21 +123,21 @@ const checkServer = async(server) => { await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000); await waitFor(element(by.label(label))).toBeVisible().withTimeout(10000); await element(by.id('sidebar-close-drawer')).tap(); -} +}; module.exports = { - navigateToWorkspace, - navigateToLogin, - navigateToRegister, - login, - logout, - mockMessage, - starMessage, - pinMessage, - dismissReviewNag, - tapBack, - sleep, - searchRoom, - tryTapping, - checkServer -}; \ No newline at end of file + navigateToWorkspace, + navigateToLogin, + navigateToRegister, + login, + logout, + mockMessage, + starMessage, + pinMessage, + dismissReviewNag, + tapBack, + sleep, + searchRoom, + tryTapping, + checkServer +}; diff --git a/e2e/helpers/data_setup.js b/e2e/helpers/data_setup.js index 7e744f54a..fd02a20c5 100644 --- a/e2e/helpers/data_setup.js +++ b/e2e/helpers/data_setup.js @@ -6,176 +6,174 @@ const TEAM_TYPE = { PRIVATE: 1 }; -let server = data.server +const { server } = data; const rocketchat = axios.create({ - baseURL: `${server}/api/v1/`, - headers: { - 'Content-Type': 'application/json;charset=UTF-8', - } -}) + baseURL: `${ server }/api/v1/`, + headers: { + 'Content-Type': 'application/json;charset=UTF-8' + } +}); -const login = async (username, password) => { - console.log(`Logging in as user ${username}`) - const response = await rocketchat.post('login', { - "user": username, - "password": password - }) - const userId = response.data.data.userId - const authToken = response.data.data.authToken - rocketchat.defaults.headers.common['X-User-Id'] = userId - rocketchat.defaults.headers.common['X-Auth-Token'] = authToken - return { authToken, userId }; -} +const login = async(username, password) => { + console.log(`Logging in as user ${ username }`); + const response = await rocketchat.post('login', { + user: username, + password + }); + const { userId } = response.data.data; + const { authToken } = response.data.data; + rocketchat.defaults.headers.common['X-User-Id'] = userId; + rocketchat.defaults.headers.common['X-Auth-Token'] = authToken; + return { authToken, userId }; +}; -const createUser = async (username, password, name, email) => { - console.log(`Creating user ${username}`) - try { - await rocketchat.post('users.create', { - "username": username, - "password": password, - "name": name, - "email": email - }) - } catch (error) { - console.log(JSON.stringify(error)) - throw "Failed to create user" - } -} +const createUser = async(username, password, name, email) => { + console.log(`Creating user ${ username }`); + try { + await rocketchat.post('users.create', { + username, + password, + name, + email + }); + } catch (error) { + console.log(JSON.stringify(error)); + throw new Error('Failed to create user'); + } +}; -const createChannelIfNotExists = async (channelname) => { - console.log(`Creating public channel ${channelname}`) - try { - const room = await rocketchat.post('channels.create', { - "name": channelname - }) - return room - } catch (createError) { - try { //Maybe it exists already? - const room = rocketchat.get(`channels.info?roomName=${channelname}`) - return room - } catch (infoError) { - console.log(JSON.stringify(createError)) - console.log(JSON.stringify(infoError)) - throw "Failed to find or create public channel" - } - } -} +const createChannelIfNotExists = async(channelname) => { + console.log(`Creating public channel ${ channelname }`); + try { + const room = await rocketchat.post('channels.create', { + name: channelname + }); + return room; + } catch (createError) { + try { // Maybe it exists already? + const room = rocketchat.get(`channels.info?roomName=${ channelname }`); + return room; + } catch (infoError) { + console.log(JSON.stringify(createError)); + console.log(JSON.stringify(infoError)); + throw new Error('Failed to find or create public channel'); + } + } +}; -const createTeamIfNotExists = async (teamname) => { - console.log(`Creating private team ${teamname}`) - try { - await rocketchat.post('teams.create', { - "name": teamname, - "type": TEAM_TYPE.PRIVATE - }) - } catch (createError) { - try { //Maybe it exists already? - await rocketchat.get(`teams.info?teamName=${teamname}`) - } catch (infoError) { - console.log(JSON.stringify(createError)) - console.log(JSON.stringify(infoError)) - throw "Failed to find or create private team" - } - } -} +const createTeamIfNotExists = async(teamname) => { + console.log(`Creating private team ${ teamname }`); + try { + await rocketchat.post('teams.create', { + name: teamname, + type: TEAM_TYPE.PRIVATE + }); + } catch (createError) { + try { // Maybe it exists already? + await rocketchat.get(`teams.info?teamName=${ teamname }`); + } catch (infoError) { + console.log(JSON.stringify(createError)); + console.log(JSON.stringify(infoError)); + throw new Error('Failed to find or create private team'); + } + } +}; -const createGroupIfNotExists = async (groupname) => { - console.log(`Creating private group ${groupname}`) - try { - await rocketchat.post('groups.create', { - "name": groupname - }) - } catch (createError) { - try { //Maybe it exists already? - await rocketchat.get(`groups.info?roomName=${groupname}`) - } catch (infoError) { - console.log(JSON.stringify(createError)) - console.log(JSON.stringify(infoError)) - throw "Failed to find or create private group" - } - } -} +const createGroupIfNotExists = async(groupname) => { + console.log(`Creating private group ${ groupname }`); + try { + await rocketchat.post('groups.create', { + name: groupname + }); + } catch (createError) { + try { // Maybe it exists already? + await rocketchat.get(`groups.info?roomName=${ groupname }`); + } catch (infoError) { + console.log(JSON.stringify(createError)); + console.log(JSON.stringify(infoError)); + throw new Error('Failed to find or create private group'); + } + } +}; -const changeChannelJoinCode = async (roomId, joinCode) => { - console.log(`Changing channel Join Code ${roomId}`) - try { - await rocketchat.post('method.call/saveRoomSettings', { - message: JSON.stringify({ - method: 'saveRoomSettings', - params: [ - roomId, - { joinCode } - ] - }) - }) - } catch (createError) { - console.log(JSON.stringify(createError)) - throw "Failed to create protected channel" - } -} +const changeChannelJoinCode = async(roomId, joinCode) => { + console.log(`Changing channel Join Code ${ roomId }`); + try { + await rocketchat.post('method.call/saveRoomSettings', { + message: JSON.stringify({ + method: 'saveRoomSettings', + params: [ + roomId, + { joinCode } + ] + }) + }); + } catch (createError) { + console.log(JSON.stringify(createError)); + throw new Error('Failed to create protected channel'); + } +}; -const sendMessage = async (user, channel, msg) => { - console.log(`Sending message to ${channel}`) - try { - await login(user.username, user.password); - await rocketchat.post('chat.postMessage', { channel, msg }); - } catch (infoError) { - console.log(JSON.stringify(infoError)) - throw "Failed to find or create private group" - } -} +const sendMessage = async(user, channel, msg) => { + console.log(`Sending message to ${ channel }`); + try { + await login(user.username, user.password); + await rocketchat.post('chat.postMessage', { channel, msg }); + } catch (infoError) { + console.log(JSON.stringify(infoError)); + throw new Error('Failed to find or create private group'); + } +}; -const setup = async () => { - await login(data.adminUser, data.adminPassword) - - for (var userKey in data.users) { - if (data.users.hasOwnProperty(userKey)) { - const user = data.users[userKey] - await createUser(user.username, user.password, user.username, user.email) - } - } +const setup = async() => { + await login(data.adminUser, data.adminPassword); - for (var channelKey in data.channels) { - if (data.channels.hasOwnProperty(channelKey)) { - const channel = data.channels[channelKey] - const { data: { channel: { _id } } } = await createChannelIfNotExists(channel.name) + for (const userKey in data.users) { + if (Object.prototype.hasOwnProperty.call(data.users, userKey)) { + const user = data.users[userKey]; + await createUser(user.username, user.password, user.username, user.email); + } + } - if (channel.joinCode) { - await changeChannelJoinCode(_id, channel.joinCode); - } - } - } + for (const channelKey in data.channels) { + if (Object.prototype.hasOwnProperty.call(data.channels, channelKey)) { + const channel = data.channels[channelKey]; + const { data: { channel: { _id } } } = await createChannelIfNotExists(channel.name); - await login(data.users.regular.username, data.users.regular.password) + if (channel.joinCode) { + await changeChannelJoinCode(_id, channel.joinCode); + } + } + } - for (var groupKey in data.groups) { - if (data.groups.hasOwnProperty(groupKey)) { - const group = data.groups[groupKey] - await createGroupIfNotExists(group.name) - } - } + await login(data.users.regular.username, data.users.regular.password); - for (var teamKey in data.teams) { - if (data.teams.hasOwnProperty(teamKey)) { - const team = data.teams[teamKey] - await createTeamIfNotExists(team.name) - } - } + for (const groupKey in data.groups) { + if (Object.prototype.hasOwnProperty.call(data.groups, groupKey)) { + const group = data.groups[groupKey]; + await createGroupIfNotExists(group.name); + } + } - return -} + for (const teamKey in data.teams) { + if (Object.prototype.hasOwnProperty.call(data.teams, teamKey)) { + const team = data.teams[teamKey]; + await createTeamIfNotExists(team.name); + } + } +}; const get = (endpoint) => { - console.log(`GET /${ endpoint }`) - return rocketchat.get(endpoint); -} + console.log(`GET /${ endpoint }`); + return rocketchat.get(endpoint); +}; const post = (endpoint, body) => { - console.log(`POST /${ endpoint } ${ JSON.stringify(body) }`) - return rocketchat.post(endpoint, body); -} + console.log(`POST /${ endpoint } ${ JSON.stringify(body) }`); + return rocketchat.post(endpoint, body); +}; module.exports = { - setup, sendMessage, get, post, login -} \ No newline at end of file + setup, sendMessage, get, post, login +}; diff --git a/e2e/helpers/random.js b/e2e/helpers/random.js index d26e832e3..d41575c07 100644 --- a/e2e/helpers/random.js +++ b/e2e/helpers/random.js @@ -6,4 +6,4 @@ function random(length) { } return text; } -module.exports = random; \ No newline at end of file +module.exports = random; diff --git a/e2e/tests/assorted/01-e2eencryption.spec.js b/e2e/tests/assorted/01-e2eencryption.spec.js index 423d96152..de5ccb225 100644 --- a/e2e/tests/assorted/01-e2eencryption.spec.js +++ b/e2e/tests/assorted/01-e2eencryption.spec.js @@ -1,12 +1,11 @@ const { - expect, element, by, waitFor -} = require('detox'); -const { navigateToLogin, login, sleep, tapBack, mockMessage, searchRoom, logout } = require('../../helpers/app'); + navigateToLogin, login, sleep, tapBack, mockMessage, searchRoom, logout +} = require('../../helpers/app'); const data = require('../../data'); -const testuser = data.users.regular -const otheruser = data.users.alternate +const testuser = data.users.regular; +const otheruser = data.users.alternate; const checkServer = async(server) => { const label = `Connected to ${ server }`; @@ -14,11 +13,11 @@ const checkServer = async(server) => { await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000); await waitFor(element(by.label(label))).toBeVisible().withTimeout(60000); await element(by.id('sidebar-close-drawer')).tap(); -} +}; const checkBanner = async() => { await waitFor(element(by.id('listheader-encryption').withDescendant(by.label('Save Your Encryption Password')))).toBeVisible().withTimeout(10000); -} +}; async function navigateToRoom(roomName) { await searchRoom(`${ roomName }`); @@ -45,36 +44,36 @@ describe('E2E Encryption', () => { const room = `encrypted${ data.random }`; const newPassword = 'abc'; - before(async () => { + before(async() => { await device.launchApp({ permissions: { notifications: 'YES' }, delete: true }); await navigateToLogin(); await login(testuser.username, testuser.password); }); - describe('Banner', async() => { - describe('Render', async () => { - it('should have encryption badge', async () => { + describe('Banner', () => { + describe('Render', () => { + it('should have encryption badge', async() => { await checkBanner(); }); }); - - describe('Usage', async () => { + + describe('Usage', () => { it('should tap encryption badge and open save password modal', async() => { await element(by.id('listheader-encryption')).tap(); await waitFor(element(by.id('e2e-save-password-view'))).toBeVisible().withTimeout(2000); }); - + it('should tap "How it works" and navigate', async() => { await element(by.id('e2e-save-password-view-how-it-works').and(by.label('How It Works'))).tap(); await waitFor(element(by.id('e2e-how-it-works-view'))).toBeVisible().withTimeout(2000); await tapBack(); }); - + it('should tap "Save my password" and close modal', async() => { await element(by.id('e2e-save-password-view-saved-password').and(by.label('I Saved My E2E Password'))).tap(); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000); }); - + it('should create encrypted room', async() => { await element(by.id('rooms-list-view-create-channel')).tap(); await waitFor(element(by.id('new-message-view'))).toBeVisible().withTimeout(2000); @@ -92,15 +91,15 @@ describe('E2E Encryption', () => { await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000); await waitFor(element(by.id(`room-view-title-${ room }`))).toBeVisible().withTimeout(60000); }); - + it('should send message and be able to read it', async() => { await mockMessage('message'); await tapBack(); }); }); - }) + }); - describe('Security and Privacy', async() => { + describe('Security and Privacy', () => { it('should navigate to security privacy', async() => { await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000); await element(by.id('rooms-list-view-sidebar')).tap(); @@ -120,7 +119,7 @@ describe('E2E Encryption', () => { }); }); - describe('E2E Encryption Security', async() => { + describe('E2E Encryption Security', () => { it('should navigate to e2e encryption security', async() => { await element(by.id('security-privacy-view-e2e-encryption')).tap(); await waitFor(element(by.id('e2e-encryption-security-view'))).toBeVisible().withTimeout(2000); @@ -133,9 +132,9 @@ describe('E2E Encryption', () => { await expect(element(by.id('e2e-encryption-security-view-change-password').and(by.label('Save Changes')))).toExist(); await expect(element(by.id('e2e-encryption-security-view-reset-key').and(by.label('Reset E2E Key')))).toExist(); }); - }) + }); - describe('Change password', async() => { + describe('Change password', () => { 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(); @@ -184,7 +183,7 @@ describe('E2E Encryption', () => { }); }); - describe('Reset E2E key', async() => { + describe('Reset E2E key', () => { it('should reset e2e key', async() => { await tapBack(); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000); @@ -195,7 +194,7 @@ describe('E2E Encryption', () => { await waitFor(element(by.text('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 sleep(2000) + await sleep(2000); 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(); @@ -203,7 +202,7 @@ describe('E2E Encryption', () => { 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')))).toBeVisible().withTimeout(2000); - }) + }); }); }); @@ -211,21 +210,21 @@ describe('E2E Encryption', () => { it('check save banner', async() => { await checkServer(data.server); await checkBanner(); - }) - + }); + it('should add server and create new user', async() => { await sleep(5000); await element(by.id('rooms-list-header-server-dropdown-button')).tap(); await waitFor(element(by.id('rooms-list-header-server-dropdown'))).toBeVisible().withTimeout(5000); await element(by.id('rooms-list-header-server-add')).tap(); - + // TODO: refactor 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 }\n`); await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(60000); await element(by.id('workspace-view-register')).tap(); await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000); - + // Register new user await element(by.id('register-view-name')).replaceText(data.registeringUser.username); await element(by.id('register-view-username')).replaceText(data.registeringUser.username); @@ -233,10 +232,10 @@ describe('E2E Encryption', () => { await element(by.id('register-view-password')).typeText(data.registeringUser.password); await element(by.id('register-view-submit')).tap(); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000); - + await checkServer(data.alternateServer); }); - + it('should change back', async() => { await element(by.id('rooms-list-header-server-dropdown-button')).tap(); await waitFor(element(by.id('rooms-list-header-server-dropdown'))).toBeVisible().withTimeout(5000); @@ -255,4 +254,4 @@ describe('E2E Encryption', () => { await checkBanner(); }); }); -}); \ No newline at end of file +}); diff --git a/e2e/tests/assorted/02-broadcast.spec.js b/e2e/tests/assorted/02-broadcast.spec.js index 059643c02..12350ee86 100644 --- a/e2e/tests/assorted/02-broadcast.spec.js +++ b/e2e/tests/assorted/02-broadcast.spec.js @@ -1,13 +1,13 @@ +// const OTP = require('otp.js'); +// const GA = OTP.googleAuthenticator; + const { - device, expect, element, by, waitFor -} = require('detox'); -const OTP = require('otp.js'); -const GA = OTP.googleAuthenticator; -const { navigateToLogin, login, mockMessage, tapBack, sleep, searchRoom } = require('../../helpers/app'); + navigateToLogin, login, mockMessage, tapBack, searchRoom +} = require('../../helpers/app'); const data = require('../../data'); -const testuser = data.users.regular -const otheruser = data.users.alternate +const testuser = data.users.regular; +const otheruser = data.users.alternate; describe('Broadcast room', () => { before(async() => { @@ -28,7 +28,7 @@ describe('Broadcast room', () => { await element(by.id('selected-users-view-submit')).tap(); await waitFor(element(by.id('create-channel-view'))).toExist().withTimeout(5000); await element(by.id('create-channel-name')).replaceText(`broadcast${ data.random }`); - await element(by.id('create-channel-broadcast')).longPress(); //https://github.com/facebook/react-native/issues/28032 + await element(by.id('create-channel-broadcast')).longPress(); // https://github.com/facebook/react-native/issues/28032 await element(by.id('create-channel-submit')).tap(); await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000); await waitFor(element(by.id(`room-view-title-broadcast${ data.random }`))).toBeVisible().withTimeout(60000); @@ -54,11 +54,11 @@ describe('Broadcast room', () => { await navigateToLogin(); await login(otheruser.username, otheruser.password); - //await waitFor(element(by.id('two-factor'))).toBeVisible().withTimeout(5000); - //await expect(element(by.id('two-factor'))).toBeVisible(); - //const code = GA.gen(data.alternateUserTOTPSecret); - //await element(by.id('two-factor-input')).replaceText(code); - //await element(by.id('two-factor-send')).tap(); + // await waitFor(element(by.id('two-factor'))).toBeVisible().withTimeout(5000); + // await expect(element(by.id('two-factor'))).toBeVisible(); + // const code = GA.gen(data.alternateUserTOTPSecret); + // await element(by.id('two-factor-input')).replaceText(code); + // await element(by.id('two-factor-send')).tap(); await searchRoom(`broadcast${ data.random }`); await element(by.id(`rooms-list-view-item-broadcast${ data.random }`)).tap(); diff --git a/e2e/tests/assorted/03-profile.spec.js b/e2e/tests/assorted/03-profile.spec.js index 86fc001db..b17485a3f 100644 --- a/e2e/tests/assorted/03-profile.spec.js +++ b/e2e/tests/assorted/03-profile.spec.js @@ -1,10 +1,7 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const { navigateToLogin, login, sleep } = require('../../helpers/app'); const data = require('../../data'); -const profileChangeUser = data.users.profileChanges +const profileChangeUser = data.users.profileChanges; const scrollDown = 200; @@ -28,7 +25,7 @@ describe('Profile screen', () => { await waitFor(element(by.id('profile-view'))).toBeVisible().withTimeout(2000); }); - describe('Render', async() => { + describe('Render', () => { it('should have profile view', async() => { await expect(element(by.id('profile-view'))).toBeVisible(); }); @@ -56,7 +53,7 @@ describe('Profile screen', () => { it('should have avatar url', async() => { await expect(element(by.id('profile-view-avatar-url'))).toExist(); }); - + it('should have reset avatar button', async() => { await waitFor(element(by.id('profile-view-reset-avatar'))).toExist().whileElement(by.id('profile-view-list')).scroll(scrollDown, 'down'); }); @@ -74,7 +71,7 @@ describe('Profile screen', () => { }); }); - describe('Usage', async() => { + 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`); @@ -87,7 +84,7 @@ 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('_UIAlertControllerTextField')).typeText(`${ profileChangeUser.password }\n`); await waitForToast(); }); diff --git a/e2e/tests/assorted/04-setting.spec.js b/e2e/tests/assorted/04-setting.spec.js index 14bdbe71f..edfb3fd40 100644 --- a/e2e/tests/assorted/04-setting.spec.js +++ b/e2e/tests/assorted/04-setting.spec.js @@ -1,11 +1,8 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); -const { navigateToLogin, login, tapBack } = require('../../helpers/app'); +const { navigateToLogin, login } = require('../../helpers/app'); const data = require('../../data'); -const testuser = data.users.regular +const testuser = data.users.regular; describe('Settings screen', () => { before(async() => { @@ -20,7 +17,7 @@ describe('Settings screen', () => { await waitFor(element(by.id('settings-view'))).toBeVisible().withTimeout(2000); }); - describe('Render', async() => { + describe('Render', () => { it('should have settings view', async() => { await expect(element(by.id('settings-view'))).toBeVisible(); }); @@ -62,14 +59,14 @@ describe('Settings screen', () => { }); }); - describe('Usage', async() => { + describe('Usage', () => { it('should tap clear cache and navigate to roomslistview', async() => { await waitFor(element(by.id('settings-view'))).toBeVisible().withTimeout(2000); await element(by.id('settings-view-clear-cache')).tap(); await waitFor(element(by.text('This will clear all your offline data.'))).toExist().withTimeout(2000); - await element(by.label('Clear').and(by.type('_UIAlertControllerActionView'))).tap(); + await element(by.label('Clear').and(by.type('_UIAlertControllerActionView'))).tap(); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(5000); await waitFor(element(by.id(`rooms-list-view-item-${ data.groups.private.name }`))).toExist().withTimeout(10000); - }) + }); }); }); diff --git a/e2e/tests/assorted/05-joinpublicroom.spec.js b/e2e/tests/assorted/05-joinpublicroom.spec.js index 15acbda9c..afeff4f76 100644 --- a/e2e/tests/assorted/05-joinpublicroom.spec.js +++ b/e2e/tests/assorted/05-joinpublicroom.spec.js @@ -1,10 +1,9 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { navigateToLogin, login, mockMessage, tapBack, sleep, searchRoom } = require('../../helpers/app'); +const { + navigateToLogin, login, mockMessage, tapBack, searchRoom +} = require('../../helpers/app'); -const testuser = data.users.regular +const testuser = data.users.regular; const room = data.channels.detoxpublic.name; async function navigateToRoom() { @@ -26,7 +25,7 @@ describe('Join public room', () => { await navigateToRoom(); }); - describe('Render', async() => { + describe('Render', () => { it('should have room screen', async() => { await expect(element(by.id('room-view'))).toBeVisible(); }); @@ -36,14 +35,14 @@ describe('Join public room', () => { // }); // Render - Header - describe('Header', async() => { + describe('Header', () => { it('should have actions button ', async() => { await expect(element(by.id('room-header'))).toBeVisible(); }); }); // Render - Join - describe('Join', async() => { + describe('Join', () => { it('should have join', async() => { await expect(element(by.id('room-view-join'))).toBeVisible(); }); @@ -61,7 +60,7 @@ describe('Join public room', () => { }); }); - describe('Room Actions', async() => { + describe('Room Actions', () => { before(async() => { await navigateToRoomActions(); }); @@ -117,11 +116,11 @@ describe('Join public room', () => { after(async() => { await tapBack(); await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(2000); - }) + }); }); }); - describe('Usage', async() => { + describe('Usage', () => { it('should join room', async() => { await element(by.id('room-view-join-button')).tap(); await tapBack(); diff --git a/e2e/tests/assorted/06-status.spec.js b/e2e/tests/assorted/06-status.spec.js index 52c6f9b98..7eeb246b1 100644 --- a/e2e/tests/assorted/06-status.spec.js +++ b/e2e/tests/assorted/06-status.spec.js @@ -1,17 +1,15 @@ -const { - expect, element, by, waitFor -} = require('detox'); const { navigateToLogin, login, sleep } = require('../../helpers/app'); const data = require('../../data'); -const testuser = data.users.regular + +const testuser = data.users.regular; async function waitForToast() { await sleep(300); } describe('Status screen', () => { - before(async () => { + before(async() => { await device.launchApp({ permissions: { notifications: 'YES' }, delete: true }); await navigateToLogin(); await login(testuser.username, testuser.password); @@ -24,8 +22,8 @@ describe('Status screen', () => { await waitFor(element(by.id('status-view'))).toBeVisible().withTimeout(2000); }); - describe('Render', async () => { - it('should have status input', async () => { + describe('Render', () => { + it('should have status input', async() => { await expect(element(by.id('status-view-input'))).toBeVisible(); await expect(element(by.id('status-view-online'))).toExist(); await expect(element(by.id('status-view-busy'))).toExist(); @@ -34,17 +32,17 @@ describe('Status screen', () => { }); }); - describe('Usage', async () => { - it('should change status', async () => { + describe('Usage', () => { + it('should change status', async() => { await element(by.id('status-view-busy')).tap(); await waitFor(element(by.id('status-view-current-busy'))).toExist().withTimeout(2000); }); - it('should change status text', async () => { + it('should change status text', async() => { await element(by.id('status-view-input')).typeText('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')))).toExist().withTimeout(2000); }); }); -}); \ No newline at end of file +}); diff --git a/e2e/tests/assorted/07-changeserver.spec.js b/e2e/tests/assorted/07-changeserver.spec.js index 06ac7c36a..4ed0d6b58 100644 --- a/e2e/tests/assorted/07-changeserver.spec.js +++ b/e2e/tests/assorted/07-changeserver.spec.js @@ -1,6 +1,3 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); const { navigateToLogin, login, checkServer } = require('../../helpers/app'); @@ -8,7 +5,7 @@ const reopenAndCheckServer = async(server) => { await device.launchApp({ permissions: { notifications: 'YES' } }); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(6000); await checkServer(server); -} +}; describe('Change server', () => { before(async() => { @@ -24,7 +21,7 @@ describe('Change server', () => { await element(by.id('rooms-list-header-server-add')).tap(); 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')).typeText(`${ data.alternateServer }\n`); await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(10000); await reopenAndCheckServer(data.server); }); @@ -64,5 +61,5 @@ describe('Change server', () => { it('should reopen the app and show main server', async() => { await reopenAndCheckServer(data.server); - }) + }); }); diff --git a/e2e/tests/assorted/08-joinprotectedroom.spec.js b/e2e/tests/assorted/08-joinprotectedroom.spec.js index 9101a9659..f10d7bc5f 100644 --- a/e2e/tests/assorted/08-joinprotectedroom.spec.js +++ b/e2e/tests/assorted/08-joinprotectedroom.spec.js @@ -1,12 +1,11 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { navigateToLogin, login, mockMessage, tapBack, sleep, searchRoom } = require('../../helpers/app'); +const { + navigateToLogin, login, mockMessage, searchRoom +} = require('../../helpers/app'); -const testuser = data.users.regular -const room = data.channels.detoxpublicprotected.name -const joinCode = data.channels.detoxpublicprotected.joinCode +const testuser = data.users.regular; +const room = data.channels.detoxpublicprotected.name; +const { joinCode } = data.channels.detoxpublicprotected; async function navigateToRoom() { await searchRoom(room); @@ -27,10 +26,10 @@ describe('Join protected room', () => { await navigateToRoom(); }); - describe('Usage', async() => { + describe('Usage', () => { it('should tap join and ask for join code', async() => { await openJoinCode(); - }) + }); it('should cancel join room', async() => { await element(by.id('join-code-cancel')).tap(); diff --git a/e2e/tests/assorted/09-joinfromdirectory.spec.js b/e2e/tests/assorted/09-joinfromdirectory.spec.js index 039ef823c..e04faabf4 100644 --- a/e2e/tests/assorted/09-joinfromdirectory.spec.js +++ b/e2e/tests/assorted/09-joinfromdirectory.spec.js @@ -1,13 +1,12 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { navigateToLogin, login, tapBack, sleep } = require('../../helpers/app'); +const { + navigateToLogin, login, tapBack, sleep +} = require('../../helpers/app'); -const testuser = data.users.regular +const testuser = data.users.regular; async function navigateToRoom(search) { - await element(by.id('directory-view-search')).replaceText(search); + await element(by.id('directory-view-search')).replaceText(search); await waitFor(element(by.id(`directory-view-item-${ search }`))).toBeVisible().withTimeout(10000); await sleep(300); // app takes some time to animate await element(by.id(`directory-view-item-${ search }`)).tap(); @@ -22,34 +21,34 @@ describe('Join room from directory', () => { await login(testuser.username, testuser.password); }); - describe('Usage', async() => { + describe('Usage', () => { it('should tap directory', async() => { - await element(by.id('rooms-list-view-directory')).tap(); + await element(by.id('rooms-list-view-directory')).tap(); await waitFor(element(by.id('directory-view'))).toExist().withTimeout(2000); - }) + }); it('should search public channel and navigate', async() => { await navigateToRoom(data.channels.detoxpublic.name); - }) - - it('should search user 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('Users')).tap(); - await element(by.label('Search by')).tap(); - await navigateToRoom(data.users.alternate.username); - }) + }); it('should search user 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.id('directory-view-dropdown')).tap(); + await element(by.label('Users')).tap(); + await element(by.label('Search by')).tap(); + await navigateToRoom(data.users.alternate.username); + }); + + it('should search user 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('Search by')).tap(); await navigateToRoom(data.teams.private.name); - }) + }); }); }); diff --git a/e2e/tests/assorted/10-deleteserver.spec.js b/e2e/tests/assorted/10-deleteserver.spec.js index 8e260fd70..d92d3c442 100644 --- a/e2e/tests/assorted/10-deleteserver.spec.js +++ b/e2e/tests/assorted/10-deleteserver.spec.js @@ -1,8 +1,7 @@ -const { - device, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { sleep, navigateToLogin, login, checkServer } = require('../../helpers/app'); +const { + sleep, navigateToLogin, login, checkServer +} = require('../../helpers/app'); describe('Delete server', () => { before(async() => { @@ -13,7 +12,7 @@ describe('Delete server', () => { it('should be logged in main server', async() => { await checkServer(data.server); - }) + }); it('should add server', async() => { await sleep(5000); @@ -22,7 +21,7 @@ describe('Delete server', () => { await element(by.id('rooms-list-header-server-add')).tap(); 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')).typeText(`${ data.alternateServer }\n`); await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(10000); await element(by.id('workspace-view-register')).tap(); await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000); @@ -42,7 +41,7 @@ describe('Delete server', () => { await element(by.id('rooms-list-header-server-dropdown-button')).tap(); await waitFor(element(by.id('rooms-list-header-server-dropdown'))).toBeVisible().withTimeout(5000); await element(by.id(`rooms-list-header-server-${ data.server }`)).longPress(1500); - await element(by.label('Delete').and(by.type('_UIAlertControllerActionView'))).tap(); + await element(by.label('Delete').and(by.type('_UIAlertControllerActionView'))).tap(); await element(by.id('rooms-list-header-server-dropdown-button')).tap(); await waitFor(element(by.id('rooms-list-header-server-dropdown'))).toBeVisible().withTimeout(5000); await waitFor(element(by.id(`rooms-list-header-server-${ data.server }`))).toBeNotVisible().withTimeout(10000); diff --git a/e2e/tests/assorted/11-deeplinking.spec.js b/e2e/tests/assorted/11-deeplinking.spec.js index c40cff7bf..8a30be0a9 100644 --- a/e2e/tests/assorted/11-deeplinking.spec.js +++ b/e2e/tests/assorted/11-deeplinking.spec.js @@ -1,13 +1,10 @@ -const { - device, element, by, waitFor -} = require('detox'); const data = require('../../data'); const { tapBack, checkServer, navigateToRegister } = require('../../helpers/app'); -const { post, get, login } = require('../../helpers/data_setup'); +const { get, login } = require('../../helpers/data_setup'); const DEEPLINK_METHODS = { AUTH: 'auth', ROOM: 'room' }; const getDeepLink = (method, server, params) => { - const deeplink = `rocketchat://${ method }?host=${ server.replace(/^(http:\/\/|https:\/\/)/, '') }&${params}`; + const deeplink = `rocketchat://${ method }?host=${ server.replace(/^(http:\/\/|https:\/\/)/, '') }&${ params }`; console.log(`Deeplinking to: ${ deeplink }`); return deeplink; }; @@ -43,7 +40,7 @@ describe('Deep linking', () => { await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000); await checkServer(data.server); await waitFor(element(by.id(`rooms-list-view-item-${ data.groups.private.name }`))).toBeVisible().withTimeout(2000); - } + }; it('should authenticate and navigate', async() => { await authAndNavigate(); @@ -63,7 +60,7 @@ describe('Deep linking', () => { }); describe('Room', () => { - describe('While logged in', async() => { + describe('While logged in', () => { it('should navigate to the room using path', async() => { await device.launchApp({ permissions: { notifications: 'YES' }, @@ -75,7 +72,7 @@ describe('Deep linking', () => { }); it('should navigate to the room using rid', async() => { - const roomResult = await get(`groups.info?roomName=${ data.groups.private.name }`) + const roomResult = await get(`groups.info?roomName=${ data.groups.private.name }`); await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true, @@ -87,7 +84,7 @@ describe('Deep linking', () => { }); }); - describe('Others', async() => { + describe('Others', () => { it('should change server', async() => { await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000); await element(by.id('rooms-list-header-server-dropdown-button')).tap(); diff --git a/e2e/tests/assorted/12-i18n.spec.js b/e2e/tests/assorted/12-i18n.spec.js index 51273fd72..1c4a6a9d5 100644 --- a/e2e/tests/assorted/12-i18n.spec.js +++ b/e2e/tests/assorted/12-i18n.spec.js @@ -1,11 +1,9 @@ -const { - device, element, by, waitFor -} = require('detox'); const { navigateToLogin, login, sleep } = require('../../helpers/app'); const { post } = require('../../helpers/data_setup'); const data = require('../../data'); -const testuser = data.users.regular + +const testuser = data.users.regular; const defaultLaunchArgs = { permissions: { notifications: 'YES' } }; const navToLanguage = async() => { @@ -25,8 +23,8 @@ describe('i18n', () => { await device.launchApp({ ...defaultLaunchArgs, languageAndLocale: { - language: "en", - locale: "en" + language: 'en', + locale: 'en' }, delete: true }); @@ -34,20 +32,20 @@ describe('i18n', () => { await expect(element(by.id('join-workspace').and(by.label('Join a workspace')))).toBeVisible(); await expect(element(by.id('create-workspace-button').and(by.label('Create a new workspace')))).toBeVisible(); }); - + it('OS set to unavailable language and fallback to \'en\'', async() => { await device.launchApp({ ...defaultLaunchArgs, languageAndLocale: { - language: "es-MX", - locale: "es-MX" + language: 'es-MX', + locale: 'es-MX' } }); await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(20000); await expect(element(by.id('join-workspace').and(by.label('Join a workspace')))).toBeVisible(); await expect(element(by.id('create-workspace-button').and(by.label('Create a new workspace')))).toBeVisible(); }); - + /** * This test might become outdated as soon as we support the language * Although this seems to be a bad approach, that's the intention for having fallback enabled @@ -110,5 +108,5 @@ describe('i18n', () => { await expect(element(by.id('sidebar-settings').withDescendant(by.label('Settings')))).toBeVisible(); await post('users.setPreferences', { data: { language: 'en' } }); // Set back to english }); - }) -}); \ No newline at end of file + }); +}); diff --git a/e2e/tests/init.js b/e2e/tests/init.js index 18ad98327..b1e08a2bd 100644 --- a/e2e/tests/init.js +++ b/e2e/tests/init.js @@ -1,13 +1,13 @@ const detox = require('detox'); -const config = require('../../package.json').detox; -const { setup } = require('../helpers/data_setup') const adapter = require('detox/runners/mocha/adapter'); +const config = require('../../package.json').detox; +const { setup } = require('../helpers/data_setup'); before(async() => { - await Promise.all([setup(), detox.init(config, { launchApp: false })]) - //await dataSetup() - //await detox.init(config, { launchApp: false }); - //await device.launchApp({ permissions: { notifications: 'YES' } }); + await Promise.all([setup(), detox.init(config, { launchApp: false })]); + // await dataSetup() + // await detox.init(config, { launchApp: false }); + // await device.launchApp({ permissions: { notifications: 'YES' } }); }); beforeEach(async function() { diff --git a/e2e/tests/onboarding/01-onboarding.spec.js b/e2e/tests/onboarding/01-onboarding.spec.js index e38a83764..a8cad8991 100644 --- a/e2e/tests/onboarding/01-onboarding.spec.js +++ b/e2e/tests/onboarding/01-onboarding.spec.js @@ -1,6 +1,3 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); describe('Onboarding', () => { @@ -12,10 +9,10 @@ describe('Onboarding', () => { describe('Render', () => { it('should have onboarding screen', async() => { await expect(element(by.id('onboarding-view'))).toBeVisible(); - }); + }); it('should have "Join a workspace"', async() => { - await expect(element(by.id('join-workspace'))).toBeVisible(); + await expect(element(by.id('join-workspace'))).toBeVisible(); }); it('should have "Create a new workspace"', async() => { @@ -27,7 +24,7 @@ describe('Onboarding', () => { // 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 navigate to join a workspace', async() => { await element(by.id('join-workspace')).tap(); await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000); @@ -50,7 +47,7 @@ describe('Onboarding', () => { await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(2000); await element(by.id('join-workspace')).tap(); await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000); - await element(by.id('new-server-view-input')).typeText(`${data.server}\n`); + await element(by.id('new-server-view-input')).typeText(`${ data.server }\n`); await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(60000); }); }); diff --git a/e2e/tests/onboarding/02-legal.spec.js b/e2e/tests/onboarding/02-legal.spec.js index 191e0647c..4ac96d985 100644 --- a/e2e/tests/onboarding/02-legal.spec.js +++ b/e2e/tests/onboarding/02-legal.spec.js @@ -1,24 +1,20 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const { navigateToRegister, navigateToLogin } = require('../../helpers/app'); describe('Legal screen', () => { - describe('From Login', () => { before(async() => { await device.launchApp({ permissions: { notifications: 'YES' }, delete: true }); await navigateToLogin(); }); - - it('should have legal button on login', async() => { + + it('should have legal button on login', async() => { await waitFor(element(by.id('login-view-more'))).toBeVisible().withTimeout(60000); }); - + it('should navigate to legal from login', async() => { await expect(element(by.id('login-view-more'))).toBeVisible(); await element(by.id('login-view-more')).tap(); - await waitFor(element(by.id('legal-view'))).toBeVisible().withTimeout(4000) + await waitFor(element(by.id('legal-view'))).toBeVisible().withTimeout(4000); }); }); @@ -28,32 +24,32 @@ describe('Legal screen', () => { await navigateToRegister(); }); - it('should have legal button on register', async() => { + it('should have legal button on register', async() => { await waitFor(element(by.id('register-view-more'))).toBeVisible().withTimeout(60000); }); - + it('should navigate to legal from register', async() => { await expect(element(by.id('register-view-more'))).toBeVisible(); await element(by.id('register-view-more')).tap(); await waitFor(element(by.id('legal-view'))).toBeVisible().withTimeout(4000); }); - + it('should have terms of service button', async() => { await expect(element(by.id('legal-terms-button'))).toBeVisible(); }); - + it('should have privacy policy button', async() => { await expect(element(by.id('legal-privacy-button'))).toBeVisible(); }); // We can't simulate how webview behaves, so I had to disable :( - /* + /* it('should navigate to terms', async() => { await element(by.id('legal-terms-button')).tap(); await waitFor(element(by.id('terms-view'))).toBeVisible().withTimeout(2000); await expect(element(by.id('terms-view'))).toBeVisible(); }); - + it('should navigate to privacy', async() => { await tapBack(); await element(by.id('legal-privacy-button')).tap(); diff --git a/e2e/tests/onboarding/03-forgotpassword.spec.js b/e2e/tests/onboarding/03-forgotpassword.spec.js index 03afe5925..d53690d6f 100644 --- a/e2e/tests/onboarding/03-forgotpassword.spec.js +++ b/e2e/tests/onboarding/03-forgotpassword.spec.js @@ -1,6 +1,3 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); const { navigateToLogin } = require('../../helpers/app'); @@ -12,7 +9,7 @@ describe('Forgot password screen', () => { await waitFor(element(by.id('forgot-password-view'))).toExist().withTimeout(2000); }); - describe('Render', async() => { + describe('Render', () => { it('should have forgot password screen', async() => { await expect(element(by.id('forgot-password-view'))).toExist(); }); @@ -26,7 +23,7 @@ describe('Forgot password screen', () => { }); }); - describe('Usage', async() => { + describe('Usage', () => { 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(); diff --git a/e2e/tests/onboarding/04-createuser.spec.js b/e2e/tests/onboarding/04-createuser.spec.js index cf706d78b..e88e9eab3 100644 --- a/e2e/tests/onboarding/04-createuser.spec.js +++ b/e2e/tests/onboarding/04-createuser.spec.js @@ -1,7 +1,4 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); -const { navigateToRegister, sleep } = require('../../helpers/app'); +const { navigateToRegister } = require('../../helpers/app'); const data = require('../../data'); describe('Create user screen', () => { @@ -37,7 +34,6 @@ describe('Create user screen', () => { }); describe('Usage', () => { - // FIXME: Detox isn't able to check if it's tappable: https://github.com/wix/Detox/issues/246 // it('should submit invalid email and do nothing', async() => { // const invalidEmail = 'invalidemail'; diff --git a/e2e/tests/onboarding/05-login.spec.js b/e2e/tests/onboarding/05-login.spec.js index 7c6b4853c..91cb91737 100644 --- a/e2e/tests/onboarding/05-login.spec.js +++ b/e2e/tests/onboarding/05-login.spec.js @@ -1,7 +1,4 @@ -const { - expect, element, by, waitFor -} = require('detox'); -const { navigateToLogin, tapBack, sleep } = require('../../helpers/app'); +const { navigateToLogin, tapBack } = require('../../helpers/app'); const data = require('../../data'); describe('Login screen', () => { @@ -46,13 +43,13 @@ describe('Login screen', () => { await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000); await tapBack(); }); - + it('should navigate to forgot password', async() => { await element(by.id('login-view-forgot-password')).tap(); await waitFor(element(by.id('forgot-password-view'))).toExist().withTimeout(2000); await tapBack(); }); - + it('should insert wrong password and get error', async() => { await element(by.id('login-view-email')).replaceText(data.users.regular.username); await element(by.id('login-view-password')).replaceText('NotMyActualPassword'); @@ -60,7 +57,7 @@ describe('Login screen', () => { await waitFor(element(by.text('Your credentials were rejected! Please try again.'))).toBeVisible().withTimeout(10000); await element(by.text('OK')).tap(); }); - + it('should login with success', async() => { await element(by.id('login-view-password')).replaceText(data.users.regular.password); await element(by.id('login-view-submit')).tap(); diff --git a/e2e/tests/onboarding/06-roomslist.spec.js b/e2e/tests/onboarding/06-roomslist.spec.js index ea6dc06c1..03e595edf 100644 --- a/e2e/tests/onboarding/06-roomslist.spec.js +++ b/e2e/tests/onboarding/06-roomslist.spec.js @@ -1,15 +1,13 @@ const { - device, expect, element, by, waitFor -} = require('detox'); -const { login, navigateToLogin, logout, tapBack, sleep, searchRoom } = require('../../helpers/app'); + login, navigateToLogin, logout, tapBack, searchRoom +} = require('../../helpers/app'); const data = require('../../data'); describe('Rooms list screen', () => { - before(async() => { await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true, delete: true }); await navigateToLogin(); - await login(data.users.regular.username, data.users.regular.password) + await login(data.users.regular.username, data.users.regular.password); }); describe('Render', () => { @@ -20,13 +18,13 @@ describe('Rooms list screen', () => { it('should have room item', async() => { await expect(element(by.id('rooms-list-view-item-general'))).toExist(); }); - + // Render - Header describe('Header', () => { it('should have create channel button', async() => { await expect(element(by.id('rooms-list-view-create-channel'))).toBeVisible(); }); - + it('should have sidebar button', async() => { await expect(element(by.id('rooms-list-view-sidebar'))).toBeVisible(); }); diff --git a/e2e/tests/onboarding/07-server-history.spec.js b/e2e/tests/onboarding/07-server-history.spec.js index fc1d6af9c..b984b9c8b 100644 --- a/e2e/tests/onboarding/07-server-history.spec.js +++ b/e2e/tests/onboarding/07-server-history.spec.js @@ -1,7 +1,6 @@ const { - device, expect, element, by, waitFor -} = require('detox'); -const { login, navigateToLogin, logout, tapBack } = require('../../helpers/app'); + login, navigateToLogin, logout, tapBack +} = require('../../helpers/app'); const data = require('../../data'); describe('Server history', () => { @@ -16,7 +15,7 @@ describe('Server history', () => { await logout(); await element(by.id('join-workspace')).tap(); await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000); - }) + }); it('should show servers history', async() => { await element(by.id('new-server-view-input')).tap(); diff --git a/e2e/tests/room/01-createroom.spec.js b/e2e/tests/room/01-createroom.spec.js index 874255e43..bc67b2c3e 100644 --- a/e2e/tests/room/01-createroom.spec.js +++ b/e2e/tests/room/01-createroom.spec.js @@ -1,10 +1,7 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { tapBack, sleep, navigateToLogin, login, tryTapping } = require('../../helpers/app'); - - +const { + tapBack, navigateToLogin, login, tryTapping +} = require('../../helpers/app'); describe('Create room screen', () => { before(async() => { @@ -13,30 +10,30 @@ describe('Create room screen', () => { await login(data.users.regular.username, data.users.regular.password); }); - describe('New Message', async() => { + describe('New Message', () => { before(async() => { await element(by.id('rooms-list-view-create-channel')).tap(); }); - describe('Render', async() => { + describe('Render', () => { it('should have new message screen', async() => { await waitFor(element(by.id('new-message-view'))).toBeVisible().withTimeout(2000); }); - + it('should have search input', async() => { await waitFor(element(by.id('new-message-view-search'))).toBeVisible().withTimeout(2000); }); - }) + }); - describe('Usage', async() => { + describe('Usage', () => { it('should back to rooms list', async() => { await waitFor(element(by.id('new-message-view-close'))).toBeVisible().withTimeout(5000); await element(by.id('new-message-view-close')).tap(); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(5000); - + await tryTapping(element(by.id('rooms-list-view-create-channel')), 3000); - //await element(by.id('rooms-list-view-create-channel')).tap(); + // await element(by.id('rooms-list-view-create-channel')).tap(); await waitFor(element(by.id('new-message-view'))).toExist().withTimeout(5000); }); @@ -56,13 +53,13 @@ describe('Create room screen', () => { await element(by.id('new-message-view-create-channel')).tap(); await waitFor(element(by.id('select-users-view'))).toExist().withTimeout(5000); }); - }) + }); }); - describe('Select Users', async() => { + describe('Select Users', () => { it('should search users', async() => { await element(by.id('select-users-view-search')).replaceText('rocket.cat'); - await waitFor(element(by.id(`select-users-view-item-rocket.cat`))).toBeVisible().withTimeout(10000); + await waitFor(element(by.id('select-users-view-item-rocket.cat'))).toBeVisible().withTimeout(10000); }); it('should select/unselect user', async() => { @@ -80,27 +77,27 @@ describe('Create room screen', () => { await element(by.id('selected-users-view-submit')).tap(); await waitFor(element(by.id('create-channel-view'))).toExist().withTimeout(10000); }); - }) + }); - describe('Create Channel', async() => { - describe('Render', async() => { + describe('Create Channel', () => { + describe('Render', () => { it('should render all fields', async() => { await expect(element(by.id('create-channel-name'))).toBeVisible(); await expect(element(by.id('create-channel-type'))).toBeVisible(); await expect(element(by.id('create-channel-readonly'))).toBeVisible(); await expect(element(by.id('create-channel-broadcast'))).toBeVisible(); - }) - }) + }); + }); - describe('Usage', async() => { + describe('Usage', () => { it('should get invalid room', async() => { await element(by.id('create-channel-name')).typeText('general'); await element(by.id('create-channel-submit')).tap(); - await waitFor(element(by.text(`A channel with name general exists`))).toExist().withTimeout(60000); - await expect(element(by.text(`A channel with name general exists`))).toExist(); + await waitFor(element(by.text('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(); }); - + it('should create public room', async() => { const room = `public${ data.random }`; await element(by.id('create-channel-name')).replaceText(''); @@ -116,7 +113,7 @@ describe('Create room screen', () => { await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(6000); await expect(element(by.id(`rooms-list-view-item-${ room }`))).toExist(); }); - + it('should create private room', async() => { const room = `private${ data.random }`; await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(5000); @@ -161,6 +158,6 @@ describe('Create room screen', () => { await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(60000); await expect(element(by.id(`rooms-list-view-item-${ room }`))).toExist(); }); - }) + }); }); }); diff --git a/e2e/tests/room/02-room.spec.js b/e2e/tests/room/02-room.spec.js index d6a374185..4e1711e64 100644 --- a/e2e/tests/room/02-room.spec.js +++ b/e2e/tests/room/02-room.spec.js @@ -1,8 +1,7 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { navigateToLogin, login, mockMessage, tapBack, sleep, searchRoom, starMessage, pinMessage, dismissReviewNag, tryTapping, logout } = require('../../helpers/app'); +const { + navigateToLogin, login, mockMessage, tapBack, sleep, searchRoom, starMessage, pinMessage, dismissReviewNag, tryTapping +} = require('../../helpers/app'); async function navigateToRoom(roomName) { await searchRoom(`${ roomName }`); @@ -20,14 +19,14 @@ describe('Room screen', () => { await navigateToRoom(mainRoom); }); - describe('Render', async() => { + 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); }); // Render - Header - describe('Header', async() => { + describe('Header', () => { it('should have actions button ', async() => { await expect(element(by.id('room-header'))).toExist(); }); @@ -38,7 +37,7 @@ describe('Room screen', () => { }); // Render - Messagebox - describe('Messagebox', async() => { + describe('Messagebox', () => { it('should have messagebox', async() => { await expect(element(by.id('messagebox'))).toExist(); }); @@ -63,15 +62,15 @@ describe('Room screen', () => { }); }); - describe('Usage', async() => { - describe('Messagebox', async() => { + describe('Usage', () => { + describe('Messagebox', () => { it('should send message', async() => { - await mockMessage('message') + await mockMessage('message'); await expect(element(by.label(`${ data.random }message`)).atIndex(0)).toExist(); }); - it('should show/hide emoji keyboard', async () => { + it('should show/hide emoji keyboard', async() => { if (device.getPlatform() === 'android') { await element(by.id('messagebox-open-emoji')).tap(); await waitFor(element(by.id('messagebox-keyboard-emoji'))).toExist().withTimeout(10000); @@ -105,20 +104,20 @@ 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 element(by.id('messagebox-input')).typeText('name:is'); await waitFor(element(by.id('messagebox-container'))).toNotExist().withTimeout(20000); await element(by.id('messagebox-input')).clearText(); }); it('should show and tap on user autocomplete and send mention', async() => { - const username = data.users.regular.username + const { username } = data.users.regular; await element(by.id('messagebox-input')).tap(); await element(by.id('messagebox-input')).typeText(`@${ username }`); await waitFor(element(by.id('messagebox-container'))).toExist().withTimeout(4000); - await waitFor(element(by.id(`mention-item-${ username }`))).toBeVisible().withTimeout(4000) + await waitFor(element(by.id(`mention-item-${ username }`))).toBeVisible().withTimeout(4000); await tryTapping(element(by.id(`mention-item-${ username }`)), 2000, true); await expect(element(by.id('messagebox-input'))).toHaveText(`@${ username } `); - await tryTapping(element(by.id('messagebox-input')), 2000) + 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); @@ -126,7 +125,7 @@ describe('Room screen', () => { 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 element(by.id('messagebox-input')).typeText('email@gmail'); await waitFor(element(by.id('messagebox-container'))).toNotExist().withTimeout(4000); await element(by.id('messagebox-input')).clearText(); }); @@ -134,9 +133,9 @@ 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('messagebox-container'))).toExist().withTimeout(4000); await waitFor(element(by.id('mention-item-general'))).toBeVisible().withTimeout(4000); - await tryTapping(element(by.id('mention-item-general')), 2000, true) + await tryTapping(element(by.id('mention-item-general')), 2000, true); await expect(element(by.id('messagebox-input'))).toHaveText('#general '); await element(by.id('messagebox-input')).clearText(); }); @@ -147,7 +146,7 @@ describe('Room screen', () => { await waitFor(element(by.id('messagebox-container'))).toNotExist().withTimeout(4000); await element(by.id('messagebox-input')).clearText(); }); - it('should draft message', async () => { + it('should draft message', async() => { await element(by.id('messagebox-input')).tap(); await element(by.id('messagebox-input')).typeText(`${ data.random }draft`); await tapBack(); @@ -159,10 +158,10 @@ describe('Room screen', () => { await navigateToRoom(mainRoom); await expect(element(by.id('messagebox-input'))).toHaveText(''); - }); + }); }); - describe('Message', async() => { + describe('Message', () => { it('should copy permalink', async() => { await element(by.label(`${ data.random }message`)).atIndex(0).longPress(); await expect(element(by.id('action-sheet'))).toExist(); @@ -184,9 +183,9 @@ describe('Room screen', () => { }); it('should star message', async() => { - await starMessage('message') + await starMessage('message'); - await sleep(1000) //https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/2324 + await sleep(1000); // https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/2324 await element(by.label(`${ data.random }message`)).atIndex(0).longPress(); await expect(element(by.id('action-sheet'))).toExist(); await expect(element(by.id('action-sheet-handle'))).toBeVisible(); @@ -229,8 +228,8 @@ describe('Room screen', () => { }); it('should ask for review', async() => { - await dismissReviewNag() //TODO: Create a proper test for this elsewhere. - }) + await dismissReviewNag(); // TODO: Create a proper test for this elsewhere. + }); it('should remove reaction', async() => { await element(by.id('message-reaction-:grinning:')).tap(); @@ -263,8 +262,8 @@ describe('Room screen', () => { }); it('should pin message', async() => { - await mockMessage('pin') - await pinMessage('pin') + await mockMessage('pin'); + await pinMessage('pin'); await waitFor(element(by.label(`${ data.random }pin`)).atIndex(0)).toExist().withTimeout(5000); await waitFor(element(by.label(`${ data.users.regular.username } Message pinned`)).atIndex(0)).toExist().withTimeout(5000); @@ -277,7 +276,7 @@ describe('Room screen', () => { }); it('should delete message', async() => { - await mockMessage('delete') + await mockMessage('delete'); await waitFor(element(by.label(`${ data.random }delete`)).atIndex(0)).toBeVisible(); await element(by.label(`${ data.random }delete`)).atIndex(0).longPress(); diff --git a/e2e/tests/room/03-roomactions.spec.js b/e2e/tests/room/03-roomactions.spec.js index ecbac2233..1d37bff3d 100644 --- a/e2e/tests/room/03-roomactions.spec.js +++ b/e2e/tests/room/03-roomactions.spec.js @@ -1,9 +1,8 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { navigateToLogin, login, tapBack, sleep, searchRoom, mockMessage, starMessage, pinMessage } = require('../../helpers/app'); -const { sendMessage } = require('../../helpers/data_setup') +const { + navigateToLogin, login, tapBack, sleep, searchRoom, mockMessage, starMessage, pinMessage +} = require('../../helpers/app'); +const { sendMessage } = require('../../helpers/data_setup'); async function navigateToRoomActions(type) { let room; @@ -36,15 +35,14 @@ async function waitForToast() { } describe('Room actions screen', () => { - before(async() => { await device.launchApp({ permissions: { notifications: 'YES' }, delete: true }); await navigateToLogin(); await login(data.users.regular.username, data.users.regular.password); }); - - describe('Render', async() => { - describe('Direct', async() => { + + describe('Render', () => { + describe('Direct', () => { before(async() => { await navigateToRoomActions('d'); }); @@ -52,41 +50,41 @@ describe('Room actions screen', () => { it('should have room actions screen', async() => { await expect(element(by.id('room-actions-view'))).toExist(); }); - + it('should have info', async() => { await expect(element(by.id('room-actions-info'))).toExist(); }); - + // it('should have voice', async() => { // await expect(element(by.id('room-actions-voice'))).toExist(); // }); - + // it('should have video', async() => { // await expect(element(by.id('room-actions-video'))).toExist(); // }); - + it('should have files', async() => { await expect(element(by.id('room-actions-files'))).toExist(); }); - + it('should have mentions', async() => { await expect(element(by.id('room-actions-mentioned'))).toExist(); }); - + it('should have starred', async() => { await expect(element(by.id('room-actions-starred'))).toExist(); }); - + it('should have share', async() => { await waitFor(element(by.id('room-actions-share'))).toExist(); await expect(element(by.id('room-actions-share'))).toExist(); }); - + it('should have pinned', async() => { await waitFor(element(by.id('room-actions-pinned'))).toExist(); await expect(element(by.id('room-actions-pinned'))).toExist(); }); - + it('should have notifications', async() => { await waitFor(element(by.id('room-actions-notifications'))).toExist(); await expect(element(by.id('room-actions-notifications'))).toExist(); @@ -102,7 +100,7 @@ describe('Room actions screen', () => { }); }); - describe('Channel/Group', async() => { + describe('Channel/Group', () => { before(async() => { await navigateToRoomActions('c'); }); @@ -110,15 +108,15 @@ describe('Room actions screen', () => { it('should have room actions screen', async() => { await expect(element(by.id('room-actions-view'))).toExist(); }); - + it('should have info', async() => { await expect(element(by.id('room-actions-info'))).toExist(); }); - + // it('should have voice', async() => { // await expect(element(by.id('room-actions-voice'))).toExist(); // }); - + // it('should have video', async() => { // await expect(element(by.id('room-actions-video'))).toExist(); // }); @@ -130,34 +128,34 @@ describe('Room actions screen', () => { it('should have add user', async() => { await expect(element(by.id('room-actions-add-user'))).toExist(); }); - + it('should have files', async() => { await expect(element(by.id('room-actions-files'))).toExist(); }); - + it('should have mentions', async() => { await expect(element(by.id('room-actions-mentioned'))).toExist(); }); - + it('should have starred', async() => { await expect(element(by.id('room-actions-starred'))).toExist(); }); - + it('should have share', async() => { await waitFor(element(by.id('room-actions-share'))).toExist(); await expect(element(by.id('room-actions-share'))).toExist(); }); - + it('should have pinned', async() => { await waitFor(element(by.id('room-actions-pinned'))).toExist(); await expect(element(by.id('room-actions-pinned'))).toExist(); }); - + it('should have notifications', async() => { await waitFor(element(by.id('room-actions-notifications'))).toExist(); await expect(element(by.id('room-actions-notifications'))).toExist(); }); - + it('should have leave channel', async() => { await waitFor(element(by.id('room-actions-leave-channel'))).toExist(); await expect(element(by.id('room-actions-leave-channel'))).toExist(); @@ -165,7 +163,7 @@ describe('Room actions screen', () => { }); }); - describe('Usage', async() => { + describe('Usage', () => { describe('TDB', async() => { // TODO: test into a jitsi call // it('should NOT navigate to voice call', async() => { @@ -191,7 +189,7 @@ describe('Room actions screen', () => { // }); }); - describe('Common', async() => { + 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); @@ -200,24 +198,23 @@ describe('Room actions screen', () => { }); it('should show starred message and unstar it', async() => { - - //Go back to room and send a message + // Go back to room and send a message await tapBack(); await mockMessage('messageToStar'); - //Star the message - await starMessage('messageToStar') + // Star the message + await starMessage('messageToStar'); - //Back into Room Actions + // Back into Room Actions await element(by.id('room-header')).tap(); await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000); - //Go to starred messages + // Go to starred messages 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')))).toExist().withTimeout(60000); - - //Unstar message + + // Unstar message await element(by.label(`${ data.random }messageToStar`)).atIndex(0).longPress(); await expect(element(by.id('action-sheet'))).toExist(); await expect(element(by.id('action-sheet-handle'))).toBeVisible(); @@ -228,15 +225,14 @@ describe('Room actions screen', () => { }); it('should show pinned message and unpin it', async() => { - - //Go back to room and send a message + // Go back to room and send a message await tapBack(); await mockMessage('messageToPin'); - //Pin the message - await pinMessage('messageToPin') + // Pin the message + await pinMessage('messageToPin'); - //Back into Room Actions + // 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-scrollview')).scrollTo('bottom'); @@ -273,7 +269,7 @@ describe('Room actions screen', () => { // }); }); - describe('Notification', async() => { + describe('Notification', () => { it('should navigate to notification preference view', async() => { await element(by.id('room-actions-scrollview')).scrollTo('bottom'); await waitFor(element(by.id('room-actions-notifications'))).toExist().withTimeout(2000); @@ -318,13 +314,13 @@ describe('Room actions screen', () => { after(async() => { await backToActions(); }); - }) + }); - describe('Channel/Group', async() => { + describe('Channel/Group', () => { // Currently, there's no way to add more owners to the room // So we test only for the 'You are the last owner...' message - const user = data.users.alternate + const user = data.users.alternate; it('should tap on leave channel and raise alert', async() => { await element(by.id('room-actions-scrollview')).scrollTo('bottom'); @@ -363,12 +359,24 @@ describe('Room actions screen', () => { await backToActions(); }); - describe('Room Members', async() => { + describe('Room Members', () => { before(async() => { await element(by.id('room-actions-members')).tap(); await waitFor(element(by.id('room-members-view'))).toExist().withTimeout(2000); }); + const openActionSheet = async(username) => { + 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(); + }; + + const closeActionSheet = async() => { + await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.6); + }; + it('should show all users', async() => { await element(by.id('room-members-view-toggle-status')).tap(); await waitFor(element(by.id(`room-members-view-item-${ user.username }`))).toExist().withTimeout(60000); @@ -397,18 +405,6 @@ describe('Room actions screen', () => { await waitFor(element(by.id(`room-members-view-item-${ user.username }`))).toExist().withTimeout(60000); }); - const openActionSheet = async(username) => { - 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(); - } - - const closeActionSheet = async() => { - await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.6); - } - it('should set/remove as owner', async() => { await openActionSheet(user.username); await element(by.id('action-sheet-set-owner')).tap(); @@ -504,9 +500,9 @@ describe('Room actions screen', () => { await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(2000); }); }); - }) + }); - describe('Direct', async() => { + describe('Direct', () => { before(async() => { await navigateToRoomActions('d'); }); diff --git a/e2e/tests/room/04-discussion.spec.js b/e2e/tests/room/04-discussion.spec.js index aa39f2eaf..29fc5a090 100644 --- a/e2e/tests/room/04-discussion.spec.js +++ b/e2e/tests/room/04-discussion.spec.js @@ -1,7 +1,6 @@ const { - expect, element, by, waitFor -} = require('detox'); -const { navigateToLogin, login, mockMessage, tapBack, searchRoom } = require('../../helpers/app'); + navigateToLogin, login, mockMessage, tapBack, searchRoom +} = require('../../helpers/app'); const data = require('../../data'); const channel = data.groups.private.name; @@ -10,28 +9,28 @@ const navigateToRoom = async() => { await searchRoom(channel); await element(by.id(`rooms-list-view-item-${ channel }`)).tap(); await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000); -} +}; describe('Discussion', () => { before(async() => { await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true, delete: true }); await navigateToLogin(); - await login(data.users.regular.username, data.users.regular.password) + await login(data.users.regular.username, data.users.regular.password); }); it('should create discussion from NewMessageView', async() => { - const discussionName = `${data.random} Discussion NewMessageView`; + const discussionName = `${ data.random } Discussion NewMessageView`; await element(by.id('rooms-list-view-create-channel')).tap(); await waitFor(element(by.id('new-message-view'))).toExist().withTimeout(2000); await element(by.label('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.id('multi-select-search')).replaceText(`${channel}`); - await waitFor(element(by.id(`multi-select-item-${channel}`))).toExist().withTimeout(10000); - await element(by.id(`multi-select-item-${channel}`)).tap(); + await element(by.id('multi-select-search')).replaceText(`${ channel }`); + await waitFor(element(by.id(`multi-select-item-${ channel }`))).toExist().withTimeout(10000); + await element(by.id(`multi-select-item-${ channel }`)).tap(); await element(by.id('multi-select-discussion-name')).replaceText(discussionName); - await waitFor(element(by.id(`create-discussion-submit`))).toExist().withTimeout(10000); + await waitFor(element(by.id('create-discussion-submit'))).toExist().withTimeout(10000); await element(by.id('create-discussion-submit')).tap(); await waitFor(element(by.id('room-view'))).toExist().withTimeout(10000); await waitFor(element(by.id(`room-view-title-${ discussionName }`))).toExist().withTimeout(5000); @@ -40,20 +39,20 @@ describe('Discussion', () => { }); it('should create discussion from action button', async() => { - const discussionName = `${data.random} Discussion Action Button`; + const discussionName = `${ data.random } Discussion Action Button`; await navigateToRoom(); await element(by.id('messagebox-actions')).tap(); await waitFor(element(by.id('action-sheet'))).toExist().withTimeout(2000); await element(by.label('Create Discussion')).atIndex(0).tap(); await waitFor(element(by.id('create-discussion-view'))).toExist().withTimeout(2000); await element(by.id('multi-select-discussion-name')).replaceText(discussionName); - await waitFor(element(by.id(`create-discussion-submit`))).toExist().withTimeout(10000); + await waitFor(element(by.id('create-discussion-submit'))).toExist().withTimeout(10000); await element(by.id('create-discussion-submit')).tap(); await waitFor(element(by.id('room-view'))).toExist().withTimeout(10000); await waitFor(element(by.id(`room-view-title-${ discussionName }`))).toExist().withTimeout(5000); }); - describe('Create Discussion from action sheet', async() => { + describe('Create Discussion from action sheet', () => { it('should send a message', async() => { await waitFor(element(by.id('messagebox'))).toBeVisible().withTimeout(60000); await mockMessage('message'); @@ -63,15 +62,15 @@ describe('Discussion', () => { const discussionName = `${ data.random }message`; await element(by.label(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.label('Start a Discussion')).atIndex(0).tap(); await waitFor(element(by.id('create-discussion-view'))).toExist().withTimeout(2000); await element(by.id('create-discussion-submit')).tap(); await waitFor(element(by.id('room-view'))).toExist().withTimeout(10000); await waitFor(element(by.id(`room-view-title-${ discussionName }`))).toExist().withTimeout(5000); }); }); - - describe('Check RoomActionsView render', async() => { + + describe('Check RoomActionsView render', () => { it('should navigete to RoomActionsView', async() => { await waitFor(element(by.id('room-header'))).toBeVisible().withTimeout(5000); await element(by.id('room-header')).tap(); diff --git a/e2e/tests/room/05-threads.spec.js b/e2e/tests/room/05-threads.spec.js index 381fa2b07..e3eee4c36 100644 --- a/e2e/tests/room/05-threads.spec.js +++ b/e2e/tests/room/05-threads.spec.js @@ -1,8 +1,7 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { navigateToLogin, login, mockMessage, tapBack, sleep, searchRoom, starMessage, pinMessage, dismissReviewNag, tryTapping } = require('../../helpers/app'); +const { + navigateToLogin, login, mockMessage, tapBack, sleep, searchRoom, dismissReviewNag +} = require('../../helpers/app'); async function navigateToRoom(roomName) { await device.launchApp({ permissions: { notifications: 'YES' }, delete: true }); @@ -20,14 +19,14 @@ describe('Threads', () => { await navigateToRoom(mainRoom); }); - describe('Render', async() => { + 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); }); // Render - Header - describe('Header', async() => { + describe('Header', () => { it('should have actions button ', async() => { await expect(element(by.id('room-header'))).toExist(); }); @@ -38,7 +37,7 @@ describe('Threads', () => { }); // Render - Messagebox - describe('Messagebox', async() => { + describe('Messagebox', () => { it('should have messagebox', async() => { await expect(element(by.id('messagebox'))).toExist(); }); @@ -63,8 +62,8 @@ describe('Threads', () => { }); }); - describe('Usage', async() => { - describe('Thread', async() => { + describe('Usage', () => { + describe('Thread', () => { const thread = `${ data.random }thread`; it('should create thread', async() => { await mockMessage('thread'); @@ -104,9 +103,9 @@ 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.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)).toNotExist().withTimeout(2000); }); @@ -117,24 +116,24 @@ describe('Threads', () => { 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.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)).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 dismissReviewNag(); // TODO: Create a proper test for this elsewhere. await element(by.id(`message-thread-button-${ thread }`)).tap(); await element(by.id('messagebox-input-thread')).typeText(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(`message-thread-replied-on-${ thread }`))).toBeVisible().withTimeout(2000); + 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(`message-thread-replied-on-${ thread }`))).toBeVisible().withTimeout(2000); await element(by.id(`message-thread-replied-on-${ thread }`)).tap(); await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000); await expect(element(by.id(`room-view-title-${ thread }`))).toExist(); @@ -155,7 +154,7 @@ describe('Threads', () => { await tapBack(); }); - it('should draft thread message', async () => { + it('should draft thread message', async() => { await element(by.id(`message-thread-button-${ thread }`)).tap(); await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000); await element(by.id('messagebox-input-thread')).typeText(`${ thread }draft`); diff --git a/e2e/tests/room/06-createdmgroup.spec.js b/e2e/tests/room/06-createdmgroup.spec.js index a6451bfd7..bd2be06ab 100644 --- a/e2e/tests/room/06-createdmgroup.spec.js +++ b/e2e/tests/room/06-createdmgroup.spec.js @@ -1,8 +1,7 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { tapBack, sleep, navigateToLogin, login, tryTapping } = require('../../helpers/app'); +const { + navigateToLogin, login +} = require('../../helpers/app'); @@ -13,41 +12,39 @@ describe('Group DM', () => { await login(data.users.regular.username, data.users.regular.password); }); - describe('Create Group DM', async() => { + describe('Create Group DM', () => { before(async() => { await element(by.id('rooms-list-view-create-channel')).tap(); }); - describe('Render', async() => { + describe('Render', () => { it('should have new message screen', async() => { await waitFor(element(by.id('new-message-view'))).toBeVisible().withTimeout(2000); }); - + it('should have search input', async() => { await waitFor(element(by.id('new-message-view-search'))).toBeVisible().withTimeout(2000); }); - }) + }); - describe('Usage', async() => { + describe('Usage', () => { it('should navigate to create DM', async() => { await element(by.label('Create Direct Messages')).tap(); }); it('should add users', async() => { await element(by.id('select-users-view-search')).replaceText('rocket.cat'); - await waitFor(element(by.id(`select-users-view-item-rocket.cat`))).toBeVisible().withTimeout(10000); + await waitFor(element(by.id('select-users-view-item-rocket.cat'))).toBeVisible().withTimeout(10000); await element(by.id('select-users-view-item-rocket.cat')).tap(); await element(by.id('select-users-view-search')).replaceText(data.users.existing.username); - await waitFor(element(by.id(`select-users-view-item-${data.users.existing.username}`))).toBeVisible().withTimeout(10000); - await element(by.id(`select-users-view-item-${data.users.existing.username}`)).tap(); + await waitFor(element(by.id(`select-users-view-item-${ data.users.existing.username }`))).toBeVisible().withTimeout(10000); + await element(by.id(`select-users-view-item-${ data.users.existing.username }`)).tap(); await element(by.id('selected-users-view-submit')).tap(); }); it('check Group DM exist', async() => { - await waitFor(element(by.id(`room-view-title-${data.users.existing.username}, rocket.cat`))).toExist().withTimeout(10000); + await waitFor(element(by.id(`room-view-title-${ data.users.existing.username }, rocket.cat`))).toExist().withTimeout(10000); }); - - - }) + }); }); }); diff --git a/e2e/tests/room/07-markasunread.spec.js b/e2e/tests/room/07-markasunread.spec.js index 383f49a7b..82920ba84 100644 --- a/e2e/tests/room/07-markasunread.spec.js +++ b/e2e/tests/room/07-markasunread.spec.js @@ -1,9 +1,8 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { navigateToLogin, login, searchRoom, sleep } = require('../../helpers/app'); -const { sendMessage } = require('../../helpers/data_setup') +const { + navigateToLogin, login, searchRoom, sleep +} = require('../../helpers/app'); +const { sendMessage } = require('../../helpers/data_setup'); async function navigateToRoom(user) { await searchRoom(`${ user }`); @@ -12,7 +11,7 @@ async function navigateToRoom(user) { } describe('Mark as unread', () => { - const user = data.users.alternate.username + const user = data.users.alternate.username; before(async() => { await device.launchApp({ permissions: { notifications: 'YES' }, delete: true }); @@ -21,9 +20,8 @@ describe('Mark as unread', () => { await navigateToRoom(user); }); - // TODO: Fix flakiness. If it fails, run it solo. - describe('Usage', async() => { - describe('Mark message as unread', async() => { + describe('Usage', () => { + describe('Mark message as unread', () => { it('should mark message as unread', async() => { const message = `${ data.random }message-mark-as-unread`; const channelName = `@${ data.users.regular.username }`; @@ -35,7 +33,7 @@ describe('Mark as unread', () => { await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5); await element(by.label('Mark Unread')).atIndex(0).tap(); await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(5000); - await expect(element(by.id(`rooms-list-view-item-${data.users.alternate.username}`))).toExist(); + await expect(element(by.id(`rooms-list-view-item-${ data.users.alternate.username }`))).toExist(); }); }); }); diff --git a/e2e/tests/room/08-roominfo.spec.js b/e2e/tests/room/08-roominfo.spec.js index fd6216cf9..8786c3761 100644 --- a/e2e/tests/room/08-roominfo.spec.js +++ b/e2e/tests/room/08-roominfo.spec.js @@ -1,10 +1,9 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { navigateToLogin, login, tapBack, sleep, searchRoom } = require('../../helpers/app'); +const { + navigateToLogin, login, tapBack, sleep, searchRoom +} = require('../../helpers/app'); -const privateRoomName = data.groups.private.name +const privateRoomName = data.groups.private.name; async function navigateToRoomInfo(type) { let room; @@ -31,14 +30,13 @@ async function waitForToast() { } describe('Room info screen', () => { - before(async() => { await device.launchApp({ permissions: { notifications: 'YES' }, delete: true }); await navigateToLogin(); await login(data.users.regular.username, data.users.regular.password); }); - describe('Direct', async() => { + describe('Direct', () => { before(async() => { await navigateToRoomInfo('d'); }); @@ -49,107 +47,107 @@ describe('Room info screen', () => { }); after(async() => { - await tapBack() - await tapBack() - await tapBack() - }) + await tapBack(); + await tapBack(); + await tapBack(); + }); }); - describe('Channel/Group', async() => { + describe('Channel/Group', () => { before(async() => { await navigateToRoomInfo('c'); }); - describe('Render', async() => { + describe('Render', () => { it('should have room info view', async() => { await expect(element(by.id('room-info-view'))).toExist(); }); - + it('should have name', async() => { await expect(element(by.id('room-info-view-name'))).toExist(); }); - + it('should have description', async() => { await expect(element(by.label('Description'))).toExist(); }); - + it('should have topic', async() => { await expect(element(by.label('Topic'))).toExist(); }); - + it('should have announcement', async() => { await expect(element(by.label('Announcement'))).toExist(); }); - + it('should have edit button', async() => { await expect(element(by.id('room-info-view-edit-button'))).toExist(); }); }); - describe('Render Edit', async() => { + describe('Render Edit', () => { before(async() => { await waitFor(element(by.id('room-info-view-edit-button'))).toExist().withTimeout(10000); await element(by.id('room-info-view-edit-button')).tap(); await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000); }); - + it('should have room info edit view', async() => { await expect(element(by.id('room-info-edit-view'))).toExist(); }); - + it('should have name input', async() => { await expect(element(by.id('room-info-edit-view-name'))).toExist(); }); - + it('should have description input', async() => { await expect(element(by.id('room-info-edit-view-description'))).toExist(); }); - + it('should have topic input', async() => { await expect(element(by.id('room-info-edit-view-topic'))).toExist(); }); - + it('should have announcement input', async() => { await expect(element(by.id('room-info-edit-view-announcement'))).toExist(); }); - + it('should have password input', async() => { await expect(element(by.id('room-info-edit-view-password'))).toExist(); }); - + 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 expect(element(by.id('room-info-edit-view-t'))).toExist(); }); - + it('should have ready only switch', async() => { await expect(element(by.id('room-info-edit-view-ro'))).toExist(); }); - + it('should have submit button', async() => { await expect(element(by.id('room-info-edit-view-submit'))).toExist(); }); - + it('should have reset button', async() => { await expect(element(by.id('room-info-edit-view-reset'))).toExist(); }); - + it('should have archive button', async() => { await expect(element(by.id('room-info-edit-view-archive'))).toExist(); }); - + it('should have delete button', async() => { await expect(element(by.id('room-info-edit-view-delete'))).toExist(); }); - + after(async() => { // Ugly hack to scroll on detox await element(by.id('room-info-edit-view-list')).swipe('down', 'fast', 0.8); }); }); - - describe('Usage', async() => { + + 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'); @@ -161,7 +159,7 @@ describe('Room info screen', () => { // 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); @@ -179,7 +177,7 @@ describe('Room info screen', () => { await waitForToast(); await element(by.id('room-info-edit-view-list')).swipe('down', 'fast', 0.8); }); - + it('should reset form', async() => { await element(by.id('room-info-edit-view-name')).replaceText('abc'); await element(by.id('room-info-edit-view-description')).replaceText('abc'); @@ -188,7 +186,7 @@ describe('Room info screen', () => { 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 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-ro')).longPress(); // https://github.com/facebook/react-native/issues/28032 await element(by.id('room-info-edit-view-react-when-ro')).tap(); await element(by.id('room-info-edit-view-reset')).tap(); // after reset @@ -202,7 +200,7 @@ describe('Room info screen', () => { 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); }); - + 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); @@ -212,7 +210,7 @@ describe('Room info screen', () => { 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(); }); - + it('should change room topic', async() => { await waitFor(element(by.id('room-info-view-edit-button'))).toExist().withTimeout(10000); await element(by.id('room-info-view-edit-button')).tap(); @@ -225,7 +223,7 @@ describe('Room info screen', () => { 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(); }); - + it('should change room announcement', async() => { await waitFor(element(by.id('room-info-view-edit-button'))).toExist().withTimeout(10000); await element(by.id('room-info-view-edit-button')).tap(); @@ -238,7 +236,7 @@ describe('Room info screen', () => { 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(); }); - + it('should change room password', async() => { await waitFor(element(by.id('room-info-view-edit-button'))).toExist().withTimeout(10000); await element(by.id('room-info-view-edit-button')).tap(); @@ -248,7 +246,7 @@ describe('Room info screen', () => { 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 element(by.id('room-info-edit-view-t')).tap(); @@ -258,7 +256,7 @@ describe('Room info screen', () => { 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'); @@ -270,7 +268,7 @@ describe('Room info screen', () => { // 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(); diff --git a/e2e/tests/room/09-jumptomessage.spec.js b/e2e/tests/room/09-jumptomessage.spec.js index 5071e4de9..82ab06e5b 100644 --- a/e2e/tests/room/09-jumptomessage.spec.js +++ b/e2e/tests/room/09-jumptomessage.spec.js @@ -1,8 +1,7 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { navigateToLogin, mockMessage, tapBack, login, sleep, searchRoom } = require('../../helpers/app'); +const { + navigateToLogin, tapBack, login, searchRoom +} = require('../../helpers/app'); async function navigateToRoom(roomName) { await searchRoom(`${ roomName }`); @@ -20,9 +19,9 @@ async function clearCache() { await waitFor(element(by.id('settings-view'))).toBeVisible().withTimeout(2000); await element(by.id('settings-view-clear-cache')).tap(); await waitFor(element(by.text('This will clear all your offline data.'))).toExist().withTimeout(2000); - await element(by.label('Clear').and(by.type('_UIAlertControllerActionView'))).tap(); + await element(by.label('Clear').and(by.type('_UIAlertControllerActionView'))).tap(); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(5000); - await waitFor(element(by.id(`rooms-list-view-item-jumping`))).toExist().withTimeout(10000); + await waitFor(element(by.id('rooms-list-view-item-jumping'))).toExist().withTimeout(10000); } async function waitForLoading() { @@ -51,7 +50,7 @@ describe('Room', () => { await element(by.id('nav-jump-to-bottom')).tap(); await waitFor(element(by.label('Quote first message'))).toExist().withTimeout(5000); await clearCache(); - }) + }); it('should load messages on scroll', async() => { await navigateToRoom('jumping'); @@ -64,6 +63,7 @@ describe('Room', () => { await expect(element(by.label('249'))).toExist(); found = true; } catch { + // } } await clearCache(); @@ -80,7 +80,7 @@ describe('Room', () => { await expect(element(by.label('30'))).toExist(); await expect(element(by.label('31'))).toExist(); await expect(element(by.label('32'))).toExist(); - }) + }); it('should load newer and older messages', async() => { await element(by.id('room-view-messages')).atIndex(0).swipe('down', 'fast', 0.8); @@ -114,9 +114,9 @@ describe('Room', () => { const expectThreadMessages = async(message) => { await waitFor(element(by.id('room-view-title-jumping-thread'))).toExist().withTimeout(5000); await expect(element(by.label(message))).toExist(); -} +}; -describe('Threads', async() => { +describe('Threads', () => { 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)).toExist().withTimeout(5000); @@ -150,5 +150,5 @@ describe('Threads', async() => { await expectThreadMessages('to be searched'); }); - //TODO: Threads pagination -}); \ No newline at end of file + // TODO: Threads pagination +}); diff --git a/e2e/tests/team/01-createteam.spec.js b/e2e/tests/team/01-createteam.spec.js index 3c9a2260c..0fb71a7b6 100644 --- a/e2e/tests/team/01-createteam.spec.js +++ b/e2e/tests/team/01-createteam.spec.js @@ -1,6 +1,3 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); const { navigateToLogin, login } = require('../../helpers/app'); @@ -13,7 +10,7 @@ describe('Create team screen', () => { await login(data.users.regular.username, data.users.regular.password); }); - describe('New Message', async() => { + describe('New Message', () => { before(async() => { await element(by.id('rooms-list-view-create-channel')).tap(); }); @@ -28,17 +25,17 @@ describe('Create team screen', () => { }); }); - describe('Select Users', async() => { + describe('Select Users', () => { it('should nav to create team', async() => { await element(by.id('selected-users-view-submit')).tap(); await waitFor(element(by.id('create-channel-view'))).toExist().withTimeout(10000); }); - }) + }); - describe('Create Team', async() => { - describe('Usage', async() => { + 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')).typeText(`${ data.teams.private.name }`); await element(by.id('create-channel-submit')).tap(); await element(by.text('OK')).tap(); }); @@ -52,10 +49,10 @@ describe('Create team screen', () => { await waitFor(element(by.id(`room-view-title-${ teamName }`))).toExist().withTimeout(6000); await expect(element(by.id(`room-view-title-${ teamName }`))).toExist(); }); - }) + }); }); - describe('Delete Team', async() => { + describe('Delete Team', () => { it('should navigate to room info edit view', async() => { await element(by.id('room-header')).tap(); await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000); diff --git a/e2e/tests/team/02-team.spec.js b/e2e/tests/team/02-team.spec.js index f9b819595..c8451cc45 100644 --- a/e2e/tests/team/02-team.spec.js +++ b/e2e/tests/team/02-team.spec.js @@ -1,8 +1,7 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { navigateToLogin, login, tapBack, sleep, searchRoom } = require('../../helpers/app'); +const { + navigateToLogin, login, tapBack, sleep, searchRoom +} = require('../../helpers/app'); async function navigateToRoom(roomName) { await searchRoom(`${ roomName }`); @@ -29,7 +28,7 @@ async function backToActions() { await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(2000); } async function closeActionSheet() { - await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.6); + await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.6); } async function waitForToast() { @@ -49,13 +48,13 @@ describe('Team', () => { await navigateToRoom(team); }); - describe('Team Room', async() => { - describe('Team Header', async() => { + describe('Team Room', () => { + describe('Team Header', () => { it('should have actions button ', async() => { await expect(element(by.id('room-header'))).toExist(); }); - - it('should have team channels button ', async() => { + + it('should have team channels button ', async() => { await expect(element(by.id('room-view-header-team-channels'))).toExist(); }); @@ -69,19 +68,19 @@ describe('Team', () => { }); }); - describe('Team Header Usage', async() => { + describe('Team Header Usage', () => { it('should navigate to team channels view', async() => { await element(by.id('room-view-header-team-channels')).tap(); await waitFor(element(by.id('team-channels-view'))).toExist().withTimeout(5000); }); - }) + }); - describe('Team Channels Header', async() => { + describe('Team Channels Header', () => { it('should have actions button ', async() => { await expect(element(by.id('room-header'))).toExist(); }); - - it('should have team channels button ', async() => { + + it('should have team channels button ', async() => { await expect(element(by.id('team-channels-view-create'))).toExist(); }); @@ -90,10 +89,10 @@ describe('Team', () => { }); }); - describe('Team Channels Header Usage', async() => { + describe('Team Channels Header Usage', () => { it('should navigate to add team channels view', async() => { await element(by.id('team-channels-view-create')).tap(); - await waitFor(element(by.id('add-channel-team-view'))).toExist().withTimeout(5000); + await waitFor(element(by.id('add-channel-team-view'))).toExist().withTimeout(5000); }); it('should have create new button', async() => { @@ -103,11 +102,10 @@ describe('Team', () => { it('should add existing button', async() => { await waitFor(element(by.id('add-channel-team-view-add-existing'))).toExist().withTimeout(5000); }); - }) + }); - describe('Channels', async() => { + describe('Channels', () => { it('should create new channel for team', async() => { - await element(by.id('add-channel-team-view-create-channel')).tap(); await element(by.id('select-users-view-search')).replaceText('rocket.cat'); @@ -138,12 +136,11 @@ describe('Team', () => { }); it('should add existing channel to team', async() => { - await element(by.id('team-channels-view-create')).tap(); await waitFor(element(by.id('add-channel-team-view'))).toExist().withTimeout(5000); await element(by.id('add-channel-team-view-add-existing')).tap(); - await waitFor(element(by.id('add-existing-channel-view'))).toExist().withTimeout(60000) + await waitFor(element(by.id('add-existing-channel-view'))).toExist().withTimeout(60000); await expect(element(by.id(`add-existing-channel-view-item-${ existingRoom }`))).toExist(); await element(by.id(`add-existing-channel-view-item-${ existingRoom }`)).tap(); await waitFor(element(by.id('add-existing-channel-view-submit'))).toExist().withTimeout(6000); @@ -174,14 +171,14 @@ describe('Team', () => { await waitFor(element(by.id('auto-join-tag'))).toBeNotVisible().withTimeout(5000); await waitFor(element(by.id(`rooms-list-view-item-${ existingRoom }`))).toExist().withTimeout(6000); }); - }) + }); - describe('Team actions', () => { + describe('Team actions', () => { before(async() => { await tapBack(); await navigateToRoomActions(); }); - + it('should add users to the team', async() => { await waitFor(element(by.id('room-actions-add-user'))).toExist().withTimeout(10000); await element(by.id('room-actions-add-user')).tap(); @@ -214,9 +211,9 @@ describe('Team', () => { await element(by.id('room-actions-leave-channel')).tap(); await waitFor(element(by.id('select-list-view'))).toExist().withTimeout(2000); - await waitFor(element(by.id(`select-list-view-item-${room}`))).toExist().withTimeout(2000); - await waitFor(element(by.id(`select-list-view-item-${existingRoom}`))).toExist().withTimeout(2000); - await element(by.id(`select-list-view-item-${room}`)).tap(); + await waitFor(element(by.id(`select-list-view-item-${ room }`))).toExist().withTimeout(2000); + await waitFor(element(by.id(`select-list-view-item-${ existingRoom }`))).toExist().withTimeout(2000); + await element(by.id(`select-list-view-item-${ room }`)).tap(); await waitFor(element(by.label('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(); @@ -227,8 +224,8 @@ describe('Team', () => { await tapBack(); await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(2000); }); - - describe('Room Members', async() => { + + describe('Room Members', () => { before(async() => { await element(by.id('room-actions-members')).tap(); await waitFor(element(by.id('room-members-view'))).toExist().withTimeout(2000); @@ -278,9 +275,9 @@ describe('Team', () => { await element(by.id('room-actions-leave-channel')).tap(); await waitFor(element(by.id('select-list-view'))).toExist().withTimeout(2000); - await waitFor(element(by.id(`select-list-view-item-${room}`))).toExist().withTimeout(2000); - await waitFor(element(by.id(`select-list-view-item-${existingRoom}`))).toExist().withTimeout(2000); - await element(by.id(`select-list-view-item-${room}`)).tap(); + await waitFor(element(by.id(`select-list-view-item-${ room }`))).toExist().withTimeout(2000); + await waitFor(element(by.id(`select-list-view-item-${ existingRoom }`))).toExist().withTimeout(2000); + await element(by.id(`select-list-view-item-${ room }`)).tap(); await waitFor(element(by.label('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(); @@ -291,4 +288,4 @@ describe('Team', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/e2e/tests/team/03-moveconvert.spec.js b/e2e/tests/team/03-moveconvert.spec.js index 17143c609..7c071442b 100644 --- a/e2e/tests/team/03-moveconvert.spec.js +++ b/e2e/tests/team/03-moveconvert.spec.js @@ -1,8 +1,7 @@ -const { - device, expect, element, by, waitFor -} = require('detox'); const data = require('../../data'); -const { navigateToLogin, login, tapBack, searchRoom, sleep } = require('../../helpers/app'); +const { + navigateToLogin, login, tapBack, searchRoom, sleep +} = require('../../helpers/app'); const toBeConverted = `to-be-converted-${ data.random }`; const toBeMoved = `to-be-moved-${ data.random }`; @@ -21,7 +20,7 @@ const createChannel = async(room) => { await tapBack(); await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(2000); await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(60000); -} +}; async function navigateToRoom(room) { await searchRoom(`${ room }`); @@ -42,7 +41,7 @@ describe('Move/Convert Team', () => { await login(data.users.regular.username, data.users.regular.password); }); - describe('Convert', async() => { + describe('Convert', () => { before(async() => { await createChannel(toBeConverted); }); @@ -61,10 +60,10 @@ describe('Move/Convert Team', () => { after(async() => { await tapBack(); await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(2000); - }) + }); }); - describe('Move', async() => { + describe('Move', () => { before(async() => { await createChannel(toBeMoved); }); @@ -78,12 +77,12 @@ describe('Move/Convert Team', () => { await element(by.id('select-list-view-submit')).tap(); await sleep(2000); await waitFor(element(by.id('select-list-view'))).toExist().withTimeout(2000); - await waitFor(element(by.id(`select-list-view-item-${toBeConverted}`))).toExist().withTimeout(2000); - await element(by.id(`select-list-view-item-${toBeConverted}`)).tap(); + await waitFor(element(by.id(`select-list-view-item-${ toBeConverted }`))).toExist().withTimeout(2000); + await element(by.id(`select-list-view-item-${ toBeConverted }`)).tap(); await element(by.id('select-list-view-submit')).atIndex(0).tap(); await waitFor(element(by.label('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 waitFor(element(by.id('room-view-header-team-channels'))).toExist().withTimeout(10000); }); - }) + }); });