บทที่ 3: เชื่อม WDIO กับ Appium สำหรับ Mobile¶
Pre-chapter Retrieval¶
ก่อนอ่านบทนี้ ลองตอบก่อน:
wdio.conf.jsต่างจากvariables.robotใน RF ยังไง? และ capabilities ใน WDIO ตั้งที่ไหน?
ดูเฉลย
`wdio.conf.js` รวม config ทั้งหมดไว้ที่เดียว (framework, reporter, capabilities, services) ในขณะที่ RF แยก variables.robot ออกมาต่างหาก ใน WDIO capabilities ตั้งที่ `capabilities` array ใน `wdio.conf.js`วัตถุประสงค์¶
อ่านจบบทนี้แล้วคุณจะ:
- ตั้ง capabilities สำหรับ Android ใน
wdio.conf.jsได้ - เข้าใจว่า
@wdio/appium-serviceทำอะไร - รัน WDIO test เชื่อมกับ Appium server ได้จริง
- Debug connection error ระหว่าง WDIO กับ Appium ได้
ทำไมต้องรู้? (Why)¶
Capabilities ใน WDIO เหมือนกับ RF ทุกตัว — เพราะทั้งคู่ส่งไปยัง Appium server เดียวกัน แต่ format ของ syntax ต่างกัน
ถ้าไม่รู้ format ที่ถูก → session ไม่ start แม้ value จะถูก
Analogy: Capabilities เหมือนสายเชื่อมต่อ¶
ก่อน WDIO จะคุยกับ Appium ได้ต้องมี "สายเชื่อมต่อ" ที่ถูกต้อง: - Appium service = ปลั๊กที่ start Appium server ให้อัตโนมัติ - Capabilities = ข้อมูลที่ส่งไปเมื่อเสียบปลั๊ก (บอกว่าจะทำอะไร) - Port 4723 = ช่องเสียบ
⚠️ ถ้าเชื่อ analogy นี้ 100% จะเข้าใจผิดว่า: - WDIO ต้อง start Appium เอง →
@wdio/appium-serviceทำให้ start อัตโนมัติ แต่ Appium ต้องติดตั้งอยู่ในเครื่องก่อน - capabilities ตั้งครั้งเดียวแล้วใช้ตลอด → แต่ละ session (test run) ส่ง capabilities ใหม่
เนื้อหาหลัก¶
ติดตั้ง Appium Service¶
"Install via npm: npm install @wdio/appium-service --save-dev" (webdriver.io/docs/appium-service)
ตั้งค่า wdio.conf.js สำหรับ Android¶
// wdio.conf.js
export const config = {
runner: 'local',
// Appium server port
port: 4723,
// @wdio/appium-service จะ start/stop Appium อัตโนมัติ
services: ['appium'],
// Test framework
framework: 'mocha',
reporters: ['spec'],
// Test file pattern
specs: ['./test/specs/**/*.js'],
// Capabilities: ระบุ device และ app ที่จะทดสอบ
capabilities: [{
platformName: 'Android',
'appium:automationName': 'UIAutomator2',
'appium:deviceName': 'emulator-5554',
'appium:appPackage': 'com.example.app',
'appium:appActivity': '.MainActivity',
'appium:noReset': true,
}],
// Mocha options
mochaOpts: {
ui: 'bdd',
timeout: 60000 // 60 วินาที ต่อ test case (ดูคำอธิบายด้านล่าง)
}
};
"Add to your wdio.conf.js: export const config = { port: 4723, services: ['appium'] };" (webdriver.io/docs/appium-service)
ทำไม timeout: 60000 (60 วินาที)?
Mobile app ใช้เวลานานกว่า web เพราะ: (1) app launch time — 3-10 วินาที (2) screen transition พร้อม animation — 1-3 วินาทีต่อ transition (3) API calls — banking app มี network latency (4) emulator ช้ากว่า real device
test case ที่ต้อง login → navigate → กรอก form → submit อาจใช้เวลา 30-50 วินาที — ถ้า timeout สั้นกว่านี้ test จะ fail ทั้งที่ app ยังทำงานอยู่ปกติ
ความแตกต่างของ Capabilities Syntax: RF vs WDIO¶
เนื้อหาเหมือนกัน แต่ format ต่างกัน:
Robot Framework:
Open Application http://localhost:4723
... platformName=Android
... appium:automationName=UIAutomator2
... appium:deviceName=emulator-5554
... appium:appPackage=com.example.app
... appium:appActivity=.MainActivity
WDIO (wdio.conf.js):
capabilities: [{
platformName: 'Android',
'appium:automationName': 'UIAutomator2',
'appium:deviceName': 'emulator-5554',
'appium:appPackage': 'com.example.app',
'appium:appActivity': '.MainActivity',
}]
Key difference: ใน WDIO capabilities ที่มี : ต้องใส่ใน quotes เพราะ colon ไม่ valid ใน JS object key ปกติ
Verify การเชื่อมต่อ¶
สร้าง test ง่ายๆ เพื่อตรวจว่า connect ได้:
// test/specs/connection.test.js
describe('Connection Test', () => {
it('should connect to app', async () => {
// ถ้า session สร้างได้ แปลว่า connect สำเร็จ
const appState = await driver.queryAppState('com.example.app');
console.log('App state:', appState);
// State 4 = running in foreground
});
});
ทำความเข้าใจ appium-service¶
เมื่อตั้ง services: ['appium'] — WDIO จะ:
1. start Appium server ก่อน test รัน (ไม่ต้องรันเอง)
2. stop Appium server หลัง test ทั้งหมดจบ
ข้อดี: ไม่ต้องเปิด terminal แยกสำหรับ Appium
ข้อควรระวัง: ถ้า Appium ไม่ได้ติดตั้งใน PATH → service จะหา Appium ไม่เจอ
ตัวอย่าง 3 ระดับ¶
Beginner: Config สำหรับ Mobile Web (Chrome)¶
capabilities: [{
platformName: 'Android',
'appium:automationName': 'UIAutomator2',
'appium:deviceName': 'emulator-5554',
'appium:browserName': 'Chrome', // เปิด Chrome แทน native app
}]
Intermediate: Parallel Testing บนหลาย Device¶
capabilities: [
// Device 1: Android 12
{
platformName: 'Android',
'appium:automationName': 'UIAutomator2',
'appium:deviceName': 'emulator-5554',
'appium:platformVersion': '12',
'appium:appPackage': 'com.example.app',
'appium:appActivity': '.MainActivity',
'appium:systemPort': 8200, // ต้องต่างกันต่อ instance
},
// Device 2: Android 13
{
platformName: 'Android',
'appium:automationName': 'UIAutomator2',
'appium:deviceName': 'emulator-5556',
'appium:platformVersion': '13',
'appium:appPackage': 'com.example.app',
'appium:appActivity': '.MainActivity',
'appium:systemPort': 8201, // port ต่างกัน ป้องกัน conflict
}
],
maxInstances: 2, // รัน parallel 2 instances พร้อมกัน
ข้อควรระวังเรื่อง port สำหรับ parallel testing:
- appium:systemPort — UIAutomator2 ใช้ port นี้คุยกับ Appium ต้องต่างกันทุก instance (default: 8200)
- emulator port — emulator-5554 และ emulator-5556 ต้องเปิดไว้ก่อนรัน test
- ถ้า port conflict → error "Could not find a connected Android device" หรือ "Address already in use"
Performance: การรัน parallel บน 2 devices ลดเวลาได้ ~40-50% แต่ต้องการ RAM เพิ่ม (emulator ละ ~2-3GB)
Advanced: Config ที่ดึงค่าจาก Environment Variables¶
// wdio.conf.js — CI/CD friendly
export const config = {
port: 4723,
services: ['appium'],
framework: 'mocha',
reporters: ['spec'],
specs: ['./test/specs/**/*.js'],
capabilities: [{
platformName: 'Android',
'appium:automationName': 'UIAutomator2',
'appium:deviceName': process.env.DEVICE_NAME || 'emulator-5554',
'appium:appPackage': process.env.APP_PACKAGE || 'com.example.app',
'appium:appActivity': process.env.APP_ACTIVITY || '.MainActivity',
'appium:noReset': process.env.NO_RESET === 'true',
}],
mochaOpts: {
ui: 'bdd',
timeout: parseInt(process.env.TEST_TIMEOUT) || 60000,
}
};
Common Mistakes¶
❌ ใส่ capabilities key ที่มี : โดยไม่ใส่ quotes
:
(source: JavaScript object literal syntax)
❌ ลืมว่า appium-service ต้องการ Appium ติดตั้งอยู่ก่อน
→ Error: "Appium command not found"
✅ ตรวจว่า appium อยู่ใน PATH: appium --version ก่อนรัน
(source: webdriver.io/docs/appium-service)
❌ ใช้ capabilities: {} (object) แทน capabilities: [{}] (array)
→ WDIO expect array เสมอ
✅ capabilities ต้องเป็น array เสมอ — แม้จะมีแค่ device เดียว
(source: webdriver.io/docs/configurationfile)
สรุปบท¶
ลองตอบก่อนดูเฉลย:
คำถาม 1: ทำไม capabilities key ที่มี
:เช่นappium:automationNameถึงต้องใส่ quotes ใน JavaScript?คำถาม 2:
@wdio/appium-serviceทำอะไรให้คุณบ้าง? และถ้าไม่ใช้ service นี้ คุณต้องทำอะไรเพิ่ม?คำถาม 3: ถ้าต้องการรัน test เดียวกันบน Android 12 และ Android 13 พร้อมกัน — ต้องแก้
wdio.conf.jsอย่างไร?
ดูเฉลย
**เฉลย 1:** ใน JavaScript `:` เป็น separator ระหว่าง key กับ value ใน object literal ดังนั้น `appium:automationName` จะถูก parse ผิด ต้องใส่ quotes ให้ engine รู้ว่านี่คือ string key **เฉลย 2:** `appium-service` auto-start Appium server ก่อน test และ stop หลัง test จบ ถ้าไม่ใช้ต้องเปิด terminal แยกรัน `appium` ก่อน และ stop เอง **เฉลย 3:** เพิ่มอีก 1 entry ใน `capabilities` array (รวมเป็น 2 objects) และตั้ง `maxInstances: 2` เพื่อให้รัน parallel พร้อมกันบทต่อไป: บทที่ 4 — เขียน Test แรก