[英]Error running tests with Detox in Expo React Native project
當我嘗試在 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 的網站下載的。 我的測試用例中的邏輯不需要任何超時,它只涉及一個簡單的登錄屏幕。
這個錯誤有什么解決辦法嗎?
我在使用最新版本的 Expo (v39) 時遇到了類似的問題。
似乎問題在於 Detox 在運行測試之前等待應用程序就緒事件,但這不會被最新版本的 Expo SDK 觸發。
我最終得到的解決方案是創建應用程序的獨立構建並針對它運行 Detox。
我的.detoxrc.json
看起來像:
{
...,
"configurations": {
"ios": {
"type": "ios.simulator",
"build": "expo build:ios -t simulator",
"binaryPath": "bin/myapp.app",
}
}
}
截至 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
副本運行。 工作人員在創建時獲得了process.env
的副本,並且它們不與父進程共享,因此該庫對環境變量所做的更改不會反映在 Jest 工作人員內部。 正在運行的應用程序無法使用鈎子框架,因此 Detox 卡在等待未到來的就緒信號。
Detox 的 iOS 模擬器的launchApp
使用SIMCTL_CHILD_DYLD_INSERT_LIBRARIES
來指定它自己的庫,但由於環境變量在 worker 中是隔離的,它看不到這個 package 所做的更改。 為了解決這個問題,我修改了這個庫,將 process.env 的更改作為單獨的導出 function 公開,然后我在測試生命周期的早期調用它,以確保在啟動任何工作程序之前設置它。 這是一個與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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.