diff --git a/app/screens/long_post/__snapshots__/long_post.test.js.snap b/app/screens/long_post/__snapshots__/long_post.test.js.snap
index 8ff6e8827..2fb5c941d 100644
--- a/app/screens/long_post/__snapshots__/long_post.test.js.snap
+++ b/app/screens/long_post/__snapshots__/long_post.test.js.snap
@@ -32,7 +32,9 @@ LongPost {
"goToThread": [Function],
"handleClose": [Function],
"handlePress": [Function],
- "navigationEventListener": undefined,
+ "navigationEventListener": Object {
+ "remove": [MockFunction],
+ },
"props": Object {
"actions": Object {
"getPostThread": [MockFunction],
diff --git a/app/screens/select_server/select_server.test.js b/app/screens/select_server/select_server.test.js
new file mode 100644
index 000000000..0d3e90bf2
--- /dev/null
+++ b/app/screens/select_server/select_server.test.js
@@ -0,0 +1,83 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+import React from 'react';
+
+import SelectServer from './select_server.js';
+import {renderWithReduxIntl} from 'test/testing_library';
+import {fireEvent, waitFor} from '@testing-library/react-native';
+
+describe('SelectServer', () => {
+ const actions = {
+ getPing: jest.fn(),
+ handleServerUrlChanged: jest.fn(),
+ scheduleExpiredNotification: jest.fn(),
+ loadConfigAndLicense: jest.fn(),
+ login: jest.fn(),
+ resetPing: jest.fn(),
+ setLastUpgradeCheck: jest.fn(),
+ setServerVersion: jest.fn(),
+ };
+
+ const baseProps = {
+ actions,
+ hasConfigAndLicense: true,
+ serverUrl: '',
+ };
+
+ test('should match error when URL is empty string', async () => {
+ const {getByTestId, getByText} = renderWithReduxIntl(
+ ,
+ );
+
+ const button = getByText('Connect');
+ fireEvent.press(button);
+
+ await waitFor(() => expect(getByTestId('error_text')).toBeTruthy());
+ expect(getByText('Please enter a valid server URL')).toBeTruthy();
+ });
+
+ test('should match error when URL is only spaces', async () => {
+ const {getByTestId, getByText} = renderWithReduxIntl(
+ ,
+ );
+
+ const urlInput = getByTestId('server_url_input');
+ fireEvent.changeText(urlInput, ' ');
+
+ const button = getByText('Connect');
+ fireEvent.press(button);
+
+ await waitFor(() => expect(getByTestId('error_text')).toBeTruthy());
+ expect(getByText('Please enter a valid server URL')).toBeTruthy();
+ });
+
+ test('should match error when URL does not start with http:// or https://', async () => {
+ const {getByTestId, getByText} = renderWithReduxIntl(
+ ,
+ );
+
+ const urlInput = getByTestId('server_url_input');
+ fireEvent.changeText(urlInput, 'ht://invalid:8065');
+
+ const button = getByText('Connect');
+ fireEvent.press(button);
+
+ await waitFor(() => expect(getByTestId('error_text')).toBeTruthy());
+ expect(getByText('URL must start with http:// or https://')).toBeTruthy();
+ });
+
+ test('should not show error when valid URL is entered', async () => {
+ const {getByTestId, getByText, queryByTestId} = renderWithReduxIntl(
+ ,
+ );
+
+ const urlInput = getByTestId('server_url_input');
+ fireEvent.changeText(urlInput, 'http://localhost:8065');
+
+ const button = getByText('Connect');
+ fireEvent.press(button);
+
+ expect(queryByTestId('error_text')).toBeNull();
+ await waitFor(() => expect(getByText('Connecting...')).toBeTruthy());
+ });
+});
\ No newline at end of file
diff --git a/app/screens/settings/notification_settings_mentions_keywords/__snapshots__/notification_settings_mentions_keywords.test.js.snap b/app/screens/settings/notification_settings_mentions_keywords/__snapshots__/notification_settings_mentions_keywords.test.js.snap
index 593d4000a..c1c44a184 100644
--- a/app/screens/settings/notification_settings_mentions_keywords/__snapshots__/notification_settings_mentions_keywords.test.js.snap
+++ b/app/screens/settings/notification_settings_mentions_keywords/__snapshots__/notification_settings_mentions_keywords.test.js.snap
@@ -5,7 +5,9 @@ NotificationSettingsMentionsKeywords {
"context": Object {},
"handleSubmit": [Function],
"keywordsRef": [Function],
- "navigationEventListener": undefined,
+ "navigationEventListener": Object {
+ "remove": [MockFunction],
+ },
"onKeywordsChangeText": [Function],
"props": Object {
"componentId": "component-id",
diff --git a/detox/e2e/test/on_boarding/login.e2e.js b/detox/e2e/test/on_boarding/login.e2e.js
index 2fdcef9e9..950825126 100644
--- a/detox/e2e/test/on_boarding/login.e2e.js
+++ b/detox/e2e/test/on_boarding/login.e2e.js
@@ -32,6 +32,31 @@ describe('On boarding', () => {
await expect(element(by.id('connect_button'))).toBeVisible();
});
+ it('MM-T3383 should show error on empty server URL', async () => {
+ await expect(element(by.id('select_server_screen'))).toBeVisible();
+
+ // # Enter an empty server URL
+ await element(by.id('server_url_input')).typeText(' ');
+
+ // # Tap anywhere to hide keyboard
+ await element(by.text('Enter Server URL')).tap();
+
+ // * Verify that the error message does not exist
+ await waitFor(element(by.id('error_text'))).not.toExist().withTimeout(timeouts.HALF_SEC);
+
+ // # Tap connect button
+ await element(by.id('connect_button')).tap();
+
+ // # Explicitly wait on Android before verifying error message
+ if (isAndroid()) {
+ await wait(timeouts.ONE_MIN);
+ }
+
+ // * Verify error message
+ await waitFor(element(by.id('error_text'))).toBeVisible().withTimeout(timeouts.ONE_MIN);
+ await expect(element(by.id('error_text'))).toHaveText('Please enter a valid server URL');
+ });
+
it('should show error on invalid server URL', async () => {
await expect(element(by.id('select_server_screen'))).toBeVisible();
diff --git a/test/setup.js b/test/setup.js
index b718063a3..a3c8e12e9 100644
--- a/test/setup.js
+++ b/test/setup.js
@@ -188,7 +188,9 @@ jest.mock('react-native-navigation', () => {
...RNN.Navigation,
events: () => ({
registerAppLaunchedListener: jest.fn(),
- bindComponent: jest.fn(),
+ bindComponent: jest.fn(() => {
+ return {remove: jest.fn()};
+ }),
}),
setRoot: jest.fn(),
pop: jest.fn(),