gpt4 book ai didi

reactjs - react native typescript 屏幕测试返回测试套件运行失败。错误 react-native-permissions : NativeModule. RNPermissions 为空

转载 作者:行者123 更新时间:2023-12-05 03:33:56 27 4
gpt4 key购买 nike

我在为 react-native 编写测试时遇到困难,这些测试涉及用 typescript 编写的模拟 Internet 和振动权限

使用以下 URL 中的说明

How to mock PermissionAndroid from react native

我不断收到以下错误

FAIL  app/screens/login/login-screen.test.tsx
● Test suite failed to run
react-native-permissions: NativeModule.RNPermissions is null. To fix this issue try these steps:
• If you are using CocoaPods on iOS, run `pod install` in the `ios` directory and then clean, rebuild and re-run the app. You may also need to re-open Xcode to get the new pods.
• If you are getting this error while unit testing you need to mock the native module. You can use this to get started: https://github.com/react-native-community/react-native-permissions/blob/master/mock.js
If none of these fix the issue, please open an issue on the Github repository: https://github.com/react-native-community/react-native-permissions

at Object.<anonymous> (node_modules/react-native-qrcode-scanner/node_modules/react-native-permissions/lib/commonjs/index.ts:6:9)
at Object.<anonymous> (node_modules/react-native-qrcode-scanner/index.js:19:1)

登录界面测试文件内容见下方

import AsyncStorage from "@react-native-community/async-storage"
import { render } from "@testing-library/react-native"
import React from "react"
import { LoginScreen } from ".."

it("renders correctly", async () => {

const { getAllByText } = await render(<LoginScreen navigation={undefined} route={undefined} />)
expect(getAllByText("Login").length).toBe(1)

expect(AsyncStorage.getItem).toBeCalledWith("myKey")

})

测试\setup.ts

// we always make sure 'react-native' gets included first
import "react-native"

// libraries to mock
import "./mock-react-native-image"
import "./mock-async-storage"
import "./mock-i18n"
import "./mock-reactotron"
import "./mock-permissions"

jest.useFakeTimers()
declare global {
let __TEST__
}

和测试\mock-permissions.ts

// eslint-disable-next-line react-native/split-platform-components
import { PermissionsAndroid } from "react-native";

const internetPermissionResult: string = PermissionsAndroid.RESULTS.GRANTED;
const vibratePermissionResult: string = PermissionsAndroid.RESULTS.GRANTED;

const internetPermissionGranted = true;
const vibratePermissionGranted = true;

const permissionsAndroidModule = jest.requireActual('react-native/Libraries/PermissionsAndroid/PermissionsAndroid.js');
jest.doMock('react-native/Libraries/PermissionsAndroid/PermissionsAndroid', () => ({
...permissionsAndroidModule,
requestMultiple: () => {
return {
[PermissionsAndroid.PERMISSIONS.INTERNET]: internetPermissionResult,
[PermissionsAndroid.PERMISSIONS.VIBRATE]: vibratePermissionResult,
};
},
check: () => {
return internetPermissionGranted && vibratePermissionGranted;
},
}));

我的包.json

  {
"name": "special-project",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "react-native start",
"ios": "react-native run-ios",
"android": "react-native run-android",
"test:e2e": "detox test -c ios.sim.debug",
"build:e2e": "detox build -c ios.sim.debug",
"ci:test:e2e": "detox test -c ios.sim.release -l verbose --cleanup",
"ci:build:e2e": "detox build -c ios.sim.release",
"compile": "tsc --noEmit -p . --pretty",
"format": "npm-run-all format:*",
"format:js": "prettier --write \"app/**/*.js\"",
"format:json": "prettier --write \"app/**/*.json\"",
"format:md": "prettier --write \"**/*.md\"",
"format:ts": "prettier --write \"app/**/*.ts{,x}\"",
"lint": "eslint index.js app storybook test --fix --ext .js,.ts,.tsx && yarn format",
"patch": "patch-package",
"storybook": "start-storybook -p 9001 -c ./storybook",
"test": "jest",
"adb": "adb reverse tcp:9090 tcp:9090 && adb reverse tcp:3000 tcp:3000 && adb reverse tcp:9001 tcp:9001 && adb reverse tcp:8081 tcp:8081",
"postinstall": "node ./bin/postInstall",
"build-ios": "react-native bundle --entry-file index.js --platform ios --dev false --bundle-output ios/main.jsbundle --assets-dest ios",
"build-android": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res",
"clean": "react-native-clean-project",
"clean-all": "npx react-native clean-project-auto"
},
"dependencies": {
"@react-native-async-storage/async-storage": "^1.15.14",
"@react-native-community/checkbox": "^0.5.9",
"@react-native-community/masked-view": "0.1.10",
"@react-navigation/drawer": "^6.1.8",
"@react-navigation/material-top-tabs": "^6.0.6",
"@react-navigation/native": "~6.0.1",
"@react-navigation/native-stack": "^6.0.2",
"@react-navigation/stack": "~6.0.1",
"@reduxjs/toolkit": "^1.6.2",
"@unimodules/core": "6.0.0",
"apisauce": "2.0.0",
"axios": "^0.24.0",
"expo-linear-gradient": "^9.2.0",
"expo-localization": "9.1.0",
"i18n-js": "3.8.0",
"mobx": "6.1.8",
"mobx-react-lite": "3.2.0",
"mobx-state-tree": "5.0.1",
"node-fetch": "^3.1.0",
"react": "17.0.1",
"react-native": "0.64.2",
"react-native-appearance": "^0.3.4",
"react-native-camera": "^4.2.1",
"react-native-gesture-handler": "^1.10.3",
"react-native-image-crop-picker": "^0.36.4",
"react-native-keychain": "6.2.0",
"react-native-material-menu": "^2.0.0",
"react-native-pager-view": "^5.4.8",
"react-native-paper": "^4.10.1",
"react-native-permissions": "^3.1.0",
"react-native-qrcode-scanner": "^1.5.4",
"react-native-radio-buttons-group": "^2.2.7",
"react-native-reanimated": "^2.2.3",
"react-native-safe-area-context": "3.1.8",
"react-native-screens": "3.4.0",
"react-native-tab-view": "^3.1.1",
"react-native-unimodules": "0.12.0",
"react-redux": "^7.2.6",
"reactotron-mst": "3.1.3",
"reactotron-react-js": "^3.3.7",
"redux": "^4.1.2",
"redux-logger": "^3.0.6",
"redux-persist": "^6.0.0",
"redux-saga": "^1.1.3",
"validate.js": "0.13.1"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@babel/plugin-proposal-decorators": "7.12.1",
"@babel/plugin-proposal-optional-catch-binding": "7.12.1",
"@babel/runtime": "^7.12.5",
"@storybook/addon-storyshots": "6.1.10",
"@storybook/react-native": "5.3.23",
"@storybook/react-native-server": "5.3.23",
"@testing-library/react-native": "^8.0.0",
"@types/i18n-js": "3.0.3",
"@types/jest": "26.0.19",
"@types/react": "16.14.0",
"@types/react-native": "0.63.40",
"@types/react-test-renderer": "16.9.4",
"@typescript-eslint/eslint-plugin": "4.10.0",
"@typescript-eslint/parser": "4.10.0",
"babel-jest": "26.6.3",
"babel-loader": "8.2.2",
"detox": "17.14.5",
"eslint": "7.15.0",
"eslint-config-prettier": "7.0.0",
"eslint-config-standard": "16.0.2",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "4.2.1",
"eslint-plugin-react": "7.21.5",
"eslint-plugin-react-native": "3.10.0",
"fbjs-scripts": "3.0.0",
"jest": "^25.5.4",
"jest-circus": "25.5.4",
"jest-expo": "^40.0.1",
"jetifier": "1.6.6",
"npm-run-all": "4.1.5",
"patch-package": "6.2.2",
"postinstall-prepare": "1.0.1",
"prettier": "2.2.1",
"react-devtools-core": "4.10.1",
"react-dom": "^17.0.2",
"react-native-clean-project": "^3.6.3",
"react-native-web": "^0.16.3",
"react-powerplug": "1.0.0",
"reactotron-react-native": "^5.0.0",
"solidarity": "2.3.1",
"typescript": "4.2.3"
},
"jest": {
"preset": "jest-expo",
"setupFiles": [
"<rootDir>/test/setup.ts"
],
"testPathIgnorePatterns": [
"/node_modules/",
"/e2e"
],
"transformIgnorePatterns": [
"node_modules/(?!(jest-)?react-native|expo-linear-gradient|@react-native|@react-native-async-storage|@react-navigation|@storybook|@react-native-community|expo-localization|@unimodules)"
]
},
"prettier": {
"printWidth": 100,
"semi": false,
"singleQuote": false,
"trailingComma": "all"
},
"detox": {
"test-runner": "jest",
"configurations": {
"ios.sim.debug": {
"binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/codix.app",
"build": "xcodebuild -workspace ios/codix.xcworkspace -scheme codix -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build -destination 'name=iPhone 11'",
"type": "ios.simulator",
"device": {
"name": "iPhone 11",
"os": "iOS 13.2"
}
},
"ios.sim.release": {
"binaryPath": "ios/build/Build/Products/Release-iphonesimulator/codix.app",
"build": "xcodebuild -workspace ios/codix.xcworkspace -scheme codix -configuration Release -sdk iphonesimulator -derivedDataPath ios/build -destination 'name=iPhone 11'",
"type": "ios.simulator",
"device": {
"name": "iPhone 11",
"os": "iOS 13.2"
}
}
}
},
"eslintConfig": {
"root": true,
"parser": "@typescript-eslint/parser",
"extends": [
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-native/all",
"standard",
"prettier",
"prettier/@typescript-eslint"
],
"plugins": [
"@typescript-eslint",
"react",
"react-native"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"project": "./tsconfig.json"
},
"settings": {
"react": {
"pragma": "React",
"version": "detect"
}
},
"globals": {
"__DEV__": false,
"jasmine": false,
"beforeAll": false,
"afterAll": false,
"beforeEach": false,
"afterEach": false,
"test": false,
"expect": false,
"describe": false,
"jest": false,
"it": false
},
"rules": {
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/explicit-member-accessibility": 0,
"@typescript-eslint/explicit-module-boundary-types": 0,
"@typescript-eslint/indent": 0,
"@typescript-eslint/member-delimiter-style": 0,
"@typescript-eslint/no-empty-interface": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-object-literal-type-assertion": 0,
"@typescript-eslint/no-var-requires": 0,
"comma-dangle": 0,
"multiline-ternary": 0,
"no-undef": 0,
"no-unused-vars": 0,
"no-use-before-define": "off",
"quotes": 0,
"react-native/no-raw-text": 0,
"react/no-unescaped-entities": 0,
"react/prop-types": "off",
"space-before-function-paren": 0
}
}
}

实际的登录屏幕文件

import React, { FC, useState } from "react"
import {
View,
SafeAreaView,
TouchableOpacity,
ScrollView,
TextInput,
ImageBackground,
KeyboardAvoidingView,
Alert,
} from "react-native"
import { StackScreenProps } from "@react-navigation/stack"
import { observer } from "mobx-react-lite"
import { Button, Text, AutoImage as Image } from "../../components"
import { NavigatorParamList } from "../../navigators"
import { Images } from "../../config"
import { setIsLoggedIn } from "../../reducers/loginReducer"
import { useDispatch } from "react-redux"
import { setTokenValue } from "../../reducers/tokenReducer"
import { LOGIN_URL, showErrorAlert } from "../../utils/constants"
import axios from "axios"
import { setSalesAgentIdValue } from "../../reducers/salesAgentIdReducer"
import {
BLUESIGNUP_TEXT,
BOTTOM_HALF,
CONTINUE,
CONTINUE_TEXT,
FOOTER_CONTENT,
FULL,
HOME_LOGO,
KEYBOARD_AVOID_VIEW,
LABEL,
LOGO_TEXT,
RED_ACTION_LINK,
RED_TEXT,
REGULAR_TEXT,
SUBJECT,
TEXT_INPUT,
TEXT_INPUT_END,
} from "./loginscreen-styles"
import { setRefreshTokenValue } from "../../reducers/refreshTokenReducer"

export const LoginScreen: FC<StackScreenProps<NavigatorParamList, "login">> = observer(
({ navigation }) => {
const dispatch = useDispatch()

const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const [errortext] = useState("")

let tokenValue: any
let refreshTokenValue: any
let salesAgenIdValue: any

const api = axios.create({
baseURL: LOGIN_URL,
})

const onLogin = async () => {
if (!email) {
showErrorAlert("Your Email")
return
}

if (!password) {
showErrorAlert("Your Password")
return
}
console.log("<<< inside onlogin >>>>>")
const dataToSend = {
email: email,
password: password,
}
try {
console.log("<<<<<<< BEFORE RESPONSE FOR LOGIN >>>>>>>>>")

const res = await api.post("/", dataToSend)
console.log("Res >> ", res)
console.log("<<<<<<<AFTER RESPONSE FOR LOGIN >>>>>>>>>")

// eslint-disable-next-line no-prototype-builtins
if (res.hasOwnProperty("data")) {
tokenValue = res.data.data.userToken
refreshTokenValue = res.data.data.refreshToken

console.log("<<<<<<<TOKEN>>>>>>>>>")
console.log(JSON.stringify(tokenValue))
console.log("<<<<<<<TOKEN>>>>>>>>>")

console.log("<<<<<<< REFRESH TOKEN>>>>>>>>>")
console.log(JSON.stringify(refreshTokenValue))
console.log("<<<<<<< REFRESH TOKEN>>>>>>>>>")

dispatch(setTokenValue(tokenValue))
dispatch(setRefreshTokenValue(refreshTokenValue))
dispatch(setIsLoggedIn(true))

salesAgenIdValue = res.data.data.userId
console.log("<<<<<<<salesAgenIdValue>>>>>>>>>")
console.log(JSON.stringify(salesAgenIdValue))
console.log("<<<<<<<salesAgenIdValue>>>>>>>>>")
dispatch(setSalesAgentIdValue(salesAgenIdValue))

setTimeout(() => {
navigation.navigate("drawer")
}, 1000)
} else {
console.log("<<<<<<< ERRRRRROR >>>>>>>>>")
}
} catch (err) {
console.log(err)
Alert.alert("An Error occurred " + err)
}
}
return (
<ImageBackground source={Images.bg} style={FULL}>
<Image source={Images.wragbyLogo} style={HOME_LOGO} />
<View style={LOGO_TEXT}>
<Text>Special App</Text>
</View>

<View style={BOTTOM_HALF}>
<SafeAreaView>
<View>
<Text style={RED_TEXT}>{errortext}</Text>
</View>
<ScrollView showsVerticalScrollIndicator={false}>
<KeyboardAvoidingView
style={KEYBOARD_AVOID_VIEW}
>
<Text style={SUBJECT}>Login</Text>
<Text style={LABEL}>Email</Text>

<TextInput
style={TEXT_INPUT}
placeholderTextColor="#707070"
onChangeText={(email) => setEmail(email)}
placeholder=""
autoCapitalize="none"
value={email}
/>
<Text style={LABEL}>Password</Text>

<TextInput
style={TEXT_INPUT_END}
placeholderTextColor="#707070"
onChangeText={(password) => setPassword(password)}
secureTextEntry={true}
placeholder=""
autoCapitalize="none"
value={password}
/>

<View style={RED_ACTION_LINK}>
<TouchableOpacity onPress={() => navigation.navigate("resetpassword")}>
<Text style={RED_TEXT}>Forgot password?</Text>
</TouchableOpacity>
</View>

<View style={FOOTER_CONTENT}>
<Button
testID="next-screen-button"
style={CONTINUE}
textStyle={CONTINUE_TEXT}
tx="welcomeScreen.signIn"
// onPress={showDashboard}
onPress={onLogin}
/>
<TouchableOpacity onPress={() => navigation.navigate("signup")}>
<Text style={REGULAR_TEXT}>
Don't have an Account yet? <Text style={BLUESIGNUP_TEXT}>Sign up</Text>
</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
</ScrollView>
</SafeAreaView>
</View>
</ImageBackground>
)
},
)

我已经和这个问题斗争了将近一个星期请告诉我正确的语法以用于编写正确的测试,或者至少告诉我如何解决异步存储问题

最佳答案

在下面添加,

jest.mock('react-native-permissions', () => require('react-native-permissions/mock'));
jest.mock('react-native-qrcode-scanner', () => jest.fn());

关于reactjs - react native typescript 屏幕测试返回测试套件运行失败。错误 react-native-permissions : NativeModule. RNPermissions 为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70251955/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com