Skip to content

Commit

Permalink
updated react native redux sample
Browse files Browse the repository at this point in the history
* Bugfixes
* Added snapshot tests
* Thumbnail preview in chats
  • Loading branch information
aibek-bird committed Jun 20, 2019
1 parent c760234 commit fc3f084
Show file tree
Hide file tree
Showing 534 changed files with 4,993 additions and 80,889 deletions.
13 changes: 12 additions & 1 deletion react-native-redux-sample/README.md
Expand Up @@ -38,4 +38,15 @@ SendBird React-Native sample using [SendBird SDK](https://github.com/sendbird/Se
5. Run the sample. Before starting, you should launch device amulator (or actual device) to run the sample in Android. This sample is not available for real device in iOS due to Apple Development Policy. In order to run React Native sample in real device, follow [React Native official guide](https://facebook.github.io/react-native/docs/running-on-device.html) for your own setup.

react-native run-android
react-native run-ios
react-native run-ios
## Troubleshooting

If you see an error like this: "Unable to load script from assets index.android.bundle."

1. (in project directory) mkdir android/app/src/main/assets
2. react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res

If you see an error like this: "Loading dependency graph...(node:45456) UnhandledPromiseRejectionWarning: Error: jest-haste-map: Haste module naming collision: Duplicate module name: react-native"

1. Try to delete ios/Pods file
3 changes: 0 additions & 3 deletions react-native-redux-sample/ReactNativeWithSendBird/.babelrc

This file was deleted.

4 changes: 4 additions & 0 deletions react-native-redux-sample/ReactNativeWithSendBird/.gitignore
Expand Up @@ -21,6 +21,7 @@ DerivedData
*.ipa
*.xcuserstate
project.xcworkspace
Pods/

# Android/IntelliJ
#
Expand Down Expand Up @@ -54,3 +55,6 @@ buck-out/

# Bundle artifact
*.jsbundle

coverage/
ios/Pods
108 changes: 52 additions & 56 deletions react-native-redux-sample/ReactNativeWithSendBird/App.js
@@ -1,37 +1,34 @@
import React, { Component } from 'react'
import {
Platform,
AppState,
PushNotificationIOS
} from 'react-native'
import { createStackNavigator, createAppContainer } from 'react-navigation'
import { Provider } from 'react-redux'
import SendBird from 'sendbird'
import firebase from 'react-native-firebase'
import React, { Component } from 'react';
import { Platform, AppState, PushNotificationIOS } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import { Provider } from 'react-redux';
import SendBird from 'sendbird';
import firebase from 'react-native-firebase';

import store from './src/store'
import store from './src/store';

import Start from './src/screens/Start'
import Login from './src/screens/Login'
import Menu from './src/screens/Menu'
import Profile from './src/screens/Profile'
import OpenChannel from './src/screens/OpenChannel'
import OpenChannelCreate from './src/screens/OpenChannelCreate'
import Chat from './src/screens/Chat'
import Member from './src/screens/Member'
import BlockUser from './src/screens/BlockUser'
import GroupChannel from './src/screens/GroupChannel'
import GroupChannelInvite from './src/screens/GroupChannelInvite'
import appStateChangeHandler from './src/appStateChangeHandler'
import Start from './src/screens/Start';
import Login from './src/screens/Login';
import Menu from './src/screens/Menu';
import Profile from './src/screens/Profile';
import OpenChannel from './src/screens/OpenChannel';
import OpenChannelCreate from './src/screens/OpenChannelCreate';
import Chat from './src/screens/Chat';
import Member from './src/screens/Member';
import BlockUser from './src/screens/BlockUser';
import GroupChannel from './src/screens/GroupChannel';
import GroupChannelInvite from './src/screens/GroupChannelInvite';
import appStateChangeHandler from './src/appStateChangeHandler';

let AppNavigator
let AppContainer
let AppNavigator;
let AppContainer;

export default class App extends Component {
constructor (props) {
super(props)
this.appStateHandler = appStateChangeHandler.getInstance()
AppNavigator = createStackNavigator({
constructor(props) {
super(props);
this.appStateHandler = appStateChangeHandler.getInstance();
AppNavigator = createStackNavigator(
{
Start: { screen: Start },
Login: { screen: Login },
Menu: { screen: Menu },
Expand All @@ -49,52 +46,51 @@ export default class App extends Component {
navigationOptions: ({ navigation }) => ({
headerTitleStyle: { fontWeight: '500' }
})
})
AppContainer = createAppContainer(AppNavigator)
}
);
AppContainer = createAppContainer(AppNavigator);
}

componentDidMount () {
componentDidMount() {
const channel = new firebase.notifications.Android.Channel(
'com.reactnativewithsendbird.default_channel_id',
'React Native Redux sample',
firebase.notifications.Android.Importance.Max
)
.setDescription('React Native Redux sample notification channel')
firebase.notifications().android.createChannel(channel)
).setDescription('React Native Redux sample notification channel');
firebase.notifications().android.createChannel(channel);

console.disableYellowBox = true
console.log('app is launched')
AppState.addEventListener('change', this._handleAppStateChange)
console.disableYellowBox = true;
console.log('app is launched');
AppState.addEventListener('change', this._handleAppStateChange);
}

componentWillUnmount () {
console.log('app is killed')
AppState.removeEventListener('change', this._handleAppStateChange)
componentWillUnmount() {
console.log('app is killed');
AppState.removeEventListener('change', this._handleAppStateChange);
}

render () {
render() {
return (
<Provider
store = {store}>
<AppContainer/>
<Provider store={store}>
<AppContainer />
</Provider>
)
);
}

_handleAppStateChange = (nextAppState) => {
const sb = SendBird.getInstance()
_handleAppStateChange = nextAppState => {
const sb = SendBird.getInstance();
if (sb) {
if (nextAppState === 'active') {
if (Platform.OS === 'ios') {
PushNotificationIOS.setApplicationIconBadgeNumber(0)
PushNotificationIOS.setApplicationIconBadgeNumber(0);
}
console.log('app is into foreground')
sb.setForegroundState()
this.appStateHandler.notify()
console.log('app is into foreground');
sb.setForegroundState();
this.appStateHandler.notify();
} else if (nextAppState === 'background') {
console.log('app is into background')
sb.setBackgroundState()
console.log('app is into background');
sb.setBackgroundState();
}
}
}
}
};
}
@@ -0,0 +1,3 @@
jest.mock('react-native-cached-image', () => ({
CachedImage: 'CachedImage'
}));
@@ -0,0 +1,18 @@
/* eslint-disable no-undef */
jest.mock('react-native-firebase', () => ({
messaging: jest.fn(() => ({
hasPermission: jest.fn(() => Promise.resolve(true)),
subscribeToTopic: jest.fn(),
unsubscribeFromTopic: jest.fn(),
requestPermission: jest.fn(() => Promise.resolve(true)),
getToken: jest.fn(() => Promise.resolve('myMockToken')),
onTokenRefresh: jest.fn(),
onMessage: jest.fn()
})),
notifications: jest.fn(() => ({
onNotification: jest.fn(),
onNotificationDisplayed: jest.fn(),
onNotificationOpened: jest.fn(),
removeAllDeliveredNotifications: jest.fn()
}))
}));
@@ -0,0 +1,9 @@
/* eslint-disable no-undef */
jest.mock('react-navigation', () => ({
StackActions: {
reset: jest.fn()
},
NavigationActions: {
navigate: jest.fn()
}
}));
@@ -0,0 +1,29 @@
/* eslint-disable no-undef */
const user = {
userId: '123',
nickname: 'test_nickname',
profileUrl: 'test_profileUrl'
};

const methods = {
getInstance: jest.fn(() => ({
createApplicationUserListQuery: jest.fn(() => ({
hasNext: false
})),
createBlockedUserListQuery: jest.fn(() => ({
hasNext: false
})),
updateCurrentUserInfo: jest.fn((nickname, profileUrl, cb) => cb(user, null)),
removeAllChannelHandlers: jest.fn(),
currentUser: user
})),
connect: jest.fn((userId, cb) => cb(true, null))
};

jest.mock('sendbird', () => {
const mock = jest.fn().mockImplementation(() => {
return methods;
});
mock.getInstance = methods.getInstance;
return mock;
});
@@ -0,0 +1,3 @@
jest.mock('react-native-video', () => {
return 'Video';
});
12 changes: 0 additions & 12 deletions react-native-redux-sample/ReactNativeWithSendBird/__tests__/App.js

This file was deleted.

@@ -0,0 +1,14 @@
import 'react-native';
import React from 'react';
import { AdminMessage } from '../../src/components';
import renderer from 'react-test-renderer';

describe('component/AdminMessage', () => {
it('renders correctly', () => {
let props = {
message: 'test_message'
};
const tree = renderer.create(<AdminMessage {...props} />).toJSON();
expect(tree).toMatchSnapshot();
});
});
@@ -0,0 +1,33 @@
import 'react-native';
import React from 'react';
import { FileItem } from '../../src/components';
import renderer from 'react-test-renderer';

describe('component/FileItem', () => {
it('renders correctly with user present, message length is small', () => {
const props = {
isUser: true,
message: 'test_message' // .length === 12
};
const tree = renderer.create(<FileItem {...props} />).toJSON();
expect(tree).toMatchSnapshot();
});

it('renders correctly with user present, message length is large', () => {
const props = {
isUser: true,
message: 'test_message123' // .length === 15
};
const tree = renderer.create(<FileItem {...props} />).toJSON();
expect(tree).toMatchSnapshot();
});

it('renders correctly with no user present', () => {
const props = {
isUser: false,
message: 'test_message123' // .length === 15
};
const tree = renderer.create(<FileItem {...props} />).toJSON();
expect(tree).toMatchSnapshot();
});
});
@@ -0,0 +1,11 @@
import 'react-native';
import React from 'react';
import { HR } from '../../src/components';
import renderer from 'react-test-renderer';

describe('component/Hr', () => {
it('renders correctly', () => {
const tree = renderer.create(<HR />).toJSON();
expect(tree).toMatchSnapshot();
});
});
@@ -0,0 +1,14 @@
import 'react-native';
import React from 'react';
import { ImageItem } from '../../src/components';
import renderer from 'react-test-renderer';

describe('component/ImageItem', () => {
it('renders correctly', () => {
let props = {
message: 'test_message_uri'
};
const tree = renderer.create(<ImageItem {...props} />).toJSON();
expect(tree).toMatchSnapshot();
});
});
@@ -0,0 +1,17 @@
import 'react-native';
import React from 'react';
import { Input } from '../../src/components';
import renderer from 'react-test-renderer';

describe('component/Input', () => {
it('renders correctly', () => {
const props = {
label: 'test_label',
value: 'test_value',
maxLength: 123,
onChangeText: () => {}
};
const tree = renderer.create(<Input {...props} />).toJSON();
expect(tree).toMatchSnapshot();
});
});
@@ -0,0 +1,27 @@
import 'react-native';
import React from 'react';
import { Message } from '../../src/components';
import renderer from 'react-test-renderer';

describe('component/Message', () => {
const textMessage = {
message: 'test_message',
isUserMessage: () => true,
isFileMessage: () => false,
type: ''
};
it('renders correctly with user present', () => {
let props = {
message: textMessage,
nickname: 'test_nickname',
time: 'test_time',
isUser: true,
isShow: true,
readCount: 1,
profileUrl: 'test_profile_url',
onPress: () => {}
};
const tree = renderer.create(<Message {...props} />).toJSON();
expect(tree).toMatchSnapshot();
});
});
@@ -0,0 +1,16 @@
import 'react-native';
import React from 'react';
import { MessageAvatar } from '../../src/components';
import renderer from 'react-test-renderer';

describe('component/MessageAvatar', () => {
it('renders correctly with user present', () => {
let props = {
uri: 'test_uri',
isShow: false,
onPress: () => {}
};
const tree = renderer.create(<MessageAvatar {...props} />).toJSON();
expect(tree).toMatchSnapshot();
});
});

0 comments on commit fc3f084

Please sign in to comment.