如何在玩笑中模拟异步 PermissionsAndroid.request?

时间:2021-04-18 09:32:54

标签: react-native jestjs

我在 react native 中有这段代码,我想进行测试:

const granted = await PermissionsAndroid.request(
          PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
          {
            title: 'Device current location permission',
            message: 'Allow app to get your current location',
            buttonNeutral: 'Ask Me Later',
            buttonNegative: 'Cancel',
            buttonPositive: 'OK',
          }
        );

我正在查看这里的答案,但似乎不起作用:How to mock PermissionAndroid from react native

jest.doMock('react-native/Libraries/PermissionsAndroid/PermissionsAndroid', () => ({
  ...jest.requireActual('react-native/Libraries/PermissionsAndroid/PermissionsAndroid'),
  request: () => ({
    [PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION]: PermissionsAndroid.RESULTS.GRANTED,
  }),
  check: () => true,
}));

在 ios 上,我这样做很快:

jest.spyOn(Geolocation, 'requestAuthorization').mockResolvedValue('granted');

我似乎想不出如何在 android 中做到这一点?

1 个答案:

答案 0 :(得分:0)

我建议您尝试使用 react-native-permissions。它已经有一个您可以使用的 mock file。您可以使用 Jest + React 测试库 Native。

就我而言,我使用了 jest-setup.js 文件

import {jest} from '@jest/globals';

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

然后在 package.json 文件中配置 jest

"jest": {
    "preset": "react-native",
    "setupFilesAfterEnv": [
      "@testing-library/jest-native/extend-expect"
    ],
    "transformIgnorePatterns": [
      "node_modules/(?!(jest-)?react-native-permissions|)"
    ],
    "setupFiles": [
      "./jest-setup.js"
    ]
  }

对于地理定位服务,我在 __mocks__/react-native-geolocation-service.js 内创建了一个 react-native-geolocation-service

export default {
  getCurrentPosition: jest.fn().mockImplementation(successCallback => {
    const position = {
      coords: {
        latitude: 57.7,
        longitude: 11.93,
      },
    };
    successCallback(position);
  }),
};

在你的 App 组件中,你可以拥有这个

import React, {useEffect, useState} from 'react';
import { View } from 'react-native';
import {check, request, PERMISSIONS, RESULTS} from 'react-native-permissions';
import Geolocation from 'react-native-geolocation-service';

const App = () => {
  const [location, setLocation] = useState(null);

  const handleLocationPermission = async () => {
    let permissionCheck = '';
    if (Platform.OS === 'ios') {
      permissionCheck = await check(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE);

      if (permissionCheck === RESULTS.DENIED) {
        const permissionRequest = await request(
          PERMISSIONS.IOS.LOCATION_WHEN_IN_USE,
        );
        permissionRequest === RESULTS.GRANTED
          ? console.warn('Location permission granted.')
          : console.warn('Location perrmission denied.');
      }
    }

    if (Platform.OS === 'android') {
      permissionCheck = await check(PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION);

      if (permissionCheck === RESULTS.DENIED) {
        const permissionRequest = await request(
          PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
        );
        permissionRequest === RESULTS.GRANTED
          ? console.warn('Location permission granted.')
          : console.warn('Location perrmission denied.');
      }
    }
  };

  useEffect(() => {
    handleLocationPermission();
  }, []);

  useEffect(() => {
     Geolocation.getCurrentPosition(
        position => {
            const {latitude, longitude} = position.coords;
            setLocation({latitude, longitude});
     },
     error => {
       console.log(error.code, error.message);
     },
     {enableHighAccuracy: true, timeout: 15000, maximumAge: 10000},
      );
     }, []);
  
  return (<View></View>)
}

然后在您的测试文件中,您可以使用 React Testing Library Native 来测试行为。

import React from 'react';
import {render, waitFor} from '@testing-library/react-native';
import App from '../App';
import {check} from 'react-native-permissions';
import Geolocation from 'react-native-geolocation-service';

describe('<UserScreen />', () => {
  test('should check for permissions', async () => {
    render(<App />);

    await waitFor(() => {
      expect(check).toHaveBeenCalledTimes(1);
      expect(Geolocation.getCurrentPosition).toHaveBeenCalledTimes(1);
    });
  });
});

我在我的网站上写了一个类似且更详细的 Post

相关问题