Mi prueba de Jest falla debido a que la marca de tiempo en la clave es diferente cada vez que se ejecuta la prueba:

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

Aquí está mi archivo 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 />;
   }
}

Aquí está mi archivo de prueba:

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();
});

¿Es posible anular el valor de la clave o hay una forma de ignorar la clave cuando se ejecuta la prueba?

4
Graeme MacFarlane 25 feb. 2018 a las 17:30

4 respuestas

La mejor respuesta

Las versiones más recientes de jest también admiten emparejadores de propiedades que permiten ciertas partes del la instantánea se evaluará utilizando un comparador en lugar de requerir que toda la instantánea sea idéntica.

Aquí hay un ejemplo que muestra algunos enfoques diferentes para usar esta función para resolver la pregunta de OP:

it('Should ignore route keys in snapshot', () => {
  const testObject = {
    index: 0,
    isTransitioning: false,
    key: 'StackRouterRoot',
    routes: [
      {
        key: `id-${Date.now()}-0`,
        routeName: 'Menu',
      },
      {
        key: `id-${Date.now()}-1`,
        routeName: 'Splash',
      },
    ],
  };

  expect(testObject).toMatchSnapshot({
    routes: [
      {
        key: expect.stringMatching(/id-\d+?-\d/),
        routeName: 'Menu',
      },
      {
        key: expect.stringMatching(/id-\d+?-\d/),
        routeName: 'Splash',
      },
    ],
  }, 'Explicitly list all routes');

  expect(testObject).toMatchSnapshot({
    routes: expect.arrayContaining([
      expect.objectContaining({
        key: expect.stringMatching(/id-\d+?-\d/),
      }),
    ]),
  }, 'Match any route');
});

Lo que produce las siguientes instantáneas:

exports[`<App /> Should ignore route keys in snapshot: Explicitly list all routes 1`] = `
Object {
  "index": 0,
  "isTransitioning": false,
  "key": "StackRouterRoot",
  "routes": Array [
    Object {
      "key": StringMatching /id-\\\\d\\+\\?-\\\\d/,
      "routeName": "Menu",
    },
    Object {
      "key": StringMatching /id-\\\\d\\+\\?-\\\\d/,
      "routeName": "Splash",
    },
  ],
}
`;

exports[`<App /> Should ignore route keys in snapshot: Match any route 1`] = `
Object {
  "index": 0,
  "isTransitioning": false,
  "key": "StackRouterRoot",
  "routes": ArrayContaining [
    ObjectContaining {
      "key": StringMatching /id-\\\\d\\+\\?-\\\\d/,
    },
  ],
}
`;

Otra característica de broma que encontré recientemente que podría ayudar aquí es serializadores de instantáneas personalizados . Usando esta función, creo que podría agregar un serializador para objetos de ruta que eliminaría la clave o la reemplazaría con un valor estático antes de que se serialice. No puedo proporcionar un ejemplo en este momento, ya que aún no he usado esta función, pero me pareció que valía la pena mencionarla.

2
Eliot 24 jun. 2019 a las 15:46

Puede burlarse de los datos que no son deterministas. https: //facebook.github. io / jest / docs / es / snapshot-testing.html # tests-should-be-deterministic

Por ejemplo, si tiene un componente Reloj que usa Date.now (), la instantánea generada a partir de este componente será diferente cada vez que se ejecute el caso de prueba. En este caso, podemos burlarnos del método Date.now () para devolver un valor consistente cada vez que se ejecuta la prueba:

Date.now = jest.fn (() => 1482363367071);

Ahora, cada vez que se ejecuta el caso de prueba de instantánea, Date.now () devolverá 1482363367071 de manera consistente. Esto dará como resultado que se genere la misma instantánea para este componente, independientemente de cuándo se ejecute la prueba.

2
sme 25 feb. 2018 a las 14:48

Puede anular el valor de la clave utilizando una función simulada en su archivo de configuración de jest: https://facebook.github.io/jest/docs/ es / configuration.html # setupfiles-array

Configure la clave para que siempre sea la misma burlándose de Date.now en Date.now = jest.fn(() => 123) ya que debajo del capó reacciona la navegación utiliza esto para generar sus claves de ruta: https://github.com/react-navigation/react-navigation/blob/master/src/routers/KeyGenerator.js

2
Eliot 5 sep. 2018 a las 15:10

He encontrado una solución completamente diferente que he puesto como respuesta a mi propia pregunta similar.

Prueba de instantánea con Jest en el componente de navegación de reacción anidado: las teclas de objeto cambian y la coincidencia de instantánea falla

Resolví mi problema, pero no burlándome de Date.now, que se sugirió en muchos otros casos.

En cambio, adapté una respuesta que encontré en https: // github. com / react-navigation / react-navigation / issues / 2269 # issuecomment-369318490 por un usuario llamado joeybaker .

La razón de esto se dio como:

Las claves no son realmente importantes para sus propósitos de prueba. Lo que realmente te importa son las rutas y el índice.

Su código es el siguiente y supone el uso de acciones y reductores en 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........
})

He adaptado esto para mi caso (todavía no uso Redux ) de la siguiente manera:

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;
};

La prueba que se procesa se ve así:

// 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",
        },
      ],
    },
  ],
}
`;
1
Kevin van Zyl 24 nov. 2018 a las 17:17