diff --git a/examples/redux/App.js b/examples/redux/App.js
new file mode 100644
index 000000000..9712cdf2d
--- /dev/null
+++ b/examples/redux/App.js
@@ -0,0 +1,27 @@
+import React from 'react';
+import { StyleSheet, View, StatusBar } from 'react-native';
+import { Provider } from 'react-redux';
+import configureStore from './store';
+import AddTodo from './components/AddTodo';
+import TodoList from './components/TodoList';
+
+const store = configureStore();
+
+export default function App() {
+ return (
+
+
+
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ paddingTop: 32,
+ },
+});
diff --git a/examples/redux/actions/todoActions.js b/examples/redux/actions/todoActions.js
new file mode 100644
index 000000000..b83a37153
--- /dev/null
+++ b/examples/redux/actions/todoActions.js
@@ -0,0 +1,25 @@
+export const actions = {
+ ADD: '@ADD_TODO',
+ REMOVE: '@REMOVE_TODO',
+ MODIFY: '@MODIFY_TODO',
+ CLEAR: '@CLEAR_TODO',
+};
+
+export const addTodo = (todo) => ({
+ type: actions.ADD,
+ payload: todo,
+});
+
+export const removeTodo = (id) => ({
+ type: actions.REMOVE,
+ payload: { id },
+});
+
+export const modifyTodo = (todo) => ({
+ type: actions.MODIFY,
+ payload: todo,
+});
+
+export const clearTodos = () => ({
+ type: actions.CLEAR,
+});
diff --git a/examples/redux/babel.config.js b/examples/redux/babel.config.js
new file mode 100644
index 000000000..4d710acf8
--- /dev/null
+++ b/examples/redux/babel.config.js
@@ -0,0 +1,6 @@
+module.exports = function (api) {
+ api.cache(true);
+ return {
+ presets: ['module:metro-react-native-babel-preset'],
+ };
+};
diff --git a/examples/redux/components/AddTodo.js b/examples/redux/components/AddTodo.js
new file mode 100644
index 000000000..7ab31fc89
--- /dev/null
+++ b/examples/redux/components/AddTodo.js
@@ -0,0 +1,73 @@
+import React from 'react';
+import { Button, StyleSheet, Text, View, TextInput } from 'react-native';
+import { bindActionCreators } from 'redux';
+import { connect } from 'react-redux';
+import { addTodo } from '../actions/todoActions';
+
+export function AddTodo(props) {
+ const [text, setText] = React.useState('');
+
+ const submitForm = () => {
+ const todo = {
+ id: props.todoLength + 1,
+ text,
+ date: new Date(),
+ };
+
+ props.addTodo(todo);
+ setText('');
+ };
+
+ return (
+
+ Enter a text below to add a new todo
+ setText(t)}
+ placeholder="Enter the name of the repository here"
+ />
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ minHeight: 156,
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ justifyContent: 'center',
+ borderBottomColor: '#EEEEEE',
+ borderBottomWidth: 2,
+ marginBottom: 16,
+ padding: 16,
+ },
+ header: {
+ fontSize: 20,
+ fontWeight: 'bold',
+ marginBottom: 8,
+ },
+ input: {
+ borderColor: '#DDDDDD',
+ borderWidth: 1,
+ paddingVertical: 8,
+ width: '100%',
+ textAlign: 'center',
+ borderRadius: 4,
+ },
+});
+
+const mapStateToProps = ({ todos }) => ({
+ todoLength: todos.length,
+});
+
+const mapDispatchToProps = (dispatch) =>
+ bindActionCreators({ addTodo }, dispatch);
+
+export default connect(mapStateToProps, mapDispatchToProps)(AddTodo);
diff --git a/examples/redux/components/AddTodo.test.js b/examples/redux/components/AddTodo.test.js
new file mode 100644
index 000000000..c90344cf2
--- /dev/null
+++ b/examples/redux/components/AddTodo.test.js
@@ -0,0 +1,42 @@
+import React from 'react';
+import { Provider } from 'react-redux';
+import { cleanup, fireEvent, render } from 'react-native-testing-library';
+import configureStore from '../store';
+import AddTodo from './AddTodo';
+
+describe('Application test', () => {
+ afterEach(cleanup);
+
+ test('adds a new test when entry has been included', () => {
+ const store = configureStore();
+
+ const component = (
+
+
+
+ );
+
+ const { getByPlaceholder, getByText } = render(component);
+
+ const input = getByPlaceholder(/repository/i);
+ expect(input).toBeTruthy();
+
+ const textToEnter = 'This is a random element';
+ fireEvent.changeText(input, textToEnter);
+ fireEvent.press(getByText('Submit form'));
+
+ const todosState = store.getState().todos;
+
+ expect(todosState.length).toEqual(1);
+
+ expect(todosState).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ id: 1,
+ text: textToEnter,
+ date: expect.any(Date),
+ }),
+ ])
+ );
+ });
+});
diff --git a/examples/redux/components/TodoElem.js b/examples/redux/components/TodoElem.js
new file mode 100644
index 000000000..8932c0471
--- /dev/null
+++ b/examples/redux/components/TodoElem.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import { StyleSheet, Button, Text, View } from 'react-native';
+
+export default function TodoElem({ todo, onDelete }) {
+ return (
+
+
+ {todo.text}
+ {new Date(todo.date).toDateString()}
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+});
diff --git a/examples/redux/components/TodoList.js b/examples/redux/components/TodoList.js
new file mode 100644
index 000000000..3c66f73e3
--- /dev/null
+++ b/examples/redux/components/TodoList.js
@@ -0,0 +1,29 @@
+import React from 'react';
+import { FlatList, Text } from 'react-native';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import { removeTodo } from '../actions/todoActions';
+import TodoElem from './TodoElem';
+
+export function TodoList(props) {
+ const onDeleteTodo = (id) => props.removeTodo(id);
+
+ return (
+ todo.id.toString()}
+ renderItem={({ item }) => (
+
+ )}
+ />
+ );
+}
+
+const mapStateToProps = (state) => ({
+ todos: state.todos,
+});
+
+const mapDispatchToProps = (dispatch) =>
+ bindActionCreators({ removeTodo }, dispatch);
+
+export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
diff --git a/examples/redux/components/TodoList.test.js b/examples/redux/components/TodoList.test.js
new file mode 100644
index 000000000..80b27f05f
--- /dev/null
+++ b/examples/redux/components/TodoList.test.js
@@ -0,0 +1,59 @@
+import React from 'react';
+import { Provider } from 'react-redux';
+import { cleanup, fireEvent, render } from 'react-native-testing-library';
+import configureStore from '../store';
+import TodoList from './TodoList';
+
+describe('Application test', () => {
+ afterEach(cleanup);
+
+ test('it should execute with a store with 4 elements', () => {
+ const initialState = {
+ todos: [
+ { id: 1, text: 'Sing something', date: new Date() },
+ { id: 2, text: 'Dance something', date: new Date() },
+ { id: 3, text: 'Sleep something', date: new Date() },
+ { id: 4, text: 'Sleep something', date: new Date() },
+ ],
+ };
+ const store = configureStore(initialState);
+
+ const component = (
+
+
+
+ );
+
+ const { getAllByText } = render(component);
+ const todoElems = getAllByText(/something/i);
+
+ expect(todoElems.length).toEqual(4);
+ });
+
+ test('should execute with 2 elements and end up with 1 after delete', () => {
+ const initialState = {
+ todos: [
+ { id: 1, text: 'Sing something', date: new Date() },
+ { id: 2, text: 'Dance something', date: new Date() },
+ ],
+ };
+ const store = configureStore(initialState);
+
+ const component = (
+
+
+
+ );
+
+ const { getAllByText } = render(component);
+ const todoElems = getAllByText(/something/i);
+
+ expect(todoElems.length).toBe(2);
+
+ const buttons = getAllByText('Delete');
+ expect(buttons.length).toBe(2);
+
+ fireEvent.press(buttons[0]);
+ expect(getAllByText('Delete').length).toBe(1);
+ });
+});
diff --git a/examples/redux/index.js b/examples/redux/index.js
new file mode 100644
index 000000000..9d5d25a62
--- /dev/null
+++ b/examples/redux/index.js
@@ -0,0 +1,8 @@
+import { registerRootComponent } from 'expo';
+
+import App from './App';
+
+// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
+// It also ensures that whether you load the app in the Expo client or in a native build,
+// the environment is set up appropriately
+registerRootComponent(App);
diff --git a/examples/redux/package.json b/examples/redux/package.json
new file mode 100644
index 000000000..95b4ea122
--- /dev/null
+++ b/examples/redux/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "redux-example",
+ "description": "Testing Redux interactions with RNTL",
+ "version": "0.0.1",
+ "scripts": {
+ "test": "jest"
+ },
+ "dependencies": {
+ "react": "~16.9.0",
+ "react-native": "~0.61.5",
+ "react-redux": "^7.2.0",
+ "redux": "^4.0.5"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.8.6",
+ "babel-jest": "~25.2.6",
+ "jest": "~25.2.6",
+ "metro-react-native-babel-preset": "^0.59.0",
+ "react-native-testing-library": "^1.13.2",
+ "react-test-renderer": "~16.9.0"
+ },
+ "private": true,
+ "jest": {
+ "preset": "react-native"
+ }
+}
diff --git a/examples/redux/reducers/index.js b/examples/redux/reducers/index.js
new file mode 100644
index 000000000..1f340fbb9
--- /dev/null
+++ b/examples/redux/reducers/index.js
@@ -0,0 +1,6 @@
+import { combineReducers } from 'redux';
+import todos from './todoReducer';
+
+export default combineReducers({
+ todos,
+});
diff --git a/examples/redux/reducers/todoReducer.js b/examples/redux/reducers/todoReducer.js
new file mode 100644
index 000000000..f55d4c3e6
--- /dev/null
+++ b/examples/redux/reducers/todoReducer.js
@@ -0,0 +1,28 @@
+import { actions } from '../actions/todoActions.js';
+
+export default function todoReducer(state = [], action) {
+ switch (action.type) {
+ case actions.ADD:
+ return state.concat(action.payload);
+
+ case actions.REMOVE:
+ console.log(action);
+ return state.filter((todo) => todo.id !== action.payload.id);
+
+ case actions.MODIFY:
+ return state.map((todo) => {
+ if (todo.id === action.payload.id) {
+ return {
+ ...todo,
+ ...action.payload,
+ };
+ }
+ });
+
+ case actions.CLEAR:
+ return [];
+
+ default:
+ return state;
+ }
+}
diff --git a/examples/redux/store.js b/examples/redux/store.js
new file mode 100644
index 000000000..f3a29b883
--- /dev/null
+++ b/examples/redux/store.js
@@ -0,0 +1,10 @@
+import { createStore } from 'redux';
+import reducers from './reducers';
+
+const initialStore = {
+ todos: [],
+};
+
+export default function configureStore(initialState = initialStore) {
+ return createStore(reducers, initialState);
+}