blog
Playwright page.route 핸들러에서 구조 분해가 안 되는 이유
Front-end / Testing#Playwright#E2E#this 바인딩#JavaScript
문제
page.route 핸들러의 첫 번째 인자(Route)에서 request를 구조 분해하면 에러가 난다.
// ❌
await page.route('**/*', ({ request }) => {
console.log(request.url()); // TypeError: request.url is not a function
});
원인 1: request는 속성이 아니라 메서드다
핸들러의 첫 번째 인자는 Route 객체이고, route.request는 Request를 반환하는 메서드다. 구조 분해로 꺼낸 request는 함수 자체이므로 request.url()은 존재하지 않는 속성을 호출하는 셈이다.
원인 2: 꺼낸 메서드를 호출해도 this가 없다
그렇다면 request()로 호출하면 될까?
await page.route('**/*', ({ request }) => {
const req = request(); // ❌ this가 Route 인스턴스가 아님
});
JavaScript에서 메서드를 객체에서 떼어 내 호출하면 this가 원래 객체를 가리키지 않는다(엄격 모드에서는 undefined). Playwright의 Route는 클래스 인스턴스이고, 메서드는 내부 상태를 this로 참조하므로 떼어 내서 호출하면 정상 동작을 기대할 수 없다.
class Counter {
count = 0;
increase() {
this.count += 1;
}
}
const { increase } = new Counter();
increase(); // TypeError: Cannot read properties of undefined (reading 'count')
React props나 일반 객체처럼 데이터 속성은 구조 분해해도 되지만, 클래스 인스턴스의 메서드는 객체에서 직접 호출해야 한다.
올바른 사용법
// ✅ 1. route에서 메서드로 호출
await page.route('**/*', async (route) => {
const request = route.request();
console.log(request.url());
await route.continue();
});
// ✅ 2. 핸들러의 두 번째 인자로 Request 받기
await page.route('**/*', async (route, request) => {
await route.continue({
headers: { ...request.headers(), foo: 'foo-value' },
});
});
route.continue(), route.fulfill(), route.abort() 중 하나를 반드시 호출해야 요청이 멈춰 있지 않는다. 비동기 메서드이므로 await한다.
정리
| 코드 | 결과 |
|---|---|
({ request }) => request.url() | request는 함수 → url is not a function |
({ request }) => request() | this 바인딩이 끊김 → 동작 보장 안 됨 |
(route) => route.request() | ✅ |
(route, request) => ... | ✅ 두 번째 인자로 Request 수신 |