typescript - Cách sử dụng hàm đã nhập trong page.evaluate trong Puppeteer với Jest?
Tôi có một dự án TypeScript sử dụng Jest cho kiểm thử đơn vị và vừa thêm Puppeteer với ý định chạy một số kiểm thử trên phía client. Nó hoạt động bình thường, trừ khi tôi cố gắng sử dụng các hàm đã nhập bên trong page.evaluate.
Ví dụ, tôi có những điều sau trong HdpiCanvas.test.ts:
import { createHdpiCanvas } from "./HdpiCanvas";
test("createHdpiCanvas", async () => {
await page.setViewport({ width: 800, height: 600, deviceScaleFactor: 2 });
let size = await page.evaluate(() => {
const canvas = createHdpiCanvas(); // document.createElement('canvas');
return [canvas.width, canvas.height];
});
console.log(size); // [600, 300] for HDPI canvas and [ 300, 150 ] for a regular one
});
Với câu lệnh document.createElement('canvas') bị chú thích lại thì bài kiểm tra chạy bình thường và ghi lại [ 300, 150 ]. Nhưng với createHdpiCanvas() thì lỗi sau được hàm page.evaluate ném ra:
Error: Evaluation failed: ReferenceError: HdpiCanvas_1 is not defined
at __puppeteer_evaluation_script__:2:24
Hàm thực tế createHdpiCanvas bên trong HdpiCanvas.ts được định nghĩa như sau:
export function createHdpiCanvas(width = 300, height = 150): HTMLCanvasElement {
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
applyHdpiOverrides(canvas);
return canvas;
}
và bản thân nó phụ thuộc vào các hàm khác được định nghĩa trong HdpiCanvas.ts, như applyHdpiOverrides.
Câu trả lời #1
Giải pháp do Meni Roytenburd đề xuất là đúng. Nếu bạn không thích việc mỗi hàm cần được trình duyệt nhận diện riêng lẻ, ý tưởng duy nhất xuất hiện trong đầu là biên dịch dự án của bạn thành một tệp JavaScript duy nhất trước và sau đó chèn nó dưới dạng thẻ <script> — giống như cách bạn sẽ làm trong thực tế.
Bước đầu tiên sẽ là tạo một tệp JavaScript duy nhất với gói của bạn. Đôi khi điều này có thể được thực hiện chỉ với trình biên dịch TypeScript, nhưng cũng có thể sử dụng một công cụ như Webpack.
Khi nó xong, bạn có thể chuyển gói của mình đến client từ bên trong Puppeteer:
await page.addScriptTag({ path: 'path/to/the/bundle' });
Hãy nhớ rằng điều này vẫn có thể làm các hàm của bạn lộ ra phạm vi toàn cầu, do đó có thể truy cập chúng thông qua window.
let size = await page.evaluate(() => {
const canvas = window.createHdpiCanvas();
return [canvas.width, canvas.height];
});
console.log(size); // [ 300, 150 ]
Một nhược điểm khác của cách tiếp cận này là phải đối phó với các cảnh báo do TypeScript tạo ra — tại thời điểm này nó không biết rằng createHdpiCanvas tồn tại trên window, vì vậy việc truy cập window.createHdpiCanvas sẽ gây ra lỗi.
Câu trả lời #2
bạn có thể làm như thế này trước khi gọi hàm evaluate:
await page.exposeFunction("applyHdpiOverrides",applyHdpiOverrides);
await page.exposeFunction("createHdpiCanvas",createHdpiCanvas);
và bây giờ cửa sổ của bạn sẽ nhận ra các chức năng này
