由于反应导航生成密钥,Jest快照测试失败

时间:2018-02-25 14:30:17

标签: react-native jestjs react-navigation

我的Jest测试失败,因为每次测试运行时密钥的时间戳都不同:

 FAIL  ./App.test.js
  ✕ renders without crashing (72ms)

  ● renders without crashing

expect(value).toMatchSnapshot()

Received value does not match stored snapshot 1.

- Snapshot
+ Received

@@ -347,11 +347,11 @@
              "index": 0,
              "isTransitioning": false,
              "key": "StackRouterRoot",
              "routes": Array [
                Object {
-                 "key": "id-1519567169760-0",
+                 "key": "id-1519567814666-0",
                  "routeName": "Menu",
                },
              ],
            },
          }

这是我的App.js文件:

import React from 'react';
import { StackNavigator } from 'react-navigation';
import Menu from './components/Menu';
import List from './components/List';

const RootStack = StackNavigator(
  {
    Menu: {
      screen: Menu,
    },
    List: {
      screen: List,
    },
  },
  {
    initialRouteName: 'Menu',
  }
);

export default class App extends React.Component {
   render() {
     return <RootStack />;
   }
}

这是我的测试文件:

import React from 'react';
import App from './App';

import renderer from 'react-test-renderer';

test('renders without crashing', () => {
  const rendered = renderer.create(<App />).toJSON();
  expect(rendered).toBeTruthy();
  expect(rendered).toMatchSnapshot();
});

是否可以覆盖键值,或者在测试运行时是否有办法忽略键?

4 个答案:

答案 0 :(得分:2)

您可以模拟不确定的数据。 https://facebook.github.io/jest/docs/en/snapshot-testing.html#tests-should-be-deterministic

  

例如,如果你有一个使用Date.now()的Clock组件,那么   从此组件生成的快照每次都会有所不同   测试用例运行。在这种情况下,我们可以模拟Date.now()方法   每次运行测试时返回一致的值:

     

Date.now = jest.fn(()=&gt; 1482363367071);

     

现在,每次快照测试用例运行时,Date.now()都会返回   始终是1482363367071。这将产生相同的快照   无论何时运行测试,都会为此组件生成。

答案 1 :(得分:2)

您可以在jest设置文件中使用模拟函数覆盖键值: https://facebook.github.io/jest/docs/en/configuration.html#setupfiles-array

通过将Date.now模拟为Date.now = jest.fn(() => 123)来将密钥设置为始终相同,因为引擎反应导航使用此方法生成路由密钥:https://github.com/react-navigation/react-navigation/blob/master/src/routers/KeyGenerator.js

答案 2 :(得分:2)

较新版本的jest还支持property matchers,该{{3}}允许使用匹配器来评估快照的某些部分,而不是要求整个快照都相同。

以下是文档中的示例:

it('will check the matchers and pass', () => {
  const user = {
    createdAt: new Date(),
    id: Math.floor(Math.random() * 20),
    name: 'LeBron James',
  };

  expect(user).toMatchSnapshot({
    createdAt: expect.any(Date),
    id: expect.any(Number),
  });
});

// Snapshot
exports[`will check the matchers and pass 1`] = `
Object {
  "createdAt": Any<Date>,
  "id": Any<Number>,
  "name": "LeBron James",
}
`;

答案 3 :(得分:1)

我找到了完全不同的解决方案,作为对自己类似问题的回答。

Snapshot test with Jest on nested react-navigation component - Object keys change so Snapshot match fails

我解决了我的问题,但没有通过嘲笑Date.now来解决。

相反,我改编了一个名为 joeybaker 的用户在https://github.com/react-navigation/react-navigation/issues/2269#issuecomment-369318490上找到的答案。

其理由如下:

  

对于您的测试目的,键并不是很重要。你什么   真正关心的是路线和索引。

他的代码如下,并假定在 Redux 中使用动作和缩减器:

// keys are date and order-of-test based, so just removed them
const filterKeys = (state) => {
  if (state.routes) {
    return {
      ...state,
      routes: state.routes.map((route) => {
        const { key, ...others } = route
        return filterKeys(others)
      }),
    }
  }
  return state
}

it('clears all other routes', () => {
    const inputState = {}
    const action = { type: AUTH_LOGOUT_SUCCESS }
    const state = filterKeys(reducer(inputState, action))
    expect(state.routes).toBe........
})

我已针对我的情况进行了以下调整(我尚未使用 Redux ):

test("renders correctly", () => {

  const tree = renderer.create(<StackNavigator />);
  const instance = tree.getInstance();
  const state = filterKeys(instance.state.nav);

  expect(state).toMatchSnapshot();
});

// keys are date and order-of-test based, so just removed them
const filterKeys = (state) => {
  if (state.routes) {
    return {
      ...state,
      routes: state.routes.map((route) => {
        const { key, ...others } = route
        return filterKeys(others);
      }),
    }
  }
  return state;
};

呈现的测试如下:

// Jest Snapshot v1

exports[`renders correctly 1`] = `
Object {
  "index": 0,
  "isTransitioning": false,
  "key": "StackRouterRoot",
  "routes": Array [
    Object {
      "index": 0,
      "isTransitioning": false,
      "routeName": "FluidTransitionNavigator",
      "routes": Array [
        Object {
          "routeName": "SignInOrRegister",
        },
      ],
    },
  ],
}
`;