diff --git a/.github/workflows/ci-app.yml b/.github/workflows/ci-app.yml index 670774ef..03d23f84 100644 --- a/.github/workflows/ci-app.yml +++ b/.github/workflows/ci-app.yml @@ -3,10 +3,10 @@ name: App CI Pipeline on: push: paths: - - "app/**" + - 'app/**' pull_request: paths: - - "app/**" + - 'app/**' jobs: build: @@ -41,3 +41,64 @@ jobs: - name: Run tests run: yarn run test working-directory: ./app + + ios-e2e-tests: + needs: build + timeout-minutes: 60 + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + + # Cache Yarn dependencies + - uses: actions/cache@v2 + with: + path: | + .yarn/cache + ./app/node_modules + key: ${{ runner.os }}-yarn-${{ hashFiles('./app/**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Install yarn + run: npm install -g yarn + + - name: Install dependencies + run: yarn install + working-directory: ./app + + # Cache CocoaPods + - uses: actions/cache@v2 + with: + path: ./app/ios/Pods + key: ${{ runner.os }}-pods-${{ hashFiles('./app/ios/Podfile.lock') }} + restore-keys: | + ${{ runner.os }}-pods- + + - name: Install CocoaPods + run: sudo gem install cocoapods + + - name: Install Pods + run: cd app/ios && pod install + + # Tap wix/brew for applesimutils + - name: Tap wix/brew + run: brew tap wix/brew + + - name: Install applesimutils + run: brew install wix/brew/applesimutils + + # Cache Detox build artifacts + - uses: actions/cache@v2 + with: + path: ./app/ios/build + key: ${{ runner.os }}-detox-build-${{ hashFiles('./app/**/*.js', './app/**/*.jsx', './app/**/yarn.lock', './app/ios/Podfile.lock') }} + restore-keys: | + ${{ runner.os }}-detox-build- + + - name: Run Detox build + run: yarn e2e:build ios.sim.release + working-directory: ./app + + - name: Run Detox tests + run: yarn e2e:test ios.sim.release --cleanup + working-directory: ./app diff --git a/app/e2e/login.test.js b/app/e2e/login.test.js index 89c36345..43e309ea 100644 --- a/app/e2e/login.test.js +++ b/app/e2e/login.test.js @@ -2,7 +2,10 @@ import { login } from './utils.js'; describe('Login', () => { beforeAll(async () => { - await device.launchApp(); + await device.launchApp({ + permissions: { location: 'always' }, + launchArgs: { detoxPrintBusyIdleResources: 'YES' }, + }); }); beforeEach(async () => { @@ -10,8 +13,8 @@ describe('Login', () => { }); it('disallow login with bad credentials', async () => { - await element(by.id('username')).typeText('invalid_username'); - await element(by.id('password')).typeText('invalid_password'); + await element(by.id('username')).typeText('invalid_username\n'); + await element(by.id('password')).typeText('invalid_password\n'); await element(by.text('Se connecter')).tap(); await expect(element(by.id('loginError'))).toBeVisible(); }); diff --git a/app/e2e/navigate.test.js b/app/e2e/navigate.test.js index ba5a6fcd..8ec7de6d 100644 --- a/app/e2e/navigate.test.js +++ b/app/e2e/navigate.test.js @@ -2,7 +2,10 @@ import { login } from './utils.js'; describe('Navigation', () => { beforeAll(async () => { - await device.launchApp(); + await device.launchApp({ + permissions: { location: 'always' }, + launchArgs: { detoxPrintBusyIdleResources: 'YES' }, + }); await login(); await login(); }); @@ -14,22 +17,18 @@ describe('Navigation', () => { // Tattoo artists list tab await element(by.id('tab-tatoueurs')).tap(); - await expect(element(by.label('Tatoueurs'))).toBeVisible(); - - await waitFor(element(by.id('tab-messagerie'))) - .toBeVisible() - .withTimeout(5000); + await expect(element(by.label('Tatoueurs')).atIndex(0)).toBeVisible(); // Messaging tab await element(by.id('tab-messagerie')).tap(); - await expect(element(by.label('Messagerie'))).toBeVisible(); + await expect(element(by.label('Messagerie')).atIndex(0)).toBeVisible(); // Account tab await element(by.id('tab-compte')).tap(); - await expect(element(by.label('Compte'))).toBeVisible(); + await expect(element(by.label('Compte')).atIndex(0)).toBeVisible(); // Home tab await element(by.id('tab-accueil')).tap(); - await expect(element(by.label('Accueil'))).toBeVisible(); + await expect(element(by.label('Accueil')).atIndex(0)).toBeVisible(); }); }); diff --git a/app/e2e/utils.js b/app/e2e/utils.js index 5e94abd8..41f515b2 100644 --- a/app/e2e/utils.js +++ b/app/e2e/utils.js @@ -3,10 +3,8 @@ export const login = async () => { const password = 'password'; await element(by.id('username')).clearText(); - await element(by.id('username')).typeText(username); - await element(by.id('password')).typeText(password); - - const loginButton = element(by.text('Se connecter')); - await loginButton.tap(); + await element(by.id('username')).typeText(username + '\n'); + await element(by.id('password')).typeText(password + '\n'); + await element(by.text('Se connecter')).tap(); await new Promise((resolve) => setTimeout(resolve, 2000)); }; diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index 3297f9c6..00fca0a1 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -348,7 +348,7 @@ PODS: - React-jsinspector (0.72.6) - React-logger (0.72.6): - glog - - react-native-get-random-values (1.10.0): + - react-native-get-random-values (1.9.0): - React-Core - react-native-safe-area-context (4.6.3): - RCT-Folly @@ -750,7 +750,7 @@ SPEC CHECKSUMS: React-jsiexecutor: 3bf18ff7cb03cd8dfdce08fbbc0d15058c1d71ae React-jsinspector: 194e32c6aab382d88713ad3dd0025c5f5c4ee072 React-logger: cebf22b6cf43434e471dc561e5911b40ac01d289 - react-native-get-random-values: 384787fd76976f5aec9465aff6fa9e9129af1e74 + react-native-get-random-values: dee677497c6a740b71e5612e8dbd83e7539ed5bb react-native-safe-area-context: 36cc67648134e89465663b8172336a19eeda493d react-native-slider: 33b8d190b59d4f67a541061bb91775d53d617d9d React-NativeModulesApple: 02e35e9a51e10c6422f04f5e4076a7c02243fff2 diff --git a/app/src/screens/guest/LoginScreen.tsx b/app/src/screens/guest/LoginScreen.tsx index e364a112..0d761ab5 100644 --- a/app/src/screens/guest/LoginScreen.tsx +++ b/app/src/screens/guest/LoginScreen.tsx @@ -12,6 +12,7 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { useAuth } from '@/hooks/useAuth'; import { useMutation } from '@apollo/client'; import LOGIN_USER from '@/graphql/mutations/auth/login-mutation'; +import { KeyboardAvoidingView, Platform } from 'react-native'; const loginSchema = z.object({ username: z.string().min(1, { message: 'Champs obligatoire' }), @@ -48,50 +49,56 @@ const LoginScreen: FC = () => { }; return ( - - - - - - {error && error.message && ( - - {error.message} - - )} - - - + + + + + + {error && error.message && ( + + {error.message} + + )} + + + + + + + + Pas encore de compte ?{' '} + Inscrivez-vous + - - - - Pas encore de compte ? Inscrivez-vous - - + ); }; diff --git a/app/src/screens/guest/RegisterScreen.tsx b/app/src/screens/guest/RegisterScreen.tsx index 57ad4513..54a20b12 100644 --- a/app/src/screens/guest/RegisterScreen.tsx +++ b/app/src/screens/guest/RegisterScreen.tsx @@ -13,6 +13,7 @@ import ScrollContainer from '@/components/ui/ScrollContainer'; import { useMutation } from '@apollo/client'; import SIGNUP_USER from '@/graphql/mutations/auth/signup-mutation'; import { useAuth } from '@/hooks/useAuth'; +import { KeyboardAvoidingView, Platform } from 'react-native'; const registerSchema = z .object({ @@ -72,76 +73,81 @@ const RegisterScreen: FC = () => { }; return ( - - - - - - {error && error.message && ( - - {error.message} - - )} - - + + + + + + + {error && error.message && ( + + {error.message} + + )} + + - + - + - + - + - + + + + + + Déjà un compte ? Connectez-vous + - - - Déjà un compte ? Connectez-vous - - - - + + ); };