为什么filter()不能缩小定位器的范围

问题描述 投票:0回答:1

我无法发布代码,但我编写了这个 HTML 文件来复制该场景(https://coral-nanci-88.tiiny.site/):

 <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    
    <style>
        body {
            margin: 0;
            font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
        }
    
        .main {
            display: flex;
        }
    
        .sidebar {
            width: 20vw;
            border-right: 2px solid black;
            height: 100vh;
            font-size: 1.2rem;
        }
    
        .content {
            flex-grow: 1;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 4rem;
            font-weight: bold;
        }
    </style>
    
    <body>
        <div class="main">
            <div class="sidebar">
                <ul>
                    <li class="side-item_lev1">
                        <div class="lev1-header">Lev1 item - 1</div>
                        <div class="lev1-body">
                            <ul>
                                <li class="side-item_lev2">
                                    <div class="lev1-header">Lev2 item</div>
                                </li>
                            </ul>
                        </div>
                    </li>
                    <li class="side-item_lev1">
                        <div class="lev1-header">Lev1 item - 2</div>
                        <div class="lev1-body">
                            <ul>
                                <li class="side-item_lev2">
                                    <div class="lev1-header">Lev2 item</div>
                                </li>
                            </ul>
                        </div>
                    </li>
                </ul>
            </div>
            <div class="content">
                <p class="content-desc">CONTENT</p>
            </div>
        </div>
    </body>
    
    </html>

如果您运行此测试(我使用带有 Live Server 扩展的 vscode):

test('test-sidebar', async ({ page }) => {
    await page.goto("http://127.0.0.1:5500/index.html")
    const site = new Site(page)
    await site.sidebar.clickLevOneItem("Lev1 item - 1")
})

使用这些类:

class Site {
    private readonly page: Page
    public readonly sidebar: SideBar

    constructor(page: Page) {
        this.page = page
        this.sidebar = new SideBar(this.page.locator(".sidebar"))
    }
}

class SideBar {
    public readonly baseNode: Locator

    constructor(baseNode: Locator) {
        this.baseNode = baseNode;
    }

    public async clickLevOneItem(name: string) {
        await this.baseNode.locator(".side-item_lev1")
            .filter({ has: this.baseNode.locator(".lev1-header", { hasText: name }) })
            .click()
    }
}

就像filter()方法不起作用.. 但是,如果您将整个页面传递到 SideBar:

class Site {
    private readonly page: Page
    public readonly sidebar: SideBar

    constructor(page: Page) {
        this.page = page
        this.sidebar = new SideBar(page)
    }
}

class SideBar {
    public readonly baseNode: Page

    /**
     * Create the common page object
     * @param {Locator} baseNode - 
     */
    constructor(baseNode: Page) {
        this.baseNode = baseNode;
    }

     ...
}

过滤器起作用了,找到 DOM 对象然后单击它。 但是为什么如果我使用定位器缩小类范围,而不传递整个页面,它就会停止工作。我不明白。

typescript automation playwright playwright-typescript
1个回答
0
投票

一旦有了可工作的代码,POM 就非常有用,但是额外的抽象层会稍微混淆基本问题。我认为如果删除 POM 并隔离单个定位器操作,然后在 POM 工作后重新添加它,会更容易看到发生了什么:

import {expect, test} from "@playwright/test"; // ^1.39.0

const html = `<!DOCTYPE html><html><body>
<div class="sidebar">
  <ul>
    <li class="side-item_lev1">
      <div class="lev1-header">Lev1 item - 1</div>
      <div class="lev1-body">
        <ul>
          <li class="side-item_lev2">
            <div class="lev0-header">Lev2 item</div>
          </li>
        </ul>
      </div>
    </li>
    <li class="side-item_lev1">
      <div class="lev1-header">Lev1 item - 2</div>
      <div class="lev1-body">
        <ul>
          <li class="side-item_lev2">
            <div class="lev1-header">Lev2 item</div>
          </li>
        </ul>
      </div>
    </li>
  </ul>
</div>
</body></html>`;

test("test-sidebar", async ({page}) => {
  await page.setContent(html);
  const baseNode = page.locator(".sidebar");
  await baseNode
    .locator(".side-item_lev1")
    .filter({has: baseNode.locator(".lev1-header", {hasText: "Lev1 item - 1"})})
    .click();
});

问题归结为是否可以像上面那样以嵌套方式使用

baseNode

显然,这是不可能的,因为它没有在任何地方的文档中显示,它说:

过滤定位器必须相对于原始定位器,并且从原始定位器匹配开始查询,而不是从文档根开始。

...然后继续仅显示在

page.
内部使用
has:
的示例。

一种选择是在嵌套定位器中使用

page

.filter({has: page.locator(".lev1-header")})
           // ^^^^

或者完全跳过

.filter()
并使用纯定位器,这似乎不那么令人困惑:

await page.locator(".sidebar")
  .locator(".side-item_lev1")
  .locator(".lev1-header")
  .getByText("Lev1 item - 1")
  .click();
© www.soinside.com 2019 - 2024. All rights reserved.