diff --git a/.eslintrc.js b/.eslintrc.js
index 9126da4..a33cc3b 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,5 +1,5 @@
module.exports = {
root: true,
extends: '@react-native',
- ignorePatterns: ['e2e/'],
+ ignorePatterns: ['e2e/', 'coverage'],
};
diff --git a/.github/actions/bootstrap/action.yml b/.github/actions/bootstrap/action.yml
new file mode 100644
index 0000000..220164d
--- /dev/null
+++ b/.github/actions/bootstrap/action.yml
@@ -0,0 +1,89 @@
+name: 'Bootstrap'
+description: 'Bootstrap Dependencies'
+runs:
+ using: 'composite'
+ steps:
+ - run: echo "IMAGE=${ImageOS}-${ImageVersion}" >> $GITHUB_ENV
+ shell: bash
+
+ - uses: actions/setup-node@v3
+ if: ${{ env.INSTALL_NODE == 'true' }}
+ with:
+ node-version: 18.x
+ cache: 'yarn'
+
+ - name: Install Yarn Dependencies
+ if: ${{ env.INSTALL_NODE == 'true' }}
+ run: yarn install --immutable
+ shell: bash
+
+ - name: Cache pods
+ uses: actions/cache@v3
+ if: ${{ env.INSTALL_PODS == 'true' }}
+ with:
+ path: ios/Pods
+ key: ${{ env.IMAGE }}-pods-${{ hashFiles('ios/Podfile.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-pods-
+
+ - uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: 3.1
+ bundler-cache: true
+
+ - name: Cache Gradle
+ if: ${{ env.INSTALL_JAVA == 'true' }}
+ uses: actions/cache@v3
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ env.IMAGE }}-gradle-${{ hashFiles('*.gradle*', 'gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+
+ - uses: actions/setup-java@v3
+ if: ${{ env.INSTALL_JAVA == 'true' }}
+ with:
+ distribution: 'zulu'
+ java-version: '11'
+ check-latest: true
+
+ - name: Install pods
+ if: ${{ env.INSTALL_PODS == 'true' }}
+ run: bundle exec fastlane pod_install
+ shell: bash
+
+ # Retrieve the cached emulator snapshot
+ - uses: actions/cache@v3
+ if: ${{ env.INSTALL_ANDROID_EMULATOR == 'true' }}
+ id: avd-cache
+ with:
+ path: |
+ ~/.android/avd/*
+ ~/.android/adb*
+ key: ${{ env.IMAGE }}-android-emulator
+
+ # Required for Maestro on iOS
+ - uses: actions/setup-python@v4.3.0
+ if: ${{ env.INSTALL_PYTHON == 'true' }}
+ with:
+ python-version: 3.8
+ cache: 'pip'
+
+ # Required to run E2E testing
+ - name: Install Maestro
+ if: ${{ env.INSTALL_MAESTRO == 'true' }}
+ shell: bash
+ run: |
+ if [ "${{ env.INSTALL_PYTHON }}" = "true" ]; then
+ brew install facebook/fb/idb-companion
+ pip install fb-idb
+ fi
+ env MAESTRO_VERSION="1.29.0" curl -Ls 'https://get.maestro.mobile.dev' | bash
+ echo "$HOME/.maestro/bin" >> $GITHUB_PATH
+
+ # Required to capture Android video during E2E testing
+ - name: Install FFmpeg
+ if: ${{ env.INSTALL_FFMPEG == 'true' }}
+ uses: FedericoCarboni/setup-ffmpeg@v2
diff --git a/.github/workflows/e2e-testing.yml b/.github/workflows/e2e-testing.yml
new file mode 100644
index 0000000..0b61c42
--- /dev/null
+++ b/.github/workflows/e2e-testing.yml
@@ -0,0 +1,91 @@
+name: E2E Testing
+env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+on:
+ pull_request:
+ types: [opened, synchronize, reopened]
+concurrency:
+ group: react-native-workflow-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ build_android:
+ name: Build Android
+ timeout-minutes: 60
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: ./.github/actions/bootstrap
+ timeout-minutes: 15
+ env:
+ INSTALL_NODE: true
+ INSTALL_JAVA: true
+
+ - name: Build
+ run: bundle exec fastlane build_android
+
+ - name: Upload .apk
+ uses: actions/upload-artifact@v3
+ with:
+ name: apk
+ path: '**/dist/*.apk'
+
+ test_android:
+ name: Test Android
+ needs: build_android
+ timeout-minutes: 100
+ runs-on: macos-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: ./.github/actions/bootstrap
+ timeout-minutes: 15
+ env:
+ INSTALL_NODE: true
+ INSTALL_FFMPEG: true
+ INSTALL_MAESTRO: true
+ INSTALL_ANDROID_EMULATOR: true
+
+ - name: Download .apk
+ uses: actions/download-artifact@v3
+ with:
+ name: apk
+
+ - name: Create AVD Snapshot
+ if: steps.avd-cache.outputs.cache-hit != 'true'
+ uses: reactivecircus/android-emulator-runner@v2
+ with:
+ api-level: 30
+ arch: x86_64
+ target: google_apis
+ profile: pixel_5
+ force-avd-creation: false
+ avd-name: test
+ ram-size: 8192M
+ disk-size: 2048M
+ emulator-boot-timeout: 1000
+ emulator-options: -no-window -no-boot-anim -no-audio -no-snapshot-load -gpu swiftshader_indirect
+ script: echo 'AVD snapshot is generated and will be cached for the future runs.'
+
+ - name: Test
+ uses: reactivecircus/android-emulator-runner@v2
+ with:
+ api-level: 30
+ arch: x86_64
+ target: google_apis
+ profile: pixel_5
+ force-avd-creation: false
+ avd-name: test
+ ram-size: 8192M
+ disk-size: 2048M
+ emulator-boot-timeout: 1000
+ emulator-options: -no-window -no-boot-anim -no-audio -no-snapshot-load -gpu swiftshader_indirect
+ script: bundle exec fastlane test_android
+
+ - uses: actions/upload-artifact@v3
+ if: failure()
+ with:
+ name: Android Test Data
+ path: |
+ **/fastlane/recordings
+ ~/.maestro/tests
+
diff --git a/Gemfile b/Gemfile
index 1fa2c2e..5aa90d3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -3,4 +3,8 @@ source 'https://rubygems.org'
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
ruby ">= 2.6.10"
-gem 'cocoapods', '~> 1.12'
+gem 'cocoapods', '~> 1.12', '>= 1.12.1'
+gem 'fastlane'
+
+plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
+eval_gemfile(plugins_path) if File.exist?(plugins_path)
diff --git a/Gemfile.lock b/Gemfile.lock
index beb926c..4620532 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -13,7 +13,25 @@ GEM
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
+ artifactory (3.0.15)
atomos (0.1.3)
+ aws-eventstream (1.2.0)
+ aws-partitions (1.822.0)
+ aws-sdk-core (3.181.0)
+ aws-eventstream (~> 1, >= 1.0.2)
+ aws-partitions (~> 1, >= 1.651.0)
+ aws-sigv4 (~> 1.5)
+ jmespath (~> 1, >= 1.6.1)
+ aws-sdk-kms (1.71.0)
+ aws-sdk-core (~> 3, >= 3.177.0)
+ aws-sigv4 (~> 1.1)
+ aws-sdk-s3 (1.134.0)
+ aws-sdk-core (~> 3, >= 3.181.0)
+ aws-sdk-kms (~> 1)
+ aws-sigv4 (~> 1.6)
+ aws-sigv4 (1.6.0)
+ aws-eventstream (~> 1, >= 1.0.2)
+ babosa (1.0.4)
claide (1.1.0)
cocoapods (1.12.1)
addressable (~> 2.8)
@@ -52,31 +70,195 @@ GEM
nap (>= 0.8, < 2.0)
netrc (~> 0.11)
cocoapods-try (1.2.0)
+ colored (1.2)
colored2 (3.1.2)
+ commander (4.6.0)
+ highline (~> 2.0.0)
concurrent-ruby (1.2.2)
+ declarative (0.0.20)
+ digest-crc (0.6.5)
+ rake (>= 12.0.0, < 14.0.0)
+ domain_name (0.5.20190701)
+ unf (>= 0.0.5, < 1.0.0)
+ dotenv (2.8.1)
+ emoji_regex (3.2.3)
escape (0.0.4)
ethon (0.16.0)
ffi (>= 1.15.0)
+ excon (0.103.0)
+ faraday (1.10.3)
+ faraday-em_http (~> 1.0)
+ faraday-em_synchrony (~> 1.0)
+ faraday-excon (~> 1.1)
+ faraday-httpclient (~> 1.0)
+ faraday-multipart (~> 1.0)
+ faraday-net_http (~> 1.0)
+ faraday-net_http_persistent (~> 1.0)
+ faraday-patron (~> 1.0)
+ faraday-rack (~> 1.0)
+ faraday-retry (~> 1.0)
+ ruby2_keywords (>= 0.0.4)
+ faraday-cookie_jar (0.0.7)
+ faraday (>= 0.8.0)
+ http-cookie (~> 1.0.0)
+ faraday-em_http (1.0.0)
+ faraday-em_synchrony (1.0.0)
+ faraday-excon (1.1.0)
+ faraday-httpclient (1.0.1)
+ faraday-multipart (1.0.4)
+ multipart-post (~> 2)
+ faraday-net_http (1.0.1)
+ faraday-net_http_persistent (1.2.0)
+ faraday-patron (1.0.0)
+ faraday-rack (1.0.0)
+ faraday-retry (1.0.3)
+ faraday_middleware (1.2.0)
+ faraday (~> 1.0)
+ fastimage (2.2.7)
+ fastlane (2.214.0)
+ CFPropertyList (>= 2.3, < 4.0.0)
+ addressable (>= 2.8, < 3.0.0)
+ artifactory (~> 3.0)
+ aws-sdk-s3 (~> 1.0)
+ babosa (>= 1.0.3, < 2.0.0)
+ bundler (>= 1.12.0, < 3.0.0)
+ colored
+ commander (~> 4.6)
+ dotenv (>= 2.1.1, < 3.0.0)
+ emoji_regex (>= 0.1, < 4.0)
+ excon (>= 0.71.0, < 1.0.0)
+ faraday (~> 1.0)
+ faraday-cookie_jar (~> 0.0.6)
+ faraday_middleware (~> 1.0)
+ fastimage (>= 2.1.0, < 3.0.0)
+ gh_inspector (>= 1.1.2, < 2.0.0)
+ google-apis-androidpublisher_v3 (~> 0.3)
+ google-apis-playcustomapp_v1 (~> 0.1)
+ google-cloud-storage (~> 1.31)
+ highline (~> 2.0)
+ json (< 3.0.0)
+ jwt (>= 2.1.0, < 3)
+ mini_magick (>= 4.9.4, < 5.0.0)
+ multipart-post (>= 2.0.0, < 3.0.0)
+ naturally (~> 2.2)
+ optparse (~> 0.1.1)
+ plist (>= 3.1.0, < 4.0.0)
+ rubyzip (>= 2.0.0, < 3.0.0)
+ security (= 0.1.3)
+ simctl (~> 1.6.3)
+ terminal-notifier (>= 2.0.0, < 3.0.0)
+ terminal-table (>= 1.4.5, < 2.0.0)
+ tty-screen (>= 0.6.3, < 1.0.0)
+ tty-spinner (>= 0.8.0, < 1.0.0)
+ word_wrap (~> 1.0.0)
+ xcodeproj (>= 1.13.0, < 2.0.0)
+ xcpretty (~> 0.3.0)
+ xcpretty-travis-formatter (>= 0.0.3)
+ fastlane-plugin-stream_actions (0.3.19)
+ xctest_list (= 1.2.1)
ffi (1.15.5)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
+ google-apis-androidpublisher_v3 (0.49.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-apis-core (0.11.1)
+ addressable (~> 2.5, >= 2.5.1)
+ googleauth (>= 0.16.2, < 2.a)
+ httpclient (>= 2.8.1, < 3.a)
+ mini_mime (~> 1.0)
+ representable (~> 3.0)
+ retriable (>= 2.0, < 4.a)
+ rexml
+ webrick
+ google-apis-iamcredentials_v1 (0.17.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-apis-playcustomapp_v1 (0.13.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-apis-storage_v1 (0.19.0)
+ google-apis-core (>= 0.9.0, < 2.a)
+ google-cloud-core (1.6.0)
+ google-cloud-env (~> 1.0)
+ google-cloud-errors (~> 1.0)
+ google-cloud-env (1.6.0)
+ faraday (>= 0.17.3, < 3.0)
+ google-cloud-errors (1.3.1)
+ google-cloud-storage (1.44.0)
+ addressable (~> 2.8)
+ digest-crc (~> 0.4)
+ google-apis-iamcredentials_v1 (~> 0.1)
+ google-apis-storage_v1 (~> 0.19.0)
+ google-cloud-core (~> 1.6)
+ googleauth (>= 0.16.2, < 2.a)
+ mini_mime (~> 1.0)
+ googleauth (1.8.0)
+ faraday (>= 0.17.3, < 3.a)
+ jwt (>= 1.4, < 3.0)
+ multi_json (~> 1.11)
+ os (>= 0.9, < 2.0)
+ signet (>= 0.16, < 2.a)
+ highline (2.0.3)
+ http-cookie (1.0.5)
+ domain_name (~> 0.5)
httpclient (2.8.3)
i18n (1.13.0)
concurrent-ruby (~> 1.0)
+ jmespath (1.6.2)
json (2.6.3)
+ jwt (2.7.1)
+ mini_magick (4.12.0)
+ mini_mime (1.1.5)
minitest (5.18.0)
molinillo (0.8.0)
+ multi_json (1.15.0)
+ multipart-post (2.3.0)
nanaimo (0.3.0)
nap (1.1.0)
+ naturally (2.2.1)
netrc (0.11.0)
+ optparse (0.1.1)
+ os (1.1.4)
+ plist (3.7.0)
public_suffix (4.0.7)
+ rake (13.0.6)
+ representable (3.2.0)
+ declarative (< 0.1.0)
+ trailblazer-option (>= 0.1.1, < 0.2.0)
+ uber (< 0.2.0)
+ retriable (3.1.2)
rexml (3.2.5)
+ rouge (2.0.7)
ruby-macho (2.5.1)
+ ruby2_keywords (0.0.5)
+ rubyzip (2.3.2)
+ security (0.1.3)
+ signet (0.18.0)
+ addressable (~> 2.8)
+ faraday (>= 0.17.5, < 3.a)
+ jwt (>= 1.5, < 3.0)
+ multi_json (~> 1.10)
+ simctl (1.6.10)
+ CFPropertyList
+ naturally
+ terminal-notifier (2.0.0)
+ terminal-table (1.8.0)
+ unicode-display_width (~> 1.1, >= 1.1.1)
+ trailblazer-option (0.1.2)
+ tty-cursor (0.7.1)
+ tty-screen (0.8.1)
+ tty-spinner (0.9.3)
+ tty-cursor (~> 0.7)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
+ uber (0.1.0)
+ unf (0.1.4)
+ unf_ext
+ unf_ext (0.0.8.2)
+ unicode-display_width (1.8.0)
+ webrick (1.8.1)
+ word_wrap (1.0.0)
xcodeproj (1.22.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
@@ -84,12 +266,19 @@ GEM
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
rexml (~> 3.2.4)
+ xcpretty (0.3.0)
+ rouge (~> 2.0.7)
+ xcpretty-travis-formatter (1.0.1)
+ xcpretty (~> 0.2, >= 0.0.7)
+ xctest_list (1.2.1)
PLATFORMS
ruby
DEPENDENCIES
- cocoapods (~> 1.12)
+ cocoapods (~> 1.12, >= 1.12.1)
+ fastlane
+ fastlane-plugin-stream_actions
RUBY VERSION
ruby 2.7.5p203
diff --git a/__tests__/FlatList.test.tsx b/__tests__/FlatList.test.tsx
index 1122b73..dc3bc77 100644
--- a/__tests__/FlatList.test.tsx
+++ b/__tests__/FlatList.test.tsx
@@ -26,14 +26,14 @@ const eventData = {
};
afterEach(cleanup);
-
+jest.useFakeTimers();
it('scrolls to bottom and loads more items', async () => {
// Render the SectionList component
render();
// First dish is visible
expect(screen.getByText(/pizza/i)).toBeOnTheScreen();
- // First dish from 2nd page is no visible yet
+ // First dish from 2nd page is not visible yet
expect(() => screen.getByText(/the impossible burger/i)).toThrow(
'Unable to find an element with text: /the impossible burger/i',
);
diff --git a/__tests__/LoginSubmission.test.tsx b/__tests__/LoginSubmission.test.tsx
index 4dd6b7d..36a3ac6 100644
--- a/__tests__/LoginSubmission.test.tsx
+++ b/__tests__/LoginSubmission.test.tsx
@@ -29,6 +29,8 @@ beforeEach(() => {
useNavigationMock.mockReset();
});
+jest.useFakeTimers();
+
it('verifies happy flow of login', async () => {
// Mock navigate function from useNavigation hook, in order to verify that
// it's called with the correct arguments and not to actually navigate
@@ -54,7 +56,7 @@ it('verifies happy flow of login', async () => {
fireEvent.press(screen.getByText(/submit/i));
// Verify that the loading indicator is shown
- expect(screen.getByText(/loading/i)).toBeVisible();
+ expect(screen.getByLabelText(/submission-in-process/i)).toBeVisible();
// Verify that the fetch function was called with the correct arguments
// Can be done in 2 ways:
// 1. Using toHaveBeenCalledWith
@@ -81,9 +83,12 @@ it('verifies happy flow of login', async () => {
],
]
`);
-
- // Verify that the navigate function was called with the correct arguments and only once
- await waitFor(() => expect(mockNavigate).toHaveBeenCalledTimes(1));
+ // Advance timers by 2.5 seconds to allow the simulated delay after fetch to complete
+ jest.advanceTimersByTime(2500);
+ // // Verify that the navigate function was called with the correct arguments and only once
+ await waitFor(() => expect(mockNavigate).toHaveBeenCalledTimes(1), {
+ timeout: 2500,
+ });
expect(mockNavigate).toHaveBeenCalledWith('Home');
// Verify that the token was saved to AsyncStorage
expect(AsyncStorage.setItem).toHaveBeenCalledWith('token', 'fake-token');
diff --git a/e2e/flow.yaml b/e2e/flow.yaml
index b460ef3..e993249 100644
--- a/e2e/flow.yaml
+++ b/e2e/flow.yaml
@@ -20,7 +20,7 @@ appId: com.reactnativetesting
- tapOn: ${output.screens.login.passwordPlaceholder}
- inputText: ${output.screens.login.password}
- tapOn: ${output.screens.login.submitButton}
-- assertVisible: ${output.screens.login.loadingIsVisible}
+- assertVisible: ${output.screens.login.submissionInProcessA11yId}
# after login, we should be redirected to home screen
# test EasyButton screen flow
- tapOn: ${output.screens.home.easyButtonButton}
@@ -57,11 +57,7 @@ appId: com.reactnativetesting
- tapOn: ${output.screens.home.listWithFetchButton}
- assertVisible: ${output.screens.listWitchFetch.firstItemId}
- scrollUntilVisible:
- element: ${output.screens.listWitchFetch.twentyNinthItemId}
+ element: ${output.screens.listWitchFetch.fifteenthItemId}
direction: "DOWN"
- # default scroll speed is 40, at that scroll speed finding the element will fail most
- # of the times, so we need to slow down the scroll speed to detect the element
- # 100% of the times
- speed: 25
- runFlow: goBackHome.yaml
- assertVisible: ${output.screens.home.title}
diff --git a/e2e/setup.js b/e2e/setup.js
index 4750d97..f323bf0 100644
--- a/e2e/setup.js
+++ b/e2e/setup.js
@@ -24,7 +24,7 @@ output.screens = {
username: 'admin',
password: 'admin',
submitButton: 'Submit',
- loadingIsVisible: 'loading...',
+ submissionInProcessA11yId: 'submission-in-process',
},
easyButton: {
button: 'Click me!',
@@ -49,6 +49,6 @@ output.screens = {
},
listWitchFetch: {
firstItemId: '1-user-container',
- twentyNinthItemId: '29-user-container',
+ fifteenthItemId: '15-user-container',
},
};
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
new file mode 100644
index 0000000..351c496
--- /dev/null
+++ b/fastlane/Fastfile
@@ -0,0 +1,70 @@
+skip_docs
+metro_port = 8081
+build_dir = 'dist'
+bundle_id = 'com.reactnativetesting'
+
+before_all do
+ if is_ci
+ setup_ci
+ ENV['FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT'] = '180'
+ end
+end
+
+desc 'Installs all Certs and Profiles necessary for appstore'
+lane :match_appstore do
+ match(
+ type: 'appstore',
+ app_identifier: [bundle_id],
+ readonly: is_ci
+ )
+end
+
+lane :stop_metro do
+ sh("lsof -t -i:#{metro_port} | xargs kill -s INT || true")
+end
+
+lane :load_package do
+ load_json(json_path: 'package.json')
+end
+
+lane :build_android do
+ gradle(project_dir: 'android', tasks: %w[clean assembleRelease])
+
+ Dir.chdir('..') do
+ sh("mkdir -p #{build_dir} && mv -f #{lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]} #{build_dir}/app.apk")
+ end
+end
+
+lane :test_android do |options|
+ build_android unless is_ci || options[:skip_install]
+ wait_android_emu_idle(load_threshold: 1, timeout: 2200)
+ emulator_status = -> { sh('adb devices').include?('emulator') }
+
+ Dir.chdir('..') do
+ unless options[:skip_install]
+ sh("adb uninstall #{bundle_id} >/dev/null || true")
+ sh("adb install #{build_dir}/app.apk")
+ end
+
+ sh('adb logcat -c || true') if emulator_status.call
+
+ # Record emulator screen using codec h264
+ # adb limits the recording to 3 minutes, so we bypass this by redirecting the stream to ffmpeg tool
+ video_group_pid = Process.spawn('adb shell "while true; do screenrecord --output-format=h264 -; done" | ' \
+ 'ffmpeg -y -i - fastlane/video.mp4 > fastlane/recording.log 2>&1 &', pgroup: true)
+ video_pid = `pgrep -g #{Process.getpgid(video_group_pid)}`.split.map(&:to_i).first
+
+ sh('yarn test:e2e')
+ ensure
+ sh("kill -s INT #{video_pid} || true")
+ sh('adb logcat -d > fastlane/device.log || true') if emulator_status.call
+ sh('maestro hierarchy > fastlane/hierarchy.json || true')
+ [
+ 'recording.log',
+ 'hierarchy.json',
+ 'device.log',
+ 'video.mp4'
+ ].each { |f| sh("mv -f fastlane/#{f} ~/.maestro/tests || true") } if is_ci
+ stop_metro
+ end
+end
diff --git a/fastlane/Pluginfile b/fastlane/Pluginfile
new file mode 100644
index 0000000..0a0bd1b
--- /dev/null
+++ b/fastlane/Pluginfile
@@ -0,0 +1,6 @@
+# Autogenerated by fastlane
+#
+# Ensure this file is checked in to source control!
+
+gem 'fastlane-plugin-stream_actions'
+
diff --git a/package.json b/package.json
index e4a2851..a4498c0 100644
--- a/package.json
+++ b/package.json
@@ -37,14 +37,14 @@
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.2.1",
"eslint": "^8.19.0",
- "jest": "^29.2.1",
+ "jest": "^29.7.0",
"metro-react-native-babel-preset": "0.76.8",
"prettier": "^2.4.1",
"react-test-renderer": "18.2.0",
"typescript": "4.8.4",
"@testing-library/jest-native": "^5.4.3",
"@testing-library/react-native": "^12.3.0",
- "@types/jest": "^29.2.1",
+ "@types/jest": "^29.5.4",
"@types/react-native-video": "^5.0.15",
"axios": "^1.5.0",
"msw": "^1.3.0"
diff --git a/src/components/LoginSubmission.tsx b/src/components/LoginSubmission.tsx
index cf2c5af..1e65b5c 100644
--- a/src/components/LoginSubmission.tsx
+++ b/src/components/LoginSubmission.tsx
@@ -1,5 +1,5 @@
import React, {useEffect, useReducer, useState} from 'react';
-import {Text, View} from 'react-native';
+import {ActivityIndicator, Text, View} from 'react-native';
import Login from './Login';
import {useNavigation} from '@react-navigation/native';
import AsyncStorage from '@react-native-community/async-storage';
@@ -55,7 +55,8 @@ const useFormSubmission = ({endpoint, data}) => {
},
});
const responseData = await response.json();
- dispatch({type: 'RESOLVE', responseData});
+ // add a delay to simulate network latency
+ setTimeout(() => dispatch({type: 'RESOLVE', responseData}), 2000);
} catch (error) {
dispatch({type: 'REJECT', error});
}
@@ -69,8 +70,8 @@ const useFormSubmission = ({endpoint, data}) => {
const Spinner = () => {
return (
-
- loading...
+
+
);
};