diff --git a/.gitignore b/.gitignore index 6fdbfa9d..bd4f4a99 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,6 @@ env.json # baca-cli build scripts/cli/build/ scripts/cli/temp/ + +# maestro +e2e-debug-output diff --git a/.maestro/auth/login-with-validation.yaml b/.maestro/auth/login-with-validation.yaml new file mode 100644 index 00000000..2ff10e86 --- /dev/null +++ b/.maestro/auth/login-with-validation.yaml @@ -0,0 +1,55 @@ +appId: ${APP_ID} +tags: + - auth +--- +# Check if the login screen is visible +- assertVisible: + id: 'sign_in:title' +- assertVisible: + id: 'sign_in:sub_title' +- assertVisible: + id: 'sign_in:email_input:label' + +# Check if empty email input is invalid +- tapOn: + id: 'sign_in:submit_button' +- assertVisible: + id: 'sign_in:email_input:error_message' +- assertVisible: + id: 'sign_in:password_input:error_message' + +# Check if invalid email input and empty password is invalid +- tapOn: + id: 'sign_in:email_input:input' +- inputText: 'invalid-email' +- hideKeyboard +- tapOn: + id: 'sign_in:submit_button' +- assertVisible: + id: 'sign_in:email_input:error_message' +- assertVisible: + id: 'sign_in:password_input:error_message' + +# Check if valid email input and empty password is invalid +- tapOn: + id: 'sign_in:email_input:input' +- eraseText +- inputText: 'email@test.com' +- hideKeyboard +- tapOn: + id: 'sign_in:submit_button' +- assertVisible: + id: 'sign_in:password_input:error_message' + +# Check if valid email input and password is valid +- tapOn: + id: 'sign_in:password_input:input' +- eraseText +- inputText: 'password' +- hideKeyboard +- tapOn: + id: 'sign_in:submit_button' + +# Check if login is successful +- assertVisible: + id: 'home_screen:title' diff --git a/.maestro/auth/logout-when-needed.yaml b/.maestro/auth/logout-when-needed.yaml new file mode 100644 index 00000000..4a03b5eb --- /dev/null +++ b/.maestro/auth/logout-when-needed.yaml @@ -0,0 +1,11 @@ +appId: ${APP_ID} +tags: + - auth +--- +- stopApp +- openLink: exp://127.0.0.1:8081/--/sign-in +- runFlow: + when: + visible: + id: 'home_screen:title' + file: ../utils/logout.yaml diff --git a/.maestro/config.yaml b/.maestro/config.yaml new file mode 100644 index 00000000..1ff0c6c2 --- /dev/null +++ b/.maestro/config.yaml @@ -0,0 +1,25 @@ +flows: + - 'auth/*' + - 'home/*' + - 'settings/*' + - 'profile/*' + +includeTags: + - 'auth' + - 'home' + - 'settings' + - 'profile' + +executionOrder: + continueOnFailure: false + flowsOrder: + - 'logout-when-needed' + - 'login-with-validation' + - 'details' + - 'full-screen-form' + - 'settings' + # https://github.com/mobile-dev-inc/maestro/issues/1484 + # Wait for it to be resolved and then remove blog from the list + # blog is not implemented, it's just a placeholder, to make tests run + - 'blog' + - 'profile' diff --git a/.maestro/home/details.yaml b/.maestro/home/details.yaml new file mode 100644 index 00000000..34eccd35 --- /dev/null +++ b/.maestro/home/details.yaml @@ -0,0 +1,16 @@ +appId: ${APP_ID} +tags: + - home +--- +- assertVisible: + id: 'home_screen:details' +- tapOn: + id: 'home_screen:details' +- extendedWaitUntil: + visible: 'Open BottomSheetModal' + timeout: 10000 +- tapOn: 'Open BottomSheetModal' +- tapOn: + point: 50%,50% +- assertVisible: 'Home' +- tapOn: 'Home' diff --git a/.maestro/home/full-screen-form.yaml b/.maestro/home/full-screen-form.yaml new file mode 100644 index 00000000..d0f4d517 --- /dev/null +++ b/.maestro/home/full-screen-form.yaml @@ -0,0 +1,77 @@ +appId: ${APP_ID} +tags: + - home +--- +- assertVisible: + id: 'home_screen:full_screen_form' +- tapOn: + id: 'home_screen:full_screen_form' +- extendedWaitUntil: + visible: 'Contact data' + timeout: 10000 +- assertVisible: 'Name* Name' +- tapOn: 'Name* Name' +- inputText: 'RandomName' +- assertVisible: 'Surname* Surname' +- tapOn: 'Surname* Surname' +- inputText: 'RandomSurname' +- assertVisible: 'E-mail* E-mail' +- tapOn: 'E-mail* E-mail' +- inputRandomEmail +- assertVisible: 'Phone number* Phone number' +- tapOn: 'Phone number* Phone number' +- inputText: '600-000-000' +- assertVisible: 'Postal code* Postal code' +- tapOn: 'Postal code* Postal code' +- inputText: '00-000' +- hideKeyboard +- assertVisible: 'City* City' +- tapOn: 'City* City' +- inputRandomText +- hideKeyboard +- assertVisible: 'Age* 18-30 31-40 41-50 51-60 61-70 71-80 81-90 91-100' +- tapOn: '18-30' +- scrollUntilVisible: + element: + text: 'what kind of music do you listen ?* Metal Heavy Metal Rock Pop Rap' + direction: DOWN + timeout: 15000 + speed: 40 + visibilityPercentage: 100 +- assertVisible: 'Sex* Male Female' +- tapOn: 'Male' +- assertVisible: 'Education* Education ' +- tapOn: 'Education* Education ' +- assertVisible: 'Bottom sheet handle' +- tapOn: + point: 6%,91% +- assertVisible: 'Shoe size* Shoe size ' +- tapOn: 'Shoe size* Shoe size ' +- assertVisible: 'Bottom sheet handle' +- tapOn: + point: 6%,91% +- scrollUntilVisible: + element: + text: 'Additional comment' + direction: DOWN + timeout: 15000 + speed: 40 + visibilityPercentage: 100 +- assertVisible: 'what kind of music do you listen ?* Metal Heavy Metal Rock Pop Rap' +- tapOn: 'Rock' +- tapOn: 'Pop' +- tapOn: 'Rap' +- scrollUntilVisible: + element: + text: 'Submit' + direction: DOWN + timeout: 15000 + speed: 40 + visibilityPercentage: 100 +- assertVisible: 'Interests* IT Cooking Sport Games Dancing' +- tapOn: 'IT' +- tapOn: 'Sport' +- assertVisible: 'Submit' +- tapOn: 'Submit' +- assertVisible: '(tabs)' +- tapOn: '(tabs)' diff --git a/.maestro/profile/profile.yaml b/.maestro/profile/profile.yaml new file mode 100644 index 00000000..1ee76879 --- /dev/null +++ b/.maestro/profile/profile.yaml @@ -0,0 +1,36 @@ +appId: ${APP_ID} +tags: + - profile +--- +- tapOn: + id: 'bottom_tab_button:profile' +# TODO: Properly implement the profile flow + +# CHANING USER DATA FLOW +# Change first name +# Change last name +# Save data +# Reload app +# Check if the changes are saved + +# CHANGING PASSWORD FLOW +# Input old password +# Input new password + +# Input wrong new password +# TODO: Finish the password flow +# - tapOn: +# id: 'passwordInput:input' +# - inputText: 'invalidpassword' +# - assertVisible: +# id: 'change_password:min_8_chars:success' +# - assertVisible: +# id: 'change_password:min_1_special_char:error' +# - tapOn: +# id: 'passwordInput:input' +# - inputText: 'invalidpassword!' +# - hideKeyboard +# - assertVisible: +# id: 'change_password:min_8_chars:success' +# - assertVisible: +# id: 'change_password:min_1_special_char:success' diff --git a/.maestro/settings/settings.yaml b/.maestro/settings/settings.yaml new file mode 100644 index 00000000..2d5544c5 --- /dev/null +++ b/.maestro/settings/settings.yaml @@ -0,0 +1,14 @@ +appId: ${APP_ID} +tags: + - settings +--- +- tapOn: + id: 'bottom_tab_button:settings' + +# TODO: Check if after changing the theme it really changes +- assertVisible: 'light' +- tapOn: 'light' +- assertVisible: 'dark' +- tapOn: 'dark' +- assertVisible: 'system' +- tapOn: 'system' diff --git a/.maestro/utils/logout.yaml b/.maestro/utils/logout.yaml new file mode 100644 index 00000000..c65e6558 --- /dev/null +++ b/.maestro/utils/logout.yaml @@ -0,0 +1,15 @@ +appId: ${APP_ID} +tags: + - util +--- +- tapOn: + id: 'bottom_tab_button:settings' + +- extendedWaitUntil: + visible: + id: 'settings:logout' + timeout: 1000 +- tapOn: + id: 'settings:logout' +- assertVisible: + id: 'sign_in:title' diff --git a/App.tsx b/App.tsx index 2a69b483..654800eb 100644 --- a/App.tsx +++ b/App.tsx @@ -9,14 +9,17 @@ import 'core-js/stable/atob' // Rest imports import '@baca/i18n' +import { isMock } from '@baca/constants' import { enableAndroidBackgroundNotificationListener, startMockedServer } from '@baca/services' import * as Device from 'expo-device' import 'expo-router/entry' -const ENABLE_MOCKED_SERVER = false +const ENABLE_MOCKED_SERVER = isMock if (ENABLE_MOCKED_SERVER) { startMockedServer() + console.error = () => {} + console.warn = () => {} } // TODO: Uncomment reactotron setup when using diff --git a/docs/docs/data-management/MOCKING.md b/docs/docs/data-management/MOCKING.md index bbddf2a2..5f4b539d 100644 --- a/docs/docs/data-management/MOCKING.md +++ b/docs/docs/data-management/MOCKING.md @@ -22,12 +22,22 @@ Mocks are automatically generated with orval script - you can check [docs here]( ## Enabling mocks +You have two types of enabling mocks in the app + +1. Start server and set mock on start + +``` +IS_MOCK=true yarn start +``` + +2. Enable mock manually + Go to `App.tsx` and change `ENABLE_MOCKED_SERVER` variable from false to true ```tsx title="/App.tsx" // FIXME: moking not working on mobile app - follow this discussion https://github.com/mswjs/msw/issues/2026 // error-line -const ENABLE_MOCKED_SERVER = false +const ENABLE_MOCKED_SERVER = isMock // success-line const ENABLE_MOCKED_SERVER = true diff --git a/docs/docs/testing/TESTING_E2E.md b/docs/docs/testing/TESTING_E2E.md new file mode 100644 index 00000000..b8138ee1 --- /dev/null +++ b/docs/docs/testing/TESTING_E2E.md @@ -0,0 +1,224 @@ +--- +id: e2e +slug: /testing/e2e +title: E2E Tests - Maestro +sidebar_position: 4 +tags: + - E2E + - E2E Tests + - Testing + - Maestro +description: E2E Testing with Maestro +--- + +# E2E Testing with Maestro + +## 1. Document Structure + +This document is structured to provide a comprehensive guide on setting up and executing end-to-end (E2E) tests using Maestro in the BACA project. The main sections include: + +- Installing Maestro +- Configuration process +- Running tests +- Explanation of YAML files +- Troubleshooting common issues +- Benefits and limitations of the E2E testing approach +- Best practices + +This documentation is designed to be understandable and useful for both new and experienced developers, UI/UX designers, testers, and other team members involved in the project. Each section contains detailed information and practical examples to facilitate the implementation and execution of E2E tests within the context of BACA. + +## 2. Configuration and Installation Process + +### Installing Maestro + +To install Maestro, follow these steps: + +1. Ensure that Node.js is installed on your system. + +2. Open a terminal in the project’s root directory. + +3. Run the following command: + + ```bash + yarn install-maestro + ``` + + This command is a custom npm script that executes: + + ```bash + curl -Ls 'https://get.maestro.mobile.dev' | bash + ``` + + The script automatically downloads and installs Maestro on your system. + +4. Verify the installation by running: + ```bash + maestro --version + ``` + You should see the Maestro version if the installation was successful. + +### Environment Setup + +1. Expo Setup: + + - https://docs.expo.dev/get-started/set-up-your-environment/ + +2. Project Setup: + + - Ensure that all project dependencies are installed: + + ```bash + yarn install + ``` + +3. Mock Server Configuration: + + - Check that the `ENABLED_MOCKED_SERVER` environment variable is correctly configured in the `.env` file. + +4. Maestro Studio Configuration (optional but recommended): + - Maestro Studio provides a visual interface for creating and debugging E2E tests. + +## 3. Running Tests + +### Running All Tests + +To run all E2E tests for Baca, follow these steps: + +1. Start the mock server: + + ```bash + yarn start:e2e + ``` + + It’s crucial that the mock server is enabled (ENABLED_MOCKED_SERVER) before running the tests. + +2. In another terminal, start Maestro Studio for a visual testing experience (optional): + + ```bash + maestro studio + ``` + +3. In a new terminal, execute all tests using the following command: + + ```bash + yarn test:e2e + ``` + +### Running Individual Tests + +To run a single test, use the following command format: + +```bash +maestro test -e APP_ID=host.exp.Exponent --debug-output=./e2e-debug-output +``` + +Replace `` with the specific path to the test you want to run. For example: + +- To run the login test: + ```bash + maestro test .maestro/auth/login-with-validation.yaml -e APP_ID=host.exp.Exponent --debug-output=./e2e-debug-output + ``` +- To run the full-screen form test: + ```bash + maestro test .maestro/home/full-screen-form.yaml -e APP_ID=host.exp.Exponent --debug-output=./e2e-debug-output + ``` + +Ensure you are in the project’s root directory when executing these commands. + +## 4. YAML File Explanation + +Each YAML file in the .maestro directory represents a specific set of E2E tests. Here’s an explanation of each file’s function: + +### logout-when-needed.yaml + +Handles logging out the user if needed before running other tests. Includes: + +- Stopping and restarting the app. +- Navigating to the login screen. +- Performing the logout flow if the user is authenticated. + +### login-with-validation.yaml + +Contains tests for the login process, including input validation. Tests include: + +- Verifying the visibility of login screen elements. +- Testing email and password validation. +- Verifying the successful login process. + +### details.yaml + +Tests the functionality of the details screen, including: + +- Navigating to the details screen. +- Interacting with specific UI elements. + +### full-screen-form.yaml + +Tests the full-screen form by performing actions such as: + +- Filling out the form. +- Navigating through different sections of the form. +- Submitting the form and verifying the outcome. + +### settings.yaml + +Tests the functionality of the settings screen, including: + +- Changing the app’s theme (light, dark, system). + +### logout.yaml + +Contains tests for the user logout process. Includes: + +- Logging out the user. +- Verifying the return to the login screen after logout. + +### config.yaml + +Configures the global execution of tests, including: + +- The order of test flow execution. +- Enabling specific tags for tests. +- Configuring whether to continue or stop on failure. + +## 5. Troubleshooting Common Issues + +- **Persistent session issue:** The logout-when-needed.yaml file automatically logs out if the home screen is visible, avoiding issues with previous sessions. +- **Login validation failures:** The login-with-validation.yaml file has been modified to include additional checks. Ensure that UI element IDs match those specified in the YAML file. +- **Language issues** To avoid issues with text selection when switching languages, identifiers (testID) are used instead of text for UI elements. For example, use `testID='sign_in:submit_button'` instead of selecting by text. +- **Server synchronization** The mock server provides faster and more reliable test execution, eliminating errors due to lack of synchronization between the server startup and immediate test execution. +- **Screen coordinate issues:** Specific coordinates are used for some interactions in full-screen-form.yaml. Ensure you use the same simulator or device to maintain consistency. + +## 6. Benefits and Limitations + +### Benefits + +- **Early bug detection** Helps identify issues on screens that haven’t been directly modified, preventing regressions. +- **Automation:** Allows running tests in the background while performing other development tasks. +- **Error prevention:** Helps catch issues before committing, improving code quality. For instance, when refactoring the test form, hiding error messages may result in a red rectangle instead of an error message. Re-running tests can reveal issues with component reuse, which the tool helps identify, increasing code reliability. +- **Living documentation** E2E tests serve as a form of documentation that is updated alongside changes in the application. +- **Expo Go Compatibility:** Maestro works with regular apps already built on the device. This means we can skip slow native builds by using Expo Go with `yarn start:e2e`. +- **Scalability:** Maestro’s ability to handle large test suites without significant performance degradation. + +### Limitations + +- **Development time:** Creating and maintaining E2E tests increases initial development time. +- **Fragility:** UI-based tests can be sensitive to interface changes, requiring frequent updates. +- **Localization issues:** There may be difficulties selecting text when changing the application’s language. +- **Limited simulation:** Some functionalities, such as saving profile data, may not work correctly with the mock server, limiting the scope of tests. +- **Advanced features limitations:** Unlike other frameworks (e.g., Detox), Maestro may not support some advanced features like physical device manipulation or integration with external APIs for more realistic simulations. + +## 7. Best Practices + +1. **Regular maintenance:** Regularly update E2E tests to reflect changes in the application. +2. **Use unique IDs:** Use unique testIDs for UI elements to make tests more resilient. +3. **Atomic tests:** Design tests to be independent of each other for easier debugging. +4. **Version control:** Include Maestro YAML files in version control alongside application code. +5. **Documentation:** Keep this documentation up to date with any changes in the testing process or configuration. + +### Additional Notes + +- We are working on improving validation on screens such as ProfileScreen. +- We plan to implement more test cases for functionalities like Sign up and password validation. + +For more information on Maestro and its usage in E2E testing, refer to the official Maestro documentation. diff --git a/docs/docs/testing/_category_.json b/docs/docs/testing/_category_.json new file mode 100644 index 00000000..7f6ab004 --- /dev/null +++ b/docs/docs/testing/_category_.json @@ -0,0 +1,10 @@ +{ + "label": "Testing", + "position": 7, + "collapsible": true, + "collapsed": false, + "link": { + "type": "generated-index", + "description": "Testing using unit tests or E2E tests" + } +} diff --git a/orval.config.ts b/orval.config.ts index 20b0f691..00321516 100644 --- a/orval.config.ts +++ b/orval.config.ts @@ -10,7 +10,6 @@ export default defineConfig({ client: 'react-query', // solution for not working mocked data on mobile - it removes automatically added "*" to address url at the beginning mock: { - baseUrl: '', type: 'msw', }, clean: true, diff --git a/package.json b/package.json index 3b02662d..96d11bd0 100644 --- a/package.json +++ b/package.json @@ -25,9 +25,9 @@ "license": "MIT", "scripts": { "android:dev-client": "IS_DEV=1 npx expo run:android", - "baca": "yarn build:baca-cli && node ./scripts/cli/build/scripts/cli", + "android": "expo run:android", "b": "yarn baca b", - "g": "yarn baca g", + "baca": "yarn build:baca-cli && node ./scripts/cli/build/scripts/cli", "build:baca-cli": "npx tsc -p ./scripts/cli/tsconfig.cli.json", "build:production:android": "yarn prepare:production && eas build --platform android --profile production", "build:production:ios": "yarn prepare:production && eas build --platform ios --profile production", @@ -48,6 +48,7 @@ "deploy:staging:ios": "yarn prepare:staging && eas build --platform ios --profile staging --auto-submit --non-interactive", "deploy:staging": "yarn prepare:staging && eas build --platform all --profile staging --auto-submit --non-interactive", "eas-build-pre-install": "base64 --help && echo $ANDROID_FIREBASE_CONFIG | base64 --decode > google-services.json && cat google-services.json && echo $IOS_FIREBASE_CONFIG | base64 --decode > GoogleService-Info.plist && cat GoogleService-Info.plist", + "g": "yarn baca g", "generate:env:production": "scripts/generate_dotenv.sh production", "generate:env:qa": "scripts/generate_dotenv.sh qa", "generate:env:staging": "scripts/generate_dotenv.sh staging", @@ -55,6 +56,8 @@ "generate:last:publish": "node ./scripts/generate_last_update_id.js", "generate:query": "yarn orval --config ./orval.config.ts", "ios:dev-client": "IS_DEV=1 npx expo run:ios", + "ios": "expo run:ios", + "install-maestro": "curl -Ls 'https://get.maestro.mobile.dev' | bash", "lint:fix": "eslint src --fix", "lint": "eslint src && yarn tsc", "postinstall": "patch-package && yarn build:baca-cli", @@ -69,9 +72,11 @@ "start:production": "yarn generate:env:production && IS_DEV=1 IS_EXPO_GO=1 expo start -c -g", "start:staging": "yarn generate:env:staging && IS_DEV=1 IS_EXPO_GO=1 expo start -c -g", "start": "yarn generate:env:qa && cross-env IS_DEV=1 IS_EXPO_GO=1 expo start -c -g", + "start:e2e": "yarn generate:env:qa && cross-env IS_MOCK=1 IS_DEV=1 IS_EXPO_GO=1 npx expo start -c -g --no-dev --minify", "test:debug": "jest -o --watch --coverage=false", "test:final": "jest", "test": "jest --watch --coverage=false --changedSince=origin/main", + "test:e2e": "maestro test .maestro/ -e APP_ID=host.exp.Exponent --debug-output=./e2e-debug-output", "typecheck": "eslint .eslintrc.js --fix", "update:expo_go": "yarn prepare:qa && cross-env IS_DEV=1 eas update --auto", "update:production:android": "yarn prepare:production && eas update --branch production --platform android && yarn generate:last:publish production", @@ -87,9 +92,7 @@ "upload:env": "./scripts/upload_env.sh", "web:build": "expo export:web", "web": "cross-env IS_DEV=1 expo start --web", - "whoami": "expo whoami", - "android": "expo run:android", - "ios": "expo run:ios" + "whoami": "expo whoami" }, "dependencies": { "@bacons/react-views": "^1.1.3", @@ -196,8 +199,8 @@ "jest": "^29.6.1", "jest-expo": "~51.0.3", "lint-staged": "^13.2.3", - "msw": "^2.3.0", - "orval": "^6.29.1", + "msw": "^2.3.5", + "orval": "^7.0.1", "patch-package": "^7.0.1", "prettier": "^2.8.8", "pretty-quick": "^4.0.0", diff --git a/patches/@mswjs+interceptors+0.29.1.patch b/patches/@mswjs+interceptors+0.29.1.patch new file mode 100644 index 00000000..540bd91a --- /dev/null +++ b/patches/@mswjs+interceptors+0.29.1.patch @@ -0,0 +1,18 @@ +diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-PSX5J3RF.js b/node_modules/@mswjs/interceptors/lib/browser/chunk-PSX5J3RF.js +index 37e2a0f..48d16d6 100644 +--- a/node_modules/@mswjs/interceptors/lib/browser/chunk-PSX5J3RF.js ++++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-PSX5J3RF.js +@@ -457,6 +457,13 @@ var XMLHttpRequestController = class { + readNextResponseBodyChunk(); + }; + readNextResponseBodyChunk(); ++ } else if (response._bodyInit) { ++ this.logger.info('mocked response has _bodyInit, faking streaming...') ++ ++ const bodyInit = response._bodyInit ++ const encoder = new TextEncoder() ++ this.responseBuffer = encoder.encode(bodyInit) ++ finalizeResponse() + } else { + finalizeResponse(); + } diff --git a/src/api/query/articles/articles.msw.ts b/src/api/query/articles/articles.msw.ts index 2e23759b..1485e297 100644 --- a/src/api/query/articles/articles.msw.ts +++ b/src/api/query/articles/articles.msw.ts @@ -12,13 +12,12 @@ import { HttpResponse, delay, http } from 'msw' import type { ArticleEntity } from '../../types' export const getArticlesControllerCreateResponseMock = ( - overrideResponse: any = {} + overrideResponse: Partial = {} ): ArticleEntity => ({ author: { email: faker.word.sample(), firstName: faker.word.sample(), lastName: faker.word.sample(), - ...overrideResponse, }, authorId: faker.helpers.arrayElement([ faker.helpers.arrayElement([faker.word.sample(), null]), @@ -38,15 +37,12 @@ export const getArticlesControllerCreateResponseMock = ( ...overrideResponse, }) -export const getArticlesControllerFindAllResponseMock = ( - overrideResponse: any = {} -): ArticleEntity[] => +export const getArticlesControllerFindAllResponseMock = (): ArticleEntity[] => Array.from({ length: faker.number.int({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ author: { email: faker.word.sample(), firstName: faker.word.sample(), lastName: faker.word.sample(), - ...overrideResponse, }, authorId: faker.helpers.arrayElement([ faker.helpers.arrayElement([faker.word.sample(), null]), @@ -63,18 +59,14 @@ export const getArticlesControllerFindAllResponseMock = ( published: faker.datatype.boolean(), title: faker.word.sample(), updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, })) -export const getArticlesControllerFindDraftsResponseMock = ( - overrideResponse: any = {} -): ArticleEntity[] => +export const getArticlesControllerFindDraftsResponseMock = (): ArticleEntity[] => Array.from({ length: faker.number.int({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ author: { email: faker.word.sample(), firstName: faker.word.sample(), lastName: faker.word.sample(), - ...overrideResponse, }, authorId: faker.helpers.arrayElement([ faker.helpers.arrayElement([faker.word.sample(), null]), @@ -91,17 +83,15 @@ export const getArticlesControllerFindDraftsResponseMock = ( published: faker.datatype.boolean(), title: faker.word.sample(), updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, })) export const getArticlesControllerFindOneResponseMock = ( - overrideResponse: any = {} + overrideResponse: Partial = {} ): ArticleEntity => ({ author: { email: faker.word.sample(), firstName: faker.word.sample(), lastName: faker.word.sample(), - ...overrideResponse, }, authorId: faker.helpers.arrayElement([ faker.helpers.arrayElement([faker.word.sample(), null]), @@ -122,13 +112,12 @@ export const getArticlesControllerFindOneResponseMock = ( }) export const getArticlesControllerUpdateResponseMock = ( - overrideResponse: any = {} + overrideResponse: Partial = {} ): ArticleEntity => ({ author: { email: faker.word.sample(), firstName: faker.word.sample(), lastName: faker.word.sample(), - ...overrideResponse, }, authorId: faker.helpers.arrayElement([ faker.helpers.arrayElement([faker.word.sample(), null]), @@ -148,100 +137,132 @@ export const getArticlesControllerUpdateResponseMock = ( ...overrideResponse, }) -export const getArticlesControllerCreateMockHandler = (overrideResponse?: ArticleEntity) => { - return http.post('/api/v1/articles', async () => { +export const getArticlesControllerCreateMockHandler = ( + overrideResponse?: + | ArticleEntity + | (( + info: Parameters[1]>[0] + ) => Promise | ArticleEntity) +) => { + return http.post('*/api/v1/articles', async (info) => { await delay(1000) + return new HttpResponse( JSON.stringify( - overrideResponse ? overrideResponse : getArticlesControllerCreateResponseMock() + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getArticlesControllerCreateResponseMock() ), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + { status: 201, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getArticlesControllerFindAllMockHandler = (overrideResponse?: ArticleEntity[]) => { - return http.get('/api/v1/articles', async () => { +export const getArticlesControllerFindAllMockHandler = ( + overrideResponse?: + | ArticleEntity[] + | (( + info: Parameters[1]>[0] + ) => Promise | ArticleEntity[]) +) => { + return http.get('*/api/v1/articles', async (info) => { await delay(1000) + return new HttpResponse( JSON.stringify( - overrideResponse ? overrideResponse : getArticlesControllerFindAllResponseMock() + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getArticlesControllerFindAllResponseMock() ), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + { status: 200, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getArticlesControllerFindDraftsMockHandler = (overrideResponse?: ArticleEntity[]) => { - return http.get('/api/v1/articles/drafts', async () => { +export const getArticlesControllerFindDraftsMockHandler = ( + overrideResponse?: + | ArticleEntity[] + | (( + info: Parameters[1]>[0] + ) => Promise | ArticleEntity[]) +) => { + return http.get('*/api/v1/articles/drafts', async (info) => { await delay(1000) + return new HttpResponse( JSON.stringify( - overrideResponse ? overrideResponse : getArticlesControllerFindDraftsResponseMock() + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getArticlesControllerFindDraftsResponseMock() ), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + { status: 200, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getArticlesControllerFindOneMockHandler = (overrideResponse?: ArticleEntity) => { - return http.get('/api/v1/articles/:id', async () => { +export const getArticlesControllerFindOneMockHandler = ( + overrideResponse?: + | ArticleEntity + | (( + info: Parameters[1]>[0] + ) => Promise | ArticleEntity) +) => { + return http.get('*/api/v1/articles/:id', async (info) => { await delay(1000) + return new HttpResponse( JSON.stringify( - overrideResponse ? overrideResponse : getArticlesControllerFindOneResponseMock() + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getArticlesControllerFindOneResponseMock() ), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + { status: 200, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getArticlesControllerUpdateMockHandler = (overrideResponse?: ArticleEntity) => { - return http.patch('/api/v1/articles/:id', async () => { +export const getArticlesControllerUpdateMockHandler = ( + overrideResponse?: + | ArticleEntity + | (( + info: Parameters[1]>[0] + ) => Promise | ArticleEntity) +) => { + return http.patch('*/api/v1/articles/:id', async (info) => { await delay(1000) + return new HttpResponse( JSON.stringify( - overrideResponse ? overrideResponse : getArticlesControllerUpdateResponseMock() + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getArticlesControllerUpdateResponseMock() ), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + { status: 201, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getArticlesControllerRemoveMockHandler = () => { - return http.delete('/api/v1/articles/:id', async () => { +export const getArticlesControllerRemoveMockHandler = ( + overrideResponse?: + | void + | ((info: Parameters[1]>[0]) => Promise | void) +) => { + return http.delete('*/api/v1/articles/:id', async (info) => { await delay(1000) - return new HttpResponse(null, { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }) + if (typeof overrideResponse === 'function') { + await overrideResponse(info) + } + return new HttpResponse(null, { status: 204 }) }) } export const getArticlesMock = () => [ diff --git a/src/api/query/articles/articles.ts b/src/api/query/articles/articles.ts index f905a8f1..cdae0924 100644 --- a/src/api/query/articles/articles.ts +++ b/src/api/query/articles/articles.ts @@ -12,6 +12,7 @@ import type { QueryFunction, QueryKey, UseMutationOptions, + UseMutationResult, UseQueryOptions, UseQueryResult, } from '@tanstack/react-query' @@ -102,7 +103,12 @@ export const useArticlesControllerCreate = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getArticlesControllerCreateMutationOptions(options) return useMutation(mutationOptions) @@ -159,7 +165,8 @@ export type ArticlesControllerFindAllQueryError = ErrorType /** * @summary Find All Articles */ -export const useArticlesControllerFindAll = < + +export function useArticlesControllerFindAll< TData = Awaited>, TError = ErrorType >( @@ -168,7 +175,7 @@ export const useArticlesControllerFindAll = < query?: UseQueryOptions>, TError, TData> request?: SecondParameter } -): UseQueryResult & { queryKey: QueryKey } => { +): UseQueryResult & { queryKey: QueryKey } { const queryOptions = getArticlesControllerFindAllQueryOptions(params, options) const query = useQuery(queryOptions) as UseQueryResult & { queryKey: QueryKey } @@ -232,7 +239,8 @@ export type ArticlesControllerFindDraftsQueryError = ErrorType>, TError = ErrorType >( @@ -241,7 +249,7 @@ export const useArticlesControllerFindDrafts = < query?: UseQueryOptions>, TError, TData> request?: SecondParameter } -): UseQueryResult & { queryKey: QueryKey } => { +): UseQueryResult & { queryKey: QueryKey } { const queryOptions = getArticlesControllerFindDraftsQueryOptions(params, options) const query = useQuery(queryOptions) as UseQueryResult & { queryKey: QueryKey } @@ -303,7 +311,8 @@ export type ArticlesControllerFindOneQueryError = ErrorType /** * @summary Find Article by ID */ -export const useArticlesControllerFindOne = < + +export function useArticlesControllerFindOne< TData = Awaited>, TError = ErrorType >( @@ -312,7 +321,7 @@ export const useArticlesControllerFindOne = < query?: UseQueryOptions>, TError, TData> request?: SecondParameter } -): UseQueryResult & { queryKey: QueryKey } => { +): UseQueryResult & { queryKey: QueryKey } { const queryOptions = getArticlesControllerFindOneQueryOptions(id, options) const query = useQuery(queryOptions) as UseQueryResult & { queryKey: QueryKey } @@ -395,7 +404,12 @@ export const useArticlesControllerUpdate = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { id: number; data: BodyType }, + TContext +> => { const mutationOptions = getArticlesControllerUpdateMutationOptions(options) return useMutation(mutationOptions) @@ -462,7 +476,12 @@ export const useArticlesControllerRemove = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { id: number }, + TContext +> => { const mutationOptions = getArticlesControllerRemoveMutationOptions(options) return useMutation(mutationOptions) diff --git a/src/api/query/auth-social/auth-social.msw.ts b/src/api/query/auth-social/auth-social.msw.ts index d8a465ab..1bed2c69 100644 --- a/src/api/query/auth-social/auth-social.msw.ts +++ b/src/api/query/auth-social/auth-social.msw.ts @@ -12,7 +12,7 @@ import { HttpResponse, delay, http } from 'msw' import type { AuthEntity } from '../../types' export const getAuthGoogleControllerLoginResponseMock = ( - overrideResponse: any = {} + overrideResponse: Partial = {} ): AuthEntity => ({ accessToken: faker.word.sample(), refreshToken: faker.word.sample(), @@ -26,7 +26,6 @@ export const getAuthGoogleControllerLoginResponseMock = ( termsAccepted: faker.datatype.boolean(), termsVersion: faker.word.sample(), updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, undefined, ]), @@ -39,24 +38,18 @@ export const getAuthGoogleControllerLoginResponseMock = ( locale: faker.word.sample(), provider: faker.word.sample(), role: { - id: faker.number.int({ min: undefined, max: undefined }), + id: faker.helpers.arrayElement([1, 2] as const), name: faker.helpers.arrayElement(['ADMIN', 'USER'] as const), - ...overrideResponse, }, socialId: faker.word.sample(), - status: { - id: faker.number.int({ min: undefined, max: undefined }), - name: faker.word.sample(), - ...overrideResponse, - }, + status: { id: faker.number.int({ min: undefined, max: undefined }), name: faker.word.sample() }, updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, ...overrideResponse, }) export const getAuthFacebookControllerLoginResponseMock = ( - overrideResponse: any = {} + overrideResponse: Partial = {} ): AuthEntity => ({ accessToken: faker.word.sample(), refreshToken: faker.word.sample(), @@ -70,7 +63,6 @@ export const getAuthFacebookControllerLoginResponseMock = ( termsAccepted: faker.datatype.boolean(), termsVersion: faker.word.sample(), updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, undefined, ]), @@ -83,24 +75,18 @@ export const getAuthFacebookControllerLoginResponseMock = ( locale: faker.word.sample(), provider: faker.word.sample(), role: { - id: faker.number.int({ min: undefined, max: undefined }), + id: faker.helpers.arrayElement([1, 2] as const), name: faker.helpers.arrayElement(['ADMIN', 'USER'] as const), - ...overrideResponse, }, socialId: faker.word.sample(), - status: { - id: faker.number.int({ min: undefined, max: undefined }), - name: faker.word.sample(), - ...overrideResponse, - }, + status: { id: faker.number.int({ min: undefined, max: undefined }), name: faker.word.sample() }, updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, ...overrideResponse, }) export const getAuthAppleControllerLoginResponseMock = ( - overrideResponse: any = {} + overrideResponse: Partial = {} ): AuthEntity => ({ accessToken: faker.word.sample(), refreshToken: faker.word.sample(), @@ -114,7 +100,6 @@ export const getAuthAppleControllerLoginResponseMock = ( termsAccepted: faker.datatype.boolean(), termsVersion: faker.word.sample(), updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, undefined, ]), @@ -127,69 +112,75 @@ export const getAuthAppleControllerLoginResponseMock = ( locale: faker.word.sample(), provider: faker.word.sample(), role: { - id: faker.number.int({ min: undefined, max: undefined }), + id: faker.helpers.arrayElement([1, 2] as const), name: faker.helpers.arrayElement(['ADMIN', 'USER'] as const), - ...overrideResponse, }, socialId: faker.word.sample(), - status: { - id: faker.number.int({ min: undefined, max: undefined }), - name: faker.word.sample(), - ...overrideResponse, - }, + status: { id: faker.number.int({ min: undefined, max: undefined }), name: faker.word.sample() }, updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, ...overrideResponse, }) -export const getAuthGoogleControllerLoginMockHandler = (overrideResponse?: AuthEntity) => { - return http.post('/api/v1/auth/google/login', async () => { +export const getAuthGoogleControllerLoginMockHandler = ( + overrideResponse?: + | AuthEntity + | ((info: Parameters[1]>[0]) => Promise | AuthEntity) +) => { + return http.post('*/api/v1/auth/google/login', async (info) => { await delay(1000) + return new HttpResponse( JSON.stringify( - overrideResponse ? overrideResponse : getAuthGoogleControllerLoginResponseMock() + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getAuthGoogleControllerLoginResponseMock() ), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + { status: 201, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getAuthFacebookControllerLoginMockHandler = (overrideResponse?: AuthEntity) => { - return http.post('/api/v1/auth/facebook/login', async () => { +export const getAuthFacebookControllerLoginMockHandler = ( + overrideResponse?: + | AuthEntity + | ((info: Parameters[1]>[0]) => Promise | AuthEntity) +) => { + return http.post('*/api/v1/auth/facebook/login', async (info) => { await delay(1000) + return new HttpResponse( JSON.stringify( - overrideResponse ? overrideResponse : getAuthFacebookControllerLoginResponseMock() + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getAuthFacebookControllerLoginResponseMock() ), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + { status: 201, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getAuthAppleControllerLoginMockHandler = (overrideResponse?: AuthEntity) => { - return http.post('/api/v1/auth/apple/login', async () => { +export const getAuthAppleControllerLoginMockHandler = ( + overrideResponse?: + | AuthEntity + | ((info: Parameters[1]>[0]) => Promise | AuthEntity) +) => { + return http.post('*/api/v1/auth/apple/login', async (info) => { await delay(1000) + return new HttpResponse( JSON.stringify( - overrideResponse ? overrideResponse : getAuthAppleControllerLoginResponseMock() + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getAuthAppleControllerLoginResponseMock() ), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + { status: 201, headers: { 'Content-Type': 'application/json' } } ) }) } diff --git a/src/api/query/auth-social/auth-social.ts b/src/api/query/auth-social/auth-social.ts index ad3ce63b..8b81010f 100644 --- a/src/api/query/auth-social/auth-social.ts +++ b/src/api/query/auth-social/auth-social.ts @@ -7,7 +7,7 @@ * OpenAPI spec version: 1.0 */ import { useMutation } from '@tanstack/react-query' -import type { MutationFunction, UseMutationOptions } from '@tanstack/react-query' +import type { MutationFunction, UseMutationOptions, UseMutationResult } from '@tanstack/react-query' import { customInstance } from '../../axios/custom-instance' import type { ErrorType, BodyType } from '../../axios/custom-instance' @@ -92,7 +92,12 @@ export const useAuthGoogleControllerLogin = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getAuthGoogleControllerLoginMutationOptions(options) return useMutation(mutationOptions) @@ -167,7 +172,12 @@ export const useAuthFacebookControllerLogin = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getAuthFacebookControllerLoginMutationOptions(options) return useMutation(mutationOptions) @@ -242,7 +252,12 @@ export const useAuthAppleControllerLogin = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getAuthAppleControllerLoginMutationOptions(options) return useMutation(mutationOptions) diff --git a/src/api/query/auth/auth.msw.ts b/src/api/query/auth/auth.msw.ts index 1df12bae..c4a0d116 100644 --- a/src/api/query/auth/auth.msw.ts +++ b/src/api/query/auth/auth.msw.ts @@ -11,7 +11,9 @@ import { HttpResponse, delay, http } from 'msw' import type { AuthEntity, RefreshEntity, UserEntity } from '../../types' -export const getAuthControllerLoginResponseMock = (overrideResponse: any = {}): AuthEntity => ({ +export const getAuthControllerLoginResponseMock = ( + overrideResponse: Partial = {} +): AuthEntity => ({ accessToken: faker.word.sample(), refreshToken: faker.word.sample(), tokenExpires: faker.number.int({ min: undefined, max: undefined }), @@ -24,7 +26,6 @@ export const getAuthControllerLoginResponseMock = (overrideResponse: any = {}): termsAccepted: faker.datatype.boolean(), termsVersion: faker.word.sample(), updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, undefined, ]), @@ -37,23 +38,19 @@ export const getAuthControllerLoginResponseMock = (overrideResponse: any = {}): locale: faker.word.sample(), provider: faker.word.sample(), role: { - id: faker.number.int({ min: undefined, max: undefined }), + id: faker.helpers.arrayElement([1, 2] as const), name: faker.helpers.arrayElement(['ADMIN', 'USER'] as const), - ...overrideResponse, }, socialId: faker.word.sample(), - status: { - id: faker.number.int({ min: undefined, max: undefined }), - name: faker.word.sample(), - ...overrideResponse, - }, + status: { id: faker.number.int({ min: undefined, max: undefined }), name: faker.word.sample() }, updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, ...overrideResponse, }) -export const getAuthControllerRegisterResponseMock = (overrideResponse: any = {}): UserEntity => ({ +export const getAuthControllerRegisterResponseMock = ( + overrideResponse: Partial = {} +): UserEntity => ({ consent: faker.helpers.arrayElement([ { createdAt: `${faker.date.past().toISOString().split('.')[0]}Z`, @@ -62,7 +59,6 @@ export const getAuthControllerRegisterResponseMock = (overrideResponse: any = {} termsAccepted: faker.datatype.boolean(), termsVersion: faker.word.sample(), updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, undefined, ]), @@ -75,21 +71,18 @@ export const getAuthControllerRegisterResponseMock = (overrideResponse: any = {} locale: faker.word.sample(), provider: faker.word.sample(), role: { - id: faker.number.int({ min: undefined, max: undefined }), + id: faker.helpers.arrayElement([1, 2] as const), name: faker.helpers.arrayElement(['ADMIN', 'USER'] as const), - ...overrideResponse, }, socialId: faker.word.sample(), - status: { - id: faker.number.int({ min: undefined, max: undefined }), - name: faker.word.sample(), - ...overrideResponse, - }, + status: { id: faker.number.int({ min: undefined, max: undefined }), name: faker.word.sample() }, updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, ...overrideResponse, }) -export const getAuthControllerMeResponseMock = (overrideResponse: any = {}): UserEntity => ({ +export const getAuthControllerMeResponseMock = ( + overrideResponse: Partial = {} +): UserEntity => ({ consent: faker.helpers.arrayElement([ { createdAt: `${faker.date.past().toISOString().split('.')[0]}Z`, @@ -98,7 +91,6 @@ export const getAuthControllerMeResponseMock = (overrideResponse: any = {}): Use termsAccepted: faker.datatype.boolean(), termsVersion: faker.word.sample(), updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, undefined, ]), @@ -111,22 +103,17 @@ export const getAuthControllerMeResponseMock = (overrideResponse: any = {}): Use locale: faker.word.sample(), provider: faker.word.sample(), role: { - id: faker.number.int({ min: undefined, max: undefined }), + id: faker.helpers.arrayElement([1, 2] as const), name: faker.helpers.arrayElement(['ADMIN', 'USER'] as const), - ...overrideResponse, }, socialId: faker.word.sample(), - status: { - id: faker.number.int({ min: undefined, max: undefined }), - name: faker.word.sample(), - ...overrideResponse, - }, + status: { id: faker.number.int({ min: undefined, max: undefined }), name: faker.word.sample() }, updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, ...overrideResponse, }) export const getAuthControllerRefreshResponseMock = ( - overrideResponse: any = {} + overrideResponse: Partial = {} ): RefreshEntity => ({ accessToken: faker.word.sample(), refreshToken: faker.word.sample(), @@ -134,183 +121,229 @@ export const getAuthControllerRefreshResponseMock = ( ...overrideResponse, }) -export const getAuthControllerLoginMockHandler = (overrideResponse?: AuthEntity) => { - return http.post('/api/v1/auth/email/login', async () => { +export const getAuthControllerLoginMockHandler = ( + overrideResponse?: + | AuthEntity + | ((info: Parameters[1]>[0]) => Promise | AuthEntity) +) => { + return http.post('*/api/v1/auth/email/login', async (info) => { await delay(1000) + return new HttpResponse( - JSON.stringify(overrideResponse ? overrideResponse : getAuthControllerLoginResponseMock()), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + JSON.stringify( + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getAuthControllerLoginResponseMock() + ), + { status: 201, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getAuthControllerRegisterMockHandler = (overrideResponse?: UserEntity) => { - return http.post('/api/v1/auth/email/register', async () => { +export const getAuthControllerRegisterMockHandler = ( + overrideResponse?: + | UserEntity + | ((info: Parameters[1]>[0]) => Promise | UserEntity) +) => { + return http.post('*/api/v1/auth/email/register', async (info) => { await delay(1000) + return new HttpResponse( - JSON.stringify(overrideResponse ? overrideResponse : getAuthControllerRegisterResponseMock()), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + JSON.stringify( + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getAuthControllerRegisterResponseMock() + ), + { status: 201, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getAuthControllerConfirmEmailMockHandler = () => { - return http.post('/api/v1/auth/email/confirm', async () => { +export const getAuthControllerConfirmEmailMockHandler = ( + overrideResponse?: + | unknown + | ((info: Parameters[1]>[0]) => Promise | unknown) +) => { + return http.post('*/api/v1/auth/email/confirm', async (info) => { await delay(1000) - return new HttpResponse(null, { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }) + if (typeof overrideResponse === 'function') { + await overrideResponse(info) + } + return new HttpResponse(null, { status: 200 }) }) } -export const getAuthControllerResendVerificationEmailMockHandler = () => { - return http.post('/api/v1/auth/email/resend', async () => { +export const getAuthControllerResendVerificationEmailMockHandler = ( + overrideResponse?: + | unknown + | ((info: Parameters[1]>[0]) => Promise | unknown) +) => { + return http.post('*/api/v1/auth/email/resend', async (info) => { await delay(1000) - return new HttpResponse(null, { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }) + if (typeof overrideResponse === 'function') { + await overrideResponse(info) + } + return new HttpResponse(null, { status: 200 }) }) } -export const getAuthControllerForgotPasswordMockHandler = () => { - return http.post('/api/v1/auth/forgot/password', async () => { +export const getAuthControllerForgotPasswordMockHandler = ( + overrideResponse?: + | unknown + | ((info: Parameters[1]>[0]) => Promise | unknown) +) => { + return http.post('*/api/v1/auth/forgot/password', async (info) => { await delay(1000) - return new HttpResponse(null, { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }) + if (typeof overrideResponse === 'function') { + await overrideResponse(info) + } + return new HttpResponse(null, { status: 200 }) }) } -export const getAuthControllerResetPasswordMockHandler = () => { - return http.post('/api/v1/auth/reset/password', async () => { +export const getAuthControllerResetPasswordMockHandler = ( + overrideResponse?: + | unknown + | ((info: Parameters[1]>[0]) => Promise | unknown) +) => { + return http.post('*/api/v1/auth/reset/password', async (info) => { await delay(1000) - return new HttpResponse(null, { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }) + if (typeof overrideResponse === 'function') { + await overrideResponse(info) + } + return new HttpResponse(null, { status: 200 }) }) } -export const getAuthControllerEmailChangeMockHandler = () => { - return http.post('/api/v1/auth/email/change', async () => { +export const getAuthControllerEmailChangeMockHandler = ( + overrideResponse?: + | unknown + | ((info: Parameters[1]>[0]) => Promise | unknown) +) => { + return http.post('*/api/v1/auth/email/change', async (info) => { await delay(1000) - return new HttpResponse(null, { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }) + if (typeof overrideResponse === 'function') { + await overrideResponse(info) + } + return new HttpResponse(null, { status: 200 }) }) } -export const getAuthControllerConfirmEmailChangeMockHandler = () => { - return http.post('/api/v1/auth/email/change-confirm', async () => { +export const getAuthControllerConfirmEmailChangeMockHandler = ( + overrideResponse?: + | unknown + | ((info: Parameters[1]>[0]) => Promise | unknown) +) => { + return http.post('*/api/v1/auth/email/change-confirm', async (info) => { await delay(1000) - return new HttpResponse(null, { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }) + if (typeof overrideResponse === 'function') { + await overrideResponse(info) + } + return new HttpResponse(null, { status: 200 }) }) } -export const getAuthControllerMeMockHandler = (overrideResponse?: UserEntity) => { - return http.get('/api/v1/auth/me', async () => { +export const getAuthControllerMeMockHandler = ( + overrideResponse?: + | UserEntity + | ((info: Parameters[1]>[0]) => Promise | UserEntity) +) => { + return http.get('*/api/v1/auth/me', async (info) => { await delay(1000) + return new HttpResponse( - JSON.stringify(overrideResponse ? overrideResponse : getAuthControllerMeResponseMock()), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + JSON.stringify( + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getAuthControllerMeResponseMock() + ), + { status: 201, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getAuthControllerUpdateMockHandler = () => { - return http.patch('/api/v1/auth/me', async () => { +export const getAuthControllerUpdateMockHandler = ( + overrideResponse?: + | unknown + | ((info: Parameters[1]>[0]) => Promise | unknown) +) => { + return http.patch('*/api/v1/auth/me', async (info) => { await delay(1000) - return new HttpResponse(null, { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }) + if (typeof overrideResponse === 'function') { + await overrideResponse(info) + } + return new HttpResponse(null, { status: 200 }) }) } -export const getAuthControllerDeleteMockHandler = () => { - return http.delete('/api/v1/auth/me', async () => { +export const getAuthControllerDeleteMockHandler = ( + overrideResponse?: + | unknown + | ((info: Parameters[1]>[0]) => Promise | unknown) +) => { + return http.delete('*/api/v1/auth/me', async (info) => { await delay(1000) - return new HttpResponse(null, { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }) + if (typeof overrideResponse === 'function') { + await overrideResponse(info) + } + return new HttpResponse(null, { status: 200 }) }) } -export const getAuthControllerRefreshMockHandler = (overrideResponse?: RefreshEntity) => { - return http.post('/api/v1/auth/refresh', async () => { +export const getAuthControllerRefreshMockHandler = ( + overrideResponse?: + | RefreshEntity + | (( + info: Parameters[1]>[0] + ) => Promise | RefreshEntity) +) => { + return http.post('*/api/v1/auth/refresh', async (info) => { await delay(1000) + return new HttpResponse( - JSON.stringify(overrideResponse ? overrideResponse : getAuthControllerRefreshResponseMock()), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + JSON.stringify( + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getAuthControllerRefreshResponseMock() + ), + { status: 201, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getAuthControllerLogoutMockHandler = () => { - return http.post('/api/v1/auth/logout', async () => { +export const getAuthControllerLogoutMockHandler = ( + overrideResponse?: + | unknown + | ((info: Parameters[1]>[0]) => Promise | unknown) +) => { + return http.post('*/api/v1/auth/logout', async (info) => { await delay(1000) - return new HttpResponse(null, { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }) + if (typeof overrideResponse === 'function') { + await overrideResponse(info) + } + return new HttpResponse(null, { status: 200 }) }) } -export const getAuthControllerLogoutAllMockHandler = () => { - return http.post('/api/v1/auth/logout/all', async () => { +export const getAuthControllerLogoutAllMockHandler = ( + overrideResponse?: + | unknown + | ((info: Parameters[1]>[0]) => Promise | unknown) +) => { + return http.post('*/api/v1/auth/logout/all', async (info) => { await delay(1000) - return new HttpResponse(null, { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }) + if (typeof overrideResponse === 'function') { + await overrideResponse(info) + } + return new HttpResponse(null, { status: 200 }) }) } export const getAuthMock = () => [ diff --git a/src/api/query/auth/auth.ts b/src/api/query/auth/auth.ts index cb0b353a..ed28a70e 100644 --- a/src/api/query/auth/auth.ts +++ b/src/api/query/auth/auth.ts @@ -12,6 +12,7 @@ import type { QueryFunction, QueryKey, UseMutationOptions, + UseMutationResult, UseQueryOptions, UseQueryResult, } from '@tanstack/react-query' @@ -128,7 +129,12 @@ export const useAuthControllerLogin = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getAuthControllerLoginMutationOptions(options) return useMutation(mutationOptions) @@ -205,7 +211,12 @@ export const useAuthControllerRegister = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getAuthControllerRegisterMutationOptions(options) return useMutation(mutationOptions) @@ -282,7 +293,12 @@ export const useAuthControllerConfirmEmail = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getAuthControllerConfirmEmailMutationOptions(options) return useMutation(mutationOptions) @@ -364,7 +380,12 @@ export const useAuthControllerResendVerificationEmail = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getAuthControllerResendVerificationEmailMutationOptions(options) return useMutation(mutationOptions) @@ -445,7 +466,12 @@ export const useAuthControllerForgotPassword = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getAuthControllerForgotPasswordMutationOptions(options) return useMutation(mutationOptions) @@ -526,7 +552,12 @@ export const useAuthControllerResetPassword = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getAuthControllerResetPasswordMutationOptions(options) return useMutation(mutationOptions) @@ -607,7 +638,12 @@ export const useAuthControllerEmailChange = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getAuthControllerEmailChangeMutationOptions(options) return useMutation(mutationOptions) @@ -684,7 +720,12 @@ export const useAuthControllerConfirmEmailChange = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getAuthControllerConfirmEmailChangeMutationOptions(options) return useMutation(mutationOptions) @@ -731,13 +772,14 @@ export type AuthControllerMeQueryError = ErrorType>, TError = ErrorType >(options?: { query?: UseQueryOptions>, TError, TData> request?: SecondParameter -}): UseQueryResult & { queryKey: QueryKey } => { +}): UseQueryResult & { queryKey: QueryKey } { const queryOptions = getAuthControllerMeQueryOptions(options) const query = useQuery(queryOptions) as UseQueryResult & { queryKey: QueryKey } @@ -819,7 +861,12 @@ export const useAuthControllerUpdate = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getAuthControllerUpdateMutationOptions(options) return useMutation(mutationOptions) @@ -883,7 +930,7 @@ export const useAuthControllerDelete = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult>, TError, void, TContext> => { const mutationOptions = getAuthControllerDeleteMutationOptions(options) return useMutation(mutationOptions) @@ -947,7 +994,12 @@ export const useAuthControllerRefresh = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + void, + TContext +> => { const mutationOptions = getAuthControllerRefreshMutationOptions(options) return useMutation(mutationOptions) @@ -1011,7 +1063,7 @@ export const useAuthControllerLogout = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult>, TError, void, TContext> => { const mutationOptions = getAuthControllerLogoutMutationOptions(options) return useMutation(mutationOptions) @@ -1075,7 +1127,12 @@ export const useAuthControllerLogoutAll = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + void, + TContext +> => { const mutationOptions = getAuthControllerLogoutAllMutationOptions(options) return useMutation(mutationOptions) diff --git a/src/api/query/files/files.msw.ts b/src/api/query/files/files.msw.ts index cc5c50b2..d5797d52 100644 --- a/src/api/query/files/files.msw.ts +++ b/src/api/query/files/files.msw.ts @@ -12,7 +12,7 @@ import { HttpResponse, delay, http } from 'msw' import type { FileEntity } from '../../types' export const getFilesControllerUploadFileResponseMock = ( - overrideResponse: any = {} + overrideResponse: Partial = {} ): FileEntity => ({ category: faker.helpers.arrayElement([faker.word.sample(), null]), createdAt: `${faker.date.past().toISOString().split('.')[0]}Z`, @@ -25,44 +25,52 @@ export const getFilesControllerUploadFileResponseMock = ( ...overrideResponse, }) -export const getFilesControllerUploadFileMockHandler = (overrideResponse?: FileEntity) => { - return http.post('/api/v1/files/upload', async () => { +export const getFilesControllerUploadFileMockHandler = ( + overrideResponse?: + | FileEntity + | ((info: Parameters[1]>[0]) => Promise | FileEntity) +) => { + return http.post('*/api/v1/files/upload', async (info) => { await delay(1000) + return new HttpResponse( JSON.stringify( - overrideResponse ? overrideResponse : getFilesControllerUploadFileResponseMock() + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getFilesControllerUploadFileResponseMock() ), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + { status: 201, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getFilesControllerDownloadMockHandler = () => { - return http.get('/api/v1/files/:fileName', async () => { +export const getFilesControllerDownloadMockHandler = ( + overrideResponse?: + | unknown + | ((info: Parameters[1]>[0]) => Promise | unknown) +) => { + return http.get('*/api/v1/files/:fileName', async (info) => { await delay(1000) - return new HttpResponse(null, { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }) + if (typeof overrideResponse === 'function') { + await overrideResponse(info) + } + return new HttpResponse(null, { status: 200 }) }) } -export const getFilesControllerDeleteFileMockHandler = () => { - return http.delete('/api/v1/files/:fileName', async () => { +export const getFilesControllerDeleteFileMockHandler = ( + overrideResponse?: + | unknown + | ((info: Parameters[1]>[0]) => Promise | unknown) +) => { + return http.delete('*/api/v1/files/:fileName', async (info) => { await delay(1000) - return new HttpResponse(null, { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - }) + if (typeof overrideResponse === 'function') { + await overrideResponse(info) + } + return new HttpResponse(null, { status: 200 }) }) } export const getFilesMock = () => [ diff --git a/src/api/query/files/files.ts b/src/api/query/files/files.ts index 0808d73c..994405c8 100644 --- a/src/api/query/files/files.ts +++ b/src/api/query/files/files.ts @@ -12,6 +12,7 @@ import type { QueryFunction, QueryKey, UseMutationOptions, + UseMutationResult, UseQueryOptions, UseQueryResult, } from '@tanstack/react-query' @@ -100,7 +101,12 @@ export const useFilesControllerUploadFile = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getFilesControllerUploadFileMutationOptions(options) return useMutation(mutationOptions) @@ -157,7 +163,8 @@ export type FilesControllerDownloadQueryError = ErrorType /** * @summary Download File */ -export const useFilesControllerDownload = < + +export function useFilesControllerDownload< TData = Awaited>, TError = ErrorType >( @@ -166,7 +173,7 @@ export const useFilesControllerDownload = < query?: UseQueryOptions>, TError, TData> request?: SecondParameter } -): UseQueryResult & { queryKey: QueryKey } => { +): UseQueryResult & { queryKey: QueryKey } { const queryOptions = getFilesControllerDownloadQueryOptions(fileName, options) const query = useQuery(queryOptions) as UseQueryResult & { queryKey: QueryKey } @@ -238,7 +245,12 @@ export const useFilesControllerDeleteFile = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { fileName: string }, + TContext +> => { const mutationOptions = getFilesControllerDeleteFileMutationOptions(options) return useMutation(mutationOptions) diff --git a/src/api/query/health/health.msw.ts b/src/api/query/health/health.msw.ts index 529a0188..9c733f36 100644 --- a/src/api/query/health/health.msw.ts +++ b/src/api/query/health/health.msw.ts @@ -11,35 +11,43 @@ import { HttpResponse, delay, http } from 'msw' import type { HealthEntity } from '../../types' -export const getHealthControllerCheckResponseMock = (overrideResponse: any = {}): HealthEntity => ({ +export const getHealthControllerCheckResponseMock = ( + overrideResponse: Partial = {} +): HealthEntity => ({ details: { - cache: { status: faker.word.sample(), ...overrideResponse }, - db: { status: faker.word.sample(), ...overrideResponse }, - domain: { status: faker.word.sample(), ...overrideResponse }, - ...overrideResponse, + cache: { status: faker.word.sample() }, + db: { status: faker.word.sample() }, + domain: { status: faker.word.sample() }, }, error: {}, info: { - cache: { status: faker.word.sample(), ...overrideResponse }, - db: { status: faker.word.sample(), ...overrideResponse }, - domain: { status: faker.word.sample(), ...overrideResponse }, - ...overrideResponse, + cache: { status: faker.word.sample() }, + db: { status: faker.word.sample() }, + domain: { status: faker.word.sample() }, }, status: faker.word.sample(), ...overrideResponse, }) -export const getHealthControllerCheckMockHandler = (overrideResponse?: HealthEntity) => { - return http.get('/api/v1/health', async () => { +export const getHealthControllerCheckMockHandler = ( + overrideResponse?: + | HealthEntity + | (( + info: Parameters[1]>[0] + ) => Promise | HealthEntity) +) => { + return http.get('*/api/v1/health', async (info) => { await delay(1000) + return new HttpResponse( - JSON.stringify(overrideResponse ? overrideResponse : getHealthControllerCheckResponseMock()), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + JSON.stringify( + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getHealthControllerCheckResponseMock() + ), + { status: 200, headers: { 'Content-Type': 'application/json' } } ) }) } diff --git a/src/api/query/health/health.ts b/src/api/query/health/health.ts index 1ee684fe..89e5529e 100644 --- a/src/api/query/health/health.ts +++ b/src/api/query/health/health.ts @@ -64,13 +64,14 @@ export type HealthControllerCheckQueryError = ErrorType /** * @summary Check Health */ -export const useHealthControllerCheck = < + +export function useHealthControllerCheck< TData = Awaited>, TError = ErrorType >(options?: { query?: UseQueryOptions>, TError, TData> request?: SecondParameter -}): UseQueryResult & { queryKey: QueryKey } => { +}): UseQueryResult & { queryKey: QueryKey } { const queryOptions = getHealthControllerCheckQueryOptions(options) const query = useQuery(queryOptions) as UseQueryResult & { queryKey: QueryKey } diff --git a/src/api/query/system/system.msw.ts b/src/api/query/system/system.msw.ts index ccddfb95..e80fe451 100644 --- a/src/api/query/system/system.msw.ts +++ b/src/api/query/system/system.msw.ts @@ -12,7 +12,7 @@ import { HttpResponse, delay, http } from 'msw' import type { AppVersionStatusEntity } from '../../types' export const getSystemControllerCheckForAppUpdateResponseMock = ( - overrideResponse: any = {} + overrideResponse: Partial = {} ): AppVersionStatusEntity => ({ appId: faker.word.sample(), currentVersionReleaseDate: `${faker.date.past().toISOString().split('.')[0]}Z`, @@ -23,20 +23,24 @@ export const getSystemControllerCheckForAppUpdateResponseMock = ( }) export const getSystemControllerCheckForAppUpdateMockHandler = ( - overrideResponse?: AppVersionStatusEntity + overrideResponse?: + | AppVersionStatusEntity + | (( + info: Parameters[1]>[0] + ) => Promise | AppVersionStatusEntity) ) => { - return http.post('*/api/v1/system/app-updates/check', async () => { + return http.post('*/api/v1/system/app-updates/check', async (info) => { await delay(1000) + return new HttpResponse( JSON.stringify( - overrideResponse ? overrideResponse : getSystemControllerCheckForAppUpdateResponseMock() + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getSystemControllerCheckForAppUpdateResponseMock() ), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + { status: 201, headers: { 'Content-Type': 'application/json' } } ) }) } diff --git a/src/api/query/system/system.ts b/src/api/query/system/system.ts index 76c5752d..360ee339 100644 --- a/src/api/query/system/system.ts +++ b/src/api/query/system/system.ts @@ -7,7 +7,7 @@ * OpenAPI spec version: 1.0 */ import { useMutation } from '@tanstack/react-query' -import type { MutationFunction, UseMutationOptions } from '@tanstack/react-query' +import type { MutationFunction, UseMutationOptions, UseMutationResult } from '@tanstack/react-query' import { customInstance } from '../../axios/custom-instance' import type { ErrorType, BodyType } from '../../axios/custom-instance' @@ -86,7 +86,12 @@ export const useSystemControllerCheckForAppUpdate = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getSystemControllerCheckForAppUpdateMutationOptions(options) return useMutation(mutationOptions) diff --git a/src/api/query/users/users.msw.ts b/src/api/query/users/users.msw.ts index 6e86e5ac..6a408915 100644 --- a/src/api/query/users/users.msw.ts +++ b/src/api/query/users/users.msw.ts @@ -11,7 +11,9 @@ import { HttpResponse, delay, http } from 'msw' import type { UserEntity } from '../../types' -export const getUsersControllerCreateResponseMock = (overrideResponse: any = {}): UserEntity => ({ +export const getUsersControllerCreateResponseMock = ( + overrideResponse: Partial = {} +): UserEntity => ({ consent: faker.helpers.arrayElement([ { createdAt: `${faker.date.past().toISOString().split('.')[0]}Z`, @@ -20,7 +22,6 @@ export const getUsersControllerCreateResponseMock = (overrideResponse: any = {}) termsAccepted: faker.datatype.boolean(), termsVersion: faker.word.sample(), updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, undefined, ]), @@ -33,21 +34,16 @@ export const getUsersControllerCreateResponseMock = (overrideResponse: any = {}) locale: faker.word.sample(), provider: faker.word.sample(), role: { - id: faker.number.int({ min: undefined, max: undefined }), + id: faker.helpers.arrayElement([1, 2] as const), name: faker.helpers.arrayElement(['ADMIN', 'USER'] as const), - ...overrideResponse, }, socialId: faker.word.sample(), - status: { - id: faker.number.int({ min: undefined, max: undefined }), - name: faker.word.sample(), - ...overrideResponse, - }, + status: { id: faker.number.int({ min: undefined, max: undefined }), name: faker.word.sample() }, updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, ...overrideResponse, }) -export const getUsersControllerFindAllResponseMock = (overrideResponse: any = {}): UserEntity[] => +export const getUsersControllerFindAllResponseMock = (): UserEntity[] => Array.from({ length: faker.number.int({ min: 1, max: 10 }) }, (_, i) => i + 1).map(() => ({ consent: faker.helpers.arrayElement([ { @@ -57,7 +53,6 @@ export const getUsersControllerFindAllResponseMock = (overrideResponse: any = {} termsAccepted: faker.datatype.boolean(), termsVersion: faker.word.sample(), updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, undefined, ]), @@ -70,21 +65,17 @@ export const getUsersControllerFindAllResponseMock = (overrideResponse: any = {} locale: faker.word.sample(), provider: faker.word.sample(), role: { - id: faker.number.int({ min: undefined, max: undefined }), + id: faker.helpers.arrayElement([1, 2] as const), name: faker.helpers.arrayElement(['ADMIN', 'USER'] as const), - ...overrideResponse, }, socialId: faker.word.sample(), - status: { - id: faker.number.int({ min: undefined, max: undefined }), - name: faker.word.sample(), - ...overrideResponse, - }, + status: { id: faker.number.int({ min: undefined, max: undefined }), name: faker.word.sample() }, updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, })) -export const getUsersControllerFindOneResponseMock = (overrideResponse: any = {}): UserEntity => ({ +export const getUsersControllerFindOneResponseMock = ( + overrideResponse: Partial = {} +): UserEntity => ({ consent: faker.helpers.arrayElement([ { createdAt: `${faker.date.past().toISOString().split('.')[0]}Z`, @@ -93,7 +84,6 @@ export const getUsersControllerFindOneResponseMock = (overrideResponse: any = {} termsAccepted: faker.datatype.boolean(), termsVersion: faker.word.sample(), updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, undefined, ]), @@ -106,21 +96,18 @@ export const getUsersControllerFindOneResponseMock = (overrideResponse: any = {} locale: faker.word.sample(), provider: faker.word.sample(), role: { - id: faker.number.int({ min: undefined, max: undefined }), + id: faker.helpers.arrayElement([1, 2] as const), name: faker.helpers.arrayElement(['ADMIN', 'USER'] as const), - ...overrideResponse, }, socialId: faker.word.sample(), - status: { - id: faker.number.int({ min: undefined, max: undefined }), - name: faker.word.sample(), - ...overrideResponse, - }, + status: { id: faker.number.int({ min: undefined, max: undefined }), name: faker.word.sample() }, updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, ...overrideResponse, }) -export const getUsersControllerUpdateResponseMock = (overrideResponse: any = {}): UserEntity => ({ +export const getUsersControllerUpdateResponseMock = ( + overrideResponse: Partial = {} +): UserEntity => ({ consent: faker.helpers.arrayElement([ { createdAt: `${faker.date.past().toISOString().split('.')[0]}Z`, @@ -129,7 +116,6 @@ export const getUsersControllerUpdateResponseMock = (overrideResponse: any = {}) termsAccepted: faker.datatype.boolean(), termsVersion: faker.word.sample(), updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, undefined, ]), @@ -142,21 +128,18 @@ export const getUsersControllerUpdateResponseMock = (overrideResponse: any = {}) locale: faker.word.sample(), provider: faker.word.sample(), role: { - id: faker.number.int({ min: undefined, max: undefined }), + id: faker.helpers.arrayElement([1, 2] as const), name: faker.helpers.arrayElement(['ADMIN', 'USER'] as const), - ...overrideResponse, }, socialId: faker.word.sample(), - status: { - id: faker.number.int({ min: undefined, max: undefined }), - name: faker.word.sample(), - ...overrideResponse, - }, + status: { id: faker.number.int({ min: undefined, max: undefined }), name: faker.word.sample() }, updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, ...overrideResponse, }) -export const getUsersControllerRemoveResponseMock = (overrideResponse: any = {}): UserEntity => ({ +export const getUsersControllerRemoveResponseMock = ( + overrideResponse: Partial = {} +): UserEntity => ({ consent: faker.helpers.arrayElement([ { createdAt: `${faker.date.past().toISOString().split('.')[0]}Z`, @@ -165,7 +148,6 @@ export const getUsersControllerRemoveResponseMock = (overrideResponse: any = {}) termsAccepted: faker.datatype.boolean(), termsVersion: faker.word.sample(), updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, - ...overrideResponse, }, undefined, ]), @@ -178,91 +160,118 @@ export const getUsersControllerRemoveResponseMock = (overrideResponse: any = {}) locale: faker.word.sample(), provider: faker.word.sample(), role: { - id: faker.number.int({ min: undefined, max: undefined }), + id: faker.helpers.arrayElement([1, 2] as const), name: faker.helpers.arrayElement(['ADMIN', 'USER'] as const), - ...overrideResponse, }, socialId: faker.word.sample(), - status: { - id: faker.number.int({ min: undefined, max: undefined }), - name: faker.word.sample(), - ...overrideResponse, - }, + status: { id: faker.number.int({ min: undefined, max: undefined }), name: faker.word.sample() }, updatedAt: `${faker.date.past().toISOString().split('.')[0]}Z`, ...overrideResponse, }) -export const getUsersControllerCreateMockHandler = (overrideResponse?: UserEntity) => { - return http.post('/api/v1/users', async () => { +export const getUsersControllerCreateMockHandler = ( + overrideResponse?: + | UserEntity + | ((info: Parameters[1]>[0]) => Promise | UserEntity) +) => { + return http.post('*/api/v1/users', async (info) => { await delay(1000) + return new HttpResponse( - JSON.stringify(overrideResponse ? overrideResponse : getUsersControllerCreateResponseMock()), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + JSON.stringify( + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getUsersControllerCreateResponseMock() + ), + { status: 201, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getUsersControllerFindAllMockHandler = (overrideResponse?: UserEntity[]) => { - return http.get('/api/v1/users', async () => { +export const getUsersControllerFindAllMockHandler = ( + overrideResponse?: + | UserEntity[] + | (( + info: Parameters[1]>[0] + ) => Promise | UserEntity[]) +) => { + return http.get('*/api/v1/users', async (info) => { await delay(1000) + return new HttpResponse( - JSON.stringify(overrideResponse ? overrideResponse : getUsersControllerFindAllResponseMock()), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + JSON.stringify( + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getUsersControllerFindAllResponseMock() + ), + { status: 200, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getUsersControllerFindOneMockHandler = (overrideResponse?: UserEntity) => { - return http.get('/api/v1/users/:id', async () => { +export const getUsersControllerFindOneMockHandler = ( + overrideResponse?: + | UserEntity + | ((info: Parameters[1]>[0]) => Promise | UserEntity) +) => { + return http.get('*/api/v1/users/:id', async (info) => { await delay(1000) + return new HttpResponse( - JSON.stringify(overrideResponse ? overrideResponse : getUsersControllerFindOneResponseMock()), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + JSON.stringify( + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getUsersControllerFindOneResponseMock() + ), + { status: 200, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getUsersControllerUpdateMockHandler = (overrideResponse?: UserEntity) => { - return http.patch('/api/v1/users/:id', async () => { +export const getUsersControllerUpdateMockHandler = ( + overrideResponse?: + | UserEntity + | ((info: Parameters[1]>[0]) => Promise | UserEntity) +) => { + return http.patch('*/api/v1/users/:id', async (info) => { await delay(1000) + return new HttpResponse( - JSON.stringify(overrideResponse ? overrideResponse : getUsersControllerUpdateResponseMock()), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + JSON.stringify( + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getUsersControllerUpdateResponseMock() + ), + { status: 201, headers: { 'Content-Type': 'application/json' } } ) }) } -export const getUsersControllerRemoveMockHandler = (overrideResponse?: UserEntity) => { - return http.delete('/api/v1/users/:id', async () => { +export const getUsersControllerRemoveMockHandler = ( + overrideResponse?: + | UserEntity + | ((info: Parameters[1]>[0]) => Promise | UserEntity) +) => { + return http.delete('*/api/v1/users/:id', async (info) => { await delay(1000) + return new HttpResponse( - JSON.stringify(overrideResponse ? overrideResponse : getUsersControllerRemoveResponseMock()), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - }, - } + JSON.stringify( + overrideResponse !== undefined + ? typeof overrideResponse === 'function' + ? await overrideResponse(info) + : overrideResponse + : getUsersControllerRemoveResponseMock() + ), + { status: 200, headers: { 'Content-Type': 'application/json' } } ) }) } diff --git a/src/api/query/users/users.ts b/src/api/query/users/users.ts index 952dc8e7..d9890d17 100644 --- a/src/api/query/users/users.ts +++ b/src/api/query/users/users.ts @@ -12,6 +12,7 @@ import type { QueryFunction, QueryKey, UseMutationOptions, + UseMutationResult, UseQueryOptions, UseQueryResult, } from '@tanstack/react-query' @@ -107,7 +108,12 @@ export const useUsersControllerCreate = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { data: BodyType }, + TContext +> => { const mutationOptions = getUsersControllerCreateMutationOptions(options) return useMutation(mutationOptions) @@ -165,7 +171,8 @@ export type UsersControllerFindAllQueryError = ErrorType< /** * @summary Find All Users */ -export const useUsersControllerFindAll = < + +export function useUsersControllerFindAll< TData = Awaited>, TError = ErrorType >( @@ -174,7 +181,7 @@ export const useUsersControllerFindAll = < query?: UseQueryOptions>, TError, TData> request?: SecondParameter } -): UseQueryResult & { queryKey: QueryKey } => { +): UseQueryResult & { queryKey: QueryKey } { const queryOptions = getUsersControllerFindAllQueryOptions(params, options) const query = useQuery(queryOptions) as UseQueryResult & { queryKey: QueryKey } @@ -234,7 +241,8 @@ export type UsersControllerFindOneQueryError = ErrorType< /** * @summary Find User by ID */ -export const useUsersControllerFindOne = < + +export function useUsersControllerFindOne< TData = Awaited>, TError = ErrorType >( @@ -243,7 +251,7 @@ export const useUsersControllerFindOne = < query?: UseQueryOptions>, TError, TData> request?: SecondParameter } -): UseQueryResult & { queryKey: QueryKey } => { +): UseQueryResult & { queryKey: QueryKey } { const queryOptions = getUsersControllerFindOneQueryOptions(id, options) const query = useQuery(queryOptions) as UseQueryResult & { queryKey: QueryKey } @@ -326,7 +334,12 @@ export const useUsersControllerUpdate = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { id: string; data: BodyType }, + TContext +> => { const mutationOptions = getUsersControllerUpdateMutationOptions(options) return useMutation(mutationOptions) @@ -395,7 +408,12 @@ export const useUsersControllerRemove = < TContext > request?: SecondParameter -}) => { +}): UseMutationResult< + Awaited>, + TError, + { id: string }, + TContext +> => { const mutationOptions = getUsersControllerRemoveMutationOptions(options) return useMutation(mutationOptions) diff --git a/src/api/types/articleEntity.ts b/src/api/types/articleEntity.ts index 13c4eabd..1368844e 100644 --- a/src/api/types/articleEntity.ts +++ b/src/api/types/articleEntity.ts @@ -10,10 +10,12 @@ import type { AuthorPublicDto } from './authorPublicDto' export interface ArticleEntity { author: AuthorPublicDto + /** @nullable */ authorId?: string | null body: string createdAt: string deletedAt: string + /** @nullable */ description?: string | null id: number published: boolean diff --git a/src/api/types/fileEntity.ts b/src/api/types/fileEntity.ts index 39be0464..fe411a26 100644 --- a/src/api/types/fileEntity.ts +++ b/src/api/types/fileEntity.ts @@ -8,7 +8,10 @@ */ export interface FileEntity { - /** Category of the file */ + /** + * Category of the file + * @nullable + */ category: string | null /** Creation date of the file */ createdAt: string diff --git a/src/api/types/healthEntityError.ts b/src/api/types/healthEntityError.ts index 821b8468..872f0387 100644 --- a/src/api/types/healthEntityError.ts +++ b/src/api/types/healthEntityError.ts @@ -10,4 +10,4 @@ /** * Details of any errors encountered during the health check */ -export type HealthEntityError = { [key: string]: any } +export type HealthEntityError = { [key: string]: unknown } diff --git a/src/components/molecules/Field/CheckboxGroup.tsx b/src/components/molecules/Field/CheckboxGroup.tsx index c74a2b0c..68e99f01 100644 --- a/src/components/molecules/Field/CheckboxGroup.tsx +++ b/src/components/molecules/Field/CheckboxGroup.tsx @@ -1,11 +1,5 @@ -import { - Box, - CheckboxButton, - FormErrorMessage, - FormLabel, - Spacer, -} from '@baca/design-system/components' -import { Fragment, useMemo } from 'react' +import { Box, CheckboxButton, FormErrorMessage, FormLabel } from '@baca/design-system/components' +import { useMemo } from 'react' import { FieldCheckboxGroupProps } from './types' @@ -36,24 +30,21 @@ export const CheckboxGroup = ({ } return ( - - - - + ) }) }, [items, selectedItems, props, onSelectItem]) return ( - + {renderCheckboxes} diff --git a/src/components/molecules/Field/Input.tsx b/src/components/molecules/Field/Input.tsx index 648199ed..22d3f9cd 100644 --- a/src/components/molecules/Field/Input.tsx +++ b/src/components/molecules/Field/Input.tsx @@ -5,7 +5,7 @@ import { Box, } from '@baca/design-system/components' import { forwardRef, useCallback, useImperativeHandle, useRef, useMemo } from 'react' -import { NativeSyntheticEvent, Pressable, TextInput, TextInputFocusEventData } from 'react-native' +import { NativeSyntheticEvent, TextInput, TextInputFocusEventData } from 'react-native' import type { FieldInputProps } from './types' @@ -47,6 +47,7 @@ export const Input = forwardRef, FieldInputProps>( labelStyle, onBlur, onFocus, + testID, ...props }, ref @@ -88,16 +89,19 @@ export const Input = forwardRef, FieldInputProps>( ) return ( - - - - - - + + + + ) } diff --git a/src/components/molecules/Field/RadioGroup.tsx b/src/components/molecules/Field/RadioGroup.tsx index 1ea51de0..5c6615c3 100644 --- a/src/components/molecules/Field/RadioGroup.tsx +++ b/src/components/molecules/Field/RadioGroup.tsx @@ -27,7 +27,6 @@ export const RadioGroup = ({ isError={isError} isSelected={item.value === selectedItem} onChange={() => onSelectItem(item.value)} - pb={2} label={item.label} size={size} /> @@ -37,7 +36,7 @@ export const RadioGroup = ({ ) return ( - + {renderRadioButtons} diff --git a/src/components/molecules/Field/Select.tsx b/src/components/molecules/Field/Select.tsx index d8aee5df..efa35149 100644 --- a/src/components/molecules/Field/Select.tsx +++ b/src/components/molecules/Field/Select.tsx @@ -7,7 +7,6 @@ import { } from '@baca/design-system/components' import { useMemo } from '@baca/hooks' import React from 'react' -import { Pressable } from 'react-native' import type { FieldSelectProps } from './types' @@ -55,12 +54,15 @@ export const Select = ({ ) return ( - - - - - - + + + + ) } diff --git a/src/constants/env.ts b/src/constants/env.ts index 6ff33041..8fa82c6c 100644 --- a/src/constants/env.ts +++ b/src/constants/env.ts @@ -5,4 +5,5 @@ export const ENV = { EAS_PROJECT_ID: Constants.expoConfig?.extra?.eas?.projectId, ENVIRONMENT_NAME: Constants?.expoConfig?.extra?.ENVIRONMENT_NAME, WEB_CLIENT_ID: Constants.expoConfig?.extra?.WEB_CLIENT_ID, + IS_MOCK: Constants.expoConfig?.extra?.IS_MOCK, } diff --git a/src/constants/environments.ts b/src/constants/environments.ts index 12d2ad22..97784438 100644 --- a/src/constants/environments.ts +++ b/src/constants/environments.ts @@ -1,8 +1,11 @@ import Constants, { AppOwnership } from 'expo-constants' import { Platform } from 'react-native' +import { ENV } from './env' + export const isExpoGo = Constants.appOwnership === AppOwnership.Expo export const isDevelopment = __DEV__ || process.env.NODE_ENV === 'development' export const isProduction = !isDevelopment || process.env.NODE_ENV === 'production' +export const isMock = !!ENV.IS_MOCK export const isWeb = Platform.OS === 'web' diff --git a/src/design-system/bottomSheets/BottomSheet.tsx b/src/design-system/bottomSheets/BottomSheet.tsx index bb9b6e9d..3309b0af 100644 --- a/src/design-system/bottomSheets/BottomSheet.tsx +++ b/src/design-system/bottomSheets/BottomSheet.tsx @@ -7,7 +7,7 @@ import { BottomSheetView, } from '@gorhom/bottom-sheet' import { useCallback } from 'react' -import { Dimensions } from 'react-native' +import { Dimensions, Platform } from 'react-native' import { BottomSheetHeader } from './BottomSheetHeader' import { BottomSheetScrollView } from './BottomSheetScrollables' @@ -45,6 +45,11 @@ export const BottomSheet = ({ snapPoints={[screenHeight - top - 24]} backdropComponent={renderBackdrop} enableDynamicSizing + accessible={Platform.select({ + // setting it to false on Android seems to cause issues with TalkBack instead + // https://github.com/mobile-dev-inc/maestro/issues/1493 + ios: false, + })} backgroundStyle={{ // eslint-disable-next-line react-native/no-inline-styles backgroundColor: colors.bg.primary, diff --git a/src/design-system/components/Button/__snapshots__/Button.test.tsx.snap b/src/design-system/components/Button/__snapshots__/Button.test.tsx.snap index c319f343..d4b1b378 100644 --- a/src/design-system/components/Button/__snapshots__/Button.test.tsx.snap +++ b/src/design-system/components/Button/__snapshots__/Button.test.tsx.snap @@ -78,7 +78,6 @@ exports[`Button renders correctly 1`] = ` "textTransform": "none", } } - testID="baseText" textAlign="center" > Button diff --git a/src/design-system/components/FormErrorMessage.tsx b/src/design-system/components/FormErrorMessage.tsx index 4574a81f..e420f7ff 100644 --- a/src/design-system/components/FormErrorMessage.tsx +++ b/src/design-system/components/FormErrorMessage.tsx @@ -1,18 +1,20 @@ import { useTheme } from '@baca/hooks' import React from 'react' -import { StyleSheet, Text } from 'react-native' +import { Text } from 'react-native' -export const FormErrorMessage = ({ errorMessage }: { errorMessage?: string }) => { +export const FormErrorMessage = ({ + errorMessage, + testId, +}: { + errorMessage?: string + testId?: string +}) => { const { colors } = useTheme() return ( errorMessage && ( - {errorMessage} + + {errorMessage} + ) ) } - -const styles = StyleSheet.create({ - text: { - marginTop: 8, - }, -}) diff --git a/src/design-system/components/FormLabel.tsx b/src/design-system/components/FormLabel.tsx index b64d750c..598acf2a 100644 --- a/src/design-system/components/FormLabel.tsx +++ b/src/design-system/components/FormLabel.tsx @@ -1,11 +1,18 @@ import { useTheme } from '@baca/hooks' import React from 'react' -import { StyleSheet, View } from 'react-native' +import { StyleSheet } from 'react-native' import { Text } from './Text' +import { Touchable } from './Touchables' import { FormLabelProps } from './types' -export const FormLabel = ({ label, isRequired, labelStyle }: FormLabelProps) => { +export const FormLabel = ({ + label, + isRequired, + labelStyle, + testID, + onLabelPress, +}: FormLabelProps) => { const { colors } = useTheme() const stylesForRequired = @@ -16,19 +23,21 @@ export const FormLabel = ({ label, isRequired, labelStyle }: FormLabelProps) => ) ) + if (!label) { + return null + } + return ( - - {label && ( - - {label} - {isRequired && ( - - * - - )} - - )} - + + + {label} + {isRequired && ( + + * + + )} + + ) } @@ -36,9 +45,6 @@ const styles = StyleSheet.create({ wrapper: { display: 'flex', flexDirection: 'row', - }, - wrapperWithLabel: { marginBottom: 8, - marginTop: 4, }, }) diff --git a/src/design-system/components/Icon.tsx b/src/design-system/components/Icon.tsx index fb1e9d32..d83621aa 100644 --- a/src/design-system/components/Icon.tsx +++ b/src/design-system/components/Icon.tsx @@ -6,10 +6,10 @@ import iconJson from 'assets/icomoon/selection.json' import { StyleProp, ViewStyle } from 'react-native' export type IconProps = { - style?: StyleProp color?: ColorNames name: IconNames size: number + style?: StyleProp } const IconFont = createIconSetFromIcoMoon(iconJson, 'IcoMoon', 'icomoon.ttf') diff --git a/src/design-system/components/Text/Text.tsx b/src/design-system/components/Text/Text.tsx index c7168fb6..d3fcea7c 100644 --- a/src/design-system/components/Text/Text.tsx +++ b/src/design-system/components/Text/Text.tsx @@ -204,15 +204,7 @@ const RawText = memo( ] ) - return ( - - ) + return } ) ) diff --git a/src/design-system/components/types.ts b/src/design-system/components/types.ts index 0edaae90..db5301b7 100644 --- a/src/design-system/components/types.ts +++ b/src/design-system/components/types.ts @@ -184,6 +184,8 @@ export type FormLabelProps = { label?: string isRequired?: boolean labelStyle?: TextStyle + testID?: string + onLabelPress?: () => void } // ----------------------- diff --git a/src/hooks/forms/useSignInForm.ts b/src/hooks/forms/useSignInForm.ts index bd421206..3f15857c 100644 --- a/src/hooks/forms/useSignInForm.ts +++ b/src/hooks/forms/useSignInForm.ts @@ -1,5 +1,6 @@ import { useAuthControllerLogin } from '@baca/api/query/auth/auth' import { AuthEmailLoginDto } from '@baca/api/types' +import { isProduction } from '@baca/constants' import { assignPushToken, setToken } from '@baca/services' import { isSignedInAtom } from '@baca/store/auth' import { handleFormError, hapticImpact } from '@baca/utils' @@ -15,12 +16,18 @@ type UseSignInFormProps = { setIsSignInButtonsDisabled?: Dispatch> } -const defaultValues: SignInFormValues = { - // TODO: Reset this values when building production app - email: 'mateusz.rostkowski+baca@binarapps.com', - password: 'Test1234,', - confirm: false, -} +const defaultValues: SignInFormValues = isProduction + ? { + email: '', + password: '', + confirm: false, + } + : { + // TODO: Reset this values when building production app + email: 'mateusz.rostkowski+baca@binarapps.com', + password: 'Test1234,', + confirm: false, + } export const useSignInForm = ({ setIsSignInButtonsDisabled }: UseSignInFormProps) => { const setIsSignedIn = useSetAtom(isSignedInAtom) diff --git a/src/hooks/usePasswordValidation.tsx b/src/hooks/usePasswordValidation.tsx index cf8a638f..d25e88fb 100644 --- a/src/hooks/usePasswordValidation.tsx +++ b/src/hooks/usePasswordValidation.tsx @@ -38,8 +38,12 @@ export const usePasswordValidation = () => { ? 'utility.error.500' : 'utility.success.500' + const testID = `change_password:${suggestion}:${ + !showValidationState ? 'disabled' : isError ? 'error' : 'success' + }` + return ( - + diff --git a/src/navigation/tabNavigator/components/BottomBar.tsx b/src/navigation/tabNavigator/components/BottomBar.tsx index f1e5063c..87365710 100644 --- a/src/navigation/tabNavigator/components/BottomBar.tsx +++ b/src/navigation/tabNavigator/components/BottomBar.tsx @@ -27,7 +27,13 @@ export function BottomBar({ visible }: { visible: boolean }) { > {bottomTabs.map((tab, i) => ( - + {({ focused, pressed, hovered }) => ( void params?: Record style?: ViewStyle + testID?: string }) { const focused = useIsTabSelected(id) if (onPress) { return ( - + {(props) => children?.({ ...props, focused })} ) @@ -34,14 +36,16 @@ export function TabBarItemWrapper({ if (name.startsWith('/') || name.startsWith('.')) { return ( - + {(props) => children?.({ ...props, focused })} ) } return ( - {(props) => children?.({ ...props, focused })} + + {(props) => children?.({ ...props, focused })} + ) } diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 7859b39e..9498fe0f 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -26,16 +26,18 @@ export const HomeScreen = () => { return (
- {t('hello')} + + {t('hello')} + {t('thanks')} {t('app_information')} - - -
diff --git a/src/screens/SettingsScreen.tsx b/src/screens/SettingsScreen.tsx index 5d32748d..bf9e2066 100644 --- a/src/screens/SettingsScreen.tsx +++ b/src/screens/SettingsScreen.tsx @@ -79,7 +79,7 @@ export const SettingsScreen = (): JSX.Element => { - + {t('settings_screen.sign_out')} diff --git a/src/screens/auth/SignInScreen.tsx b/src/screens/auth/SignInScreen.tsx index 1db1ece0..c81bcb5c 100644 --- a/src/screens/auth/SignInScreen.tsx +++ b/src/screens/auth/SignInScreen.tsx @@ -48,9 +48,16 @@ export const SignInScreen = (): JSX.Element => { - {t('sign_in_screen.welcome_back')} + + {t('sign_in_screen.welcome_back')} + - + {t('sign_in_screen.welcome_back_enter_details')} @@ -71,7 +78,7 @@ export const SignInScreen = (): JSX.Element => { message: t('form.validation.invalid_email_format'), }, }} - testID="emailInput" + testID="sign_in:email_input" /> { rules={{ required: t('form.validation.required'), }} - testID="passwordInput" + testID="sign_in:password_input" type="password" /> @@ -93,9 +100,12 @@ export const SignInScreen = (): JSX.Element => { {...{ control, errors }} label={t('form.checkbox.remember_me')} name="confirm" - testID="confirmCheckbox" + testID="sign_in:confirm_checkbox" /> - + {t('sign_in_screen.forgot_password')} @@ -104,7 +114,7 @@ export const SignInScreen = (): JSX.Element => { loading={isSubmitting} my={4} onPress={submit} - testID="signInButton" + testID="sign_in:submit_button" w="full" > {t('sign_in_screen.sign_in')} @@ -117,7 +127,7 @@ export const SignInScreen = (): JSX.Element => { {t('sign_in_screen.do_not_have_an_account')} - + {t('sign_in_screen.sign_up')}
diff --git a/yarn.lock b/yarn.lock index e5b0ad1a..d99a65d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -930,6 +930,14 @@ dependencies: statuses "^2.0.1" +"@bundled-es-modules/tough-cookie@^0.1.6": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz#fa9cd3cedfeecd6783e8b0d378b4a99e52bde5d3" + integrity sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw== + dependencies: + "@types/tough-cookie" "^4.0.5" + tough-cookie "^4.1.4" + "@egjs/hammerjs@^2.0.17": version "2.0.17" resolved "https://registry.yarnpkg.com/@egjs/hammerjs/-/hammerjs-2.0.17.tgz#5dc02af75a6a06e4c2db0202cae38c9263895124" @@ -2100,11 +2108,6 @@ hey-listen "^1.0.8" tslib "^2.3.1" -"@mswjs/cookies@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@mswjs/cookies/-/cookies-1.1.0.tgz#1528eb43630caf83a1d75d5332b30e75e9bb1b5b" - integrity sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw== - "@mswjs/interceptors@^0.29.0": version "0.29.1" resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.29.1.tgz#e77fc58b5188569041d0440b25c9e9ebb1ccd60a" @@ -2163,24 +2166,24 @@ resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-2.1.0.tgz#0acf32f470af2ceaf47f095cdecd40d68666efda" integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg== -"@orval/angular@6.29.1": - version "6.29.1" - resolved "https://registry.yarnpkg.com/@orval/angular/-/angular-6.29.1.tgz#1f576453974613fb113d3f12dd0a4ee4696bbcfa" - integrity sha512-nxoDP/m5B+Y5hilxbVHDuCb7LP9WPW250iVuxUHiQLCYFfrQiMJVizIHGZoBS1tx911qbHqFHB7XKHFsGqY1Zw== +"@orval/angular@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@orval/angular/-/angular-7.0.1.tgz#db2ec97098c60602c395dd5f3cddc1460b433a25" + integrity sha512-a1gEjxXEPZM/riysHYzBPPB/rU9YlW+n/E0X1x25gPfkrmns0NfrKl5N8O6Vxawq7uK2nDTxvXEakEylrzEl3g== dependencies: - "@orval/core" "6.29.1" + "@orval/core" "7.0.1" -"@orval/axios@6.29.1": - version "6.29.1" - resolved "https://registry.yarnpkg.com/@orval/axios/-/axios-6.29.1.tgz#4e783861754b8743db9387ccbed1ce1b548d3675" - integrity sha512-qNRfPqSUiuA7m5aUMCBI1+ANJTjHl65ivpLTstfKExf1rvFqZ7gJpGBOGTcxaZdzwBbkN7Zm2CsGBpsWYxDmDg== +"@orval/axios@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@orval/axios/-/axios-7.0.1.tgz#cadb32af9d8b6612fb983ec5461fd27a23c83da4" + integrity sha512-KBlUAgm9ERg+oVuF2UuBCg8htDehEeIo62kgpE3XnKXOHo3QN8p0bxAL26POdf40vP7S42pzBT3f1Q75fbqgug== dependencies: - "@orval/core" "6.29.1" + "@orval/core" "7.0.1" -"@orval/core@6.29.1": - version "6.29.1" - resolved "https://registry.yarnpkg.com/@orval/core/-/core-6.29.1.tgz#6c869ca30cf57988548bdf266d892dc533c0efe6" - integrity sha512-InWH4heF+2KT2e8Qxoa+w8bourNl/MIr2+camJnGbbX6RzsWmfvGCtfW2kiaYMPc4RnGwTg7Qvfqeung2Dj4GQ== +"@orval/core@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@orval/core/-/core-7.0.1.tgz#649f63801283b51723b093e82bf35358f974c134" + integrity sha512-AcRSPTqCYdXqX/rznYk9SJ9CcxtrPR90N+0ILquXB3rxREAzp1uztH0oymoEtfu0izN4O5c52HQaTJh5sx1b2g== dependencies: "@apidevtools/swagger-parser" "^10.1.0" "@ibm-cloud/openapi-ruleset" "^1.14.2" @@ -2203,46 +2206,55 @@ openapi3-ts "4.2.2" swagger2openapi "^7.0.8" -"@orval/hono@6.29.1": - version "6.29.1" - resolved "https://registry.yarnpkg.com/@orval/hono/-/hono-6.29.1.tgz#2ffe1c5660f85433fb6e58f343feeaf916b026c1" - integrity sha512-nA4TpWRtGBzDok+BZl6yA4PZbmrXfaasuV0AfM9vmqlpEWn+X/x3ASzOrMBK2OkXc7oDfOToaaiq7CLIfEP8+g== +"@orval/fetch@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@orval/fetch/-/fetch-7.0.1.tgz#7f5e5a1d03180b919aee501615ff7ae09d924d6e" + integrity sha512-GgVhbvPUYyvZd3bwFSwtx9g+Ojxv1+c+yuWC6OkKVsGb/o2+gbRRsGFL3TYfMgXPYTfgT+U0MkvLeax0TdL+oQ== + dependencies: + "@orval/core" "7.0.1" + +"@orval/hono@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@orval/hono/-/hono-7.0.1.tgz#417e8992689608464f7ac3a00cafda1e46304aff" + integrity sha512-1y846isycK7pbcV85wtAVnOs4b0UO58+7b7dyTznWlvekin7qhL4jwESNRsi4Fy59k0woksQthrJhrz4KtJKXA== dependencies: - "@orval/core" "6.29.1" - "@orval/zod" "6.29.1" + "@orval/core" "7.0.1" + "@orval/zod" "7.0.1" lodash.uniq "^4.5.0" -"@orval/mock@6.29.1": - version "6.29.1" - resolved "https://registry.yarnpkg.com/@orval/mock/-/mock-6.29.1.tgz#6e967337f771f740f1c213e5a230f53f34beb410" - integrity sha512-l8UEtE1EOX40EHcl4qtu2IeQSRExqc63ekX84BqSWUZx0XicqZRzR348dqd3BB5qaPXKal6Y4ChX3qDeiuDJOw== +"@orval/mock@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@orval/mock/-/mock-7.0.1.tgz#bebf2af7351549e72ad7f389577688ac758725c9" + integrity sha512-yDVh3MjvSr/jPUT5vUcke7bGPLMSlILdT2LmQF/HRWSZYxPgKDkqNAR3ovbFJ2M5ckoBhBoNh3t2Jjcrs4QCzg== dependencies: - "@orval/core" "6.29.1" + "@orval/core" "7.0.1" lodash.get "^4.4.2" lodash.omit "^4.5.0" openapi3-ts "^4.2.2" -"@orval/query@6.29.1": - version "6.29.1" - resolved "https://registry.yarnpkg.com/@orval/query/-/query-6.29.1.tgz#857f9cd626ed2193f9138c33a8c59c2e8fac3ba1" - integrity sha512-voJ3WO0AzQmfFxH0iQc2HsKVlzq7cy4Qik8sLT85upehpmJa/UlFjXr23FaW8SKkIG4kS2t80imCmpMfEezTbw== +"@orval/query@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@orval/query/-/query-7.0.1.tgz#71aa065f6430f25e26498e4ec6ef1a159027abe4" + integrity sha512-rk8HZrPtWM4JJB8GPVS4fY3N1o7eIgTSaG237f5DGaeebI11qt6aUfrxMHm6Ybfs13dhCl4ApvVX7494FKdXHA== dependencies: - "@orval/core" "6.29.1" + "@orval/core" "7.0.1" + "@orval/fetch" "7.0.1" lodash.omitby "^4.6.0" -"@orval/swr@6.29.1": - version "6.29.1" - resolved "https://registry.yarnpkg.com/@orval/swr/-/swr-6.29.1.tgz#878c4e4bc41533f13d448d708f3ae3a5267a7048" - integrity sha512-/B7czuGVtWZ9GYeq2E7C8JuoOfd4wm94Qtu0E1gNTSFWgD0rLx3ZSEvR4cmt46t3tUbOw17Ra0k8lJg8T1MPAQ== +"@orval/swr@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@orval/swr/-/swr-7.0.1.tgz#70e1d3fd75dff4962528deb266d251dee320694a" + integrity sha512-Op6VdhvWXdKHjJCm+M1CPr/Iaj0R3Kt9dM7xiUm0NMI/Q1VQFBFj20MTKWcfie4iFvjLO+AJOfjn0y+BUMaboA== dependencies: - "@orval/core" "6.29.1" + "@orval/core" "7.0.1" + "@orval/fetch" "7.0.1" -"@orval/zod@6.29.1": - version "6.29.1" - resolved "https://registry.yarnpkg.com/@orval/zod/-/zod-6.29.1.tgz#7348c518906cd11d49ef0b6d72fc3c628da89c7c" - integrity sha512-CPrcB7HnBoEtFKLvHSHB2vB3f1NlvI/eKd3P0wE7DsCn+c7YBXpRoOPxHpxIER+Y2kFUBh3DqKDLlRtYgg4JHA== +"@orval/zod@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@orval/zod/-/zod-7.0.1.tgz#965b59e39ae98389fe88fa245bc62d266553a882" + integrity sha512-jxrWCLKPffEWR0OY/lDnzrq4rGGdzSvu/apdL4Qr0j/qeYddrUurt/bdDtcS+l8ZPcTz7ppnp4KMhv1gG4549A== dependencies: - "@orval/core" "6.29.1" + "@orval/core" "7.0.1" lodash.uniq "^4.5.0" "@pkgjs/parseargs@^0.11.0": @@ -3449,7 +3461,7 @@ resolved "https://registry.yarnpkg.com/@types/statuses/-/statuses-2.0.5.tgz#f61ab46d5352fd73c863a1ea4e1cef3b0b51ae63" integrity sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A== -"@types/tough-cookie@*": +"@types/tough-cookie@*", "@types/tough-cookie@^4.0.5": version "4.0.5" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== @@ -4808,7 +4820,7 @@ charenc@0.0.2, charenc@~0.0.1: resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== -"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3: +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3, chokidar@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== @@ -9817,15 +9829,15 @@ ms@2.1.3, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -msw@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/msw/-/msw-2.3.0.tgz#7d48ab8472a435878f4ee94dfa0efcd2b3c2264b" - integrity sha512-cDr1q/QTMzaWhY8n9lpGhceY209k29UZtdTgJ3P8Bzne3TSMchX2EM/ldvn4ATLOktpCefCU2gcEgzHc31GTPw== +msw@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/msw/-/msw-2.3.5.tgz#424ad91b20a548d6b77fc26aca0c789e5cbc4764" + integrity sha512-+GUI4gX5YC5Bv33epBrD+BGdmDvBg2XGruiWnI3GbIbRmMMBeZ5gs3mJ51OWSGHgJKztZ8AtZeYMMNMVrje2/Q== dependencies: "@bundled-es-modules/cookie" "^2.0.0" "@bundled-es-modules/statuses" "^1.0.1" + "@bundled-es-modules/tough-cookie" "^0.1.6" "@inquirer/confirm" "^3.0.0" - "@mswjs/cookies" "^1.1.0" "@mswjs/interceptors" "^0.29.0" "@open-draft/until" "^2.1.0" "@types/cookie" "^0.6.0" @@ -10315,24 +10327,25 @@ ora@^5.4.1: strip-ansi "^6.0.0" wcwidth "^1.0.1" -orval@^6.29.1: - version "6.29.1" - resolved "https://registry.yarnpkg.com/orval/-/orval-6.29.1.tgz#e0651d9072f4a4a5bc9de597d4278c8a67206415" - integrity sha512-hYGuPNucbHZeQgSpcoujuR6GzRKbHhl59zFMt6bxZd6XkeEONhGAqOLETAFQ9og/arOlPOMvchy6COCnrEKlRQ== +orval@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/orval/-/orval-7.0.1.tgz#12e8b4913d8c52a42850b5562a7883e989fa9de2" + integrity sha512-IEdllXbTD34u00NU4jj2jgaroQgpafNnaGP647gaF3NJ5SgxH2sGgxJUQslpoCwR3Dp0pLkj/IZbbxGMPOCMVQ== dependencies: "@apidevtools/swagger-parser" "^10.1.0" - "@orval/angular" "6.29.1" - "@orval/axios" "6.29.1" - "@orval/core" "6.29.1" - "@orval/hono" "6.29.1" - "@orval/mock" "6.29.1" - "@orval/query" "6.29.1" - "@orval/swr" "6.29.1" - "@orval/zod" "6.29.1" + "@orval/angular" "7.0.1" + "@orval/axios" "7.0.1" + "@orval/core" "7.0.1" + "@orval/fetch" "7.0.1" + "@orval/hono" "7.0.1" + "@orval/mock" "7.0.1" + "@orval/query" "7.0.1" + "@orval/swr" "7.0.1" + "@orval/zod" "7.0.1" ajv "^8.12.0" cac "^6.7.14" chalk "^4.1.2" - chokidar "^3.5.3" + chokidar "^3.6.0" enquirer "^2.4.1" execa "^5.1.1" find-up "5.0.0" @@ -12871,7 +12884,7 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -tough-cookie@^4.1.2: +tough-cookie@^4.1.2, tough-cookie@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==