【问题标题】:How do I screenshot tests in React Native?如何在 React Native 中截屏测试?
【发布时间】:2015-10-22 15:43:21
【问题描述】:

我想使用屏幕截图测试我的 React Native 应用程序。 UIAutomation javascript 文件将由fastlane 执行,并且应该向我提供我需要的所有子视图。这部分工作正常。

我的主要问题是我不明白如何点击一个元素。我发现的每个示例都是简单的objective-c,并使用标准元素进行导航,例如标签栏。我的应用程序有一个汉堡图标,它在TouchableHighlight 上有一个点击事件,它会打开一个菜单。我正在寻找一种可能性来引用单个 TouchableHighlightelement 以便与之交互。

这样的答案加分,我不用写 Objective-C。

【问题讨论】:

  • 很好奇,你有没有找到“点击”这个 TouchableHighlight 的方法?我有一个非常相似的问题,很想听听你是否在这里取得了任何进展:)
  • 很抱歉告诉您,但我已停止解决该问题:/ 如果您成功了,请分享您的见解 ;)

标签: javascript ios ui-automation react-native fastlane


【解决方案1】:

Fastlane(更具体的快照)已弃用 UI 测试的 UI 自动化。如果您需要更新 gem,您的 UIA javascript 将不适用于 UI 测试(使用 Obj C 或 Swift 编写)

为什么要改为 UI 测试?

UI 自动化已弃用 UI 测试将在未来发展并支持更多功能 UI 测试更容易调试 UI 测试是用 Swift 或 Objective C 编写的 UI 测试可以以更干净、更好的方式执行

https://github.com/fastlane/snapshot

看起来使用 React Native 的其他人在 UI 测试和快照方面取得了一些进展:https://github.com/fastlane/snapshot/issues/267

【讨论】:

    【解决方案2】:

    我不熟悉 fastlane,但您可能想尝试一下 Jest,因为它已得到官方支持。诚然,他们并没有完全覆盖,而且在某些情况下,你很有可能不得不推出自己的解决方案,因为 react native 还很年轻,但这应该会让你从正确的角度开始Snapshot Tests (iOS only)

    【讨论】:

      【解决方案3】:

      注意:我们使用 detox 进行测试,所以我使用 device.getPlatform() 来测试 iOS 或 Android。

      我最终做的是混合使用 JavaScript 库(pixelmatchpngjs),使用 fs 和使用命令行命令(xcrun simctladb)。

      const {device} = require('detox');
      const {execSync} = require('child_process');
      const fs = require('fs');
      const {existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync} = fs;
      const PNG = require('pngjs').PNG;
      const pixelmatch = require('pixelmatch');
      
      const IOS_SCREENSHOT_OPTIONS = {
        timeout: 1000,
        killSignal: 'SIGKILL'
      };
      
      function getScreenShotDirectory() { ... }
      function getActualFileName(testName) { ... }
      function getExpectedFileName(testName) { ... }
      function getDiffFileName(testName) { ... }
      
      async function takeScreenshot(testName) {
        const actualFileName = getActualFileName(testName);
        const directoryName = getScreenShotDirectory();
        if (!existsSync(directoryName)) {
          mkdirSync(directoryName, {recursive: true});
        }
      
        if (device.getPlatform() === 'ios') {
          execSync(`xcrun simctl io booted screenshot "${actualFileName}"`, IOS_SCREENSHOT_OPTIONS);
          await removeIosStatusBar(actualFileName);
        } else {
          execSync(`adb exec-out screencap -p > "${actualFileName}"`);
        }
      }
      
      const compareScreenshot = async testName => {
        const actualFileName = getActualFileName(testName);
        await takeScreenshot(testName);
        const expectedFileName = getExpectedFileName(testName);
        const actualImage = PNG.sync.read(readFileSync(actualFileName));
        if (!existsSync(expectedFileName)) {
          console.warn(`No expected image for ${testName} @ ${expectedFileName}`);
          return false;
        }
      
        const expectedImage = PNG.sync.read(readFileSync(getExpectedFileName(testName)));
        const {width, height} = actualImage;
        const diffImage = new PNG({width, height});
        const numDiffPixels = pixelmatch(actualImage.data, expectedImage.data, diffImage.data, width, height);
      
        if (numDiffPixels === 0) {
          unlinkSync(actualFileName);
          return true;
        } else {
          const percentDiffPixels = numDiffPixels / (width * height);
          console.warn(
            `Images are different ${testName} numDiffPixels=${numDiffPixels} percentDiffPixels=${percentDiffPixels}`
          );
          writeFileSync(getDiffFileName(testName), PNG.sync.write(diffImage));
          return false;
        }
      };
      

      为了改善您的测试结果,您应该使用 Android 的demo mode,例如:

      execSync('adb shell settings put global sysui_demo_allowed 1');
      execSync('adb shell am broadcast -a com.android.systemui.demo -e command ...');
      execSync('adb shell am broadcast -a com.android.systemui.demo -e command exit');
      

      从 xcode 11 你有:

      execSync('xcrun simctl status_bar <device> override ...')
      

      我使用以下代码从 iOS 中删除了状态栏(但这会降低性能):

      const IOS_STATUS_BAR_HEIGHT = 40;
      async function removeIosStatusBar(imageFileName) {
        return new Promise((resolve, reject) => {
          const image = PNG.sync.read(readFileSync(imageFileName));
          let {width, height} = image;
          height -= IOS_STATUS_BAR_HEIGHT;
          const dst = new PNG({width, height});
          fs.createReadStream(imageFileName)
            .pipe(new PNG())
            .on('error', error => reject(error))
            .on('parsed', function () {
              this.bitblt(dst, 0, IOS_STATUS_BAR_HEIGHT, width, height, 0, 0);
              dst
                .pack()
                .pipe(fs.createWriteStream(imageFileName))
                .on('error', error => reject(error))
                .on('finish', () => resolve(imageFileName));
            });
        });
      }
      

      【讨论】:

        【解决方案4】:

        创建一个新项目。

        $ react-native -v
        react-native-cli: 2.0.1
        
        $ react-native init NativeSnapshots
        
        $ cd NativeSnapshots
        
        $ react-native run-ios
        

        测试它是否有效,启动欢迎屏幕。

        $ cd ios
        
        $ fastlane snapshot init
        

        快车道输出:

        [14:37:56]: For more information, check out https://docs.fastlane.tools/getting-started/ios/setup/#use-a-gemfile
        ✅  Successfully created SnapshotHelper.swift './SnapshotHelper.swift'
        ✅  Successfully created new Snapfile at './Snapfile'
        -------------------------------------------------------
        Open your Xcode project and make sure to do the following:
        1) Add a new UI Test target to your project
        2) Add the ./fastlane/SnapshotHelper.swift to your UI Test target
           You can move the file anywhere you want
        3) Call `setupSnapshot(app)` when launching your app
        
          let app = XCUIApplication()
          setupSnapshot(app)
          app.launch()
        
        4) Add `snapshot("0Launch")` to wherever you want to create the screenshots
        
        More information on GitHub: https://github.com/fastlane/fastlane/tree/master/snapshot
        

        第 1 步:将新的 UI 测试目标添加到您的项目中

        Xcode 版本 8.3.3 > 打开 NativeSnapshots.xcodeproj

        File > New > Target > iOS UI Testing Bundle
        

        第 2 步:将 ./fastlane/SnapshotHelper.swift 添加到您的 UI 测试目标中

        Highlight NativeSnapshotsUITests
        File > Add Files to NativeSnapshots
        Select ./fastlane/SnapshotHelper.swift, Enter
        

        第 3 步:启动应用时调用 setupSnapshot(app)

        在 Xcode 中打开 NativeSnapshotsUITests/NativeSnapshotsUITests.swift

        替换:

            XCUIApplication().launch()
        

        与:

            let app = XCUIApplication()
            setupSnapshot(app)
            app.launch()
        

        第 4 步:将snapshot("0Launch") 添加到您要创建屏幕截图的任何位置

        在 UI 测试的 testExample() 中添加快照调用。

        func testExample() {
            snapshot("0Launch")
        }
        

        编辑 Snapfile 以避免出现巨大的矩阵。

        devices([
          "iPhone 6"
        ])
        
        languages([
          "en-US"
        ])
        
        scheme "NativeSnapshots"
        

        应该准备好了。

        $ cd ios && fastlane snapshot
        

        复制自aj0strow

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-11
          • 2021-10-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-01-17
          相关资源
          最近更新 更多