playwright-release-notes

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Release notes

发布说明

In this skill,
1.xx
is the release (for example
1.64
).
Every release has a
## Version 1.xx
section in four files in
docs/src/
:
LanguageNotesDocs base URLGitHub release in
Node.js
release-notes-js.md
https://playwright.dev/docs/
microsoft/playwright
Python
release-notes-python.md
https://playwright.dev/python/docs/
microsoft/playwright-python
Java
release-notes-java.md
https://playwright.dev/java/docs/
microsoft/playwright-java
.NET
release-notes-csharp.md
https://playwright.dev/dotnet/docs/
microsoft/playwright-dotnet
Write the Node.js notes and the three translations in the same PR, so every language has its notes when it starts its release. The language repos then add only their own significant changes, and each one writes its GitHub release from its section (step 3).
在本 skill 中,
1.xx
表示版本号(例如
1.64
)。
每个版本在
docs/src/
下的四个文件中都有一个
## Version 1.xx
章节:
语言说明文档基础 URLGitHub 发布仓库
Node.js
release-notes-js.md
https://playwright.dev/docs/
microsoft/playwright
Python
release-notes-python.md
https://playwright.dev/python/docs/
microsoft/playwright-python
Java
release-notes-java.md
https://playwright.dev/java/docs/
microsoft/playwright-java
.NET
release-notes-csharp.md
https://playwright.dev/dotnet/docs/
microsoft/playwright-dotnet
在同一个 PR 中编写 Node.js 说明和另外三个翻译版本,这样每种语言开始发布时就已经有对应的发布说明。随后,各语言仓库只需添加自身的重要变更,并各自根据对应章节编写 GitHub Release(步骤 3)。

1. Node.js notes

1. Node.js 说明

In
docs/src/release-notes-js.md
, add a
## Version 1.xx
section above the previous version, and use previous versions as a guide:
  • Highlights come first, each with an emoji heading and a short sample. Ask teammates for help with them.
  • Then
    ### New APIs
    with
    ####
    groups,
    ### Breaking Changes ⚠️
    ,
    ### Announcements
    and
    ### Browser Versions
    . Print the browser versions with
    node utils/print_versions.js
    .
  • Refer to APIs with docs link macros:
    [`method: Page.frameLocator`]
    ,
    [`property: Page.webmcp`]
    ,
    [`event: Page.dialogClosed`]
    ,
    [`option: Tracing.start.ariaSnapshots`]
    ,
    [Locator]
    . Each language's docs show them with that language's names.
  • Link other docs pages with relative paths:
    [test locks](./test-parallel.md#test-locks)
    .
在
docs/src/release-notes-js.md
中,在上一个版本之上添加
## Version 1.xx
章节,并参考之前的版本:
  • 重点变更放在最前面,每项使用 emoji 标题和简短示例。可以请同事协助编写。
  • 随后添加
    ### New APIs
    (使用
    ####
    分组)、
    ### Breaking Changes ⚠️
    、
    ### Announcements
    和
    ### Browser Versions
    。使用
    node utils/print_versions.js
    打印浏览器版本。
  • 引用 API 时使用文档链接宏:
    [`method: Page.frameLocator`]
    、
    [`property: Page.webmcp`]
    、
    [`event: Page.dialogClosed`]
    、
    [`option: Tracing.start.ariaSnapshots`]
    、
    [Locator]
    。各语言文档会使用相应语言的名称显示这些内容。
  • 使用相对路径链接其他文档页面:
    [test locks](./test-parallel.md#test-locks)
    。

2. Python, Java and .NET translations

2. Python、Java 和 .NET 翻译

In each of
release-notes-python.md
,
release-notes-java.md
and
release-notes-csharp.md
, add a
## Version 1.xx
section above the previous version. Translate it from the Node.js section. Compare the
Version 1.63
sections of the files to see what past translations dropped and changed.
For every language:
  • Keep the structure: highlights with emoji headings,
    ### New APIs
    with
    ####
    groups,
    ### Breaking Changes ⚠️
    ,
    ### Announcements
    and
    ### Browser Versions
    .
  • Remove what the language does not have:
    • the test runner:
      @playwright/test
      ,
      test.*
      , config, fixtures, projects, reporters and
      npx playwright test
      options
    • UI mode, the HTML report, component testing and the VS Code extension
    • TypeScript-only features (generics, JSX,
      tsconfig
      ) and
      devices
      descriptors
    • every API whose
      langs
      excludes the language (
      python
      ,
      java
      ,
      csharp
      ). Check
      langs
      in
      docs/src/api/
      ; options shared between methods are defined in
      docs/src/api/params.md
      .
  • Use the language's API where it differs from Node.js:
    • A language-specific option has its own
      langs
      . For example,
      recordVideoFps
      is
      langs: csharp, java, python
      , while Node.js has
      recordVideo.fps
      .
    • alias-<lang>
      renames a member, e.g.
      alias-java: isVisible
      for
      LocatorAssertions.toBeVisible
      .
    • The generated APIs in sibling checkouts confirm the names:
      ../playwright-python/playwright/sync_api/_generated.py
      ,
      ../playwright-java/playwright/src/main/java/com/microsoft/playwright/
      and
      ../playwright-dotnet/src/Playwright/API/Generated/
      .
  • When a Node.js sample shows a library feature through
    playwright.config.ts
    , show the API call instead. For example, the 1.64 video config became calls to
    Screencast.start
    and
    Screencast.showActions
    .
  • Keep API links as docs link macros, and link the language's own option where it differs (
    [`option: Browser.newContext.recordVideoFps`]
    ). In plain text, use the language's names.
  • A relative link must point to a page that exists in the language:
    *-js.md
    pages are Node.js only.
    npm run doc
    reports broken links for each language.
  • Do not add changes that only a language port made. The language repo adds those to its notes.
Rewrite code samples in each language's style. The
infra
workflow checks the syntax of
python
,
java
and
csharp
snippets.
分别在
release-notes-python.md
、
release-notes-java.md
和
release-notes-csharp.md
中,在上一个版本之上添加
## Version 1.xx
章节。根据 Node.js 章节进行翻译。对比这些文件中的
Version 1.63
章节,了解以往翻译删减和更改了哪些内容。
对于每种语言:
  • 保持结构:使用 emoji 标题的重点变更、
    ### New APIs
    (使用
    ####
    分组)、
    ### Breaking Changes ⚠️
    、
    ### Announcements
    和
    ### Browser Versions
    。
  • 移除该语言不支持的内容:
    • 测试运行器:
      @playwright/test
      、
      test.*
      、config、fixtures、projects、reporters 和
      npx playwright test
      选项
    • UI mode、HTML report、component testing 和 VS Code extension
    • 仅 TypeScript 支持的功能(generics、JSX、
      tsconfig
      )和
      devices
      descriptors
    • 移除所有
      langs
      不包含当前语言(
      python
      、
      java
      、
      csharp
      )的 API。检查
      docs/src/api/
      中的
      langs
      ;方法之间共享的选项定义在
      docs/src/api/params.md
      中。
  • 当 API 与 Node.js 不同时,使用该语言对应的 API:
    • 语言专属选项具有自己的
      langs
      。例如,
      recordVideoFps
      的
      langs
      为
      csharp, java, python
      ,而 Node.js 使用
      recordVideo.fps
      。
    • alias-<lang>
      会重命名成员,例如
      LocatorAssertions.toBeVisible
      使用
      alias-java: isVisible
      。
    • 相邻检出目录中生成的 API 可确认具体名称:
      ../playwright-python/playwright/sync_api/_generated.py
      、
      ../playwright-java/playwright/src/main/java/com/microsoft/playwright/
      和
      ../playwright-dotnet/src/Playwright/API/Generated/
      。
  • 当 Node.js 示例通过
    playwright.config.ts
    展示某个库功能时,改为展示 API 调用。例如,1.64 的视频配置应改为调用
    Screencast.start
    和
    Screencast.showActions
    。
  • API 链接应继续使用文档链接宏;如果选项名称因语言而异,应链接该语言对应的选项(
    [`option: Browser.newContext.recordVideoFps`]
    )。在纯文本中,使用该语言的名称。
  • 相对链接必须指向该语言中存在的页面:
    *-js.md
    页面仅适用于 Node.js。
    npm run doc
    会报告各语言中的失效链接。
  • 不要添加仅由某个语言移植产生的变更。这些内容由相应的语言仓库添加到其发布说明中。
按照每种语言的代码风格重写代码示例。
infra
workflow 会检查
python
、
java
和
csharp
代码片段的语法。

Python

Python

  • Use the sync API:
    page.get_by_role("button").click()
    . Use snake_case names and Python values (
    True
    ,
    False
    ,
    None
    ).
  • Options become keyword arguments:
    page.get_by_role("button", name="Save")
    . Objects and arrays become dicts and lists:
    size={"width": 1920, "height": 1080}
    .
  • Aria roles and other string values stay strings:
    "button"
    ,
    "ai"
    .
  • Events:
    page.on("dialogclosed", handler)
    . Assertions:
    expect(locator).to_have_text([...])
    . Print with
    print(...)
    .
  • Use the
    alias-python
    names:
    route.continue_()
    ,
    locator.or_()
    ,
    page.expect_request()
    .
  • Commands: write
    playwright install
    , not
    npx playwright install
    .
  • 使用同步 API:
    page.get_by_role("button").click()
    。使用 snake_case 名称和 Python 值(
    True
    、
    False
    、
    None
    )。
  • 选项变为关键字参数:
    page.get_by_role("button", name="Save")
    。对象和数组分别变为 dict 和 list:
    size={"width": 1920, "height": 1080}
    。
  • ARIA role 和其他字符串值保持为字符串:
    "button"
    、
    "ai"
    。
  • 事件:
    page.on("dialogclosed", handler)
    。断言:
    expect(locator).to_have_text([...])
    。输出:
    print(...)
    。
  • 使用
    alias-python
    名称:
    route.continue_()
    、
    locator.or_()
    、
    page.expect_request()
    。
  • 命令:使用
    playwright install
    ,不要使用
    npx playwright install
    。

Java

Java

Node.jsJava
await page.goto('...')
page.navigate("...");
: no
await
, double quotes, semicolons, typed locals (
Locator dialog = ...
)
page.getByRole('button', { name: 'Save' })
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Save"))
options object
{ path: 'video.webm', fps: 60 }
options builder
new Screencast.StartOptions().setPath(Paths.get("video.webm")).setFps(60)
object literal
{ name: 'session-id', value: '42', url }
value class
new Cookie("session-id", "42").setUrl(url)
['a', 'b']
,
{ a: 2 }
Arrays.asList("a", "b")
,
Map.of("a", 2)
;
new String[] {"a", "b"}
for assertion arguments
property
page.webmcp
,
context.tracing
getter
page.webmcp()
,
context.tracing()
event
page.on('dialogclosed', handler)
page.onDialogClosed(handler)
expect(locator).toHaveText(...)
assertThat(locator).hasText(...)
. Likewise
toBeX
→
isX
,
toHaveX
→
hasX
,
toContainX
→
containsX
,
toMatchX
→
matchesX
route.continue()
and other members with
alias-java
the alias, e.g.
route.resume()
npx playwright install --no-remove
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --no-remove"
"array",
undefined
,
'ai'
in prose
"list",
null
,
"ai"
Node.jsJava
await page.goto('...')
page.navigate("...");
:不使用
await
,使用双引号和分号,并使用带类型的局部变量(
Locator dialog = ...
)
page.getByRole('button', { name: 'Save' })
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Save"))
选项对象
{ path: 'video.webm', fps: 60 }
选项构建器
new Screencast.StartOptions().setPath(Paths.get("video.webm")).setFps(60)
对象字面量
{ name: 'session-id', value: '42', url }
值类
new Cookie("session-id", "42").setUrl(url)
['a', 'b']
、
{ a: 2 }
Arrays.asList("a", "b")
、
Map.of("a", 2)
;断言参数使用
new String[] {"a", "b"}
属性
page.webmcp
、
context.tracing
getter
page.webmcp()
、
context.tracing()
事件
page.on('dialogclosed', handler)
page.onDialogClosed(handler)
expect(locator).toHaveText(...)
assertThat(locator).hasText(...)
。同理,
toBeX
→
isX
,
toHaveX
→
hasX
,
toContainX
→
containsX
,
toMatchX
→
matchesX
route.continue()
和其他带
alias-java
的成员
使用别名,例如
route.resume()
npx playwright install --no-remove
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --no-remove"
正文中的
"array"
、
undefined
、
'ai'
"list"
、
null
、
"ai"

.NET

.NET

Node.js.NET
await page.goto('...')
await page.GotoAsync("...");
: PascalCase members,
Async
suffix on async methods,
var
locals, double quotes, semicolons
page.getByRole('button', { name: 'Save' })
page.GetByRole(AriaRole.Button, new() { Name = "Save" })
options object
{ path: 'video.webm', fps: 60 }
options initializer
new() { Path = "video.webm", Fps = 60 }
nested object
size: { width: 1920, height: 1080 }
Size = new() { Width = 1920, Height = 1080 }
object literal
{ name: 'session-id', value: '42', url }
new Cookie { Name = "session-id", Value = "42", Url = url }
['a', 'b']
, free-form object
{ a: 2 }
new[] { "a", "b" }
, anonymous object
new { a = 2 }
string-literal union value
'ai'
,
'button'
enum member
AriaSnapshotMode.Ai
,
AriaRole.Button
property
page.webmcp
,
context.tracing
property
page.Webmcp
,
context.Tracing
event
page.on('dialogclosed', handler)
page.DialogClosed += (_, dialog) => { ... };
expect(locator).toHaveText(...)
await Expect(locator).ToHaveTextAsync(...);
console.log(x)
Console.WriteLine(x);
members with
alias-csharp
the alias, e.g.
page.request
→
page.APIRequest
union-typed option, e.g.
httpCredentials
as a list
one property per type, e.g.
HttpCredentialsList
npx playwright install --no-remove
pwsh bin/Debug/netX/playwright.ps1 install --no-remove
option names in prose (
fontSize
),
undefined
FontSize
,
null
Open one PR for all four files, titled
docs: release notes for v1.xx
. After it merges, cherry-pick it to
release-1.xx
with the
playwright-cherry-pick
skill.
Node.js.NET
await page.goto('...')
await page.GotoAsync("...");
:成员使用 PascalCase,异步方法带
Async
后缀,使用
var
局部变量、双引号和分号
page.getByRole('button', { name: 'Save' })
page.GetByRole(AriaRole.Button, new() { Name = "Save" })
选项对象
{ path: 'video.webm', fps: 60 }
选项初始化器
new() { Path = "video.webm", Fps = 60 }
嵌套对象
size: { width: 1920, height: 1080 }
Size = new() { Width = 1920, Height = 1080 }
对象字面量
{ name: 'session-id', value: '42', url }
new Cookie { Name = "session-id", Value = "42", Url = url }
['a', 'b']
、自由形式对象
{ a: 2 }
new[] { "a", "b" }
、匿名对象
new { a = 2 }
字符串字面量 union 值
'ai'
、
'button'
枚举成员
AriaSnapshotMode.Ai
、
AriaRole.Button
属性
page.webmcp
、
context.tracing
属性
page.Webmcp
、
context.Tracing
事件
page.on('dialogclosed', handler)
page.DialogClosed += (_, dialog) => { ... };
expect(locator).toHaveText(...)
await Expect(locator).ToHaveTextAsync(...);
console.log(x)
Console.WriteLine(x);
带
alias-csharp
的成员
使用别名,例如
page.request
→
page.APIRequest
union 类型选项,例如作为列表的
httpCredentials
每种类型使用一个属性,例如
HttpCredentialsList
npx playwright install --no-remove
pwsh bin/Debug/netX/playwright.ps1 install --no-remove
正文中的选项名称(
fontSize
)、
undefined
FontSize
、
null
为这四个文件创建一个 PR,标题为
docs: release notes for v1.xx
。合并后,使用
playwright-cherry-pick
skill 将其 cherry-pick 到
release-1.xx
。

3. GitHub release markdown

3. GitHub Release Markdown

Each repo publishes the GitHub release for its language, with markdown converted from its
## Version 1.xx
section on
release-1.xx
. Convert the notes yourself:
  • Leave out the
    ## Version 1.xx
    heading. Move every other heading up one level (
    ###
    becomes
    ##
    ,
    ####
    becomes
    ###
    ).
  • Replace each link macro with a full link: the language's docs base URL from the table at the top, plus the path below. Use the language's name as the link text:
    MacroPath after the docs base URLNode.jsPythonJava.NET
    [Locator]
    api/class-locator
    Locator
    Locator
    Locator
    Locator
    [`method: Page.frameLocator`]
    api/class-page#page-frame-locator
    page.frameLocator()
    page.frame_locator()
    page.frameLocator()
    Page.FrameLocator()
    [`method: Page.ariaSnapshot`]
    api/class-page#page-aria-snapshot
    page.ariaSnapshot()
    page.aria_snapshot()
    page.ariaSnapshot()
    Page.AriaSnapshotAsync()
    [`method: Locator.first`]
    api/class-locator#locator-first
    locator.first()
    locator.first
    locator.first()
    Locator.First
    [`property: Page.webmcp`]
    api/class-page#page-webmcp
    page.webmcp
    page.webmcp
    page.webmcp()
    Page.Webmcp
    [`event: BrowserContext.dialogClosed`]
    api/class-browsercontext#browser-context-event-dialog-closed
    browserContext.on('dialogclosed')
    browser_context.on("dialogclosed")
    browserContext.onDialogClosed()
    BrowserContext.DialogClosed
    [`method: LocatorAssertions.toBeVisible`]
    api/class-locatorassertions#locator-assertions-to-be-visible
    expect(locator).toBeVisible()
    expect(locator).to_be_visible()
    assertThat(locator).isVisible()
    Expect(Locator).ToBeVisibleAsync()
    [`option: Page.content.includeShadow`]
    api/class-page#page-content-option-include-shadow
    `includeShadow`
    `include_shadow`
    `includeShadow`
    `IncludeShadow`
    [Playwright MCP](./getting-started-mcp.md)
    getting-started-mcp
    Playwright MCP
    Playwright MCP
    Playwright MCP
    Playwright MCP
  • An image
    ![alt](./images/foo.png)
    becomes
    ![alt](https://github.com/microsoft/playwright/blob/main/docs/src/images/foo.png?raw=true)
    in every language.
The page is
class-
and the class name in lower case. The anchor is the class and member names in kebab-case, so
APIRequestContext.addCookies
becomes
api-request-context-add-cookies
. Options add
-option-<name>
, and events add
-event-<name>
. Anchors use the names from
docs/src/api/
even where a language renames the member, so Java's
isVisible()
links to
#locator-assertions-to-be-visible
.
The link text follows the language:
  • Node.js: the class in lower camel case (
    page
    ,
    apiRequestContext
    ,
    testConfig
    ). Methods get
    ()
    , properties none, events become
    on('<event in lower case>')
    , and assertions start with
    expect(locator).
    ,
    expect(page).
    or
    expect(response).
    .
  • Python: the class and member in snake_case (
    browser_context
    ,
    api_request_context
    ). Methods get
    ()
    . A member is a property, without
    ()
    , if
    _generated.py
    declares it with
    @property
    . Events become
    on("<event in lower case>")
    , and assertions start with
    expect(locator).
    .
  • Java: the class in lower camel case and the
    alias-java
    member name. Methods and properties get
    ()
    , events become
    on<Event>()
    , and assertions start with
    assertThat(locator).
    .
  • .NET: the class without the interface
    I
    (
    Page
    ,
    APIRequestContext
    ) and the member exactly as the generated
    I<Class>.cs
    declares it. Async methods take the
    Async
    suffix and
    ()
    , sync methods get
    ()
    , and properties and events get no parentheses. Assertions start with
    Expect(Locator).
    .
Check that every link resolves. playwright.dev already documents the release once the Node.js docs roll has landed. It serves minified HTML, so an anchor may appear without quotes (
id=page-webmcp>
):
bash
grep -oE 'https://playwright\.dev/[^) ]+' <notes-file> | sort -u | while read -r url; do
  page=${url%%#*}
  html=$(curl -sfL "$page") || { echo "MISSING PAGE   $url"; continue; }
  if [[ "$url" == *"#"* ]]; then
    anchor=${url#*#}
    grep -qE "id=\"?${anchor}[\" >]" <<<"$html" || echo "MISSING ANCHOR $url"
  fi
done
Then scan for anything that wasn't converted, and for stray spaces inside link text (
[Page. DialogClosed]
,
[`HttpCredentialsList `]
). The first command applies to every language; then run the one for the language. They should print nothing:
bash
undefined
每个仓库发布对应语言的 GitHub Release,其 Markdown 由
release-1.xx
分支中的
## Version 1.xx
章节转换而来。请自行转换说明内容:
  • 不要保留
    ## Version 1.xx
    标题。其余每个标题的层级都上调一级(
    ###
    变为
    ##
    ,
    ####
    变为
    ###
    )。
  • 将每个链接宏替换为完整链接:使用表格顶部该语言的文档基础 URL,再加上下方路径。使用该语言的名称作为链接文本:
    宏文档基础 URL 之后的路径Node.jsPythonJava.NET
    [Locator]
    api/class-locator
    Locator
    Locator
    Locator
    Locator
    [`method: Page.frameLocator`]
    api/class-page#page-frame-locator
    page.frameLocator()
    page.frame_locator()
    page.frameLocator()
    Page.FrameLocator()
    [`method: Page.ariaSnapshot`]
    api/class-page#page-aria-snapshot
    page.ariaSnapshot()
    page.aria_snapshot()
    page.ariaSnapshot()
    Page.AriaSnapshotAsync()
    [`method: Locator.first`]
    api/class-locator#locator-first
    locator.first()
    locator.first
    locator.first()
    Locator.First
    [`property: Page.webmcp`]
    api/class-page#page-webmcp
    page.webmcp
    page.webmcp
    page.webmcp()
    Page.Webmcp
    [`event: BrowserContext.dialogClosed`]
    api/class-browsercontext#browser-context-event-dialog-closed
    browserContext.on('dialogclosed')
    browser_context.on("dialogclosed")
    browserContext.onDialogClosed()
    BrowserContext.DialogClosed
    [`method: LocatorAssertions.toBeVisible`]
    api/class-locatorassertions#locator-assertions-to-be-visible
    expect(locator).toBeVisible()
    expect(locator).to_be_visible()
    assertThat(locator).isVisible()
    Expect(Locator).ToBeVisibleAsync()
    [`option: Page.content.includeShadow`]
    api/class-page#page-content-option-include-shadow
    `includeShadow`
    `include_shadow`
    `includeShadow`
    `IncludeShadow`
    [Playwright MCP](./getting-started-mcp.md)
    getting-started-mcp
    Playwright MCP
    Playwright MCP
    Playwright MCP
    Playwright MCP
  • 图像
    ![alt](./images/foo.png)
    在每种语言中都会转换为
    ![alt](https://github.com/microsoft/playwright/blob/main/docs/src/images/foo.png?raw=true)
    。
页面路径以
class-
开头,后接小写的类名。锚点由类名和成员名转换为 kebab-case,因此
APIRequestContext.addCookies
会变成
api-request-context-add-cookies
。选项需追加
-option-<name>
,事件需追加
-event-<name>
。即使某种语言重命名了成员,锚点仍使用
docs/src/api/
中的名称,因此 Java 的
isVisible()
会链接到
#locator-assertions-to-be-visible
。
链接文本遵循各语言的规则:
  • Node.js: 类名使用 lower camel case(
    page
    、
    apiRequestContext
    、
    testConfig
    )。方法带
    ()
    ,属性不带括号,事件变为
    on('<event in lower case>')
    ,断言以
    expect(locator).
    、
    expect(page).
    或
    expect(response).
    开头。
  • Python: 类和成员使用 snake_case(
    browser_context
    、
    api_request_context
    )。方法带
    ()
    。如果
    _generated.py
    使用
    @property
    声明某个成员,则该成员是属性,不带
    ()
    。事件变为
    on("<event in lower case>")
    ,断言以
    expect(locator).
    开头。
  • Java: 类名使用 lower camel case,成员使用
    alias-java
    名称。方法和属性带
    ()
    ,事件变为
    on<Event>()
    ,断言以
    assertThat(locator).
    开头。
  • .NET: 类名不带接口
    I
    (
    Page
    、
    APIRequestContext
    ),成员名称与生成的
    I<Class>.cs
    中声明的完全一致。异步方法带
    Async
    后缀和
    ()
    ,同步方法带
    ()
    ,属性和事件不带括号。断言以
    Expect(Locator).
    开头。
检查每个链接是否可解析。Node.js 文档上线后,playwright.dev 就会记录该版本。它提供的是压缩后的 HTML,因此锚点可能不带引号出现(
id=page-webmcp>
):
bash
grep -oE 'https://playwright\.dev/[^) ]+' <notes-file> | sort -u | while read -r url; do
  page=${url%%#*}
  html=$(curl -sfL "$page") || { echo "MISSING PAGE   $url"; continue; }
  if [[ "$url" == *"#"* ]]; then
    anchor=${url#*#}
    grep -qE "id=\"?${anchor}[\" >]" <<<"$html" || echo "MISSING ANCHOR $url"
  fi
done
然后扫描是否有遗漏的未转换内容,以及链接文本中是否存在多余空格(
[Page. DialogClosed]
、
[`HttpCredentialsList `]
)。先运行适用于所有语言的第一个命令,再运行对应语言的命令。它们都不应输出任何内容:
bash
undefined

every language

every language

grep -nE '[
(method|property|event|option|param): |\]\(\./|\[[A-Z][A-Za-z]*\]([^(]|$)|\[[A-Za-z_]+\. |\[
[^
]+ 
]' <notes-file>
grep -nE '[
(method|property|event|option|param): |\]\(\./|\[[A-Z][A-Za-z]*\]([^(]|$)|\[[A-Za-z_]+\. |\[
[^
]+ 
]' <notes-file>

Python: camelCase names in link text

Python: camelCase names in link text

grep -nE '[[a-z_]+.[a-z_]*[A-Z]|[`[a-z]+[A-Z]' <notes-file>
grep -nE '[[a-z_]+.[a-z_]*[A-Z]|[`[a-z]+[A-Z]' <notes-file>

Java: JS-style events, assertions and properties

Java: JS-style events, assertions and properties

grep -nE ".on('|\b(toBe|toHave|toContain|toMatch)[A-Z]|\bawait\b|\barray\b|\bundefined\b|[[a-z][A-Za-z].[a-z][A-Za-z]](" <notes-file>
grep -nE ".on('|\b(toBe|toHave|toContain|toMatch)[A-Z]|\bawait\b|\barray\b|\bundefined\b|[[a-z][A-Za-z].[a-z][A-Za-z]](" <notes-file>

.NET: lower-case classes or members, JS-style events

.NET: lower-case classes or members, JS-style events

grep -nE ".on('|\bundefined\b|[[a-z][A-Za-z].|[[A-Z][A-Za-z].[a-z]|[Expect([a-z]" <notes-file>

If the conversion shows a problem in the notes themselves, such as an API the language does not have or a sample in the wrong style, fix the notes too (step 2). Otherwise the problem stays on playwright.dev.
grep -nE ".on('|\bundefined\b|[[a-z][A-Za-z].|[[A-Z][A-Za-z].[a-z]|[Expect([a-z]" <notes-file>

如果转换过程暴露出发布说明本身的问题,例如某语言不支持的 API 或样式错误的示例,也应修复发布说明(步骤 2)。否则,该问题会保留在 playwright.dev 上。