【问题标题】:Error running tests with Detox in Expo React Native project在 Expo React Native 项目中使用 Detox 运行测试时出错
【发布时间】:2020-11-18 01:58:29
【问题描述】:

当我尝试在 React Native Expo 项目中使用 detox 运行测试时,我收到以下错误:

detox[18834] WARN:  [Client.js/PENDING_REQUESTS] App has not responded to the network requests below:
  (id = -1000) isReady: {}

That might be the reason why the test "Login workflow should have login screen" has timed out.

detox[18834] INFO:  Login workflow: should have login screen [FAIL]

 FAIL  e2e/firstTest.e2e.js (137.697 s)
  Login workflow
    ✕ should have login screen (120015 ms)

  ● Login workflow › should have login screen

    thrown: "Exceeded timeout of 120000 ms for a hook.
    Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."

       7 |   });
       8 |
    >  9 |   it('should have login screen', async () => {
         |   ^
      10 |     await expect(element(by.id('loginFormTitle'))).toBeVisible()
      11 |   });
      12 |

      at firstTest.e2e.js:9:3
      at Object.<anonymous> (firstTest.e2e.js:8:1)

detox[18833] ERROR: [cli.js] Error: Command failed: node_modules/.bin/jest --config e2e/config.json '--testNamePattern=^((?!:android:).)*$' --maxWorkers 1 e2e

我正在运行 iPhone 11 Pro 模拟器,并且 expo 应用程序已经在单独的服务器中运行。我的/bin 文件夹中还有一个Exponent.app,这是我从Expo 网站下载的。我的测试用例中的逻辑不需要任何超时,它只涉及一个简单的登录屏幕。

这个错误有什么解决办法吗?

【问题讨论】:

    标签: react-native expo e2e-testing detox


    【解决方案1】:

    我在使用最新版本的 Expo (v39) 时遇到了类似的问题。

    问题似乎在于,Detox 在运行测试之前会等待应用程序就绪事件,但这不会在最新版本的 Expo SDK 中触发。

    我最终得到的解决方案是创建应用的独立版本并针对它运行 Detox。

    我的.detoxrc.json 看起来像:

    {
      ...,
      "configurations": {
        "ios": {
          "type": "ios.simulator",
          "build": "expo build:ios -t simulator",
          "binaryPath": "bin/myapp.app",                                                                                                            
        }
      }
    }
    

    【讨论】:

    • 那么构建二进制文件而不是下载它?
    • @conor909 是的,它会触发 Expo 服务器上的二进制构建过程,这需要一些时间。我厌倦了等待它运行并最终编写了自己的构建脚本,该脚本利用turtle-cli(另一个 Expo 工具)来构建二进制文件。它的速度要快得多。
    【解决方案2】:

    截至 2020 年 12 月,我将 detox 17.14.3 与 Expo 39.0.5 一起使用,并且无需使用独立版本即可解决此问题。下面提供了补丁和解释。

    原来detox-expo-helpers 覆盖了一个环境变量(特别是SIMCTL_CHILD_DYLD_INSERT_LIBRARIES)来指定ExpoDetoxHook 框架的路径(由expo-detox-hook 包提供)。好吧,对环境的更新现在在周期中发生得太晚了。它发生在运行 Detox 的 reloadApp 时,但到那时,Detox 已经启动了 Jest,它让工作人员使用自己的 process.env 副本运行。在创建时 get a copyprocess.env 的工作人员,并且它们不与父进程共享,因此该库对环境变量所做的更改不会反映在 Jest 工作人员内部。正在运行的应用程序无法使用钩子框架,因此 Detox 卡在等待未到来的就绪信号。

    Detox 的 iOS 模拟器 launchApp 使用 SIMCTL_CHILD_DYLD_INSERT_LIBRARIES 指定它自己的库,但由于环境变量在工作器中是隔离的,它看不到这个包所做的更改。为了解决这个问题,我修改了这个库,将对 process.env 的更改作为一个单独的导出函数公开,然后我在测试生命周期的更早的时候调用它,以确保在启动任何工作程序之前设置它。这是一个兼容patch-package的补丁。

    # file patches/detox-expo-helpers+0.6.0.patch
    
    diff --git a/node_modules/detox-expo-helpers/index.js b/node_modules/detox-expo-helpers/index.js
    index 864493b..3147a55 100644
    --- a/node_modules/detox-expo-helpers/index.js
    +++ b/node_modules/detox-expo-helpers/index.js
    @@ -45,7 +45,16 @@ function resetEnvDyldVar(oldEnvVar) {
       }
     }
     
    -const reloadApp = async (params) => {
    +let initialized = false;
    +let detoxVersion;
    +let oldEnvVar;
    +const init = () => {
    +  if (initialized) {
    +    return;
    +  }
    +
    +  initialized = true;
    +
       if (!fs.existsSync(expoDetoxHookPackageJsonPath)) {
         throw new Error("expo-detox-hook is not installed in this directory. You should declare it in package.json and run `npm install`");
       }
    @@ -56,12 +65,16 @@ const reloadApp = async (params) => {
         throw new Error ("expo-detox-hook is not installed in your osx Library. Run `npm install -g expo-detox-cli && expotox clean-framework-cache && expotox build-framework-cache` to fix this.");
       }
     
    -  const detoxVersion = getDetoxVersion();
    -  const oldEnvVar = process.env.SIMCTL_CHILD_DYLD_INSERT_LIBRARIES;
    +  detoxVersion = getDetoxVersion();
    +  oldEnvVar = process.env.SIMCTL_CHILD_DYLD_INSERT_LIBRARIES;
     
       if (semver.gte(detoxVersion, '9.0.6')) {
         process.env.SIMCTL_CHILD_DYLD_INSERT_LIBRARIES = expoDetoxHookFrameworkPath;
       }
    +}
    +
    +const reloadApp = async (params) => {
    +  init();
     
       const formattedBlacklistArg = await blacklistCmdlineFormat(params && params.urlBlacklist);
       const url = await getAppUrl();
    @@ -121,5 +134,6 @@ module.exports = {
       getAppUrl,
       getAppHttpUrl,
       blacklistLiveReloadUrl,
    +  init,
       reloadApp,
     };
    
    

    有了这个,我修改了我的e2e/environment.js 文件,如下所示。添加的是initExpo 调用。当它在测试生命周期的早期运行时,环境会在任何工作程序启动之前被修改,因此,对reloadApp 的调用不再无限期地等待。

    /* eslint-disable import/no-extraneous-dependencies */
    const { init: initExpo } = require('detox-expo-helpers');
    const { DetoxCircusEnvironment, SpecReporter, WorkerAssignReporter } = require('detox/runners/jest-circus');
    
    class CustomDetoxEnvironment extends DetoxCircusEnvironment {
      constructor(config) {
        super(config);
    
        initExpo();
    
        // Can be safely removed, if you are content with the default value (=300000ms)
        this.initTimeout = 300000;
    
        // This takes care of generating status logs on a per-spec basis. By default, Jest only reports at file-level.
        // This is strictly optional.
        this.registerListeners({
          SpecReporter,
          WorkerAssignReporter,
        });
      }
    }
    
    module.exports = CustomDetoxEnvironment;
    
    

    【讨论】:

    • 不错!您是否向图书馆的 github 提交了 PR,以便此修复将其纳入未来的版本?
    猜你喜欢
    • 2019-10-19
    • 2021-01-07
    • 2018-06-04
    • 2018-03-11
    • 2019-07-15
    • 2022-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多