追蹤檢視器
簡介
Playwright 追蹤檢視器是一個 GUI 工具,可協助您在腳本執行後探索錄製的 Playwright 追蹤。當您的測試在 CI 上失敗時,追蹤是偵錯測試的好方法。您可以在本機或瀏覽器上透過 trace.playwright.dev 開啟追蹤。
開啟追蹤檢視器
您可以使用 Playwright CLI 或瀏覽器在 trace.playwright.dev 開啟已儲存的追蹤。請務必新增 trace.zip
檔案所在位置的完整路徑。
pwsh bin/Debug/netX/playwright.ps1 show-trace trace.zip
使用 trace.playwright.dev
trace.playwright.dev 是追蹤檢視器的靜態託管變體。您可以使用拖放或透過 Select file(s)
按鈕上傳追蹤檔案。
追蹤檢視器完全在您的瀏覽器中載入追蹤,且不會在外部傳輸任何資料。

檢視遠端追蹤
您可以直接使用 URL 開啟遠端追蹤。這樣可以輕鬆檢視遠端追蹤,而無需手動從 CI 執行下載檔案,例如。
pwsh bin/Debug/netX/playwright.ps1 show-trace https://example.com/trace.zip
使用 trace.playwright.dev 時,您也可以將您上傳的追蹤 URL 作為查詢參數傳遞到某些可存取的儲存空間(例如,在您的 CI 內)。CORS(跨來源資源分享)規則可能適用。
https://trace.playwright.dev/?trace=https://demo.playwright.dev/reports/todomvc/data/cb0fa77ebd9487a5c899f3ae65a7ffdbac681182.zip
錄製追蹤
可以使用 BrowserContext.Tracing API 錄製追蹤,如下所示
- 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.dev.org.tw/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/
目錄中。
僅在失敗時執行追蹤
設定您的測試,使其僅在測試失敗時錄製追蹤
- 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.dev.org.tw/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)
{
}
}
追蹤檢視器功能
動作
在「動作」標籤中,您可以看到每個動作使用了哪個定位器,以及每個動作的執行時間。將滑鼠懸停在測試的每個動作上,並以視覺方式查看 DOM 快照中的變化。在時間軸上來回移動,並按一下動作以檢查和偵錯。使用「之前」和「之後」標籤,以視覺方式查看動作之前和之後發生的情況。
選取每個動作會顯示
- 動作快照
- 動作記錄
- 原始碼位置
螢幕截圖
當使用 Screenshots 選項開啟(預設)進行追蹤時,每個追蹤都會錄製螢幕錄影,並將其呈現為膠片。您可以將滑鼠懸停在膠片上,以查看每個動作和狀態的放大影像,這有助於您輕鬆找到要檢查的動作。
按兩下動作以查看該動作的時間範圍。您可以使用時間軸中的滑桿來增加選取的動作,這些動作將顯示在「動作」標籤中,並且所有主控台記錄和網路記錄將被篩選,僅顯示選取動作的記錄。
快照
當使用 Snapshots 選項開啟(預設)進行追蹤時,Playwright 會針對每個動作擷取一組完整的 DOM 快照。根據動作的類型,它將擷取
類型 | 描述 |
---|---|
之前 | 呼叫動作時的快照。 |
動作 | 執行輸入時的快照。當探索 Playwright 點擊的確切位置時,此類型的快照特別有用。 |
之後 | 動作後的快照。 |
以下是一般動作快照的外觀
請注意它如何同時醒目提示 DOM 節點和確切的點擊位置。
原始碼
當您按一下側邊欄中的動作時,該動作的程式碼行會在原始碼面板中醒目提示。
呼叫
「呼叫」標籤會顯示有關動作的資訊,例如所花費的時間、使用的定位器、是否處於嚴格模式以及使用的按鍵。
記錄
查看測試的完整記錄,以更好地了解 Playwright 在幕後執行的操作,例如捲動到檢視畫面、等待元素可見、已啟用且穩定,以及執行按一下、填寫、按下等動作。
錯誤
如果您的測試失敗,您將在「錯誤」標籤中看到每個測試的錯誤訊息。時間軸也會顯示一條紅線,醒目提示錯誤發生的位置。您也可以按一下「原始碼」標籤,以查看錯誤發生的原始碼行。
主控台
查看來自瀏覽器以及來自測試的主控台記錄。會顯示不同的圖示,以顯示主控台記錄是來自瀏覽器還是來自測試檔案。
按兩下動作側邊欄中測試的動作。這將篩選主控台,僅顯示在該動作期間產生的記錄。按一下顯示全部按鈕以再次查看所有主控台記錄。
使用時間軸篩選動作,方法是按一下起點並拖曳到終點。「主控台」標籤也會篩選,僅顯示在選取動作期間產生的記錄。
網路
「網路」標籤會顯示測試期間發出的所有網路請求。您可以依不同的請求類型、狀態碼、方法、請求、內容類型、持續時間和大小排序。按一下請求以查看有關它的更多資訊,例如請求標頭、回應標頭、請求主體和回應主體。
按兩下動作側邊欄中測試的動作。這將篩選網路請求,僅顯示在該動作期間發出的請求。按一下顯示全部按鈕以再次查看所有網路請求。
使用時間軸篩選動作,方法是按一下起點並拖曳到終點。「網路」標籤也會篩選,僅顯示在選取動作期間發出的網路請求。
中繼資料
在「動作」標籤旁邊,您會找到「中繼資料」標籤,其中會顯示有關測試的更多資訊,例如瀏覽器、檢視區大小、測試持續時間等等。