Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add React Native with RTK Query example #65

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules
*.DS_Store
__*
!/examples/ReactNativeWithRTKQ/__*
*-error.log
*-debug.log
msw-v*
Expand Down
6 changes: 6 additions & 0 deletions examples/ReactNativeWithRTKQ/.buckconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

[android]
target = Google Inc.:Google APIs:23

[maven_repositories]
central = https://repo1.maven.org/maven2
2 changes: 2 additions & 0 deletions examples/ReactNativeWithRTKQ/.bundle/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
BUNDLE_PATH: "vendor/bundle"
BUNDLE_FORCE_RUBY_PLATFORM: 1
14 changes: 14 additions & 0 deletions examples/ReactNativeWithRTKQ/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
root: true,
extends: ['@react-native-community', 'plugin:jest/recommended'],
plugins: ['jest'],
overrides: [
{
files: ['jestSetup.js'],
rules: {
'import/no-extraneous-dependencies': 'off',
'import/no-default-export': 'off',
},
},
],
};
3 changes: 3 additions & 0 deletions examples/ReactNativeWithRTKQ/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Windows files should use crlf line endings
# https://help.github.com/articles/dealing-with-line-endings/
*.bat text eol=crlf
63 changes: 63 additions & 0 deletions examples/ReactNativeWithRTKQ/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# OSX
#
.DS_Store

# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate

# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
*.hprof

# node.js
#
node_modules/
npm-debug.log
yarn-error.log

# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore

# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/

*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots

# Bundle artifact
*.jsbundle

# CocoaPods
/ios/Pods/

# Env
*.env
7 changes: 7 additions & 0 deletions examples/ReactNativeWithRTKQ/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
bracketSpacing: false,
jsxBracketSameLine: true,
singleQuote: true,
trailingComma: 'all',
arrowParens: 'avoid',
};
1 change: 1 addition & 0 deletions examples/ReactNativeWithRTKQ/.ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.7.4
1 change: 1 addition & 0 deletions examples/ReactNativeWithRTKQ/.watchmanconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
4 changes: 4 additions & 0 deletions examples/ReactNativeWithRTKQ/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source 'https://rubygems.org'
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
ruby '2.7.4'
gem 'cocoapods', '~> 1.11', '>= 1.11.2'
96 changes: 96 additions & 0 deletions examples/ReactNativeWithRTKQ/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.5)
rexml
activesupport (6.1.4.6)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
atomos (0.1.3)
claide (1.1.0)
cocoapods (1.11.2)
addressable (~> 2.8)
claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.11.2)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.4.0, < 2.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-trunk (>= 1.4.0, < 2.0)
cocoapods-try (>= 1.1.0, < 2.0)
colored2 (~> 3.1)
escape (~> 0.0.4)
fourflusher (>= 2.3.0, < 3.0)
gh_inspector (~> 1.0)
molinillo (~> 0.8.0)
nap (~> 1.0)
ruby-macho (>= 1.0, < 3.0)
xcodeproj (>= 1.21.0, < 2.0)
cocoapods-core (1.11.2)
activesupport (>= 5.0, < 7)
addressable (~> 2.8)
algoliasearch (~> 1.0)
concurrent-ruby (~> 1.1)
fuzzy_match (~> 2.0.4)
nap (~> 1.0)
netrc (~> 0.11)
public_suffix (~> 4.0)
typhoeus (~> 1.0)
cocoapods-deintegrate (1.0.5)
cocoapods-downloader (1.5.1)
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.1)
cocoapods-trunk (1.6.0)
nap (>= 0.8, < 2.0)
netrc (~> 0.11)
cocoapods-try (1.2.0)
colored2 (3.1.2)
concurrent-ruby (1.1.9)
escape (0.0.4)
ethon (0.15.0)
ffi (>= 1.15.0)
ffi (1.15.5)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
httpclient (2.8.3)
i18n (1.10.0)
concurrent-ruby (~> 1.0)
json (2.6.1)
minitest (5.15.0)
molinillo (0.8.0)
nanaimo (0.3.0)
nap (1.1.0)
netrc (0.11.0)
public_suffix (4.0.6)
rexml (3.2.5)
ruby-macho (2.5.1)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
xcodeproj (1.21.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
rexml (~> 3.2.4)
zeitwerk (2.5.4)
PLATFORMS
ruby
DEPENDENCIES
cocoapods (~> 1.11, >= 1.11.2)
RUBY VERSION
ruby 2.7.4p191
BUNDLED WITH
2.2.27
64 changes: 64 additions & 0 deletions examples/ReactNativeWithRTKQ/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# ReactNativeWithRTKQ
This repository illustrates how to use [Mock Service Worker](https://mswjs.io/) to mock a REST API handled with [RTK Query](https://redux-toolkit.js.org/rtk-query/overview) in [React Native](https://reactnative.dev/) project for unit and integration tests that run in Node.

Note that since React Native does not execute in a browser environment, you cannot run a Service Worker alongside your application. You can use msw with React Native only for NodeJS integration.

## Technologies
- [**React Native CLI**](https://reactnative.dev/docs/environment-setup) environment
- [Jest](https://jestjs.io) for running unit tests
- [React Native Testing Library](https://callstack.github.io/react-native-testing-library/) for unit test assertions
- [yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/)
- [node.js](https://nodejs.org/)

## Getting started

These instructions will get you a copy of the project up and running on your local machine.

### Clone project repository
1. Clone examples repo into your local machine:
- with https
`git clone https://github.com/mswjs/examples.git`
- with ssh
`git clone [email protected]:mswjs/examples.git`
- or with GitHub CLI
`gh repo clone mswjs/examples`

2. Copy `examples/ReactNativeWithRTKQ` under your git directory

### Prepare repository
1. Install dependencies for `ReactNativeWithRTKQ`:
- with npm
`npm install`
- or with yarn
`yarn install`
2. Create `.env` file under the root directory of the project ([see example](#env-file-example))

## Running locally
1. Start your virtual or plug or physical device
2. Start React Native
`yarn start`
3. Start app
`yarn android`

## Tests
### Unit tests
1. Run tests in the interactive watch mode
- with npm
`npm test`
- or with yarn
`yarn test`

## Key points
- [`src/store.ts`](src/store.ts) redux store
- [`src/services/api.ts`](src/services/api.ts) RTK Query API
- [`.env`](.env) environment variables (this project utilizes [`react-native-config`](https://github.com/luggit/react-native-config) module)
- [`__mocks__/react-native-config.js`](__mocks__/react-native-config.js) mocked environment variables
- [`jestSetup.js`](jestSetup.js) jest setup file
- [`src/mocks/handlers.ts`](src/mocks/handlers.ts) MSW request handlers
- [`src/mocks/server.ts`](src/mocks/server.ts) MSW server

## .env file example:

```
API_BASE_URL=https://random-data-api.com/api
```
3 changes: 3 additions & 0 deletions examples/ReactNativeWithRTKQ/__mocks__/react-native-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
API_BASE_URL: 'https://random-data-api.com/api',
};
49 changes: 49 additions & 0 deletions examples/ReactNativeWithRTKQ/__tests__/App-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @format
*/

import 'react-native';
import React from 'react';
import App from '../src/App';
import {renderWithProviders} from '../src/utils/testUtils';
import {mockedResponse} from '../src/mocks/mockedResponse';
import Config from 'react-native-config';
import {server} from '../src/mocks/server';
import {rest} from 'msw';

const {API_BASE_URL} = Config;
const mockedName = mockedResponse[0].first_name;

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

afterEach(() => {
jest.useRealTimers();
});

test("App component should render 'Loading...' text while waiting for api response", () => {
const {getByText} = renderWithProviders(<App />);
const loadingText = getByText('Loading...');
expect(loadingText).toBeDefined();
});

test('App component should render name received from api', async () => {
const {findByText} = renderWithProviders(<App />);
const name = await findByText(mockedName);
expect(name).toBeDefined();
});

// server.use overrides the initial request handler with runtime request handler.
// afterEach(() => server.resetHandlers()) defined in jestSetup.js resets handlers
// back to the initial list given to the setupServer call.
test("App component should render 'Error' text when api fails", async () => {
server.use(
rest.get(`${API_BASE_URL}/name/random_name`, (req, res, ctx) => {
return res(ctx.status(500), ctx.json({message: 'Internal Server Error'}));
}),
);
const {findByText} = renderWithProviders(<App />);
const errorText = await findByText('Error');
expect(errorText).toBeDefined();
});
55 changes: 55 additions & 0 deletions examples/ReactNativeWithRTKQ/android/app/_BUCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#

load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")

lib_deps = []

create_aar_targets(glob(["libs/*.aar"]))

create_jar_targets(glob(["libs/*.jar"]))

android_library(
name = "all-libs",
exported_deps = lib_deps,
)

android_library(
name = "app-code",
srcs = glob([
"src/main/java/**/*.java",
]),
deps = [
":all-libs",
":build_config",
":res",
],
)

android_build_config(
name = "build_config",
package = "com.reactnativewithrtkq",
)

android_resource(
name = "res",
package = "com.reactnativewithrtkq",
res = "src/main/res",
)

android_binary(
name = "app",
keystore = "//android/keystores:debug",
manifest = "src/main/AndroidManifest.xml",
package_type = "debug",
deps = [
":app-code",
],
)
Loading