Testing I';我正在努力测试这部重演传奇

Testing I';我正在努力测试这部重演传奇,testing,redux,react-redux,redux-saga,Testing,Redux,React Redux,Redux Saga,我是redux传奇的新手,正在努力测试这段代码: import { normalize } from 'normalizr'; export function* normalizeResponse(denormalized, schema) { const normalized = yield call(normalize, denormalized, schema); return normalized; } export function* request(apiFn, acti

我是redux传奇的新手,正在努力测试这段代码:

import { normalize } from 'normalizr';

export function* normalizeResponse(denormalized, schema) {
  const normalized = yield call(normalize, denormalized, schema);
  return normalized;
}

export function* request(apiFn, action, schema) {
  try {
    yield put(requestStart({ type: action.type }));
    const denormalized = yield call(apiFn, action.payload, action.meta);
    const normalized = yield call(normalizeResponse, denormalized, schema);
    yield put(requestSuccess({ type: action.type }));
    return normalized;
  } catch (e) {
    if (__DEV__ && !__TEST__) {
      Alert.alert('Something went wrong');
      console.log(`Error in request saga: ${action.type}`, e);
    }
    if (action.type) {
      const payload = { type: action.type, error: e };
      const meta = action.payload || {};
      yield put(requestFailure(payload, meta));
    }
  }
}

export function* photosShow() {
  while (true) {
    const action = yield take(t.PHOTOS_SHOW);
    const normalized = yield call(request, api.show, action, {
      photo: schema.photo,
    });
    if (normalized) yield put(setEntities(normalized));
  }
}
在网上,我找到了许多redux saga测试包和一些教程,但似乎没有一个比基本内容涵盖更多。下面是这部传奇的一步一步的运作过程:

  • photoshow
    通过通量标准操作调用,有效负载为{id:1}
  • 这将调用生成器
    请求
    ,这是一个实用函数,用于发出API请求,然后使响应正常化
  • 首先,将触发
    requestStart
    操作
  • 然后将调用api端点
  • 如果成功,将触发requestSuccess操作
  • 然后使用normalizer对响应进行归一化
  • 然后使用
    setEntities
    (返回Photoshow)以redux状态存储

任何关于如何进行这项工作的帮助都将不胜感激。

我也在努力阅读所有的
redux saga
测试资源。。。没有找到合适的解决方案(至少对我来说)

我的结局是:

  • 我“呈现”一个空的React应用程序和一个工作商店
  • 我手动触发有趣的动作(触发我正在测试的传奇故事的动作)
  • 我窥探传说消耗的所有外部资源
最后:我触发了传说,我发现他们触发了其他东西

<>我认为SAGAS是一个黑盒子,我检查他们和应用程序的所有其他部分都遵守合同。

我从我的身份验证sagas测试中举了一个例子(我打破了很多测试良好实践,我知道,它来自于我早期使用saga进行测试的日子)(参见下面的
renderWithRedux
spyUtil
函数):

其中:

  • LOGIN\u SUCCESS\u creator
    是一个动作创建者
  • 导航
    来自Reach路由器
  • postLogin
    发出AJAX请求(用假函数模拟它,几乎立即返回“成功”响应(但解决承诺))
  • redirectBackFromLoginPage
    是一个函数,可在某些条件下再次使用
    导航
    实用程序

    • 我触发了
      LOGIN\u请求
      操作,我希望使用正确的凭据调用了AJAX触发器函数
  • 我检查
    LOGIN\u SUCCESS
    操作是否将与auth令牌一起发送
  • 我检查路由器是否使用正确的路由调用(
    /
    用于主页)
  • 然后,我清除了一切



这是“我的”(来自Kent C.Dodds)
renderWithRedux
函数

// @see https://github.com/kentcdodds/react-testing-library/blob/master/examples/__tests__/react-redux.js
export function renderWithRedux(ui, { initialState, store = configureStore() } = {}) {
  return {
    ...render(
      <div>
        <Provider store={store}>{ui}</Provider>
      </div>
    ),
    // adding `store` to the returned utilities to allow us
    // to reference it in our tests (just try to avoid using
    // this to test implementation details).
    store
  };
}
/**
 * A all-in-one spy and mock function
 * @param {object} obj
 * @param {string} name
 * @param {function} mockFunction
 */
export function spyUtil(obj, name, mockFunction = undefined) {
  const spy = jest.spyOn(obj, name);
  let mock;
  if (mockFunction) {
    mock = jest.fn(mockFunction);
    obj[name].mockImplementation(mock);
  }
  return { spy, mock };
}
请注意,这只是身份验证流程之一,我没有在这里报告所有案例


我想知道你对此的想法我也在努力阅读所有的
redux传奇
测试资源。。。没有找到合适的解决方案(至少对我来说)

我的结局是:

  • 我“呈现”一个空的React应用程序和一个工作商店
  • 我手动触发有趣的动作(触发我正在测试的传奇故事的动作)
  • 我窥探传说消耗的所有外部资源
最后:我触发了传说,我发现他们触发了其他东西

<>我认为SAGAS是一个黑盒子,我检查他们和应用程序的所有其他部分都遵守合同。

我从我的身份验证sagas测试中举了一个例子(我打破了很多测试良好实践,我知道,它来自于我早期使用saga进行测试的日子)(参见下面的
renderWithRedux
spyUtil
函数):

其中:

  • LOGIN\u SUCCESS\u creator
    是一个动作创建者
  • 导航
    来自Reach路由器
  • postLogin
    发出AJAX请求(用假函数模拟它,几乎立即返回“成功”响应(但解决承诺))
  • redirectBackFromLoginPage
    是一个函数,可在某些条件下再次使用
    导航
    实用程序

    • 我触发了
      LOGIN\u请求
      操作,我希望使用正确的凭据调用了AJAX触发器函数
  • 我检查
    LOGIN\u SUCCESS
    操作是否将与auth令牌一起发送
  • 我检查路由器是否使用正确的路由调用(
    /
    用于主页)
  • 然后,我清除了一切



这是“我的”(来自Kent C.Dodds)
renderWithRedux
函数

// @see https://github.com/kentcdodds/react-testing-library/blob/master/examples/__tests__/react-redux.js
export function renderWithRedux(ui, { initialState, store = configureStore() } = {}) {
  return {
    ...render(
      <div>
        <Provider store={store}>{ui}</Provider>
      </div>
    ),
    // adding `store` to the returned utilities to allow us
    // to reference it in our tests (just try to avoid using
    // this to test implementation details).
    store
  };
}
/**
 * A all-in-one spy and mock function
 * @param {object} obj
 * @param {string} name
 * @param {function} mockFunction
 */
export function spyUtil(obj, name, mockFunction = undefined) {
  const spy = jest.spyOn(obj, name);
  let mock;
  if (mockFunction) {
    mock = jest.fn(mockFunction);
    obj[name].mockImplementation(mock);
  }
  return { spy, mock };
}
请注意,这只是身份验证流程之一,我没有在这里报告所有案例


我想知道你的想法,亚历克斯?你看过我的答案了吗?亚历克斯?你看过我的答案了吗?
test("2 - then when the login API is successfull, a LOGIN_SUCCESS action should be dispatched with the tokens", async () => {
  expect(spies.LOGIN_SUCCESS_creator.spy).toHaveBeenCalledWith(
    expect.any(String),
    expect.any(String)
  );
});
test("3 - then the router should be asked to make a redirect to the initial location", async () => {
  expect(spies.redirectBackFromLoginPage.spy).toHaveBeenCalled();
  expect(spies.navigate.spy).toHaveBeenCalledWith(expect.stringMatching(/\//));
});
afterAll(() => {
  spies.values().forEach(obj => obj.spy.mockRestore());
  // spiedConsole.mockRestore();
  cleanup();
});
// @see https://github.com/kentcdodds/react-testing-library/blob/master/examples/__tests__/react-redux.js
export function renderWithRedux(ui, { initialState, store = configureStore() } = {}) {
  return {
    ...render(
      <div>
        <Provider store={store}>{ui}</Provider>
      </div>
    ),
    // adding `store` to the returned utilities to allow us
    // to reference it in our tests (just try to avoid using
    // this to test implementation details).
    store
  };
}
/**
 * A all-in-one spy and mock function
 * @param {object} obj
 * @param {string} name
 * @param {function} mockFunction
 */
export function spyUtil(obj, name, mockFunction = undefined) {
  const spy = jest.spyOn(obj, name);
  let mock;
  if (mockFunction) {
    mock = jest.fn(mockFunction);
    obj[name].mockImplementation(mock);
  }
  return { spy, mock };
}