อัพเดตการทำ Web Automation Testing with Puppeteer จากงาน Google I/O 2019

Traitanit Huangsri
5 min readMay 12, 2019

--

จากงาน Google I/O 2019 ที่ผ่านพ้นไป มี Session ที่พูดถึงการนำ Puppeteer ไปใช้ในการทำ Web Automation Test แล้ว ซึ่งมีหลายเรื่องที่น่าสนใจเลยทีเดียวครับ ผมจะมาสรุปทั้งหมดให้ฟังจบภายในบทความนี้เลยครับ

Puppeteer คืออะไร ?

ก่อนจะไปพูดถึงว่าจะนำ Puppeteer มาเขียน Automation Test ได้อย่างไร เรามาทำความเข้าใจกันก่อนว่า Puppeteer คืออะไร สำหรับคนที่ยังไม่รู้จักหรือยังไม่เคยใช้งาน Puppeteer มาก่อนนะครับ

Puppeteer คือ Open Source NodeJS Library ที่ Provide API ในการ Control Chrome Browser ผ่าน Chrome DevTool Protocol ซึ่งแตกต่างกับ Web Automation Test Framework อื่นๆ อย่าง Selenium ที่ใช้ Web Driver ในการ Control Browser ซึ่งข้อดีของ Puppeteer คือเป็น Native Access ตัว Chrome โดยตรง ทำงานได้อย่างรวดเร็วและได้รับการ Support โดยตรงจาก Engineer ของ Google ซึ่งเป็นผู้พัฒนา Chrome Browser ด้วยนั่นเอง

Puppeteer ถูก Released ให้ใช้งานครั้งแรกตั้งแต่ประมาณปี 2017 โดยแรกเริ่มเดิมทีจุดประสงค์หลักคือใช้เป็น Library เพื่อ Automate งานบางอย่างบน Chrome Browser ยกตัวอย่างเช่น ทำ Full Page Screenshot, การทำ Automate Form Submission เป็นต้น

แต่ช่วงหลังๆ เริ่มมีการนำ Puppeteer ไปใช้งานในการทำ Web Automation Testing มากขึ้น ซึ่งด้วยตัว Puppeteer เองนั้นมีความสามารถเพียงแค่ Control Chrome Browser เท่านั้น แต่ไม่ได้มีความสามารถในการจัดการ Test Cases เหมือนกับ Testing Framework อื่นๆ เช่น การทำ Assertion หรือการทำ Test Setup/Teardown หรือ Test Report ดังนั้นการที่จะนำ Puppeteer ไปใช้ทำ Web Automation Test ที่ดีได้ควรจะต้องพึ่งพา Testing Framework อื่นๆ ร่วมด้วย เช่น Jest, Mocha, Karma เป็นต้น

มีอะไรใหม่ใน Puppeteer จากงาน Google I/O 2019

ในงาน Google I/O 2019 ที่ผ่านมา มี Session หนึ่งที่ใช้ชื่อว่า “Modern Web Testing and Automation with Puppeteer” โดยคุณ Andrey Lushnikov และคุณ Joel Einbinder ซึ่งเป็น Chromium Engineer ผู้รับผิดชอบ Chrome DevTools และ Puppeteer มาพูดถึงการ Apply นำ Puppeteer ไปใช้ในการทำ Modern Web Automation Testing ว่าจะทำได้อย่างไรบ้าง

Puppeteer for Firefox

เริ่มต้นของ Session ก็มีประกาศ Announcement สำคัญ จากการทำงานร่วมกันระหว่าง Google และ Mozilla ทำให้เกิด Puppeteer for Firefox ซึ่งเป็นการเริ่มต้นทดลองนำ Puppeteer ไปใช้งานบน Firefox ครั้งแรกเลย แต่ยังเป็นช่วงทดลองอยู่นะครับ ใครอยากทดลองใช้งานก็สามารถใช้ npm install puppeteer-firefox ลองใช้ได้เลยครับ น่าลองมากๆ

Puppeteer for Web Automation Test

แน่นอนว่า Puppeteer นั้นมี API ที่สามารถใช้ Control Chrome Browser มากมาย ตั้งแต่การทำ Action ต่างๆ บน Browser เช่น Click, TypeText, Form Submission, etc ซึ่งเป็นสิ่งที่คนที่ทำ Web Automation Test ต้องการอยู่แล้ว แต่ในช่วงหลังๆ Puppeteer เริ่มมีการเพิ่ม API บางอย่างที่สนับสนุนการทำ Web Automation Test อย่างเฉพาะเจาะจงมากขึ้น ถือว่าดีมากเลยนะครับ

Problem and Solution

ปกติ คนที่เคยเขียน Web Automation Test คงทราบปัญหา Classic ที่มักจะเจอบ่อยๆ ซึ่งสรุปปัญหาได้ดังนี้

1.Tests Slowness

เป็นปัญหาที่ปฏิเสธไม่ได้เลยว่าการทำ Test ที่รันบน Web Browser นั้นใช้เวลาเทสค่อนข้างนาน ซึ่งหลายคนเวลาเขียน Test ก็มักที่จะใช้วิธีการเปิด/ปิด Browser ทุกครั้งเมื่อมีการรันเทสแต่ละข้อเพื่อที่จะให้ได้มั่นใจว่าไม่มี Cookie, Network Caching อะไรค้างอยู่และทำให้เกิด Test Isolation ที่ดีด้วย แต่นั่นก็เป็นสาเหตุที่ทำให้รันเทสได้ช้าลงนั่นเอง ซึ่ง Puppeteer ได้ Provide BrowserContexts API เพื่อใช้ในการสร้าง Browser Context อันใหม่ขึ้นมาเป็นแบบ Incognito Mode ให้เราแทนที่จะรัน Browser ขึ้นมาใหม่ทุกครั้ง ซึ่งทาง Google Claim ว่าจะทำให้รันเร็วขึ้น 100 เท่า!!

ใช้ Browser Contexts ทำให้รันเร็วขึ้น 100 เท่า
const browser = await puppeteer.launch();it('should have a pay button', () => {
// Create a new incognito browser context
const context = await browser.createIncognitoBrowserContext();
// Create a new page inside context.
const page = await context.newPage();
// ... do stuff with page ...
await page.goto('https://example.com');
// Dispose context once it's no longer needed.
await context.close();
});

2. Flaky Tests

Flaky Test คือ Test ที่ให้ผลลัพธ์ไม่เหมือนกันในแต่ละครั้ง บางครั้งรันผ่านบางครั้งก็รันแล้วไม่ผ่าน ทั้งที่ไม่ได้แก้ไขโค้ดใดๆ ซึ่งสาเหตุหลักๆ ก็มาจากการที่ Web Application นั้นทำงานเป็นแบบ ​Asynchronous ทำให้ Test ที่จะมา Control Web Browser นั้นจะต้องมีการ Synchronize การทำงานร่วมกับ Web Application ด้วย Puppeteer แก้ปัญหานี้ด้วยการ Provide Set of Waits API มาให้เราใช้เพื่อให้ Puppeteer หยุดรอการทำงานบางอย่างก่อนค่อยทำ Action หรือ Assertion ต่อไป

page.waitFor(selectorOrFunctionOrTimeout[, options]);
page.waitForFunction(pageFunction [, options]);
page.waitForNavigation(options);
page.waitForRequest(urlOrPredicate, options); // network request
page.waitForResponse(urlOrPredicate, options); // network response
page.waitForSelector(selector [, options]);
page.waitForXPath(xpath [, options]);

Puppeteer for Modern Web Testing

Puppeteer ยังมี APIs อีกหลายตัวที่ถูกออกแบบมาให้ใช้กับการทำเทสได้ ดังนี้

Emulate Browser on Mobile

เราสามารถทำให้เว็บที่เราต้องการจะเทสเสมือนอยู่กับว่ารันอยู่บน Mobile Browser ได้ง่ายๆ ผ่านทาง Emulate API ของ Puppeteer ซึ่งมีให้เลือกใช้ถึงกว่า 100+ Devices เช่น iPhone, Samsung, Pixel, etc ซึ่ง​ API นี้จะช่วยเช็ตทั้ง User-Agent Device Pixel Ratio ViewPort size และ Touch Support ทำให้เหมือนกับใช้จริงบนมือถือเลย

page.emulate(puppeteer.devices['iPhone 6']);

Offline Support

เราสามารถ Simulate Scenario ให้ Web App เรารันแบบ Offline Mode ได้ผ่าน Puppeteer API ได้เช่นกัน ทำให้เราสามารถสร้างเทส Scenario เมื่อ Web App ไม่มี Internet Connection ได้ง่ายๆ เลยแถมเป็น Automate ด้วย

page.setOfflineMode(true);

Service Worker

Service Worker คือ Javascript ที่ทำงานอยู่เบื้องหลังของ Browser คอยช่วยจัดการหลายๆ อย่างให้กับเว็บของเรา เช่นการทำ Network Caching หรือจัดการพวก Push Notifications ต่างๆ ให้เรา รายละเอียดเพิ่มเติมสามารถอ่านได้จากบล็อคนี้เลยครับ

Puppeteer มีความสามารถในการ Access ตัว Service Worker เพื่อให้เราสามารถเช็คอะไรบางอย่างที่ Service Worker ได้ เช่น เช็คว่า App ของเราได้ถูก Register เข้าไปยัง Service Worker แล้วหรือยัง เป็นต้น ตัวอย่างข้างล่างคือการเช็คว่า logo ของเว็บ https://pptr.dev ถูก Cache ด้วย Service Worker แล้วหรือยัง

it('should register a service worker', () => {
const page = await context.newPage();
await page.goto('https://pptr.dev');
const swTarget = await context.waitForTarget(target => {
return target.type() === 'service_worker';
}
const serviceWorker = await swTarget.worker();
const isCached = await serviceWorker.evaluate(async () => {
return !!(await caches.match('https://pptr.dev/logo.png'));
}
expect(isCached).toBe(true);
});

Geolocation

เราสามารถ Set GeoLocation ของ Browser เราให้เหมือนกับอยู่ใน Location ที่เราต้องการได้ ทำให้สามารถสร้าง Test Scenario สำหรับเว็บที่ต้องการดึง Browser GeoLocation มาใช้งานได้จริงเลย

await context.overridePermissions('https://pptr.dev', [ 'geolocation' ]);
const page = await context.newPage();
await page.setGeolocation({
latitude: 51.507351,
longitude: -0.127758
}); // set geolocation to London

Network Monitoring

ไฮไลท์เด็ดของ Feature ของ Puppeteer คือมันสามารถทำ Network Monitoring ได้แล้ว ซึ่งในมุมของการทำเทสนั่นแปลว่า เราสามารถ Mock Network Request/Response ที่ ​Web App ของเรา Call ไปหา Server ได้แล้ว Puppeteer เรียก Feature นี้ว่า Network Request Interception

puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.setRequestInterception(true);
page.on('request', request => {
if (request.resourceType() == 'image') {
request.respond({ body: randomCatImage() });
else {
request.continue();
}
});

ตัวอย่างด้านบนคือการ Intercept Network Request ที่มี ResouceType เป็นรูปภาพให้ทำการ Return Response เป็นรูปแมวที่เซตไว้ทั้งหมด

ซึ่งการทำ Network Request Interception ก็ช่วยให้เราสามารถสร้าง Test Scenario ที่เป็น Negative Test ได้เช่น Server return Error, Failure กลับมาหา Web App ของเราก็สามารถทำได้ง่ายๆ เลย

Dispatch Event

Dispatch Event คือการส่ง Javascript Code บางอย่างไปให้ Browser เราทำงานเพื่อให้เกิด Event บน Web App ของเรา เช่นการกดปุ่ม Enter บน Keyboard, Mouse Down Event เป็นต้น ซึ่ง Puppeteer ก็สามารถ Simulate Event ลักษณะนี้เหมือนกับที่ User ทำได้เช่นกัน

it('should fuzzy search', () => {
const page = await context.newPage();
await page.goto('https://pptr.dev/');
const input = await page.waitForSelector('[type=search]');
await input.type('javascript');
await page.keyboard.press('Enter');
expect(await page.title().toInclude('javascriptenabled'));
});

Performance Testing

นอกจากจะทำ Functional UI Test ได้แล้ว Puppeteer ยังสามารถช่วยทำ Performance Testing ให้กับ Web Application ของเราได้ด้วย

Metrics

เราสามารถ Check ค่า Page Metrics ของ Web App ของเราได้ว่าใช้ Resource มากน้อยขนาดไหน เช่นการ Check ว่า App เราใช้ Memory มากน้อยขนาดไหนก็สามารถเรียก API page.metrics() เพื่อ Get ค่าออกมาดูได้เลย

ค่า JSHeapUsedSize คือ Memory Usage เฉพาะของแอพเรา (ไม่รวม Browser)

Chrome Tracing

Chrome Tracing บน DevTools

Tracing คือ Feature ของ Chrome DevTools เพื่อจับการทำงานของ CSS, DOM, Animation Frames, Network บน Web App เราว่าทำงานช้าเร็วขนาดไหน ซึ่ง Puppeteer ก็มี API ที่สามารถทำเหมือนบน DevTools ได้เหมือนกัน

await page.tracing.start({path: 'trace.json'});
await page.goto('https://www.google.com');
await page.tracing.stop();

Code Coverage

เราสามารถทำ Code Coverage ผ่าน Puppeteer API ได้ด้วย โดยสามารถเลือกดูได้ทั้ง CSS Coverage และ Javascript Coverage

// Enable both JavaScript and CSS coverage
await Promise.all([
page.coverage.startJSCoverage(),
page.coverage.startCSSCoverage()
]);
// Navigate to page
await page.goto('https://example.com');
// Disable both JavaScript and CSS coverage
const [jsCoverage, cssCoverage] = await Promise.all([
page.coverage.stopJSCoverage(),
page.coverage.stopCSSCoverage(),
]);

Accessibility

Puppeteer มี API ที่สามารถช่วยเข้าไป Inspect ตัว Accessibility Tree บน Browser ได้เพื่อเช็คว่า App ของเรามี Accessibility Tree อะไรที่สามารถให้ตัว Screen Readers (เทคโนโลยีที่ช่วยอ่านออกเสียงให้ผู้พิการทางสายตาให้ได้ยินแทนการมองเห็น) ต่างๆ สามารถนำไปใช้งานได้บ้าง วิธีการคือการ Snapshot ตัว Accessibility Object ใน Web App เราออกมาเช็คนั่นเอง

const snapshot = await page.accessibility.snapshot();
console.log(snapshot);

Community

ตอนนี้ Google ก็ใช้ Puppeteer ภายในองค์กร รวมถึง Facebook และ Netflix ก็ใช้ Puppeteer อยู่เช่นเดียวกัน ซึ่งตอนนี้ Community ของ Puppeteer ก็กำลังเติบโตอย่างรวดเร็ว มี Slack Channel https://puppeteer.slack.com ที่มีคน Join อยู่มากกว่า 270 คน และก็มีคนที่ช่วย Maintain Document บน GitHub มากมาย

สรุป

Puppeteer น่าจะเป็น Web Automation Library สำหรับ Web Developers ในอนาคตอย่างแน่นอนครับ เพราะมีความสามารถมากมายหลายอย่างเหลือเกิน แถมยังเป็น Native Library ที่ Support โดยตรงจาก Google อีกด้วย ก็ต้องติดตามกันต่อไปว่า Puppeteer จะมี Features เจ๋งๆ ใหม่ๆ มาให้เราได้ใช้กันอีกนะครับ แต่รับรองว่าน่าจะไปไกลอย่างแน่นอนครับ

--

--

No responses yet