/** * Copyright 2018 Google Inc. All rights reserved. * Modifications copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { Page } from 'playwright-core'; import { test as it, expect } from './pageTest'; async function routeIframe(page: Page) { await page.route('**/empty.html', route => { route.fulfill({ body: '', contentType: 'text/html' }).catch(() => {}); }); await page.route('**/iframe.html', route => { route.fulfill({ body: `
1 2 `, contentType: 'text/html' }).catch(() => {}); }); await page.route('**/iframe-2.html', route => { route.fulfill({ body: '', contentType: 'text/html' }).catch(() => {}); }); } async function routeAmbiguous(page: Page) { await page.route('**/empty.html', route => { route.fulfill({ body: ` `, contentType: 'text/html' }).catch(() => {}); }); await page.route('**/iframe-*', route => { const path = new URL(route.request().url()).pathname.slice(1); route.fulfill({ body: ``, contentType: 'text/html' }).catch(() => {}); }); } it('should work for iframe @smoke', async ({ page, server }) => { await routeIframe(page); await page.goto(server.EMPTY_PAGE); const button = page.frameLocator('iframe').locator('button'); await button.waitFor(); expect(await button.innerText()).toBe('Hello iframe'); await expect(button).toHaveText('Hello iframe'); await button.click(); }); it('should work for nested iframe', async ({ page, server }) => { await routeIframe(page); await page.goto(server.EMPTY_PAGE); const button = page.frameLocator('iframe').frameLocator('iframe').locator('button'); await button.waitFor(); expect(await button.innerText()).toBe('Hello nested iframe'); await expect(button).toHaveText('Hello nested iframe'); await button.click(); }); it('should work for $ and $$', async ({ page, server }) => { await routeIframe(page); await page.goto(server.EMPTY_PAGE); const locator = page.frameLocator('iframe').locator('button'); await expect(locator).toHaveText('Hello iframe'); const spans = page.frameLocator('iframe').locator('span'); await expect(spans).toHaveCount(2); }); it('should wait for frame', async ({ page, server }) => { await page.goto(server.EMPTY_PAGE); const error = await page.frameLocator('iframe').locator('span').click({ timeout: 1000 }).catch(e => e); expect(error.message).toContain('waiting for frame "iframe"'); }); it('should wait for frame 2', async ({ page, server }) => { await routeIframe(page); setTimeout(() => page.goto(server.EMPTY_PAGE).catch(() => {}), 300); await page.frameLocator('iframe').locator('button').click(); }); it('should wait for frame to go', async ({ page, server, isAndroid }) => { it.fixme(isAndroid); await routeIframe(page); await page.goto(server.EMPTY_PAGE); setTimeout(() => page.$eval('iframe', e => e.remove()).catch(() => {}), 300); await expect(page.frameLocator('iframe').locator('button')).toBeHidden(); }); it('should not wait for frame', async ({ page, server }) => { await page.goto(server.EMPTY_PAGE); await expect(page.frameLocator('iframe').locator('span')).toBeHidden(); }); it('should not wait for frame 2', async ({ page, server }) => { await page.goto(server.EMPTY_PAGE); await expect(page.frameLocator('iframe').locator('span')).not.toBeVisible(); }); it('should not wait for frame 3', async ({ page, server }) => { await page.goto(server.EMPTY_PAGE); await expect(page.frameLocator('iframe').locator('span')).toHaveCount(0); }); it('should click in lazy iframe', async ({ page, server }) => { await page.route('**/iframe.html', route => { route.fulfill({ body: '', contentType: 'text/html' }).catch(() => {}); }); // empty pge await page.goto(server.EMPTY_PAGE); // add blank iframe setTimeout(() => { page.evaluate(() => { const iframe = document.createElement('iframe'); document.body.appendChild(iframe); }); // navigate iframe setTimeout(() => { page.evaluate(() => document.querySelector('iframe').src = 'iframe.html'); }, 500); }, 500); // Click in iframe const button = page.frameLocator('iframe').locator('button'); const [, text] = await Promise.all([ button.click(), button.innerText(), expect(button).toHaveText('Hello iframe') ]); expect(text).toBe('Hello iframe'); }); it('waitFor should survive frame reattach', async ({ page, server }) => { await routeIframe(page); await page.goto(server.EMPTY_PAGE); const button = page.frameLocator('iframe').locator('button:has-text("Hello nested iframe")'); const promise = button.waitFor(); await page.locator('iframe').evaluate(e => e.remove()); await page.evaluate(() => { const iframe = document.createElement('iframe'); iframe.src = 'iframe-2.html'; document.body.appendChild(iframe); }); await promise; }); it('click should survive frame reattach', async ({ page, server }) => { await routeIframe(page); await page.goto(server.EMPTY_PAGE); const button = page.frameLocator('iframe').locator('button:has-text("Hello nested iframe")'); const promise = button.click(); await page.locator('iframe').evaluate(e => e.remove()); await page.evaluate(() => { const iframe = document.createElement('iframe'); iframe.src = 'iframe-2.html'; document.body.appendChild(iframe); }); await promise; }); it('click should survive iframe navigation', async ({ page, server }) => { await routeIframe(page); await page.goto(server.EMPTY_PAGE); const button = page.frameLocator('iframe').locator('button:has-text("Hello nested iframe")'); const promise = button.click(); page.locator('iframe').evaluate(e => (e as HTMLIFrameElement).src = 'iframe-2.html'); await promise; }); it('should non work for non-frame', async ({ page, server }) => { await routeIframe(page); await page.setContent('
'); const button = page.frameLocator('div').locator('button'); const error = await button.waitFor().catch(e => e); expect(error.message).toContain('
'); expect(error.message).toContain('