- Mobilewright คืออะไร
- Architecture ของ Mobilewright
- จุดเด่นของ Mobilewright
- Requirement
- ตรวจสอบ Environment
- สร้าง Project
- ตรวจสอบ Device
- Config สำหรับ Android
- Config สำหรับ iOS
- เขียน Test แรก
- Workshop: ทดสอบ Login
- Negative Test
- Locator ที่ควรรู้
- Locator Priority
- Mobilewright Inspector
- Assertion
- Chaining Locator
- ทดสอบ Deep Link
- Screenshot
- HTML Report
- Filter Test
- Retry
- Parallel Testing
- iOS และ Android ใน Test Suite เดียว
- โครงสร้าง Project ที่แนะนำ
- CI/CD Workflow
- ตัวอย่าง GitHub Actions
- Mobilewright กับ Accessibility Tree
- Mobilewright vs Playwright
- Mobilewright vs Appium
- Test Pyramid สำหรับ Mobile App
- Best Practices
- Workflow ที่แนะนำ
- คำสั่ง Mobilewright ที่ควรรู้
- Checklist สำหรับ Workshop
- สรุป
- References
การทดสอบแอปบน Mobile แบบอัตโนมัติมีความซับซ้อนกว่าการทดสอบ Web Application เพราะต้องจัดการทั้ง Simulator, Emulator, Real Device, Native UI, Accessibility, Application State และระบบปฏิบัติการ iOS/Android
Mobilewright เป็น Mobile Automation Framework ที่ได้รับแรงบันดาลใจจาก Playwright โดยนำแนวคิด เช่น
getByRole()getByLabel()getByText()getByTestId()expect()- Auto-waiting
- Retry Assertion
มาใช้กับ Native Mobile Application
จึงเหมาะกับทีมที่ใช้ Playwright อยู่แล้วและต้องการนำ Developer Experience แบบเดียวกันมาสู่ Mobile Testing
บทความนี้อ้างอิง Mobilewright Documentation และ GitHub Repository ที่ตรวจสอบ ณ วันที่ 25 กันยายน 2026
#Mobilewright คืออะไร
Mobilewright เป็น Framework สำหรับทำ Mobile App Testing และ Automation ที่รองรับ
- iOS Simulator
- Android Emulator
- iPhone/iPad จริง
- Android Device จริง
- Remote Device
- Cloud Device Provider
รูปแบบ API มีลักษณะคล้าย Playwright
await screen
.getByLabel('Email')
.fill('student@example.com');
await screen
.getByRole('button', { name: 'Sign In' })
.tap();
await expect(
screen.getByText('Welcome back')
).toBeVisible();
ถ้าเคยใช้ Playwright จะพบว่าแนวคิดใกล้เคียงกันมาก
await page
.getByLabel('Email')
.fill('student@example.com');
await page
.getByRole('button', { name: 'Sign In' })
.click();
ความแตกต่างสำคัญคือ Playwright ทำงานกับ Web DOM เป็นหลัก ส่วน Mobilewright ทำงานกับ Native Mobile UI และ Accessibility Tree
#Architecture ของ Mobilewright
flowchart LR
A[Test Script<br/>TypeScript] --> B[@mobilewright/test]
B --> C[Mobilewright Core]
C --> D[Mobile Driver]
D --> E[iOS Simulator]
D --> F[iOS Device]
D --> G[Android Emulator]
D --> H[Android Device]
C -. Remote .-> I[Remote / Cloud Driver]
I --> J[Cloud Devices]
องค์ประกอบสำคัญประกอบด้วย
#screen
ใช้ค้นหาและโต้ตอบกับ UI
screen.getByText('Welcome')
screen.getByLabel('Email')
screen.getByTestId('login-submit')
screen.getByRole('button', { name: 'Login' })
#device
ใช้ควบคุม Device และ Application เช่น
- Launch App
- Terminate App
- Deep Link
- Geolocation
- Device-level Operation
#Accessibility Tree
Mobilewright ใช้ข้อมูล Semantic จาก Accessibility Tree เพื่อให้ Locator อ่านง่ายและสามารถใช้ Test Logic เดียวกันข้าม iOS และ Android ได้
#จุดเด่นของ Mobilewright
#1. Playwright-style API
ตัวอย่าง
await screen
.getByRole('button', { name: 'Login' })
.tap();
อ่านง่ายกว่าการอ้าง Coordinate หรือ Selector ที่ผูกกับโครงสร้าง UI มากเกินไป
#2. Auto-waiting
Mobilewright มี Auto-waiting ก่อนทำ Action
เช่น
await screen
.getByRole('button', { name: 'Submit' })
.tap();
Framework จะรอให้ Element อยู่ในสถานะที่พร้อมสำหรับ Interaction
ดังนั้นควรหลีกเลี่ยง
await new Promise(resolve =>
setTimeout(resolve, 5000)
);
และใช้ Assertion ที่มี Auto-retry แทน
await expect(
screen.getByText('Dashboard')
).toBeVisible();
#3. Semantic Locator
Mobilewright รองรับ Locator ที่สื่อความหมาย
screen.getByTestId('login-button')
screen.getByRole(
'button',
{ name: 'Sign In' }
)
screen.getByLabel('Email')
screen.getByText('Welcome')
แนวทางนี้ช่วยลด Flaky Test ที่เกิดจาก Layout หรือโครงสร้าง UI เปลี่ยน
#4. Retry Assertion
ตัวอย่าง
await expect(
screen.getByText('Login successful')
).toBeVisible();
Assertion จะตรวจซ้ำจนสำเร็จหรือหมด Timeout
#5. Cross-platform
getByRole() สามารถใช้ Test Logic เดียวกันกับ iOS และ Android ได้ เพราะ Mobilewright ทำการ Normalize Native UI Type ให้เป็น Semantic Role
#Requirement
#Node.js
เอกสารหลักของ Repository ระบุ Node.js ขั้นต่ำ 20.19+ ขณะที่ Windows Setup Guide ระบุ 22.12+
ดังนั้นสำหรับ Project ใหม่ แนะนำ
Node.js 22.12+
หรือใช้ Node.js LTS รุ่นใหม่ที่รองรับ
ตรวจสอบเวอร์ชัน
node --version
#Android
ต้องมีโดยทั่วไป
- Node.js
- JDK
- Android SDK
- Android Platform Tools
- ADB
- Android Emulator หรือ Android Device
ANDROID_HOME
Windows รองรับ Android Testing โดยตรง
#iOS
ต้องมี
- macOS
- Xcode
- Xcode Command Line Tools
- iOS Simulator หรือ iOS Device
เนื่องจาก iOS Simulator ต้องใช้ Xcode จึงไม่สามารถรัน Local iOS Simulator บน Windows ได้
#ตรวจสอบ Environment
ใช้
npx mobilewright doctor
ตรวจเฉพาะ Android
npx mobilewright doctor \
--category android
ตรวจเฉพาะ iOS
npx mobilewright doctor \
--category ios
Output แบบ JSON
npx mobilewright doctor \
--json
คำสั่งนี้ช่วยตรวจสอบ Environment เช่น
- Node.js
- Java
- Android SDK
- ADB
- Emulator
- Xcode
- Device
#สร้าง Project
ติดตั้ง Mobilewright
npm install mobilewright
หากต้องการใช้ Test Fixtures
npm install \
--save-dev \
mobilewright \
@mobilewright/test
จากนั้นสร้าง Config เริ่มต้น
npx mobilewright init
ตัวอย่างโครงสร้าง
mobilewright-demo/
├── mobilewright.config.ts
├── package.json
└── tests/
└── login.test.ts
#ตรวจสอบ Device
ใช้คำสั่ง
npx mobilewright devices
ตัวอย่าง
ID Name Platform Type
------------------------------------------------
... iPhone 17 Pro ios simulator
... Pixel android emulator
#Config สำหรับ Android
สร้างไฟล์
mobilewright.config.ts
ตัวอย่าง
import {
defineConfig
} from 'mobilewright';
export default defineConfig({
platform: 'android',
bundleId: 'com.example.myapp',
deviceName: /Pixel/,
installApps:
'./builds/app.apk',
timeout: 30_000,
});
ถ้าติดตั้งแอปไว้แล้ว สามารถใช้เพียง
import {
defineConfig
} from 'mobilewright';
export default defineConfig({
platform: 'android',
bundleId:
'com.example.myapp',
});
#Config สำหรับ iOS
import {
defineConfig
} from 'mobilewright';
export default defineConfig({
platform: 'ios',
bundleId:
'com.example.myapp',
deviceName:
/iPhone/,
installApps:
'./builds/MyApp.ipa',
timeout:
30_000,
});
#เขียน Test แรก
สร้าง
tests/home.test.ts
จากนั้นเขียน
import {
test,
expect
} from '@mobilewright/test';
test(
'เปิดแอปและแสดง Home Screen',
async ({ screen }) => {
await expect(
screen.getByText('Welcome')
).toBeVisible();
}
);
รัน
npx mobilewright test
#Workshop: ทดสอบ Login
สมมติ Mobile App มีหน้าจอ
Email
Password
[ Sign In ]
และหลัง Login สำเร็จแสดง
Welcome back
สร้างไฟล์
tests/login.test.ts
import {
test,
expect
} from '@mobilewright/test';
test(
'ผู้ใช้สามารถ Login ได้',
async ({ screen }) => {
await screen
.getByLabel('Email')
.fill(
'student@example.com'
);
await screen
.getByLabel('Password')
.fill(
'secret123'
);
await screen
.getByRole(
'button',
{
name: 'Sign In'
}
)
.tap();
await expect(
screen.getByText(
'Welcome back'
)
).toBeVisible();
}
);
รันเฉพาะไฟล์
npx mobilewright test \
tests/login.test.ts
#Negative Test
ควรมีทั้ง Positive และ Negative Scenario
import {
test,
expect
} from '@mobilewright/test';
test(
'Login ไม่สำเร็จเมื่อ Password ไม่ถูกต้อง',
async ({ screen }) => {
await screen
.getByLabel('Email')
.fill(
'student@example.com'
);
await screen
.getByLabel('Password')
.fill(
'wrong-password'
);
await screen
.getByRole(
'button',
{
name: 'Sign In'
}
)
.tap();
await expect(
screen.getByText(
'Invalid credentials'
)
).toBeVisible();
}
);
#Locator ที่ควรรู้
#getByTestId()
screen.getByTestId(
'login-submit'
)
เหมาะสำหรับ Element ที่ทีมพัฒนากำหนด Test ID ไว้ชัดเจน
#getByRole()
screen.getByRole(
'button',
{
name: 'Submit'
}
)
เหมาะสำหรับ Cross-platform Test
#getByLabel()
screen.getByLabel(
'Email'
)
เหมาะกับ Input หรือ Element ที่มี Accessibility Label
#getByText()
screen.getByText(
'Welcome'
)
เหมาะกับข้อความที่แสดงให้ผู้ใช้เห็น
#Locator Priority
Mobilewright Inspector ใช้ลำดับ Locator โดยประมาณ
getByTestId
↓
getByRole
↓
getByLabel
↓
getByText
ใน Project จริงควรเลือก Locator ที่
- Unique
- สื่อความหมาย
- ไม่ผูกกับ Layout
- ไม่พึ่ง Coordinate
- ไม่เปลี่ยนง่ายเมื่อ Refactor
#Mobilewright Inspector
เปิดด้วย
npx mobilewright inspect
Inspector เป็น Browser-based UI สำหรับดู
- Screenshot
- Element Tree
- Locator
- Duplicate Locator
- Bounding Box
Default Port ปัจจุบันคือ
4621
กำหนด Port เอง
npx mobilewright inspect \
--port 8080
Inspector เหมาะมากสำหรับค้นหา Locator ก่อนเขียน Test
#Assertion
ตัวอย่างที่ใช้บ่อย
#Visible
await expect(
screen.getByText('Welcome')
).toBeVisible();
Hidden
await expect(
screen.getByText('Loading')
).toBeHidden();
#Enabled
await expect(
screen.getByRole(
'button',
{
name: 'Submit'
}
)
).toBeEnabled();
#Disabled
await expect(
screen.getByRole(
'button',
{
name: 'Submit'
}
)
).toBeDisabled();
Assertion แบบ Locator มี Auto-retry
#Chaining Locator
สามารถจำกัดขอบเขตการค้นหา Element
const row =
screen
.getByType('Cell')
.first();
await row
.getByRole(
'button',
{
name: 'Delete'
}
)
.tap();
นอกจากนี้ยังมี
screen.getByRole('button').first();
screen.getByRole('button').last();
screen.getByRole('button').nth(2);
นับ Element
const count =
await screen
.getByRole('listitem')
.count();
#ทดสอบ Deep Link
สมมติแอปรองรับ
myapp://profile/123
เขียน Test ได้ในแนวทาง
test(
'เปิด Profile ผ่าน Deep Link',
async ({
device,
screen
}) => {
await device.openUrl(
'myapp://profile/123'
);
await expect(
screen.getByText(
'Profile'
)
).toBeVisible();
}
);
เหมาะสำหรับทดสอบ
- Product Detail
- Payment Callback
- Profile
- Notification Navigation
- App Link / Universal Link
#Screenshot
Capture Screenshot
npx mobilewright screenshot
กำหนดชื่อไฟล์
npx mobilewright screenshot \
-o home.png
เลือก Device
npx mobilewright screenshot \
-d <device-id>
#HTML Report
รันพร้อม HTML Reporter
npx mobilewright test \
--reporter html
เปิด Report
npx mobilewright show-report
โดย Default Report Server ใช้
localhost:9323
HTML Report ช่วยตรวจสอบ
- Passed
- Failed
- Error
- Screenshot
- Attachment
- Test Result
#Filter Test
รันเฉพาะ Test ที่ชื่อ Match
npx mobilewright test \
--grep "login"
ข้าม Test ที่ Match
npx mobilewright test \
--grep-invert "flaky"
ดูรายการ Test โดยไม่รัน
npx mobilewright test \
--list
#Retry
ใช้ CLI
npx mobilewright test \
--retries 2
อย่างไรก็ตาม Retry ไม่ควรใช้เพื่อซ่อนปัญหา Flaky Test
ควรวิเคราะห์สาเหตุ เช่น
- Locator ไม่ Stable
- Data ชนกัน
- Network ไม่ Deterministic
- App State ไม่ Reset
- Animation
- Device Resource ไม่เพียงพอ
#Parallel Testing
รันหลาย Worker
npx mobilewright test \
--workers 4
ใน Mobile Testing จำนวน Worker มักสัมพันธ์กับจำนวน Device ที่ใช้ได้
Worker 1 → Device 1
Worker 2 → Device 2
Worker 3 → Device 3
Worker 4 → Device 4
ดังนั้นการเพิ่ม Worker โดยไม่มี Device เพียงพอไม่ได้ทำให้ Test เร็วขึ้นโดยอัตโนมัติ
#iOS และ Android ใน Test Suite เดียว
สามารถกำหนด Projects
import {
defineConfig
} from 'mobilewright';
export default defineConfig({
testDir: './tests',
bundleId:
'com.example.myapp',
projects: [
{
name: 'ios',
use: {
platform: 'ios',
installApps:
'./builds/MyApp.ipa',
},
},
{
name: 'android',
use: {
platform: 'android',
installApps:
'./builds/app.apk',
},
},
],
});
รัน Android
npx mobilewright test \
--project android
รัน iOS
npx mobilewright test \
--project ios
#โครงสร้าง Project ที่แนะนำ
mobile-tests/
├── mobilewright.config.ts
├── package.json
├── tests/
│ ├── auth/
│ │ ├── login.test.ts
│ │ └── logout.test.ts
│ ├── profile/
│ │ └── profile.test.ts
│ └── checkout/
│ └── checkout.test.ts
├── fixtures/
│ └── test-data.ts
└── builds/
├── app.apk
└── MyApp.ipa
แนะนำให้จัด Test ตาม
Feature
หรือ
User Journey
เช่น
auth/
checkout/
orders/
profile/
payment/
#CI/CD Workflow
แนวคิด Pipeline
flowchart LR
A[Push / Pull Request]
--> B[Build Mobile App]
B --> C[Prepare Device]
C --> D[Install App]
D --> E[Mobilewright Test]
E --> F[HTML Report]
F --> G[Upload Artifact]
#ตัวอย่าง GitHub Actions
ตัวอย่าง Conceptual Workflow
name: Mobile Test
on:
push:
branches:
- main
pull_request:
jobs:
mobile-test:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install Dependencies
run: npm ci
- name: Check Environment
run: npx mobilewright doctor
- name: Run Tests
run: |
npx mobilewright test \
--reporter html
- name: Upload Report
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: mobilewright-report
path: mobilewright-report/
การใช้งานจริงต้องเตรียม Simulator/Emulator หรือ Remote Device ให้พร้อมตาม Platform ที่ทดสอบ
#Mobilewright กับ Accessibility Tree
แนวคิดสำคัญของ Mobilewright คือ
Mobile UI
↓
Accessibility Tree
↓
Semantic Element
↓
Locator
↓
Action / Assertion
ตัวอย่าง
screen.getByRole(
'button',
{
name: 'Sign In'
}
)
ข้อดีคือ
- Test อ่านง่าย
- Cross-platform ได้ง่ายขึ้น
- ลดการใช้ Coordinate
- ช่วยส่งเสริม Accessibility ที่ดี
- เหมาะกับ AI Agent ที่ต้องอ่าน UI ในรูปแบบ Semantic
#Mobilewright vs Playwright
| ประเด็น | Playwright | Mobilewright |
|---|---|---|
| เป้าหมาย | Web App | Native Mobile App |
| UI Model | DOM | Native UI / Accessibility Tree |
| Object | page |
screen, device |
| Interaction | click() |
tap() |
| Browser | Chromium, Firefox, WebKit | ไม่ใช่ Browser Automation เป็นหลัก |
| iOS/Android Native | ไม่ใช่เป้าหมายหลัก | รองรับ |
| Auto-wait | มี | มี |
| Semantic Locator | มี | มี |
Mobilewright ไม่ได้มาแทน Playwright สำหรับ Web แต่เป็นการนำแนวคิดแบบ Playwright มาใช้กับ Mobile Native Testing
#Mobilewright vs Appium
| ประเด็น | Mobilewright | Appium |
|---|---|---|
| API Style | Playwright-style | WebDriver-style |
| Auto-wait | Built-in | ขึ้นกับการออกแบบ Test |
| Locator | Semantic-focused | หลาย Strategy |
| Setup | เน้นง่าย | มี Server/Driver Ecosystem |
| Cross-platform | iOS + Android | iOS + Android |
| Ecosystem | ใหม่กว่า | Mature กว่า |
| Accessibility Tree | เน้น | รองรับผ่าน Platform Driver |
Appium มี Ecosystem ที่ใหญ่และ Mature กว่า ขณะที่ Mobilewright เหมาะกับทีมที่ต้องการ Developer Experience ใกล้ Playwright
#Test Pyramid สำหรับ Mobile App
Mobile E2E Test ไม่ควรใช้แทน Testing ทุกระดับ
flowchart TB
A[Mobile E2E<br/>Mobilewright]
B[Integration / API Test]
C[Unit Test]
A --> B
B --> C
#Unit Test
ใช้ทดสอบ
- Business Logic
- Validation
- State
- Utility Function
#Integration/API Test
ใช้ทดสอบ
- Backend API
- Service
- Database
- Integration
#Mobile E2E Test
ใช้ทดสอบ User Journey สำคัญ
- Login
- Register
- Checkout
- Payment
- Profile
- Deep Link
- Critical Navigation
#Best Practices
#1. ใช้ Semantic Locator
แนะนำ
getByTestId()
getByRole()
getByLabel()
getByText()
หลีกเลี่ยง Fixed Coordinate หากไม่จำเป็น
#2. อย่าใช้ Sleep โดยไม่มีเหตุผล
ไม่ควร
await sleep(5000);
ควร
await expect(
screen.getByText(
'Dashboard'
)
).toBeVisible();
#3. ให้แต่ละ Test Independent
หลีกเลี่ยงการออกแบบแบบ
Test A Login
↓
Test B Edit Profile
↓
Test C Logout
ที่ Test B และ C ต้องพึ่งผลจาก Test ก่อนหน้า
แต่ละ Test ควร Setup State ของตัวเองเท่าที่ทำได้
#4. ใช้ Test Account
อย่า Hard-code Credential จริงลง Repository
ใช้ Environment Variable
const email =
process.env.TEST_USER!;
const password =
process.env.TEST_PASSWORD!;
ใน CI ควรเก็บค่าผ่าน Secret Management
#5. กำหนด Test ID ตั้งแต่ Development
ตัวอย่าง
login-email
login-password
login-submit
checkout-pay
profile-save
ช่วยให้ Automation Test Stable ขึ้น
#6. เก็บ Artifact เมื่อ Test Fail
ควรเก็บ
- Screenshot
- HTML Report
- App Log
- Device Log
- UI/Accessibility Information
เพื่อช่วยวิเคราะห์ Root Cause
#Workflow ที่แนะนำ
flowchart LR
A[Developer]
--> B[Unit Test]
B --> C[API / Integration]
C --> D[Mobilewright Smoke Test]
D --> E[Pull Request]
E --> F[CI Regression]
F --> G[Real / Cloud Devices]
G --> H[Release]
สำหรับ Pull Request อาจรันเฉพาะ Smoke Test
Launch App
Login
Main Navigation
Critical Feature
ส่วนก่อน Release จึงค่อยรัน Full Regression หลาย Device และ OS Version
#คำสั่ง Mobilewright ที่ควรรู้
# install
npm install mobilewright
# initialize
npx mobilewright init
# check environment
npx mobilewright doctor
# Android doctor
npx mobilewright doctor \
--category android
# devices
npx mobilewright devices
# inspector
npx mobilewright inspect
# run all tests
npx mobilewright test
# run file
npx mobilewright test \
tests/login.test.ts
# filter
npx mobilewright test \
--grep "login"
# retries
npx mobilewright test \
--retries 2
# workers
npx mobilewright test \
--workers 4
# project
npx mobilewright test \
--project android
# HTML report
npx mobilewright test \
--reporter html
# open report
npx mobilewright show-report
# screenshot
npx mobilewright screenshot \
-o home.png
#Checklist สำหรับ Workshop
[ ] Node.js 22.12+
[ ] Mobilewright
[ ] @mobilewright/test
[ ] Android SDK / Xcode
[ ] Emulator / Simulator
[ ] Application Build
[ ] Bundle ID
[ ] Accessibility Label
[ ] Test ID
จากนั้น
npx mobilewright doctor
npx mobilewright devices
npx mobilewright inspect
npx mobilewright test
#สรุป
Mobilewright เป็น Framework สำหรับ Mobile Test Automation ที่น่าสนใจ โดยเฉพาะทีมที่คุ้นเคยกับ Playwright และ TypeScript
จุดเด่นสำคัญคือ
- Playwright-style API
- Auto-waiting
- Retry Assertion
- Semantic Locator
- Accessibility Tree
- รองรับ iOS และ Android
- รองรับ Simulator, Emulator และ Real Device
- มี Inspector
- มี HTML Report
- รองรับ Parallel Test
- รองรับ Projects
- รองรับ Remote/Cloud Device
- เหมาะสำหรับ CI/CD
- มีแนวทางที่เอื้อต่อ AI Agent
อย่างไรก็ตาม Mobilewright ยังเป็น Framework ที่ใหม่กว่า Appium มาก ดังนั้นสำหรับระบบ Production ขนาดใหญ่ควรเริ่มจาก Proof of Concept (PoC) กับ Critical User Journey ก่อน เช่น Login, Checkout หรือ Payment แล้วจึงประเมินความเหมาะสมด้าน Device Support, Stability, CI/CD และ Ecosystem ก่อนขยายเป็น Full Regression Suite
#References
-
Mobilewright Official Documentation
https://mobilewright.dev/docs/ -
Mobilewright GitHub
https://github.com/mobile-next/mobilewright -
Writing Tests
https://mobilewright.dev/docs/getting-started/writing-tests -
Running Tests
https://mobilewright.dev/docs/getting-started/running-tests -
Windows Setup
https://mobilewright.dev/docs/getting-started/windows