英文:
Test is failing in Detox when the layout is overlayed
问题
Detox在测试点击按钮时出现以下错误,点击动作生效,但由于状态更改导致组件重新渲染,测试奇怪地希望再次点击按钮,但由于按钮不在视图中,测试失败。
测试失败:等待
[com.wix.detox.reactnative.idlingresources.AnimatedModuleIdlingResource]
变为空闲已超时
我的测试脚本:
await element(by.id("post-1-cm")).tap();
await waitFor(element(by.id("comment-error")))
.not.toExist()
.withTimeout(5000);
按钮组件:
<AppButton
onPress={() => toggleComments(true)}
disabled={disabled || submitting}
inverted
testID={`${testID}-cm`}
buttonStyles={styles.button}>
当点击按钮并且toggleComments
更改showComments
状态为True时,渲染的组件代码:
{showComments && (
<CommentsModal
reloadPosts={props.reload}
visible={showComments}
blockUser={blockUser}
close={() => toggleComments(false)}
/>
)}
英文:
I get the following error in Detox when the test clicks on a button, the click works but after the component re-renders because of a state change, the test strangely wants to click on the button again but since the button is not in the view, the test fails.
> Test Failed: Wait for
> [com.wix.detox.reactnative.idlingresources.AnimatedModuleIdlingResource]
> to become idle timed out
My test script:
await element(by.id("post-1-cm")).tap();
await waitFor(element(by.id("comment-error")))
.not.toExist()
.withTimeout(5000);
The Button component:
<AppButton
onPress={() => toggleComments(true)}
disabled={disabled || submitting}
inverted
testID={`${testID}-cm`}
buttonStyles={styles.button}>
Code of the component that gets rendered when the button is clicked and toggleComments changes the showComments state to True:
{showComments && (
<CommentsModal
reloadPosts={props.reload}
visible={showComments}
blockUser={blockUser}
close={() => toggleComments(false)}
/>
)}
答案1
得分: 1
Detox android/espressoapi/UIDevice.js
中有一个 waitForIdle(element)
函数。
但如果这不适用于您的用例,您可以尝试将测试脚本包装在 InteractionManager
中:
InteractionManager.runAfterInteractions(() => {
// ...长时间运行的同步任务...
element(by.id("post-1-cm")).tap();
});
这样,您可以在运行测试之前首先检查是否足够让您的 AnimatedModuleIdlingResource
变为空闲状态。
由于在 Detox 测试文件中导入 InteractionManager
复杂或不可能,因为 InteractionManager
是 React Native API 的一部分,旨在用于应用程序代码,而不是测试代码,您可能需要另一种方法。
我了解 Detox 测试旨在与应用程序的 UI 进行交互并模拟用户操作。它们在单独的 JavaScript 环境中运行,没有直接访问应用程序代码中使用的 React Native API。
因此,您可能需要等待 CommentsModal
组件出现,然后再检查按钮不存在。这应该有助于确保测试在视图中不存在按钮时不会再次尝试点击按钮,从而避免错误。
如果可能的话,请尝试在代码中为 CommentsModal
组件添加一个 testID
:
{showComments && (
<CommentsModal
testID="CommentsModal"
reloadPosts={props.reload}
visible={showComments}
blockUser={blockUser}
close={() => toggleComments(false)}
/>
)}
这将允许脚本等待 CommentsModal
出现,然后再检查按钮不存在。
await element(by.id("post-1-cm")).tap();
// 等待CommentsModal出现
await waitFor(element(by.id("CommentsModal")))
.toBeVisible()
.withTimeout(5000);
await waitFor(element(by.id("comment-error")))
.not.toExist()
.withTimeout(5000);
可以通过 await device.disableSynchronization();
进行禁用。
或者使用启动参数,例如 -detoxEnableSynchronization NO
。
OP 确认 await device.disableSynchronization();
已足够。
英文:
Detox android/espressoapi/UIDevice.js
does have a waitForIdle(element)
function.
But if this does not apply to your use case, you might try and wrap your test script in a InteractionManager
:
InteractionManager.runAfterInteractions(() => {
// ...long-running synchronous task...
element(by.id("post-1-cm")).tap();
});
That way, you can check if that is enough to allow your AnimatedModuleIdlingResource
to become idle first, before running your rest.
Since importing InteractionManager
in the Detox test file is complex/impossible, because InteractionManager
is part of the React Native API and is intended for use within the application code, not the test code, you might need another approach.
I understand Detox tests are designed to interact with the application's UI and simulate user actions. They run in a separate JavaScript environment and don't have direct access to the React Native APIs that are used in the application code.
So you might have to wait for the CommentsModal
component to appear before checking for the non-existence of the button. This should help ensure that the test doesn't try to click the button again when it's not in the view, thus avoiding the error.
If possible, try and add a testID
to the CommentsModal
component in your code:
{showComments && (
<CommentsModal
testID="CommentsModal"
reloadPosts={props.reload}
visible={showComments}
blockUser={blockUser}
close={() => toggleComments(false)}
/>
)}
That would allow for the script to wait for the CommentsModal
to appear before checking for the non-existence of the button.
await element(by.id("post-1-cm")).tap();
// Wait for CommentsModal to appear
await waitFor(element(by.id("CommentsModal")))
.toBeVisible()
.withTimeout(5000);
await waitFor(element(by.id("comment-error")))
.not.toExist()
.withTimeout(5000);
If this is not enough, as seen in the discussion, you can try and try and disable synchronization.
Either through await device.disableSynchronization();
Or with a launch parameter like -detoxEnableSynchronization NO
.
The OP confirms await device.disableSynchronization();
was enough.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论