微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Detox 测试 + React Native + PouchDB 应用程序:由于某些 PouchDB 同步,我们的登录测试一直失败并超时? 版本

如何解决Detox 测试 + React Native + PouchDB 应用程序:由于某些 PouchDB 同步,我们的登录测试一直失败并超时? 版本

tldr

似乎初始化 PouchDB 客户端的实例(调用 new PouchDB(...))会导致一些队列工作者或后台进程产生,这些进程定期向其 CouchDB 服务器发送网络请求,这样做会阻止我们的 Detox 测试套件让我们的 React Native 应用程序 + iOS 模拟器闲置并继续下一个断言,导致我们的测试失败并显示 App has not responded to the network requests belowDetoxRuntimeError: Test Failed: No elements found for “MATCHER(identifier == “foo”)”

我们曾尝试调用 device.disableSynchronization/device.enableSyncronization 或使用 launchArgs: { detoxURLBlacklistRegex: '.*' }device.setURLBlacklist(['.*']) 设置黑名单,但似乎没有任何效果

有什么方法可以让 Detox 忽略 PouchDB 网络请求,或者手动暂停 PouchDB,以便我们可以进行下一个断言?

概述

我的团队正在尝试使用 Detox 为在使用 React Native 构建的模拟器中运行的 iOS 应用编写登录测试。该应用程序使用 PouchDB 作为其网络/数据层,因此它可以连接到远程 CouchDB 服务器。

问题是 Detox 似乎总是失败/冻结/挂起和超时超过某个点,这基本上是在 PouchDB 初始化时(通过调用 new PouchDB(...))。

在我们的测试中,这是作为使用有效凭据点击登录按钮的副作用而发生的:

await element(by.id('auth.login.button')).tap();

该行之前的所有有效断言都可以正常工作(例如,尝试单击忘记密码按钮,查看下一个组件加载等)。 该行之后的任何断言都不会成功,

await expect(element(by.id('auth.linkedin.skip'))).toBeVisible();

即使我们引用的确切组件 (auth.linkedin.skip) 在计时器到期之前在模拟器中清晰可见,这通常会以两种方式之一导致失败。

场景 1 - 测试因超时而失败

测试运行了很长时间,直到它失败并显示错误消息 Timeout exceeded,或者更准确地说:

App has not responded to the network requests below:
  (id = 8) invoke: {"type":"expectation","predicate":{"type":"id","value":"auth.linkedin.skip"},"expectation":"toBeVisible"}

That might be the reason why the test "Login test allow existing the existing test user to sign in" has timed out.

在详细模式下,我们也会一遍又一遍地看到这个,直到它失败:

detox[35499] INFO:  [actions.js] The system is busy with the following tasks:

dispatch Queue
⏱ Queue: “Main Queue (<OS_dispatch_queue_main: com.apple.main-thread>)” with 2 work items

Run Loop
⏱ “Main Run Loop”

One-time Events
⏱ “Network Request” with object: “URL: “https://our.couch.endpoint/userdb-foo/bar/baz””
⏱ “Network Request” with object: “URL: “https://our.couch.endpoint/userdb-foo/bar/baz””

场景 2 - 测试过早失败

测试运行时间较短,失败并显示错误消息 DetoxRuntimeError: Test Failed: No elements found for “MATCHER(identifier == “auth.linkedin.skip”)” 并打印加载到模拟器中的本地组件堆栈,这些组件与前一个登录屏幕(而不是下一个屏幕,具有Linkedin 按钮,并且在失败时已经加载到模拟器中)。

另外令人困惑的是,这两种情况大约会在 67% / 33% 的时间内发生,这意味着每次没有超时的失败都会发生大约两次超时失败,所有这些都使用完全相同的测试命令,执行之间的测试和配置。

排毒测试

describe('Login test',() => {

  beforeAll(async () => {
    await device.launchApp({
      newInstance: true,launchArgs: {
        // detoxURLBlacklistRegex: '.*',}
    });
  });

  beforeEach(async () => {
    await device.reloadReactNative();
  });

  it('allow existing the existing test user to sign in',async () => {
    // see login screen
    await expect(element(by.id('auth.login.keyboardView'))).toBeVisible();
    // run login
    await element(by.id('auth.login.emailInput')).replaceText('test@example.com');
    await element(by.id('auth.login.passwordInput')).replaceText('pass123');    
    await element(by.id('auth.login.button')).tap();

    // the test fails on the line below (it times out while waiting for some pouchdb thing...even though the skip button is visible in the simulator)
    await expect(element(by.id('auth.linkedin.skip'))).toBeVisible();
  });
});

版本

节点:12.18.3

xcode: 12.0.1

package.json:

"@craftzdog/pouchdb-core-react-native": "^7.0.0","@craftzdog/pouchdb-replication-react-native": "^7.0.0","detox": "^18.9.0","jest": "^25.1.0","jest-circus": "^26.6.3","pouchdb-adapter-http": "^7.2.1","pouchdb-adapter-react-native-sqlite": "^2.0.0","pouchdb-authentication": "^1.1.3","pouchdb-debug": "^7.2.1","pouchdb-find": "^7.2.1","pouchdb-upsert": "^2.2.0","pouchdb-upsert-bulk": "^1.0.2","pouchdb-validation": "^4.2.0","react": "16.11.0","react-native": "0.62.2",

测试命令

`detox test -c ios -l verbose --record-logs all`

配置

.detoxrc.json

{
  "testRunner": "jest","runnerConfig": "e2e/config.json","apps": {
    "ios": {
      "type": "ios.app","binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/hooli.app","build": "xcodebuild -workspace appName.xcworkspace/ -scheme appScheme -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build"
    },"android": {
      "type": "android.apk","binaryPath": "SPECIFY_PATH_TO_YOUR_APP_BINARY"
    }
  },"devices": {
    "simulator": {
      "type": "ios.simulator","device": {
        "type": "iPhone 11"
      }
    },"emulator": {
      "type": "android.emulator","device": {
        "avdName": "Pixel_3a_API_30_x86"
      }
    }
  },"configurations": {
    "ios": {
      "device": "simulator","app": "ios"
    },"android": {
      "device": "emulator","app": "android"
    }
  }
}

e2e/config.json

{
    "testEnvironment": "./environment","testRunner": "jest-circus/runner","testTimeout": 35000,"testRegex": "\\.e2e\\.js$","reporters": ["detox/runners/jest/streamlineReporter"],"verbose": true
}

e2e/environment.js

const {
  DetoxCircusEnvironment,SpecReporter,WorkerAssignReporter,} = require('detox/runners/jest-circus');

class CustomDetoxEnvironment extends DetoxCircusEnvironment {
  constructor(config,context) {
    super(config,context);

    // 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,});
  }
}

module.exports = CustomDetoxEnvironment;

最后的笔记

我们试过打电话

device.disableSynchronization();
...
device.enableSynchronization();

并设置黑名单

// this
device.launchApp({ 
  launchArgs: { detoxURLBlacklistRegex: '.*' },});
// or this
device.setURLBlacklist(['.*']);

但似乎没有一个让它起作用。

解决方法

有什么方法可以让 Detox 忽略 PouchDB 网络请求,或者手动暂停 PouchDB,以便我们可以进行下一个断言?

作者在这里,每当我们处于测试环境中时,我都可以通过将此配置值切换为 false 来手动暂停 PouchDB 的实时同步。资料来源:PouchDB docs on sync

// localDB,authDB have been initialized with new PouchDB(...)
// isTestEnv=true
localDB.sync(authDB,{
  live: (isTestEnv)?false:true,// rest of options
});

在此更改后,Detox 测试能够跳过登录步骤并在应用程序内进行更多断言!感觉很糟糕,但至少它又可以工作了。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。