Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set defaultPlatform for specific test #1370

Closed
brentvatne opened this issue Aug 4, 2016 · 26 comments
Closed

Set defaultPlatform for specific test #1370

brentvatne opened this issue Aug 4, 2016 · 26 comments

Comments

@brentvatne
Copy link
Contributor

In react-native we have .android.js, .ios.js, .web.js, .windows.js, etc. In order to test components on different platforms easily, it would be helpful to be able to specify what platform a specific test is for and have it automatically include the correct files based on the extension. As discussed on messenger @cpojer

@fahrradflucht
Copy link

To extend this issue:

There is not just the problem with platform specific files. If you have code like this:

import { StyleSheet, Platform } from 'react-native';

export default StyleSheet.create({
  container: {
    paddingTop: Platform.OS === 'ios' ? 30 : 10,
  }
});

Platform.OS is always 'ios' in jest tests.

@lilach
Copy link

lilach commented Nov 21, 2016

Just to make sure it won't go unnoticed, Platform.select has the same problem as Platform.OS.

@bgeihsgt
Copy link

bgeihsgt commented Dec 23, 2016

FWIW, I've been able to work around this by setting up jest mocks to point to the different files. It's pretty janky, so a built-in solution would be really nice :)

Something like:

   jest.resetModules()
      .doMock('./MyModule', () => {
         return require.requireActual(`./MyModule.${Platform.OS}.js`);
      });

Then in your test assign Platform.OS to your desired platform before requiring in your subject under test:

   Platform.OS = 'android';
   const subjectUnderTest = require('./subject-under-test');

@FDMatthias
Copy link

Little bit late to the party but might be of value:

I have a 'general helpers' file in my app which exports an 'onAndroid' function with the implementation as such:

/* App/Lib/GeneralHelpers.js */
import { Platform } from 'react-native'

// Simple Platform boolean
export const onAndroid = () => Platform.OS === 'android'

This gives me the opportunity to easily make platform-specific code in components like this:

/* App/Components/randomComponent.js */
[...]
return(
 <Text>
    { onAndroid() ? "android device" : "ios device" } 
 </Text>
)

and, why I'm typing this, to test components on a specific platform by mocking the 'onAndroid' function like so:

/* Tests/Components/randomComponent-test.js */
import * as helpers from '../../App/Lib/GeneralHelpers'

helpers.onAndroid = jest.fn(() => true)
  [...]
  // do some android specific testing
  expect(TestRandomComponent.children[0]).toBe("android device")

helpers.onAndroid = jest.fn(() => false)
  [...]
  // do some iOS specific testing
  expect(TestRandomComponent.children[0]).toBe("ios device")

@Milesyan
Copy link

Platform.select can be mocked to return android branch:

Platform.select = jest.fn(dict => dict.android);

Platform.OS can be specified easily by:

Platform.OS = 'android' or 'ios'

@Palisand
Copy link

Anyone have any idea on how to deal with creating snapshots with platform-specific modules?

When testing a component that relies on TouchableNativeFeedback for Android devices, setting Platform.OS to android for snapshot tests results in snapshots of error messages:

<View ...>
  <Text ...>
    TouchableNativeFeadback is not supported on this platform!
  </Text>
</View>

@AlanFoster
Copy link

AlanFoster commented Jul 27, 2017

I've been using this approach to switch to using an android version of Platform selet:

jest.mock('react-native', function() {
  const reactNative = require.requireActual('react-native');
  jest
    .spyOn(reactNative.Platform, 'select')
    .mockImplementation(obj => obj.android || obj.default);
  return reactNative;
});

Not sure if it's the best approach

@gogumai
Copy link

gogumai commented Dec 14, 2017

Any update on this? I can't find an elegant approach to solve this :(

@oshimayoan
Copy link

oshimayoan commented Dec 14, 2017

@gogumai I did this on my code and it actually works.

...
it('should render picker on Android only with required props', () => {
  jest.mock('Platform', () => ({
    OS: 'android',
  }));
  let component = renderer.create(<Picker options={OPTIONS} />);
  expect(component.toJSON()).toMatchSnapshot();
});
...

I'm using Jest v21.2.1.

@grigored
Copy link

@gogumai After spending many hours, found this solution:
I moved the jest config from package.json to separate files.
So far everything seems to work great, including:
a) the right file is imported according to the platform. For example on ios: .ios.tsx, then .native.tsx then .tsx
b) PLATFORM.IOS returns true when running test-ios, no need to mock anything

// 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"
    ]
  },
}

@treyp
Copy link

treyp commented Jan 10, 2018

Hey @grigored, that solution from #4455 is a step in the right direction, but any idea how to use snapshots when you want to test on multiple platforms? When testing on one platform, the snapshots don't match up with the output from the other platform.

Per #1650, there seems to be no way to configure Android snapshots to go in one place while iOS snapshots go to another.

@grigored
Copy link

Hm... I guess you could write a short bash script to save the snapshots in snapshots_ios after the test is run, and back when you run the tests. something like this might work

// package.json
"scripts": {
"test-ios": "find __tests__ -type d -name '__snapshots_ios__' -print0 | xargs -0 -I {} mv {} {}/../__snapshots__ && cross-env NODE_ENV=test jest --config config/jest.ios.json && find __tests__ -type d -name '__snapshots__' -print0 | xargs -0 -I {} mv {} {}/../__snapshots_ios__"
}

@pranavjandial008
Copy link

Any latest solution to this?

@thymikee
Copy link
Collaborator

No other than setting projects config separately for iOS/Android/other platforms.

@shawfire
Copy link

shawfire commented Dec 4, 2018

Non of the above worked for me.
I have outlined a solution below that works for me.

// styles.js
// Styled component.

import styled from "styled-components";

export const Heading = styled.View`
  flex-direction: row;
  justify-content: space-between;
  align-items: flex-start;
  padding-top: ${props => props.platform && props.platform === 'ios' ? 30 : 20};
  padding-left: 28;
  padding-right: 28;
  min-height: 70;
`;

// styles.test.js
// Tests.

import React from "react";
import { shallow } from "enzyme";
import toJson from "enzyme-to-json";

import { Heading } from "../styles";

describe("Heading Component", () => {

  it("Should render without issues", () => {
    const component = shallow(<Heading/>);

    expect(component.length).toBe(1);
    expect(toJson(component)).toMatchSnapshot();
  });
  it("Should render without issues on ios", () => {

    const component = shallow(<Heading platform='ios'/>);

    expect(component.length).toBe(1);
    expect(toJson(component)).toMatchSnapshot();
  });

  it("Should render without issues on android", () => {
    const component = shallow(<Heading platform='android'/>);

    expect(component.length).toBe(1);
    expect(toJson(component)).toMatchSnapshot();
  });

});

// CommonHeader/index.js
// Usage example.

import PropTypes from "prop-types";
import React from "react";
import styled from "styled-components";
import { Platform } from 'react-native';

import { BackButton } from "../BackButton";
import { CloseButton } from "../CloseButton";
import { Heading } from "./styles";
export class CommonHeader extends React.Component {
  render() {
    const { componentId } = this.props;

    const logo = this.props.logo
      ? this.props.logo
      : require("@/images/Logos/rouge.png");

    return (
      <Heading platform={Platform.OS}>
        <BackButton componentId={componentId} />
        <LogoContainer>
          <Logo source={logo} />
        </LogoContainer>
        <CloseButton componentId={componentId} />
      </Heading>
    );
  }
}

CommonHeader.propTypes = {
    componentId: PropTypes.string.isRequired
};

const LogoContainer = styled.View`
  flex-direction: column;
  justify-content: flex-start;
`;

const Logo = styled.Image``;

@marianoqueirel
Copy link

Hi !

Any update on this? I've started a project two weeks ago with an updated react-native and jest version and the issue is still present.

@jeanregisser
Copy link

Looks like https://jestjs.io/docs/en/configuration.html#snapshotresolver-string could be leveraged to store the snapshots in different paths based on the config.

@quyenhoa
Copy link

In react-native we use Platform check a lot and it's a shame that there is no easy way to mock Platform to our tests.

@oshimayoan
Copy link

Currently, the best way to do this is by using @expo/universal approach from Expo team.

If you use Expo you could use @expo/universal directly but if you use bare react-native, you can copy the approach and edit it to work with your project.

@karltaylor
Copy link

Little bit late to the party but might be of value:

I have a 'general helpers' file in my app which exports an 'onAndroid' function with the implementation as such:

/* App/Lib/GeneralHelpers.js */
import { Platform } from 'react-native'

// Simple Platform boolean
export const onAndroid = () => Platform.OS === 'android'

This gives me the opportunity to easily make platform-specific code in components like this:

/* App/Components/randomComponent.js */
[...]
return(
 <Text>
    { onAndroid() ? "android device" : "ios device" } 
 </Text>
)

and, why I'm typing this, to test components on a specific platform by mocking the 'onAndroid' function like so:

/* Tests/Components/randomComponent-test.js */
import * as helpers from '../../App/Lib/GeneralHelpers'

helpers.onAndroid = jest.fn(() => true)
  [...]
  // do some android specific testing
  expect(TestRandomComponent.children[0]).toBe("android device")

helpers.onAndroid = jest.fn(() => false)
  [...]
  // do some iOS specific testing
  expect(TestRandomComponent.children[0]).toBe("ios device")

Absolutely brilliant approach works wonderfully.

@vyarmak
Copy link

vyarmak commented Mar 11, 2020

Bumped on the same problem. It seems like haste for now is the only way to solve this.
Created a dummy test project to have a possibility to run 2 set of tests (iOS and Android):

https://github.com/vyarmak/react-native-platform-testing

@Temirtator
Copy link

i have the same issue too.

@jagwingchoy
Copy link

jagwingchoy commented Aug 26, 2020

No other than setting projects config separately for iOS/Android/other platforms.

I would like to do snapshot tests for both iOS and Android, so the haste settings in the config file are not working for me.
@thymikee Any other working solution for snapshot tests? Thanks.

@github-actions
Copy link

This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label Feb 25, 2023
@github-actions
Copy link

This issue was closed because it has been stalled for 30 days with no activity. Please open a new issue if the issue is still relevant, linking to this one.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Mar 27, 2023
@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 27, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests