Testing ứng dụng di động dễ dàng hơn với Maestro

Ngôn ngữ

Tôi đã từng sử dụng Detox để testing các ứng dụng viết bằng React Native. Tại thời điểm đó Detox khá “hịn” và bá đạo, tiết kiệm được cả khối thời gian cũng như công sức của đội dev và đội tester. Tuy nhiên sau này, tôi thấy độ phức tạp, cũng như độ “khó” với các thành viên mới trong team, đó là thời điểm Maestro đến với tôi như một vị cứu tinh. “Xạo quần” tí thôi chứ tôi biết Maestro qua một bài viết trên trang dev.to, nhưng team tôi “gà” là sự thật 😂 (nhưng đồng đội tôi không tin vào điều đó).

Nội dung:

  • Maestro là cái gì?
  • Cài đặt môi trường và dự án React Native
  • Cài đặt Maestro
  • Mô tả các bước test
  • Maestro studio
  • Test case
  • Kiểm tra phần tử bằng testID
  • Sử dụng biến
  • runFlow
  • Quay màn hình
  • Tags
  • Testing trên cloud
  • Videos testing của Maestro

Maestro là cái gì?

Tóm cái váy lại, Maestro là một framework giúp testing giao diện người dùng (UI) đơn giản và hiệu quả. Maestro dựa trên ý tưởng từ những người đàn anh đi trước như: Appium, Espresso, UIAutomator, XCTest. Sự khác biệt chủ yếu ở đây là Maestro viết test theo dạng Flows.

Flows là gì? Nôm na, Flows sẽ giống như một hành trình đi tìm ánh sáng phía cuối con hẻm cụt, đi từng bước từng bước qua những ngôi nhà, các bước test được viết trong file yaml hoặc yml. Nó giống như việc ta ra lệnh cho máy biết phải làm gì và kiểm tra gì. Đọc thêm tại Why Maestro?

Maestro hỗ trợ các nền tảng như:

PlatformSupport
iOS
Android
React Native
Flutter
Web Views

Cá nhân tôi rất thích sử dụng Maestro cho testing ứng dụng di động. Quá trình cài đặt, viết test cũng hết sức dễ dàng với tất cả những ai chưa biết sử dụng máy tính Casio FX-570.
Trong ví dụ này, tôi sẽ hướng dẫn các bạn cài đặt và viết một vài test case phổ biến. Tôi sử dụng Mac OS và ứng dụng đơn giản viết bằng React Native.

Cài đặt môi trường và dự án React Native

Đầu tiên, tất nhiên là bạn phải có ứng dụng cần testing rồi. Để tạo dự án React Native có thể tham khảo các bước đầy đủ tại Setting up the development environment.

Giả sử bạn đã có môi trường, tiến hành khởi tạo ứng dụng:

npx react-native init RNMaestro

Sau khi khởi tạo xong bạn để ý applicationId của Android (android/app/build.gradle -> applicationId) và iOS (Dự án trong Xcode -> Signing & Capabilities -> Bundle Identifier). Bạn có thể tuỳ ý chỉnh sửa chúng để sử dụng sau này, trong hướng dẫn này tôi chỉnh sửa Android và iOS thành com.rnmaestro.

Tại file App.tsx của dự án, bạn copy & paste đoạn code phía dưới.

// App.tsx
import React, { useState } from 'react';
import {
  View,
  Alert,
  SafeAreaView,
  TextInput,
  Button,
  FlatList,
} from 'react-native';

const TASKS = Array.from({ length: 25 }, (_, i) => ({ title: 'Task ' + i }));

interface Item {
  title: string;
}

const App = () => {
  const [title, setTitle] = useState('');
  const [tasks, setTasks] = useState(TASKS);

  const addTask = () => {
    if (title?.trim()?.length === 0) {
      Alert.alert('Title is required');
    } else {
      const newTasks = [...tasks];
      newTasks.unshift({ title });
      setTasks(newTasks);
      setTitle('');
    }
  };

  const renderItem = ({ item }: { item: Item }) => (
    <Button title={item?.title} onPress={() => Alert.alert(item?.title)} />
  );

  const keyExtractor = (item: Item, idx: number) => `${idx}`;

  return (
    <SafeAreaView>
      <FlatList
        data={tasks}
        renderItem={renderItem}
        keyExtractor={keyExtractor}
        ListHeaderComponent={
          <View>
            <TextInput
              value={title}
              placeholder="Enter your title"
              onChangeText={setTitle}
            />
            <Button testID="btn_add_task" title="Add task" onPress={addTask} />
          </View>
        }
      />
    </SafeAreaView>
  );
};

export default App;

Hoặc bạn có thể sử dụng dự án của tôi (bỏ qua bước dưới nếu không cần):

  • Clone dự án
git clone https://github.com/tuantvk/rnmaestro.git
  • Cài đặt packages
cd rnmaestro; yarn install
  • Pod (dành cho iOS)
npx pod-install

Cài đặt Maestro

Thông tin cài đặt cho Windows hoặc chi tiết các môi trường khác, vui lòng xem thêm ở tài liệu chính gốc Installing Maestro .

Cài đặt trên Mac OS, Linux:

curl -Ls "https://get.maestro.mobile.dev" | bash

Kiểm tra xem em hàng đã cài đặt thành công hay chưa:

maestro -v

Nếu thấy trả về các số dạng vi.xxx.com (ví dụ: 1.27.0) là đã thành công!
Trong trường hợp máy báo zsh: command not found: maestro, hãy tắt terminal đi rồi mở lại.

Để chạy trên máy ảo trên iOS, cần cài đặt thêm Facebook IDB:

brew tap facebook/fb
brew install idb-companion
  • Xcode khuyên nên dùng các phiên bản từ 14 trở nên.
  • Một tin chẳng mấy vui, hiện tại, Tháng Năm 2023 Maestro chưa hỗ trợ chạy trên máy thật.

Sau khi hoàn thành xong các bước trên là đã xong phần cài đặt. Bắt đầu vào phần viết test case.

https://media1.giphy.com/media/26u4lOMA8JKSnL9Uk/giphy.gif

Mô tả các bước test

Dựa vào chức năng của ứng dụng hiện tại, sẽ có một vài bước như sau:

  1. Mở ứng dụng lên
  2. Nhấn nút Add task xem đã kiểm tra rỗng TextInput chưa
  3. Kiểm tra thông báo nếu rỗng
  4. Nhập title
  5. Nhấn nút Add task
  6. Kiểm tra task mới đã có chưa

Maestro studio

Để dễ dàng xem được phần tử trong ứng dụng hoặc chạy trực tiếp các câu lệnh trên trình duyệt, ta có thể sử dụng Maestro studio.

maestro studio

Sau khi chạy lệnh trên maestro sẽ mở một tab trên trình duyệt, mặc định sẽ là http://localhost:9999.

Video demo on Github – Maestro Studio

Test case

Tại thư mục gốc của dự án, tôi tạo file với đường dẫn .maestro/app.yaml.

# .maestro/app.yaml
appId: com.rnmaestro # applicationId
---
- launchApp
# Kiểm tra hiện thông báo "Title is required"
- tapOn: "Add task"
- assertVisible: "Title is required"
- tapOn: "OK"

# Kiểm tra thêm task
- tapOn: "Enter your title"
- inputText: "Task from maestro"
- hideKeyboard # Lưu ý 1
- tapOn: "Add task"
- assertVisible: "Task from maestro"

Lưu ý 1:
Trên iOS hideKeyboard có thể không ẩn được bàn phím, do vậy, tài liệu hướng dẫn khuyên nên sử dụng tapOn nhấn ra ngoài để có thể tắt được bàn phím. Xem thêm iOS implementation caveat.

Để chạy file test case tôi sử dụng lệnh:

# Chạy 1 file duy nhất
maestro test .maestro/app.yaml
# hoặc
# Chạy nhiều file trong thư mục
maestro test .maestro/

Video demo on Github – Test case

Trong terminal sẽ như hình dưới:

Để tự động testing lại mỗi khi có thay đổi, bạn có thể chạy test với câu lệnh:

maestro test -c .maestro/app.yaml

Commands

assertVisibleassertNotVisibleassertTrueback
clearKeychainclearStatecopyTextFromevalScript
eraseTextextendedWaitUntilhideKeyboardinputText
launchAppopenLinkpressKeypasteText
repeatrunFlowrunScriptscroll
scrollUntilVisiblesetLocationstopAppswipe
takeScreenshottapOntravelwaitForAnimationToEnd

Xem chi tiết tại Maestro – Commands.

Kiểm tra phần tử bằng testID

Trong ví dụ ở trên, tôi đã hướng dẫn viết flow bằng cách gọi trực tiếp vào các nội dung có trong màn hình. Tuy nhiên, sẽ có nhiều phần testing có nội dung thay đổi sau mỗi lần thao tác, do đó bạn cần phải sử dụng testID để xác định như: View, Button, Text, Image.

Ví dụ:

# .maestro/app.yaml
appId: com.rnmaestro # applicationId
---
- launchApp
# Kiểm tra hiện thông báo "Title is required"
- tapOn:
    id: "btn_add_task" # testID ở đây
- assertVisible: "Title is required"
- tapOn: "OK"

Sử dụng biến

Trong trường hợp cần truyền các biến từ bên ngoài vào file flow, ta có thể truyền theo dạng qua các tham số:

maestro test -e APP_ID=com.rnmaestro .maestro/app.yaml

Tại các vị trí sử dụng theo cú pháp ${name}:

# .maestro/app.yaml
appId: ${APP_ID} # applicationId
---
- launchApp

Nếu như có quá nhiều biến cần khai báo, ta có thể viết toàn bộ vào key env trước dòng ---:

# .maestro/app.yaml
appId: ${APP_ID} # applicationId
env:
  APP_ID: com.rnmaestro
---
- launchApp

Bạn muốn chạy test từ scripts của package.json có thể config:

{
  "scripts": {
    "test": "$HOME/.maestro/bin/maestro test",
    "test-dev": "yarn test -e APP_ID=com.rnmaestro.dev",
    "test-prod": "yarn test -e APP_ID=com.rnmaestro"
  }
}

Ở đây, tôi ví dụ có 2 môi trường là devproduction.

  • com.rnmaestro.dev dành cho môi trường dev
  • com.rnmaestro dành cho môi trường production

Chạy test:

yarn run test-prod .maestro/app.yaml

runFlow

Nếu như bạn không muốn bị trùng lặp các bước, phải viết đi viết lại 1 đoạn test nào đó, bạn có thể sử dụng runFlow để thực thi một luồng khác. Ví dụ:

# Login.yaml
appId: com.example.app
---
- launchApp
- tapOn: Username
- inputText: Test User
- tapOn: Password
- inputText: Test Password
- tapOn: Login
# Settings.yaml
appId: com.example.app
---
- runFlow: Login.yaml # Testing từ file `Login.yaml`
- tapOn: Settings
- assertVisible: Switch to dark mode

Xem thêm tại Maestro – runFlow.

Quay màn hình

Để quay lại quá trình testing tôi sử dụng lệnh:

maestro record .maestro/app.yaml

Sau khi quá trình testing hoàn tất, maestro sẽ xuất ra một video định dạng mp4 ghi lại toàn bộ quá trình.

Hiện tại, Maestro các phiên bản CLI 1.26.0, CLI 1.26.1, CLI 1.27.0 tôi thấy tính năng record đang bị lỗi trên iOS, tuy nhiên đã được fix tại commit 2bd380d, nhưng chưa thấy release. Nếu bạn đang sử dụng các phiên bản trên, có thể tính năng quay màn hình sẽ không hoạt động (Ngày cập nhật: 2023-05-09).

Tags

Trong trường hợp bạn chỉ testing (--include-tags) hoặc loại bỏ (--exclude-tags) những file nào đó, bạn có thể sử dụng tags. Ví dụ tôi có 2 file:

# flowA.yaml
appId: com.example.app
tags: 
  - dev
  - pull-request
# flowB.yaml
appId: com.example.app
tags: 
  - dev
maestro test --include-tags=dev --exclude-tags=pull-request workspaceFolder/

Một số kịch bản sẽ như sau:

  • --include-tags=dev, flowA và flowB sẽ chạy.
  • --include-tags=dev,pull-request, cả 2 file sẽ chạy.
  • --exclude-tags=pull-request, chỉ flowB chạy.
  • --exclude-tags=dev, không file nào chạy.
  • --include-tags=dev --exclude-tags=pull-request, chỉ flowB chạy.

Xem thêm Maestro – Tags.

Testing trên cloud

Ta có thể chạy Maestro Flows trên cloud qua tài liệu Maestro Cloud Documentation.

Maestro Cloud hỗ trợ các nền tảng CI như:

CI PlatformSupport via CLINative Intergation
GitHub Actions
Bitrise
Bitbucket
CircleCI
GitLab CI/CD🚧
TravisCI
Jenkins
Tất cả các nền tảng CI khác

Videos testing của Maestro

Android contacts flow automation
Facebook signup flow automation

Tham khảo thêm

https://media.tenor.com/blHCE4Hrc20AAAAd/bravo.gif

Maestro cũng còn rất mới với cộng đồng testing ứng dụng di động, còn nhiều vấn đề phải chỉnh sửa, nâng cấp. Tuy nhiên, rất xứng đáng để được 1 star trên Maestro Github cho đội ngũ phát triển.

🎉 🎉 🎉 Hy vọng bài viết hữu ích với mọi người! Cảm ơn ! 🎉 🎉 🎉

Đóng góp

Mọi ý kiến cũng như đóng góp luôn được chào đón. Hãy tạo Issues hoặc Pull requests cho tôi.