跟踪查看器
介绍
¥Introduction
Playwright Trace Viewer 是一个 GUI 工具,可帮助你在脚本运行后探索记录的 Playwright 跟踪。当测试在 CI 上失败时,跟踪是调试测试的好方法。你可以打开跟踪 locally 或在浏览器中打开 trace.playwright.dev。
¥Playwright Trace Viewer is a GUI tool that helps you explore recorded Playwright traces after the script has run. Traces are a great way for debugging your tests when they fail on CI. You can open traces locally or in your browser on trace.playwright.dev.
打开跟踪查看器
¥Opening Trace Viewer
你可以使用 Playwright CLI 或浏览器中的 trace.playwright.dev 打开已保存的跟踪。确保添加 trace.zip
文件所在位置的完整路径。
¥You can open a saved trace using either the Playwright CLI or in the browser at trace.playwright.dev. Make sure to add the full path to where your trace.zip
file is located.
pwsh bin/Debug/netX/playwright.ps1 show-trace trace.zip
使用 trace.playwright.dev
¥Using trace.playwright.dev
trace.playwright.dev 是跟踪查看器的静态托管变体。你可以使用拖放或通过 Select file(s)
按钮上传跟踪文件。
¥trace.playwright.dev is a statically hosted variant of the Trace Viewer. You can upload trace files using drag and drop or via the Select file(s)
button.
Trace Viewer 会将跟踪完全加载到你的浏览器中,而不会向外部传输任何数据。
¥Trace Viewer loads the trace entirely in your browser and does not transmit any data externally.

查看远程痕迹
¥Viewing remote traces
你可以使用其 URL 直接打开远程跟踪。例如,这使得查看远程跟踪变得容易,而无需从 CI 运行中手动下载文件。
¥You can open remote traces directly using its URL. This makes it easy to view the remote trace without having to manually download the file from CI runs, for example.
pwsh bin/Debug/netX/playwright.ps1 show-trace https://example.com/trace.zip
使用 trace.playwright.dev 时,你还可以将上传的跟踪的 URL 传递到某些可访问的存储(例如,在你的 CI 内部)作为查询参数。CORS(跨域资源共享)规则可能适用。
¥When using trace.playwright.dev, you can also pass the URL of your uploaded trace at some accessible storage (e.g. inside your CI) as a query parameter. CORS (Cross-Origin Resource Sharing) rules might apply.
https://trace.playwright.dev/?trace=https://demo.playwright.dev/reports/todomvc/data/fa874b0d59cdedec675521c21124e93161d66533.zip
记录跟踪
¥Recording a trace
可以使用 BrowserContext.Tracing API 记录跟踪,如下所示:
¥Traces can be recorded using the BrowserContext.Tracing API as follows:
- MSTest
- NUnit
- xUnit
namespace PlaywrightTests;
[Parallelizable(ParallelScope.Self)]
[TestFixture]
public class Tests : PageTest
{
[SetUp]
public async Task Setup()
{
await Context.Tracing.StartAsync(new()
{
Title = TestContext.CurrentContext.Test.ClassName + "." + TestContext.CurrentContext.Test.Name,
Screenshots = true,
Snapshots = true,
Sources = true
});
}
[TearDown]
public async Task TearDown()
{
// This will produce e.g.:
// bin/Debug/net8.0/playwright-traces/PlaywrightTests.Tests.Test1.zip
await Context.Tracing.StopAsync(new()
{
Path = Path.Combine(
TestContext.CurrentContext.WorkDirectory,
"playwright-traces",
$"{TestContext.CurrentContext.Test.ClassName}.{TestContext.CurrentContext.Test.Name}.zip"
)
});
}
[Test]
public async Task TestYourOnlineShop()
{
// ..
}
}
using System.Text.RegularExpressions;
using Microsoft.Playwright;
using Microsoft.Playwright.MSTest;
namespace PlaywrightTestsMSTest;
[TestClass]
public class UnitTest1 : PageTest
{
[TestInitialize]
public async Task TestInitialize()
{
await Context.Tracing.StartAsync(new()
{
Title = TestContext.TestName,
Screenshots = true,
Snapshots = true,
Sources = true
});
}
[TestCleanup]
public async Task TestCleanup()
{
// This will produce e.g.:
// bin/Debug/net8.0/playwright-traces/PlaywrightTests.UnitTest1.zip
await Context.Tracing.StopAsync(new()
{
Path = Path.Combine(
Environment.CurrentDirectory,
"playwright-traces",
$"{TestContext.FullyQualifiedTestClassName}.zip"
)
});
}
[TestMethod]
public async Task TestYourOnlineShop()
{
// ...
}
}
using System.Reflection;
using Microsoft.Playwright;
using Microsoft.Playwright.Xunit;
using Xunit.Sdk;
namespace PlaywrightTests;
[WithTestName]
public class UnitTest1 : PageTest
{
public override async Task InitializeAsync()
{
await base.InitializeAsync().ConfigureAwait(false);
await Context.Tracing.StartAsync(new()
{
Title = $"{WithTestNameAttribute.CurrentClassName}.{WithTestNameAttribute.CurrentTestName}",
Screenshots = true,
Snapshots = true,
Sources = true
});
}
public override async Task DisposeAsync()
{
await Context.Tracing.StopAsync(new()
{
Path = Path.Combine(
Environment.CurrentDirectory,
"playwright-traces",
$"{WithTestNameAttribute.CurrentClassName}.{WithTestNameAttribute.CurrentTestName}.zip"
)
});
await base.DisposeAsync().ConfigureAwait(false);
}
[Fact]
public async Task GetStartedLink()
{
// ...
await Page.GotoAsync("https://playwright.nodejs.cn/dotnet/docs/intro");
}
}
public class WithTestNameAttribute : BeforeAfterTestAttribute
{
public static string CurrentTestName = string.Empty;
public static string CurrentClassName = string.Empty;
public override void Before(MethodInfo methodInfo)
{
CurrentTestName = methodInfo.Name;
CurrentClassName = methodInfo.DeclaringType!.Name;
}
public override void After(MethodInfo methodInfo)
{
}
}
这将记录跟踪并将其放入 bin/Debug/net8.0/playwright-traces/
目录中。
¥This will record the trace and place it into the bin/Debug/net8.0/playwright-traces/
directory.
仅在失败时运行跟踪
¥Run trace only on failure
设置测试仅在测试失败时记录跟踪:
¥Setup your tests to record a trace only when the test fails:
- MSTest
- NUnit
- xUnit
namespace PlaywrightTests;
[Parallelizable(ParallelScope.Self)]
[TestFixture]
public class ExampleTest : PageTest
{
[SetUp]
public async Task Setup()
{
await Context.Tracing.StartAsync(new()
{
Title = $"{TestContext.CurrentContext.Test.ClassName}.{TestContext.CurrentContext.Test.Name}",
Screenshots = true,
Snapshots = true,
Sources = true
});
}
[TearDown]
public async Task TearDown()
{
var failed = TestContext.CurrentContext.Result.Outcome == NUnit.Framework.Interfaces.ResultState.Error
|| TestContext.CurrentContext.Result.Outcome == NUnit.Framework.Interfaces.ResultState.Failure;
await Context.Tracing.StopAsync(new()
{
Path = failed ? Path.Combine(
TestContext.CurrentContext.WorkDirectory,
"playwright-traces",
$"{TestContext.CurrentContext.Test.ClassName}.{TestContext.CurrentContext.Test.Name}.zip"
) : null,
});
}
[Test]
public async Task GetStartedLink()
{
// ..
}
}
using System.Text.RegularExpressions;
using Microsoft.Playwright;
using Microsoft.Playwright.MSTest;
namespace PlaywrightTests;
[TestClass]
public class ExampleTest : PageTest
{
[TestInitialize]
public async Task TestInitialize()
{
await Context.Tracing.StartAsync(new()
{
Title = $"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}",
Screenshots = true,
Snapshots = true,
Sources = true
});
}
[TestCleanup]
public async Task TestCleanup()
{
var failed = new[] { UnitTestOutcome.Failed, UnitTestOutcome.Error, UnitTestOutcome.Timeout, UnitTestOutcome.Aborted }.Contains(TestContext.CurrentTestOutcome);
await Context.Tracing.StopAsync(new()
{
Path = failed ? Path.Combine(
Environment.CurrentDirectory,
"playwright-traces",
$"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}.zip"
) : null,
});
}
[TestMethod]
public async Task GetStartedLink()
{
// ...
}
}
using System.Reflection;
using Microsoft.Playwright;
using Microsoft.Playwright.Xunit;
using Xunit.Sdk;
namespace PlaywrightTests;
[WithTestName]
public class UnitTest1 : PageTest
{
public override async Task InitializeAsync()
{
await base.InitializeAsync().ConfigureAwait(false);
await Context.Tracing.StartAsync(new()
{
Title = $"{WithTestNameAttribute.CurrentClassName}.{WithTestNameAttribute.CurrentTestName}",
Screenshots = true,
Snapshots = true,
Sources = true
});
}
public override async Task DisposeAsync()
{
await Context.Tracing.StopAsync(new()
{
Path = !TestOk ? Path.Combine(
Environment.CurrentDirectory,
"playwright-traces",
$"{WithTestNameAttribute.CurrentClassName}.{WithTestNameAttribute.CurrentTestName}.zip"
) : null
});
await base.DisposeAsync().ConfigureAwait(false);
}
[Fact]
public async Task GetStartedLink()
{
// ...
await Page.GotoAsync("https://playwright.nodejs.cn/dotnet/docs/intro");
}
}
public class WithTestNameAttribute : BeforeAfterTestAttribute
{
public static string CurrentTestName = string.Empty;
public static string CurrentClassName = string.Empty;
public override void Before(MethodInfo methodInfo)
{
CurrentTestName = methodInfo.Name;
CurrentClassName = methodInfo.DeclaringType!.Name;
}
public override void After(MethodInfo methodInfo)
{
}
}
跟踪查看器功能
¥Trace Viewer features
行动
¥Actions
在“操作”选项卡中,你可以查看每个操作使用的定位器以及每个操作运行的时间。将鼠标悬停在测试的每个操作上,并直观地查看 DOM 快照中的变化。及时返回和前进,然后单击一个操作来检查和调试。使用“之前”和“之后”选项卡可以直观地查看操作之前和之后发生的情况。
¥In the Actions tab you can see what locator was used for every action and how long each one took to run. Hover over each action of your test and visually see the change in the DOM snapshot. Go back and forward in time and click an action to inspect and debug. Use the Before and After tabs to visually see what happened before and after the action.
选择每个操作会显示:
¥Selecting each action reveals:
-
操作快照
¥Action snapshots
-
操作日志
¥Action log
-
源代码位置
¥Source code location
截图
¥Screenshots
当跟踪时打开 截图 选项(默认),每个跟踪都会记录一个截屏并将其渲染为胶片。你可以将鼠标悬停在胶片上以查看每个操作和状态的放大图片,这有助于你轻松找到要检查的操作。
¥When tracing with the Screenshots option turned on (default), each trace records a screencast and renders it as a film strip. You can hover over the film strip to see a magnified image of for each action and state which helps you easily find the action you want to inspect.
双击某个操作可查看该操作的时间范围。你可以使用时间线中的滑块来增加所选操作,这些操作将显示在“操作”选项卡中,并且所有控制台日志和网络日志将被过滤,仅显示所选操作的日志。
¥Double click on an action to see the time range for that action. You can use the slider in the timeline to increase the actions selected and these will be shown in the Actions tab and all console logs and network logs will be filtered to only show the logs for the actions selected.
快照
¥Snapshots
当启用 快照 选项(默认)进行跟踪时,Playwright 会为每个动作捕获一组完整的 DOM 快照。根据操作的类型,它将捕获:
¥When tracing with the Snapshots option turned on (default), Playwright captures a set of complete DOM snapshots for each action. Depending on the type of the action, it will capture:
类型 | 描述 |
---|---|
前 | 调用操作时的快照。 |
行动 | 执行输入时的快照。当探索 Playwright 具体点击的位置时,这种类型的快照特别有用。 |
后 | 动作后的快照。 |
典型的操作快照如下所示:
¥Here is what the typical Action snapshot looks like:
请注意它如何高亮 DOM 节点以及确切的单击位置。
¥Notice how it highlights both, the DOM Node as well as the exact click position.
来源
¥Source
当你单击侧边栏中的某个操作时,该操作的代码行将在源面板中高亮。
¥When you click on an action in the sidebar, the line of code for that action is highlighted in the source panel.
调用
¥Call
调用选项卡向你显示有关操作的信息,例如所花费的时间、使用的定位器、是否处于严格模式以及使用的键。
¥The call tab shows you information about the action such as the time it took, what locator was used, if in strict mode and what key was used.
日志
¥Log
查看测试的完整日志,以更好地了解 Playwright 在幕后所做的事情,例如滚动到视图中、等待元素可见、启用和稳定以及执行单击、填充、按下等操作。
¥See a full log of your test to better understand what Playwright is doing behind the scenes such as scrolling into view, waiting for element to be visible, enabled and stable and performing actions such as click, fill, press etc.
错误
¥Errors
如果测试失败,你将在“错误”选项卡中看到每个测试的错误消息。时间线还将显示一条红线,高亮错误发生的位置。你还可以单击“源代码”选项卡来查看错误出现在源代码的哪一行。
¥If your test fails you will see the error messages for each test in the Errors tab. The timeline will also show a red line highlighting where the error occurred. You can also click on the source tab to see on which line of the source code the error is.
控制台
¥Console
查看来自浏览器和测试的控制台日志。将显示不同的图标来显示控制台日志是来自浏览器还是来自测试文件。
¥See console logs from the browser as well as from your test. Different icons are displayed to show you if the console log came from the browser or from the test file.
在操作侧边栏中双击测试中的操作。这将过滤控制台以仅显示在该操作期间生成的日志。单击“显示全部”按钮可再次查看所有控制台日志。
¥Double click on an action from your test in the actions sidebar. This will filter the console to only show the logs that were made during that action. Click the Show all button to see all console logs again.
使用时间线过滤操作,方法是单击起点并拖动到终点。控制台选项卡也将被过滤,以仅显示在所选操作期间生成的日志。
¥Use the timeline to filter actions, by clicking a start point and dragging to an ending point. The console tab will also be filtered to only show the logs that were made during the actions selected.
网络
¥Network
“网络”选项卡显示测试期间触发的所有网络请求。你可以按不同类型的请求、状态代码、方法、请求、内容类型、持续时间和大小进行排序。单击请求可查看有关该请求的更多信息,例如请求标头、响应标头、请求正文和响应正文。
¥The Network tab shows you all the network requests that were made during your test. You can sort by different types of requests, status code, method, request, content type, duration and size. Click on a request to see more information about it such as the request headers, response headers, request body and response body.
在操作侧边栏中双击测试中的操作。这将过滤网络请求以仅显示在该操作期间生成的请求。单击“显示全部”按钮可再次查看所有网络请求。
¥Double click on an action from your test in the actions sidebar. This will filter the network requests to only show the requests that were made during that action. Click the Show all button to see all network requests again.
使用时间线过滤操作,方法是单击起点并拖动到终点。网络选项卡也将被过滤,以仅显示在所选操作期间发送的网络请求。
¥Use the timeline to filter actions, by clicking a start point and dragging to an ending point. The network tab will also be filtered to only show the network requests that were made during the actions selected.
元数据
¥Metadata
在“操作”选项卡旁边,你将找到“元数据”选项卡,它将显示有关测试的更多信息,例如浏览器、视口大小、测试持续时间等。
¥Next to the Actions tab you will find the Metadata tab which will show you more information on your test such as the Browser, viewport size, test duration and more.