Skip to content

Commit

Permalink
Merge branch 'main' into combine-ios-android-e2e
Browse files Browse the repository at this point in the history
  • Loading branch information
mattermost-build authored Feb 11, 2025
2 parents 62acb6d + 4407ca0 commit ea2af63
Show file tree
Hide file tree
Showing 19 changed files with 297 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,25 @@
import android.content.Intent;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.Person;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;

import com.mattermost.helpers.*;
import com.mattermost.turbolog.TurboLog;
import com.wix.reactnativenotifications.core.NotificationIntentAdapter;
import com.wix.reactnativenotifications.core.notification.INotificationsApplication;
import com.wix.reactnativenotifications.core.notification.PushNotificationProps;

public class NotificationReplyBroadcastReceiver extends BroadcastReceiver {
private Context mContext;
private Bundle bundle;
private NotificationManager notificationManager;

private ReactApplicationContext getReactContext(Context context) {
if (context instanceof ReactApplication) {
ReactNativeHost host = ((ReactApplication) context).getReactNativeHost();
return (ReactApplicationContext) host.getReactInstanceManager().getCurrentReactContext();
}

return null;
}

@Override
public void onReceive(Context context, Intent intent) {
try {
Expand Down Expand Up @@ -80,7 +69,6 @@ protected void replyToMessage(final String serverUrl, final int notificationId,
WritableMap headers = Arguments.createMap();
headers.putString("Content-Type", "application/json");


WritableMap body = Arguments.createMap();
body.putString("channel_id", channelId);
body.putString("message", message.toString());
Expand All @@ -92,9 +80,19 @@ protected void replyToMessage(final String serverUrl, final int notificationId,

String postsEndpoint = "/api/v4/posts?set_online=false";
Network.post(serverUrl, postsEndpoint, options, new ResolvePromise() {
private boolean isSuccessful(int statusCode) {
return statusCode >= 200 && statusCode < 300;
}
@Override
public void resolve(@Nullable Object value) {
if (value != null) {
ReadableMap response = (ReadableMap)value;
ReadableMap data = response.getMap("data");
if (data != null && data.hasKey("status_code") && !isSuccessful(data.getInt("status_code"))) {
TurboLog.Companion.i("ReactNative", String.format("Reply FAILED exception %s", data.getString("message")));
onReplyFailed(notificationId);
return;
}
onReplySuccess(notificationId, message);
TurboLog.Companion.i("ReactNative", "Reply SUCCESS");
} else {
Expand All @@ -104,13 +102,13 @@ public void resolve(@Nullable Object value) {
}

@Override
public void reject(Throwable reason) {
public void reject(@NonNull Throwable reason) {
TurboLog.Companion.i("ReactNative", String.format("Reply FAILED exception %s", reason.getMessage()));
onReplyFailed(notificationId);
}

@Override
public void reject(String code, String message) {
public void reject(@NonNull String code, String message) {
TurboLog.Companion.i("ReactNative",
String.format("Reply FAILED status %s BODY %s", code, message)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public static Bundle send(final String ackId, final String serverUrl, final Stri
JSONObject jsonResponse = new JSONObject(responseBody);
return parseAckResponse(jsonResponse);
} catch (Exception e) {
TurboLog.Companion.e("ReactNative", "Send receipt delivery failed " + e.getMessage());
e.printStackTrace();
return null;
}
Expand Down
16 changes: 8 additions & 8 deletions app/screens/home/recent_mentions/recent_mentions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,19 +162,19 @@ const RecentMentionsScreen = ({appsEnabled, customEmojiNames, mentions, currentT
return (
<Freeze freeze={!isFocused}>
<ExtraKeyboardProvider>
<NavigationHeader
isLargeTitle={true}
showBackButton={false}
subtitle={subtitle}
title={title}
hasSearch={false}
scrollValue={scrollValue}
/>
<SafeAreaView
style={styles.flex}
edges={EDGES}
testID='recent_mentions.screen'
>
<NavigationHeader
isLargeTitle={true}
showBackButton={false}
subtitle={subtitle}
title={title}
hasSearch={false}
scrollValue={scrollValue}
/>
<Animated.View style={[styles.flex, animated]}>
<Animated.View style={top}>
<RoundedHeaderContext/>
Expand Down
16 changes: 8 additions & 8 deletions app/screens/home/saved_messages/saved_messages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,19 +164,19 @@ function SavedMessages({appsEnabled, posts, currentTimezone, customEmojiNames}:
return (
<Freeze freeze={!isFocused}>
<ExtraKeyboardProvider>
<NavigationHeader
isLargeTitle={true}
showBackButton={false}
subtitle={subtitle}
title={title}
hasSearch={false}
scrollValue={scrollValue}
/>
<SafeAreaView
edges={edges}
style={styles.flex}
testID='saved_messages.screen'
>
<NavigationHeader
isLargeTitle={true}
showBackButton={false}
subtitle={subtitle}
title={title}
hasSearch={false}
scrollValue={scrollValue}
/>
<Animated.View style={[styles.flex, animated]}>
<Animated.View style={top}>
<RoundedHeaderContext/>
Expand Down
168 changes: 168 additions & 0 deletions app/screens/home/search/search.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {fireEvent, waitFor} from '@testing-library/react-native';
import React from 'react';

import {addSearchToTeamSearchHistory} from '@actions/local/team';
import {searchPosts, searchFiles} from '@actions/remote/search';
import {bottomSheet} from '@screens/navigation';
import {renderWithEverything} from '@test/intl-test-helper';
import TestHelper from '@test/test_helper';

import SearchScreen from './search';

import type {TeamModel} from '@database/models/server';
import type {Database} from '@nozbe/watermelondb';

// Some subcomponents require react-native-camera-roll, which is not available in the test environment
jest.mock('@react-native-camera-roll/camera-roll', () => ({}));

jest.mock('@react-navigation/native', () => ({
...jest.requireActual('@react-navigation/native'),
useNavigation: () => ({
getState: () => ({
index: 0,
routes: [{params: {searchTerm: ''}}],
}),
}),
useIsFocused: () => true,
}));

jest.mock('@actions/local/post', () => ({
getPosts: jest.fn().mockResolvedValue([]),
}));

jest.mock('@actions/local/team', () => ({
addSearchToTeamSearchHistory: jest.fn(),
}));

jest.mock('@actions/remote/search', () => ({
searchPosts: jest.fn().mockResolvedValue({order: [], matches: {}}),
searchFiles: jest.fn().mockResolvedValue({files: [], channels: []}),
}));

jest.mock('@mattermost/hardware-keyboard', () => ({
useHardwareKeyboardEvents: jest.fn(),
}));

jest.mock('@screens/navigation', () => ({
bottomSheet: jest.fn(),
}));

describe('SearchScreen', () => {
const baseProps = {
teamId: 'team1',
teams: [
{id: 'team1', displayName: 'Team 1'},
{id: 'team2', displayName: 'Team 2'},
] as TeamModel[],
crossTeamSearchEnabled: true,
};

let database: Database;
beforeAll(async () => {
const server = await TestHelper.setupServerDatabase();
database = server.database;
});

beforeEach(() => {
jest.clearAllMocks();
});

it('renders search screen correctly', () => {
const {getByTestId, getByText, getByPlaceholderText} = renderWithEverything(
<SearchScreen {...baseProps}/>,
{database},
);
expect(getByTestId('search_messages.screen')).toBeTruthy();

// The page title
expect(getByText('Search')).toBeTruthy();

// The search input with the expected placeholder
expect(getByPlaceholderText('Search messages & files')).toBeTruthy();
});

it('handles search input changes', () => {
const {getByTestId} = renderWithEverything(
<SearchScreen {...baseProps}/>,
{database},
);

const searchInput = getByTestId('navigation.header.search_bar.search.input');
fireEvent.changeText(searchInput, 'test search');
expect(searchInput.props.value).toBe('test search');
});

it('performs search when submitting', async () => {
const {getByTestId} = renderWithEverything(
<SearchScreen {...baseProps}/>,
{database},
);

const searchInput = getByTestId('navigation.header.search_bar.search.input');
fireEvent.changeText(searchInput, 'test search');
fireEvent(searchInput, 'submitEditing');

await waitFor(() => {
expect(searchPosts).toHaveBeenCalledWith(
expect.any(String),
'team1',
expect.objectContaining({terms: 'test search'}),
);
expect(searchFiles).toHaveBeenCalledWith(
expect.any(String),
'team1',
expect.objectContaining({terms: 'test search'}),
);
});
});

it('handles team changes', async () => {
const {getByTestId} = renderWithEverything(
<SearchScreen {...baseProps}/>,
{database},
);

const teamPicker = getByTestId('team_picker.button');
fireEvent.press(teamPicker);

expect(teamPicker).toBeTruthy();
expect(bottomSheet).toHaveBeenCalled();
});

it('clears search when clear button is pressed', async () => {
const {getByTestId} = renderWithEverything(
<SearchScreen {...baseProps}/>,
{database},
);

const searchInput = getByTestId('navigation.header.search_bar.search.input');
fireEvent.changeText(searchInput, 'test search');

const clearButton = getByTestId('navigation.header.search_bar.search.clear.button');
fireEvent.press(clearButton);

expect(searchInput.props.value).toBe('');
});

it('adds search to team history when searching in a specific team', async () => {
const {getByTestId} = renderWithEverything(
<SearchScreen {...baseProps}/>,
{database},
);

const searchInput = getByTestId('navigation.header.search_bar.search.input');
fireEvent.changeText(searchInput, 'test search');
fireEvent(searchInput, 'submitEditing');

await waitFor(() => {
expect(addSearchToTeamSearchHistory).toHaveBeenCalledWith(
expect.any(String),
'team1',
'test search',
);
});
});
});
Loading

0 comments on commit ea2af63

Please sign in to comment.