[Playwright] font style bị khác khi chạy trên Github Action

Một câu hỏi hay trên cộng đồng Playwright discord
noah.choi:
Xin chào! 👋 Mình đang thử làm một bài kiểm tra hồi quy trực quan cho một thư viện thành phần, dùng iframe của Storybook làm môi trường test.
Mình muốn kiểm tra bằng cách chụp snapshot trong môi trường local, rồi so sánh các snapshot đó trong GitHub Action mỗi khi mình tạo một PR.
Nhưng mà có vẻ kiểu font cứ bị áp dụng khác nhau trong môi trường GitHub Action (Linux). 😕
Giao diện kiểm tra qua trace mode không khác nhiều so với snapshot mong đợi, nên mình tự hỏi liệu đây chỉ là sự khác biệt giữa Linux và macOS thôi không?
Đây là link báo cáo về bài test snapshot trong GitHub Action: [link].
Và dưới đây là file cấu hình + file test mà mình đã viết:
// playwright.config.ts
import { defineConfig, devices } from "@playwright/test";
const BASE_URL = process.env.TEST_BASE_URL || "http://localhost:6006";
export default defineConfig({
snapshotPathTemplate: "./tests/__screenshot__/{testFilePath}/{arg}{ext}",
outputDir: `./tests/results/`,
reporter: [["html", { outputFolder: "./tests/report" }]],
use: { baseURL: BASE_URL, trace: "retain-on-failure" },
projects: [
{ name: "chromium", use: { ...devices["Desktop Chrome"]}},
],
workers: process.env.CI ? 1 : undefined,
webServer: {
command: "cd ../../ && pnpm storybook",
url: BASE_URL,
reuseExistingServer: false,
},
});
// button.test.ts
import { test, expect } from "@playwright/test";
test("button", async ({ page }) => {
const params = new URLSearchParams({
id: "vanilla-button--test-bed",
viewMode: "story",
});
await page.goto(`/iframe.html?${params.toString()}`);
await page.waitForSelector("#storybook-root");
await page.waitForLoadState("domcontentloaded");
await expect(page).toHaveScreenshot({
fullPage: true,
animations: "disabled",
});
});marshmn:
Chào bạn! Snapshot thì thường sẽ có sự khác biệt giữa các môi trường (hệ điều hành và trình duyệt). Vì vậy, bạn cần dùng cùng một hệ thống để tạo ảnh tham chiếu (reference images) và chạy test.
Một cách là dùng một Docker image chung. Bạn có thể dùng nó ở local để tạo ảnh tham chiếu, rồi dùng cùng image đó trong CI. 🐳
noah.choi:
Vậy là mình nên luôn luôn test trên Linux à? 🤔
Có cách nào để chụp snapshot của môi trường macOS trong CI hoặc Docker không nhỉ?
marshmn:
Nếu bạn đang dùng Mac trên máy tính cá nhân, cách đơn giản nhất có lẽ là:
- Chạy một container Docker Linux trên Mac để tạo ảnh tham chiếu.
- Dùng cùng container đó trong pipeline CI của bạn.
Một số pipeline hỗ trợ chạy trên Mac (ví dụ GitLab làm được—mình không rõ GitHub thế nào). Nếu dùng cách đó, khả năng ảnh khớp nhau sẽ cao hơn. Nhưng lưu ý là vẫn có thể khác nếu phiên bản OS khác nhau chẳng hạn, nên bạn cần cẩn thận giữ môi trường nhất quán—điều này hơi đau đầu thật. 😅 Đó là lý do mình thấy cách dùng Docker ổn hơn, nó cách ly tốt hơn mấy vấn đề này.
noah.choi:
Cảm ơn bạn vì câu trả lời! 🙏
Nhưng mình hỏi thêm một câu được không?
Mình đã thử test trong môi trường macOS bằng cách thêm macos-latest vào tùy chọn runs-on của GitHub Action. Nhưng kết quả vẫn giống như khi dùng ubuntu-latest.
Khi xem trace result, ảnh trong tab action giống với snapshot chụp ở local. Nhưng như ảnh đính kèm, nó lại khác với ảnh trong phần screenshot phía trên.
Mình thật sự không hiểu tiêu chí nào khiến snapshot khác nhau thế này. Giúp mình với nhé, cảm ơn nhiều! 😭
marshmn:
Như mình đã nói, việc tạo ảnh tham chiếu trên một máy Mac và chạy test trên một máy Mac khác không đảm bảo 100% giống nhau đâu. Ví dụ như hệ điều hành khác phiên bản chút, font cài đặt khác, hoặc thư viện khác nhau, v.v.
Nhưng mà cũng có thể nguyên nhân khác nữa. Chẳng hạn trong CI có race condition, font “xịn” chưa kịp load xong thì screenshot đã chụp, nên dùng font mặc định thay thế? 🤔
noah.choi:
Vậy chắc mình cần thêm logic để đợi font load xong. Bạn có gợi ý gì cho phần này không?
Mình đã thử thêm tùy chọn như này:
await page.goto(`/iframe.html?${params.toString()}`, {
waitUntil: "domcontentloaded"
});
Và thêm logic đợi một khoảng thời gian:
await page.waitForTimeout(300000);
Nhưng vẫn không được kết quả như mong muốn. 😢
refactoreric:
Bạn có thể thử thêm một cách nữa là dùng browser channel. Nó sẽ dùng chế độ headless mới, đảm bảo trình duyệt giống hệt nhau cho cả headless và headful.
Nhưng mình nghĩ chạy trong Docker và tránh race condition vẫn quan trọng hơn.
P.S. Mình biết đây chỉ là ví dụ, nhưng đợi 300 giây thì lâu kinh khủng luôn á, thường sẽ gây timeout trong test đấy! ⏳
Còn bạn thì sao? Theo bạn, lí do fail là gì?
