chore: use contentFrame() as a canonical locator representation (#32697)
This commit is contained in:
parent
790dbfd78f
commit
2f4acbb001
|
@ -1,30 +1,30 @@
|
|||
# class: FrameLocator
|
||||
* since: v1.17
|
||||
|
||||
FrameLocator represents a view to the `iframe` on the page. It captures the logic sufficient to retrieve the `iframe` and locate elements in that iframe. FrameLocator can be created with either [`method: Page.frameLocator`] or [`method: Locator.frameLocator`] method.
|
||||
FrameLocator represents a view to the `iframe` on the page. It captures the logic sufficient to retrieve the `iframe` and locate elements in that iframe. FrameLocator can be created with either [`method: Locator.contentFrame`], [`method: Page.frameLocator`] or [`method: Locator.frameLocator`] method.
|
||||
|
||||
```js
|
||||
const locator = page.frameLocator('#my-frame').getByText('Submit');
|
||||
const locator = page.locator('#my-frame').contentFrame().getByText('Submit');
|
||||
await locator.click();
|
||||
```
|
||||
|
||||
```java
|
||||
Locator locator = page.frameLocator("#my-frame").getByText("Submit");
|
||||
Locator locator = page.locator("#my-frame").contentFrame().getByText("Submit");
|
||||
locator.click();
|
||||
```
|
||||
|
||||
```python async
|
||||
locator = page.frame_locator("#my-frame").get_by_text("Submit")
|
||||
locator = page.locator("#my-frame").content_frame.get_by_text("Submit")
|
||||
await locator.click()
|
||||
```
|
||||
|
||||
```python sync
|
||||
locator = page.frame_locator("my-frame").get_by_text("Submit")
|
||||
locator = page.locator("my-frame").content_frame.get_by_text("Submit")
|
||||
locator.click()
|
||||
```
|
||||
|
||||
```csharp
|
||||
var locator = page.FrameLocator("#my-frame").GetByText("Submit");
|
||||
var locator = page.Locator("#my-frame").ContentFrame.GetByText("Submit");
|
||||
await locator.ClickAsync();
|
||||
```
|
||||
|
||||
|
@ -34,42 +34,42 @@ Frame locators are strict. This means that all operations on frame locators will
|
|||
|
||||
```js
|
||||
// Throws if there are several frames in DOM:
|
||||
await page.frameLocator('.result-frame').getByRole('button').click();
|
||||
await page.locator('.result-frame').contentFrame().getByRole('button').click();
|
||||
|
||||
// Works because we explicitly tell locator to pick the first frame:
|
||||
await page.frameLocator('.result-frame').first().getByRole('button').click();
|
||||
await page.locator('.result-frame').contentFrame().first().getByRole('button').click();
|
||||
```
|
||||
|
||||
```python async
|
||||
# Throws if there are several frames in DOM:
|
||||
await page.frame_locator('.result-frame').get_by_role('button').click()
|
||||
await page.locator('.result-frame').content_frame.get_by_role('button').click()
|
||||
|
||||
# Works because we explicitly tell locator to pick the first frame:
|
||||
await page.frame_locator('.result-frame').first.get_by_role('button').click()
|
||||
await page.locator('.result-frame').first.content_frame.get_by_role('button').click()
|
||||
```
|
||||
|
||||
```python sync
|
||||
# Throws if there are several frames in DOM:
|
||||
page.frame_locator('.result-frame').get_by_role('button').click()
|
||||
page.locator('.result-frame').content_frame.get_by_role('button').click()
|
||||
|
||||
# Works because we explicitly tell locator to pick the first frame:
|
||||
page.frame_locator('.result-frame').first.get_by_role('button').click()
|
||||
page.locator('.result-frame').first.content_frame.get_by_role('button').click()
|
||||
```
|
||||
|
||||
```java
|
||||
// Throws if there are several frames in DOM:
|
||||
page.frame_locator(".result-frame").getByRole(AriaRole.BUTTON).click();
|
||||
page.locator(".result-frame").contentFrame().getByRole(AriaRole.BUTTON).click();
|
||||
|
||||
// Works because we explicitly tell locator to pick the first frame:
|
||||
page.frame_locator(".result-frame").first().getByRole(AriaRole.BUTTON).click();
|
||||
page.locator(".result-frame").first().contentFrame().getByRole(AriaRole.BUTTON).click();
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Throws if there are several frames in DOM:
|
||||
await page.FrameLocator(".result-frame").GetByRole(AriaRole.Button).ClickAsync();
|
||||
await page.Locator(".result-frame").ContentFrame.GetByRole(AriaRole.Button).ClickAsync();
|
||||
|
||||
// Works because we explicitly tell locator to pick the first frame:
|
||||
await page.FrameLocator(".result-frame").First.getByRole(AriaRole.Button).ClickAsync();
|
||||
await page.Locator(".result-frame").First.ContentFrame.getByRole(AriaRole.Button).ClickAsync();
|
||||
```
|
||||
|
||||
**Converting Locator to FrameLocator**
|
||||
|
@ -82,6 +82,7 @@ If you have a [FrameLocator] object it can be converted to [Locator] pointing to
|
|||
|
||||
|
||||
## method: FrameLocator.first
|
||||
* deprecated: Use [`method: Locator.first`] followed by [`method: Locator.contentFrame`] instead.
|
||||
* since: v1.17
|
||||
- returns: <[FrameLocator]>
|
||||
|
||||
|
@ -171,6 +172,7 @@ in that iframe.
|
|||
### option: FrameLocator.getByTitle.exact = %%-locator-get-by-text-exact-%%
|
||||
|
||||
## method: FrameLocator.last
|
||||
* deprecated: Use [`method: Locator.last`] followed by [`method: Locator.contentFrame`] instead.
|
||||
* since: v1.17
|
||||
- returns: <[FrameLocator]>
|
||||
|
||||
|
@ -195,6 +197,7 @@ Returns locator to the last matching frame.
|
|||
* since: v1.33
|
||||
|
||||
## method: FrameLocator.nth
|
||||
* deprecated: Use [`method: Locator.nth`] followed by [`method: Locator.contentFrame`] instead.
|
||||
* since: v1.17
|
||||
- returns: <[FrameLocator]>
|
||||
|
||||
|
@ -217,37 +220,36 @@ For a reverse operation, use [`method: Locator.contentFrame`].
|
|||
**Usage**
|
||||
|
||||
```js
|
||||
const frameLocator = page.frameLocator('iframe[name="embedded"]');
|
||||
const frameLocator = page.locator('iframe[name="embedded"]').contentFrame();
|
||||
// ...
|
||||
const locator = frameLocator.owner();
|
||||
await expect(locator).toBeVisible();
|
||||
```
|
||||
|
||||
```java
|
||||
FrameLocator frameLocator = page.frameLocator("iframe[name=\"embedded\"]");
|
||||
FrameLocator frameLocator = page.locator("iframe[name=\"embedded\"]").contentFrame();
|
||||
// ...
|
||||
Locator locator = frameLocator.owner();
|
||||
assertThat(locator).isVisible();
|
||||
```
|
||||
|
||||
```python async
|
||||
frame_locator = page.frame_locator("iframe[name=\"embedded\"]")
|
||||
frame_locator = page.locator("iframe[name=\"embedded\"]").content_frame
|
||||
# ...
|
||||
locator = frame_locator.owner
|
||||
await expect(locator).to_be_visible()
|
||||
```
|
||||
|
||||
```python sync
|
||||
frame_locator = page.frame_locator("iframe[name=\"embedded\"]")
|
||||
frame_locator = page.locator("iframe[name=\"embedded\"]").content_frame
|
||||
# ...
|
||||
locator = frame_locator.owner
|
||||
expect(locator).to_be_visible()
|
||||
```
|
||||
|
||||
```csharp
|
||||
var frameLocator = Page.FrameLocator("iframe[name=\"embedded\"]");
|
||||
var frameLocator = Page.Locator("iframe[name=\"embedded\"]").ContentFrame;
|
||||
// ...
|
||||
var locator = frameLocator.Owner;
|
||||
await Expect(locator).ToBeVisibleAsync();
|
||||
```
|
||||
|
||||
|
|
|
@ -50,16 +50,6 @@ export function asLocators(lang: Language, selector: string, isFrameLocator: boo
|
|||
|
||||
function innerAsLocators(factory: LocatorFactory, parsed: ParsedSelector, isFrameLocator: boolean = false, maxOutputSize = 20): string[] {
|
||||
const parts = [...parsed.parts];
|
||||
// frameLocator('iframe').first is actually "iframe >> nth=0 >> internal:control=enter-frame"
|
||||
// To make it easier to parse, we turn it into "iframe >> internal:control=enter-frame >> nth=0"
|
||||
for (let index = 0; index < parts.length - 1; index++) {
|
||||
if (parts[index].name === 'nth' && parts[index + 1].name === 'internal:control' && (parts[index + 1].body as string) === 'enter-frame') {
|
||||
// Swap nth and enter-frame.
|
||||
const [nth] = parts.splice(index, 1);
|
||||
parts.splice(index + 1, 0, nth);
|
||||
}
|
||||
}
|
||||
|
||||
const tokens: string[][] = [];
|
||||
let nextBase: LocatorBase = isFrameLocator ? 'frame-locator' : 'page';
|
||||
for (let index = 0; index < parts.length; index++) {
|
||||
|
@ -167,15 +157,15 @@ function innerAsLocators(factory: LocatorFactory, parsed: ParsedSelector, isFram
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if (part.name === 'internal:control' && (part.body as string) === 'enter-frame') {
|
||||
tokens.push([factory.generateLocator(base, 'frame', '')]);
|
||||
nextBase = 'frame-locator';
|
||||
continue;
|
||||
}
|
||||
|
||||
let locatorType: LocatorType = 'default';
|
||||
|
||||
const nextPart = parts[index + 1];
|
||||
if (nextPart && nextPart.name === 'internal:control' && (nextPart.body as string) === 'enter-frame') {
|
||||
locatorType = 'frame';
|
||||
nextBase = 'frame-locator';
|
||||
index++;
|
||||
}
|
||||
|
||||
const selectorPart = stringifySelector({ parts: [part] });
|
||||
const locatorPart = factory.generateLocator(base, locatorType, selectorPart);
|
||||
|
@ -264,7 +254,7 @@ export class JavaScriptLocatorFactory implements LocatorFactory {
|
|||
return `locator(${this.quote(body as string)}, { hasNotText: ${this.toHasText(options.hasNotText)} })`;
|
||||
return `locator(${this.quote(body as string)})`;
|
||||
case 'frame':
|
||||
return `frameLocator(${this.quote(body as string)})`;
|
||||
return `contentFrame()`;
|
||||
case 'nth':
|
||||
return `nth(${body})`;
|
||||
case 'first':
|
||||
|
@ -356,7 +346,7 @@ export class PythonLocatorFactory implements LocatorFactory {
|
|||
return `locator(${this.quote(body as string)}, has_not_text=${this.toHasText(options.hasNotText)})`;
|
||||
return `locator(${this.quote(body as string)})`;
|
||||
case 'frame':
|
||||
return `frame_locator(${this.quote(body as string)})`;
|
||||
return `content_frame`;
|
||||
case 'nth':
|
||||
return `nth(${body})`;
|
||||
case 'first':
|
||||
|
@ -461,7 +451,7 @@ export class JavaLocatorFactory implements LocatorFactory {
|
|||
return `locator(${this.quote(body as string)}, new ${clazz}.LocatorOptions().setHasNotText(${this.toHasText(options.hasNotText)}))`;
|
||||
return `locator(${this.quote(body as string)})`;
|
||||
case 'frame':
|
||||
return `frameLocator(${this.quote(body as string)})`;
|
||||
return `contentFrame()`;
|
||||
case 'nth':
|
||||
return `nth(${body})`;
|
||||
case 'first':
|
||||
|
@ -556,7 +546,7 @@ export class CSharpLocatorFactory implements LocatorFactory {
|
|||
return `Locator(${this.quote(body as string)}, new() { ${this.toHasNotText(options.hasNotText)} })`;
|
||||
return `Locator(${this.quote(body as string)})`;
|
||||
case 'frame':
|
||||
return `FrameLocator(${this.quote(body as string)})`;
|
||||
return `ContentFrame`;
|
||||
case 'nth':
|
||||
return `Nth(${body})`;
|
||||
case 'first':
|
||||
|
|
|
@ -75,6 +75,7 @@ function parseLocator(locator: string, testIdAttributeName: string): { selector:
|
|||
.replace(/has_text/g, 'hastext')
|
||||
.replace(/has_not/g, 'hasnot')
|
||||
.replace(/frame_locator/g, 'framelocator')
|
||||
.replace(/content_frame/g, 'contentframe')
|
||||
.replace(/[{}\s]/g, '')
|
||||
.replace(/new\(\)/g, '')
|
||||
.replace(/new[\w]+\.[\w]+options\(\)/g, '')
|
||||
|
@ -154,6 +155,7 @@ function transform(template: string, params: TemplateParams, testIdAttributeName
|
|||
template = template
|
||||
.replace(/\,set([\w]+)\(([^)]+)\)/g, (_, group1, group2) => ',' + group1.toLowerCase() + '=' + group2.toLowerCase())
|
||||
.replace(/framelocator\(([^)]+)\)/g, '$1.internal:control=enter-frame')
|
||||
.replace(/contentframe(\(\))?/g, 'internal:control=enter-frame')
|
||||
.replace(/locator\(([^)]+),hastext=([^),]+)\)/g, 'locator($1).internal:has-text=$2')
|
||||
.replace(/locator\(([^)]+),hasnottext=([^),]+)\)/g, 'locator($1).internal:has-not-text=$2')
|
||||
.replace(/locator\(([^)]+),hastext=([^),]+)\)/g, 'locator($1).internal:has-text=$2')
|
||||
|
|
|
@ -18240,11 +18240,12 @@ export interface FileChooser {
|
|||
/**
|
||||
* FrameLocator represents a view to the `iframe` on the page. It captures the logic sufficient to retrieve the
|
||||
* `iframe` and locate elements in that iframe. FrameLocator can be created with either
|
||||
* [locator.contentFrame()](https://playwright.dev/docs/api/class-locator#locator-content-frame),
|
||||
* [page.frameLocator(selector)](https://playwright.dev/docs/api/class-page#page-frame-locator) or
|
||||
* [locator.frameLocator(selector)](https://playwright.dev/docs/api/class-locator#locator-frame-locator) method.
|
||||
*
|
||||
* ```js
|
||||
* const locator = page.frameLocator('#my-frame').getByText('Submit');
|
||||
* const locator = page.locator('#my-frame').contentFrame().getByText('Submit');
|
||||
* await locator.click();
|
||||
* ```
|
||||
*
|
||||
|
@ -18255,10 +18256,10 @@ export interface FileChooser {
|
|||
*
|
||||
* ```js
|
||||
* // Throws if there are several frames in DOM:
|
||||
* await page.frameLocator('.result-frame').getByRole('button').click();
|
||||
* await page.locator('.result-frame').contentFrame().getByRole('button').click();
|
||||
*
|
||||
* // Works because we explicitly tell locator to pick the first frame:
|
||||
* await page.frameLocator('.result-frame').first().getByRole('button').click();
|
||||
* await page.locator('.result-frame').contentFrame().first().getByRole('button').click();
|
||||
* ```
|
||||
*
|
||||
* **Converting Locator to FrameLocator**
|
||||
|
@ -18274,6 +18275,8 @@ export interface FileChooser {
|
|||
export interface FrameLocator {
|
||||
/**
|
||||
* Returns locator to the first matching frame.
|
||||
* @deprecated Use [locator.first()](https://playwright.dev/docs/api/class-locator#locator-first) followed by
|
||||
* [locator.contentFrame()](https://playwright.dev/docs/api/class-locator#locator-content-frame) instead.
|
||||
*/
|
||||
first(): FrameLocator;
|
||||
|
||||
|
@ -18598,6 +18601,8 @@ export interface FrameLocator {
|
|||
|
||||
/**
|
||||
* Returns locator to the last matching frame.
|
||||
* @deprecated Use [locator.last()](https://playwright.dev/docs/api/class-locator#locator-last) followed by
|
||||
* [locator.contentFrame()](https://playwright.dev/docs/api/class-locator#locator-content-frame) instead.
|
||||
*/
|
||||
last(): FrameLocator;
|
||||
|
||||
|
@ -18650,6 +18655,8 @@ export interface FrameLocator {
|
|||
|
||||
/**
|
||||
* Returns locator to the n-th matching frame. It's zero based, `nth(0)` selects the first frame.
|
||||
* @deprecated Use [locator.nth(index)](https://playwright.dev/docs/api/class-locator#locator-nth) followed by
|
||||
* [locator.contentFrame()](https://playwright.dev/docs/api/class-locator#locator-content-frame) instead.
|
||||
* @param index
|
||||
*/
|
||||
nth(index: number): FrameLocator;
|
||||
|
@ -18666,7 +18673,7 @@ export interface FrameLocator {
|
|||
* **Usage**
|
||||
*
|
||||
* ```js
|
||||
* const frameLocator = page.frameLocator('iframe[name="embedded"]');
|
||||
* const frameLocator = page.locator('iframe[name="embedded"]').contentFrame();
|
||||
* // ...
|
||||
* const locator = frameLocator.owner();
|
||||
* await expect(locator).toBeVisible();
|
||||
|
|
|
@ -28,7 +28,7 @@ function generate(locator: Locator | FrameLocator) {
|
|||
function generateForSelector(selector: string) {
|
||||
const result: any = {};
|
||||
for (const lang of ['javascript', 'python', 'java', 'csharp']) {
|
||||
const locatorString = asLocator(lang, selector, false);
|
||||
const locatorString = asLocator(lang, selector);
|
||||
expect.soft(parseLocator(lang, locatorString, 'data-testid'), lang + ' mismatch').toBe(selector);
|
||||
result[lang] = locatorString;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ async function generateForNode(pageOrFrame: Page | Frame, target: string): Promi
|
|||
const selector = await pageOrFrame.locator(target).evaluate(e => (window as any).playwright.selector(e));
|
||||
const result: any = {};
|
||||
for (const lang of ['javascript', 'python', 'java', 'csharp']) {
|
||||
const locatorString = asLocator(lang, selector, false);
|
||||
const locatorString = asLocator(lang, selector);
|
||||
expect.soft(parseLocator(lang, locatorString)).toBe(selector);
|
||||
result[lang] = locatorString;
|
||||
}
|
||||
|
@ -374,15 +374,15 @@ it('reverse engineer frameLocator', async ({ page }) => {
|
|||
.frameLocator('iframe')
|
||||
.locator('span');
|
||||
expect.soft(generate(locator)).toEqual({
|
||||
csharp: `FrameLocator("iframe").GetByText("foo", new() { Exact = true }).FrameLocator("frame").First.FrameLocator("iframe").Locator("span")`,
|
||||
java: `frameLocator("iframe").getByText("foo", new FrameLocator.GetByTextOptions().setExact(true)).frameLocator("frame").first().frameLocator("iframe").locator("span")`,
|
||||
javascript: `frameLocator('iframe').getByText('foo', { exact: true }).frameLocator('frame').first().frameLocator('iframe').locator('span')`,
|
||||
python: `frame_locator("iframe").get_by_text("foo", exact=True).frame_locator("frame").first.frame_locator("iframe").locator("span")`,
|
||||
csharp: `Locator("iframe").ContentFrame.GetByText("foo", new() { Exact = true }).Locator("frame").First.ContentFrame.Locator("iframe").ContentFrame.Locator("span")`,
|
||||
java: `locator("iframe").contentFrame().getByText("foo", new FrameLocator.GetByTextOptions().setExact(true)).locator("frame").first().contentFrame().locator("iframe").contentFrame().locator("span")`,
|
||||
javascript: `locator('iframe').contentFrame().getByText('foo', { exact: true }).locator('frame').first().contentFrame().locator('iframe').contentFrame().locator('span')`,
|
||||
python: `locator("iframe").content_frame.get_by_text("foo", exact=True).locator("frame").first.content_frame.locator("iframe").content_frame.locator("span")`,
|
||||
});
|
||||
|
||||
// Note that frame locators with ">>" are not restored back due to ambiguity.
|
||||
const selector = (page.frameLocator('div >> iframe').locator('span') as any)._selector;
|
||||
expect.soft(asLocator('javascript', selector, false)).toBe(`locator('div').frameLocator('iframe').locator('span')`);
|
||||
expect.soft(asLocator('javascript', selector)).toBe(`locator('div').locator('iframe').contentFrame().locator('span')`);
|
||||
});
|
||||
|
||||
it('generate multiple locators', async ({ page }) => {
|
||||
|
@ -462,7 +462,7 @@ it('generate multiple locators', async ({ page }) => {
|
|||
],
|
||||
};
|
||||
for (const lang of ['javascript', 'java', 'python', 'csharp'] as const) {
|
||||
expect.soft(asLocators(lang, selector, false)).toEqual(locators[lang]);
|
||||
expect.soft(asLocators(lang, selector)).toEqual(locators[lang]);
|
||||
for (const locator of locators[lang])
|
||||
expect.soft(parseLocator(lang, locator, 'data-testid'), `parse(${lang}): ${locator}`).toBe(selector);
|
||||
}
|
||||
|
@ -485,38 +485,38 @@ it.describe(() => {
|
|||
python: 'locator("div").filter(has_text="Goodbye world").locator("span")',
|
||||
});
|
||||
|
||||
expect.soft(asLocator('javascript', 'div >> internal:has-text="foo"s', false)).toBe(`locator('div').locator('internal:has-text="foo"s')`);
|
||||
expect.soft(asLocator('javascript', 'div >> internal:has-not-text="foo"s', false)).toBe(`locator('div').locator('internal:has-not-text="foo"s')`);
|
||||
expect.soft(asLocator('javascript', 'div >> internal:has-text="foo"s')).toBe(`locator('div').locator('internal:has-text="foo"s')`);
|
||||
expect.soft(asLocator('javascript', 'div >> internal:has-not-text="foo"s')).toBe(`locator('div').locator('internal:has-not-text="foo"s')`);
|
||||
});
|
||||
});
|
||||
|
||||
it('asLocator internal:and', async () => {
|
||||
expect.soft(asLocator('javascript', 'div >> internal:and="span >> article"', false)).toBe(`locator('div').and(locator('span').locator('article'))`);
|
||||
expect.soft(asLocator('python', 'div >> internal:and="span >> article"', false)).toBe(`locator("div").and_(locator("span").locator("article"))`);
|
||||
expect.soft(asLocator('java', 'div >> internal:and="span >> article"', false)).toBe(`locator("div").and(locator("span").locator("article"))`);
|
||||
expect.soft(asLocator('csharp', 'div >> internal:and="span >> article"', false)).toBe(`Locator("div").And(Locator("span").Locator("article"))`);
|
||||
expect.soft(asLocator('javascript', 'div >> internal:and="span >> article"')).toBe(`locator('div').and(locator('span').locator('article'))`);
|
||||
expect.soft(asLocator('python', 'div >> internal:and="span >> article"')).toBe(`locator("div").and_(locator("span").locator("article"))`);
|
||||
expect.soft(asLocator('java', 'div >> internal:and="span >> article"')).toBe(`locator("div").and(locator("span").locator("article"))`);
|
||||
expect.soft(asLocator('csharp', 'div >> internal:and="span >> article"')).toBe(`Locator("div").And(Locator("span").Locator("article"))`);
|
||||
});
|
||||
|
||||
it('asLocator internal:or', async () => {
|
||||
expect.soft(asLocator('javascript', 'div >> internal:or="span >> article"', false)).toBe(`locator('div').or(locator('span').locator('article'))`);
|
||||
expect.soft(asLocator('python', 'div >> internal:or="span >> article"', false)).toBe(`locator("div").or_(locator("span").locator("article"))`);
|
||||
expect.soft(asLocator('java', 'div >> internal:or="span >> article"', false)).toBe(`locator("div").or(locator("span").locator("article"))`);
|
||||
expect.soft(asLocator('csharp', 'div >> internal:or="span >> article"', false)).toBe(`Locator("div").Or(Locator("span").Locator("article"))`);
|
||||
expect.soft(asLocator('javascript', 'div >> internal:or="span >> article"')).toBe(`locator('div').or(locator('span').locator('article'))`);
|
||||
expect.soft(asLocator('python', 'div >> internal:or="span >> article"')).toBe(`locator("div").or_(locator("span").locator("article"))`);
|
||||
expect.soft(asLocator('java', 'div >> internal:or="span >> article"')).toBe(`locator("div").or(locator("span").locator("article"))`);
|
||||
expect.soft(asLocator('csharp', 'div >> internal:or="span >> article"')).toBe(`Locator("div").Or(Locator("span").Locator("article"))`);
|
||||
});
|
||||
|
||||
it('asLocator internal:chain', async () => {
|
||||
expect.soft(asLocator('javascript', 'div >> internal:chain="span >> article"', false)).toBe(`locator('div').locator(locator('span').locator('article'))`);
|
||||
expect.soft(asLocator('python', 'div >> internal:chain="span >> article"', false)).toBe(`locator("div").locator(locator("span").locator("article"))`);
|
||||
expect.soft(asLocator('java', 'div >> internal:chain="span >> article"', false)).toBe(`locator("div").locator(locator("span").locator("article"))`);
|
||||
expect.soft(asLocator('csharp', 'div >> internal:chain="span >> article"', false)).toBe(`Locator("div").Locator(Locator("span").Locator("article"))`);
|
||||
expect.soft(asLocator('javascript', 'div >> internal:chain="span >> article"')).toBe(`locator('div').locator(locator('span').locator('article'))`);
|
||||
expect.soft(asLocator('python', 'div >> internal:chain="span >> article"')).toBe(`locator("div").locator(locator("span").locator("article"))`);
|
||||
expect.soft(asLocator('java', 'div >> internal:chain="span >> article"')).toBe(`locator("div").locator(locator("span").locator("article"))`);
|
||||
expect.soft(asLocator('csharp', 'div >> internal:chain="span >> article"')).toBe(`Locator("div").Locator(Locator("span").Locator("article"))`);
|
||||
});
|
||||
|
||||
it('asLocator xpath', async () => {
|
||||
const selector = `//*[contains(normalizer-text(), 'foo']`;
|
||||
expect.soft(asLocator('javascript', selector, false)).toBe(`locator('//*[contains(normalizer-text(), \\'foo\\']')`);
|
||||
expect.soft(asLocator('python', selector, false)).toBe(`locator(\"//*[contains(normalizer-text(), 'foo']\")`);
|
||||
expect.soft(asLocator('java', selector, false)).toBe(`locator(\"//*[contains(normalizer-text(), 'foo']\")`);
|
||||
expect.soft(asLocator('csharp', selector, false)).toBe(`Locator(\"//*[contains(normalizer-text(), 'foo']\")`);
|
||||
expect.soft(asLocator('javascript', selector)).toBe(`locator('//*[contains(normalizer-text(), \\'foo\\']')`);
|
||||
expect.soft(asLocator('python', selector)).toBe(`locator(\"//*[contains(normalizer-text(), 'foo']\")`);
|
||||
expect.soft(asLocator('java', selector)).toBe(`locator(\"//*[contains(normalizer-text(), 'foo']\")`);
|
||||
expect.soft(asLocator('csharp', selector)).toBe(`Locator(\"//*[contains(normalizer-text(), 'foo']\")`);
|
||||
expect.soft(parseLocator('javascript', `locator('//*[contains(normalizer-text(), \\'foo\\']')`, 'data-testid')).toBe("//*[contains(normalizer-text(), 'foo']");
|
||||
expect.soft(parseLocator('javascript', `locator("//*[contains(normalizer-text(), 'foo']")`, 'data-testid')).toBe("//*[contains(normalizer-text(), 'foo']");
|
||||
expect.soft(parseLocator('javascript', `locator('xpath=//*[contains(normalizer-text(), \\'foo\\']')`, 'data-testid')).toBe("xpath=//*[contains(normalizer-text(), 'foo']");
|
||||
|
|
|
@ -1232,16 +1232,16 @@ test('should pick locator in iframe', async ({ page, runAndTrace, server }) => {
|
|||
const snapshot = await traceViewer.snapshotFrame('page.evaluate');
|
||||
|
||||
await snapshot.frameLocator('#frame1').getByText('Hello1').click();
|
||||
await expect.soft(cmWrapper).toContainText(`frameLocator('#frame1').getByText('Hello1')`);
|
||||
await expect.soft(cmWrapper).toContainText(`locator('#frame1').contentFrame().getByText('Hello1')`);
|
||||
|
||||
await snapshot.frameLocator('#frame1').frameLocator('iframe').getByText('Hello2').click();
|
||||
await expect.soft(cmWrapper).toContainText(`frameLocator('#frame1').frameLocator('iframe').getByText('Hello2')`, { timeout: 0 });
|
||||
await expect.soft(cmWrapper).toContainText(`locator('#frame1').contentFrame().locator('iframe').contentFrame().getByText('Hello2')`, { timeout: 0 });
|
||||
|
||||
await snapshot.frameLocator('#frame1').frameLocator('iframe').frameLocator('[name=one]').getByText('HelloNameOne').click();
|
||||
await expect.soft(cmWrapper).toContainText(`frameLocator('#frame1').frameLocator('iframe').frameLocator('iframe[name="one"]').getByText('HelloNameOne')`, { timeout: 0 });
|
||||
await expect.soft(cmWrapper).toContainText(`locator('#frame1').contentFrame().locator('iframe').contentFrame().locator('iframe[name="one"]').contentFrame().getByText('HelloNameOne')`, { timeout: 0 });
|
||||
|
||||
await snapshot.frameLocator('#frame1').frameLocator('iframe').frameLocator('[name=two]').getByText('HelloNameTwo').click();
|
||||
await expect.soft(cmWrapper).toContainText(`frameLocator('#frame1').frameLocator('iframe').frameLocator('iframe[name="two"]').getByText('HelloNameTwo')`, { timeout: 0 });
|
||||
await expect.soft(cmWrapper).toContainText(`locator('#frame1').contentFrame().locator('iframe').contentFrame().locator('iframe[name="two"]').contentFrame().getByText('HelloNameTwo')`, { timeout: 0 });
|
||||
});
|
||||
|
||||
test('should highlight locator in iframe while typing', async ({ page, runAndTrace, server, platform }) => {
|
||||
|
@ -1270,15 +1270,15 @@ test('should highlight locator in iframe while typing', async ({ page, runAndTra
|
|||
await traceViewer.page.locator('.CodeMirror').click();
|
||||
|
||||
const locators = [{
|
||||
text: `frameLocator('#frame1').getByText('Hello1')`,
|
||||
text: `locator('#frame1').contentFrame().getByText('Hello1')`,
|
||||
element: snapshot.frameLocator('#frame1').locator('div', { hasText: 'Hello1' }),
|
||||
highlight: snapshot.frameLocator('#frame1').locator('x-pw-highlight'),
|
||||
}, {
|
||||
text: `frameLocator('#frame1').frameLocator('iframe').getByText('Hello2')`,
|
||||
text: `locator('#frame1').contentFrame().locator('iframe').contentFrame().getByText('Hello2')`,
|
||||
element: snapshot.frameLocator('#frame1').frameLocator('iframe').locator('div', { hasText: 'Hello2' }),
|
||||
highlight: snapshot.frameLocator('#frame1').frameLocator('iframe').locator('x-pw-highlight'),
|
||||
}, {
|
||||
text: `frameLocator('#frame1').frameLocator('iframe').frameLocator('iframe[name="one"]').getByText('HelloNameOne')`,
|
||||
text: `locator('#frame1').contentFrame().locator('iframe').contentFrame().locator('iframe[name="one"]').contentFrame().getByText('HelloNameOne')`,
|
||||
element: snapshot.frameLocator('#frame1').frameLocator('iframe').frameLocator('iframe[name="one"]').locator('div', { hasText: 'HelloNameOne' }),
|
||||
highlight: snapshot.frameLocator('#frame1').frameLocator('iframe').frameLocator('iframe[name="one"]').locator('x-pw-highlight'),
|
||||
}];
|
||||
|
|
|
@ -98,7 +98,7 @@ it('should work for $ and $$', async ({ page, server }) => {
|
|||
it('should wait for frame', async ({ page, server }) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const error = await page.locator('body').frameLocator('iframe').locator('span').click({ timeout: 1000 }).catch(e => e);
|
||||
expect(error.message).toContain(`waiting for locator('body').frameLocator('iframe')`);
|
||||
expect(error.message).toContain(`waiting for locator('body').locator('iframe').contentFrame()`);
|
||||
});
|
||||
|
||||
it('should wait for frame 2', async ({ page, server }) => {
|
||||
|
|
|
@ -246,9 +246,9 @@ it('should allow some, but not all nested frameLocators', async ({ page }) => {
|
|||
await expect(page.frameLocator('iframe').locator('article').or(page.frameLocator('iframe').locator('span'))).toHaveText('world');
|
||||
await expect(page.frameLocator('iframe').locator('span').and(page.frameLocator('iframe').locator('#target'))).toHaveText('world');
|
||||
const error1 = await expect(page.frameLocator('iframe').locator('div').or(page.frameLocator('#iframe').locator('span'))).toHaveText('world').catch(e => e);
|
||||
expect(error1.message).toContain(`Frame locators are not allowed inside composite locators, while querying "frameLocator('iframe').locator('div').or(frameLocator('#iframe').locator('span'))`);
|
||||
expect(error1.message).toContain(`Frame locators are not allowed inside composite locators, while querying "locator('iframe').contentFrame().locator('div').or(locator('#iframe').contentFrame().locator('span'))`);
|
||||
const error2 = await expect(page.frameLocator('iframe').locator('div').and(page.frameLocator('#iframe').locator('span'))).toHaveText('world').catch(e => e);
|
||||
expect(error2.message).toContain(`Frame locators are not allowed inside composite locators, while querying "frameLocator('iframe').locator('div').and(frameLocator('#iframe').locator('span'))`);
|
||||
expect(error2.message).toContain(`Frame locators are not allowed inside composite locators, while querying "locator('iframe').contentFrame().locator('div').and(locator('#iframe').contentFrame().locator('span'))`);
|
||||
});
|
||||
|
||||
it('should enforce same frame for has/leftOf/rightOf/above/below/near', async ({ page, server }) => {
|
||||
|
|
Loading…
Reference in New Issue