javascript - Playwright Chọn khung với tên động
Tôi cần truy cập một iframe trong Playwright mà có tên được tạo tự động.
Tên của iframe luôn được tiền tố bằng '__privateStripeFrame' và sau đó là một số được tạo ngẫu nhiên
Làm thế nào tôi có thể truy cập frame với page.frame({name: })?
Theo tài liệu, có vẻ như tôi không thể sử dụng biểu thức chính quy!
Câu trả lời #1
Không cần phải chỉ định frameSelector bằng tên. Hãy thử một xpath với contains - điều này hoạt động trên trang mẫu W3:
await page.goto('https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_iframe');
await page.frame("//iframe[contains(@title,'W3s')]");
Nếu bạn muốn một cách tiếp cận tổng quát hơn - bạn cũng có thể sử dụng page.frames(). Điều đó sẽ trả về một mảng các frame và bạn có thể duyệt qua và tìm frame mà bạn cần.
Điều này phù hợp với tôi:
let myFrames = page.frames();
console.log("#frames: " + myFrames.length)
myFrames.map((f) => console.log(f.name()));
(W3S không phải là trang demo tốt nhất vì có nhiều khung lồng nhau - nhưng điều này xuất ra các khung cấp cao nhất có tên)
Đầu ra:
kết quả iframe
__tcfapiLocator
__uspapiLocator
__tcfapiLocator
__uspapiLocator
Câu trả lời #2
Chúng tôi đã gặp vấn đề với nhiều iframe của Stripe Elements tải không đồng bộ và rất chậm, vì vậy cuối cùng chúng tôi đã có cách giải quyết tạm thời này để thử lặp lại tất cả các khung và truy vấn các trường nhập thẻ cho từng khung, cho đến khi tìm thấy hoặc hết thời gian chờ.
Không tinh tế, nhưng nó đã hoạt động đối với chúng tôi.
async function findStripeElementsIframeAsync(page: Page, timeout: number) {
const startTime = Date.now();
let stripeFrame = null;
while (!stripeFrame && Date.now() - startTime < timeout) {
const stripeIframes = await page.locator('iframe[name^=__privateStripeFrame]');
const stripeIframeCount = await stripeIframes.count();
for (let i = 0; i < stripeIframeCount; i++) {
const stripeIFrameElement = await stripeIframes.nth(i).elementHandle();
if (!stripeIFrameElement)
throw 'No Stripe iframe element handle.';
const cf = await stripeIFrameElement.contentFrame();
if (!cf)
throw 'No Stripe iframe content frame.';
// Does this iframe have a CVC input? If so, it's our guy.
// 1 ms timeout did not work, because the selector requires some time to find the element.
try {
await cf.waitForSelector('input[name=cvc]', { timeout: 200 });
stripeFrame = cf;
console.log('Found Stripe iframe with CVC input');
return stripeFrame;
} catch {
// Expected for iframes without this input.
}
}
// Give some time for iframes to load before retrying.
await new Promise(resolve => setTimeout(resolve, 200));
}
return null;
}
