【问题标题】:Jasmine functional tests with React使用 React 进行 Jasmine 功能测试
【发布时间】:2018-10-25 23:40:37
【问题描述】:

有人可以解释将 Jasmine 测试运行器集成到 React 应用程序(不添加 Karma)的正确方法吗?我正在将我的测试用例部署到电视上并在现场运行独立的规范运行器。我不得不内联和转译 JS,这是我遇到麻烦的地方。我最终手动将 jasmine.js jasmine-html.js 和 boot.js 文件连接到 jasmine-all.js 文件中,并插入一个调用来定义 jasmineRequire,如下所示:

jasmineRequire = getJasmineRequireObj();

这是在 jasmine-html.js 内联之前。然后我在我的 React 根组件中添加了一个 sn-p 来加载整个内容,如下所示:

  componentDidMount() {
   import('./jasmine/lib/jasmine-3.2.1/jasmine-all')
     .then(() => {return import('./spec/MyAppSpec');});
  }

我在这里使用动态导入来保证执行顺序。这个想法是让应用程序加载,然后加载测试运行程序,最后加载 功能 测试,这些测试作为一个整体来运行应用程序。这些测试会将关键事件和输入发送到应用,就像它是最终用户一样。

我知道有一种不那么笨拙的方法可以做到这一点,但我想不通。我想以正确的方式执行此操作,以便我可以正确地包含我目前直接在我的规范文件中导入的任何规范助手文件。非常感谢任何指导!

【问题讨论】:

  • 我不确定在componentDidMount 中进行导入有什么意义。这是一个应该实例化组件的规范,而不是相反的方式。 我在这里使用动态导入来保证执行顺序 - 你不能。组件在安装后可能会发生变化。它们可能是异步的,并且不会有链接的承诺。您可能会在规范中到处出现笨拙的 setTimeouts 。我建议不要将工具用于他们不适合的工作。一些像 Testcafe 这样的 e2e 框架会更合适。如果你想测试整个 React 应用程序是如何工作的,只需像任何其他 JS 应用程序一样测试它
  • 我没有从规范中实例化组件。这些功能测试旨在在整个应用加载后运行,因为它们将应用作为单个黑盒单元进行测试。
  • 我还需要确保在测试运行程序加载之前不执行规范。这就是我使用动态导入背后的意图。我导入测试运行器,然后加载/运行我的规范。我更新了我的问题,以进一步强调这些是功能测试,如果标题中不清楚的话。
  • 看来我理解正确。正如我所说,您选择了错误的工具。 E2e 框架具有用于黑盒测试的特定功能,例如等待 DOM 元素出现等,不管幕后的异步进程如何。 Jasmine 仅具有单元测试功能。可以在那里进行 e2e 测试,但您需要从头开始编写此功能,即编写一组专用于 E2E 的辅助函数(Protractor E2E 框架基于 Jasmine,IIRC)。
  • 谢谢,我明白你在说什么。为了澄清,我研究了各种 e2e 框架,不幸的是,其中许多对我正在开发的平台提出了挑战。我的目标是访问受限的 Tizen 2.x 电视。许多这些工具将需要 root 访问权限和/或添加二进制文件以促进检测。我将 Jasmine 用作穷人自己的自动化,这是我过去在 Android 上做过的事情。

标签: javascript reactjs jasmine


【解决方案1】:

无法保证应用程序在根组件componentDidMount 中达到其稳定状态,即使 API 请求等所有异步操作都被存根。它应该以相反的方式完成,即应用程序在测试中初始化并等待稳定。

Jasmine 中没有用于功能/E2E 测试的内置功能,它必须从头开始编写。

有点像:

async function waitForElement(selector, parent = document, timeout = 2000) {
  let isTimeout;

  setTimeout(() => {
    isTimeout = true;
  }, timeout);

  let el;
  while (!(el = parent.querySelector(selector))) {
    if (isTimeout) throw new Error('timeout');
    await new Promise(resolve => setTimeout(resolve, 50));
  }

  return el;
}

const root = document.getElementById('root');
beforeEach(() => {
  ReactDOM.render(<App/>, root);
});

afterEach(() => {
  ReactDOM.unmountComponentAtNode(root);
});

it('should have foo child', async () => {
  const foo = await waitForElement('div.foo', root, 5000);
  expect($(foo).text()).toContain('foo text');
});  

测试是基于 promise 的,并且依赖于等待结果出现在 DOM 中,因为这是异步发生的。

waitForElement仅供参考,因为它不足以进行实际的端到端测试;将需要 querySelector 不支持的高级选择器(可以通过 jQuery 增强)或自定义谓词函数。

这是 E2E 框架(如 TestCafe 和 Protractor)应该具备的功能,此功能的可用性不同于用于单元测试的框架。例如。 TestCafe 有reusable and chainable selectors,可以在需要元素的地方进行隐式处理。

【讨论】:

  • 谢谢,我知道你要去哪里了。我在想我的直接问题是通过导入正确加载茉莉花,但您表示我最终会遇到同步问题,因为当componentDidMount() 触发时,某些元素不能保证可用。我会研究一下 testcafe,因为它听起来像是解决了我在设备上运行 Web 驱动程序的直接限制。
  • 我最终会遇到同步问题,因为某些元素不能保证可用 - 没错,这就是黑盒测试应该解决的问题。
  • 仍然很难弄清楚如何让 testcafe 自动化我的 React TV 应用程序,因为它与启动浏览器不同。我需要加载的“页面”是应用程序包上下文中的 index.js。我不得不以某种方式欺骗电视启动应用程序而不是加载页面。 testcafe 是否有一个我可以捆绑的测试 html,它可以调用跑步者的家?
  • 在此处进行远程测试:devexpress.github.io/testcafe/documentation/recipes/… 看起来我可以让我的远程设备在本地网络上打开一个 URL,但随后会退出我的app 并运行网络浏览器。我需要在我的应用程序中加载/测试页面,而不是运行可能有点挑战的浏览器。
  • 刚刚忘记了npmjs.com/package/react-testing-library。它不依赖于测试框架,可以与 Jasmine 一起使用。由于它专注于功能测试,它已经包含了几个帮助器,比如 waitForElement。
最近更新 更多