web-dev-qa-db-fra.com

Détection de plate-forme moqueuse dans Jest et React Native

Une partie du code que je suis en train de tester détecte la plate-forme, en utilisant, par exemple:

import { Platform } from 'react-native';
...

if (Platform.OS === 'Android') {
  ...
} else {
  ...
}

Existe-t-il un moyen judicieux de se moquer de cela avec Jest et/ou autre chose afin de pouvoir tester les deux branches en une fois?

Ou bien, le moyen intelligent de le découpler et de placer la plate-forme, par exemple, dans une variable de contexte? Bien que le code de restructuration soit toujours considéré comme un tricheur, il est difficile de le tester. 

12
Stuart Watt

Cela a fonctionné pour moi (Jest 21.2.1, Enzyme 3.2.0):

jest.mock('Platform', () => {
    const Platform = require.requireActual('Platform');
    Platform.OS = 'Android';
    return Platform;
});

Mettez-le en haut de votre test ou dans une beforeAll par exemple.

15
Bramus

La façon dont j'ai réalisé les réglages moqueurs de la plate-forme était juste définie directement dans les tests:

it('should only run for Android', () => {
  Platform.OS = 'Android'; // or 'ios'

  // For my use case this module was failing on iOS
  NativeModules.MyAndroidOnlyModule = {
    fetch: jest.fn(
      (url, event) => Promise.resolve(JSON.stringify(event.body))
    ),
  }; 
  return myParentFunction().then(() => {
    expect(NativeModules.MyAndroidOnlyModule.fetch.mock.calls.length).toBe(1);
    expect(fetch.mock.calls.length).toBe(0);
  });
});

Cela permettrait à la plate-forme de ne s'exécuter que sur Android lors des tests pour s'assurer que ma fonction appelait uniquement des fonctions spécifiques. Ma fonction qui était encapsulée dans une compilation dépendante de la plate-forme ressemblait à:

export default function myParentFunction() {
  if (Platform.OS === 'ios') {
    return fetch();
  }
  return NativeModules.MyAndroidOnlyModule.fetch();
}

Je suggérerais simplement de créer deux tests différents, l'un avec la plate-forme définie sur iOS et l'autre sous Android, car idéalement, une fonction ne devrait avoir qu'une seule responsabilité. Cependant, je suis sûr que vous pouvez utiliser ceci pour exécuter le premier test, définir dynamiquement la plate-forme et exécuter le test numéro deux, le tout dans une fonction.

4
Boomer Rogers

Étant donné que les autres réponses ne fonctionneront pas si vous souhaitez simuler différents systèmes d'exploitation dans la même suite de tests et lors d'un test, voici un autre moyen. Au lieu d'utiliser Platform.OS directement dans votre code, définissez une fonction d'assistance quelque part et utilisez-la:

export function getOS() {
  return Platform.OS;
}

Cette fonction peut puis être simulée dans vos tests, par exemple.

it('does something on Android', () => {
  helpers.getOS = jest.fn().mockImplementationOnce(() => 'Android');
  // ...
}

it('does something else on iOS', () => {
  helpers.getOS = jest.fn().mockImplementationOnce(() => 'ios');
  // ...
}

Le mérite de cette idée va à ce commentaire sur le problème GitHub .

2
d0gb3r7

Peut-être le problème dans la méthode "import", vérifiez ceci:

const isAndroid = require('app/helpers/is_Android');

//import isAndroid from 'app/helpers/is_Android'

avec "import" cela ne fonctionnera pas, il faut utiliser "nécessite".

beforeEach(() => {
  jest.resetModules();
});

it("should be true when Android", () => {
  jest.mock('Platform', () => {
    return { OS: 'Android' };
  });

  expect(isAndroid).toBe(true);
});   
1
user10124150

J'utilise la solution de ce problème github https://github.com/facebook/jest/issues/1370#issuecomment-352597475

J'ai déplacé la configuration de plaisanterie de package.json vers des fichiers séparés. Jusqu'à présent, tout semble bien fonctionner, y compris: A) le bon fichier est importé en fonction de la plate-forme. Par exemple sur ios: .ios.tsx, puis .native.tsx, puis .tsx B. PLATFORM.IOS renvoie true lors de l'exécution de test-ios, inutile de vous moquer de rien

// package.json
"scripts": {
  "test": "cross-env NODE_ENV=test jest --config config/jest.desktop.json",
  "test-ios": "cross-env NODE_ENV=test jest --config config/jest.ios.json",
  "test-Android": "cross-env NODE_ENV=test jest --config config/jest.Android.json"
}

// config/jest.web.json
{
...
}

// config/jest.ios.json
{
...
  "preset": "react-native",
  "haste": {
    "defaultPlatform": "ios",
    "platforms": [
      "Android",
      "ios",
      "native"
    ],
    "providesModuleNodeModules": [
      "react-native"
    ]
  },
}

// config/jest.Android.json
{
...
  "preset": "react-native",
  "haste": {
    "defaultPlatform": "Android",
    "platforms": [
      "Android",
      "ios",
      "native"
    ],
    "providesModuleNodeModules": [
      "react-native"
    ]
  },
}
1
user3526468

c'est la maquette dont vous avez besoin: 

const mockPlatform = OS => {    
  jest.resetModules();  
  jest.doMock("Platform", () => ({ OS, select: objs => objs[OS] }));
};

avec cela, vous pouvez faire ce qui suit: 

it("my test on Android", () => {
  mockPlatform("Android");
});

it("my test on iOS", () => {
  mockPlatform("ios");
});

De cette façon, vous pouvez avoir des tests pour les deux plates-formes

1
Estevão Lucas

utilisez jest.doMock et jest.resetModules

jest.resetModules()
jest.doMock('react-native', () => ({ Platform: { OS: 'Android' }}))
1
jkvim

Vous pouvez vous moquer de ce que vous voulez de React-Native comme ceci:

describe('notifications actions tests', () => {
  let Platform;


  beforeEach(() => {
    jest.mock('react-native', () => ({
          Platform: {
           ... 
        }));


    Platform = require('react-native').Platform; // incase u would like to refer to Platform in your tests
  });
0
gran33
import React from "react";
import renderer from "react-test-renderer";
import SmartText from "../SmartText";

describe("markdown smart text component", () => {
  beforeEach(() => {
    jest.resetModules();
  });

  it("renders with props on ios", () => {
    jest.mock("Platform", () => {
      return { OS: "ios" };
    });
    expect(
      renderer.create(<SmartText title="code ios" code />).toJSON()
    ).toMatchSnapshot();
  });

  it("renders with props on Android", () => {
    jest.mock("Platform", () => {
      return { OS: "Android" };
    });
    expect(
      renderer.create(<SmartText title="code Android" code />).toJSON()
    ).toMatchSnapshot();
  });
});
0
ethanneff