Skip to content

Commit

Permalink
Upgrade Playwright
Browse files Browse the repository at this point in the history
Cherry-pick of #38414
  • Loading branch information
TanayParikh authored and MackinnonBuck committed Jul 9, 2024
1 parent a9f3592 commit a45498a
Show file tree
Hide file tree
Showing 19 changed files with 158 additions and 179 deletions.
8 changes: 4 additions & 4 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
"isRoot": true,
"tools": {
"dotnet-serve": {
"version": "1.7.139",
"version": "1.8.15",
"commands": [
"dotnet-serve"
]
},
"playwright-sharp-tool": {
"version": "0.170.2",
"Microsoft.Playwright.CLI": {
"version": "1.2.2",
"commands": [
"playwright-sharp"
"playwright"
]
}
}
Expand Down
2 changes: 1 addition & 1 deletion eng/Dependencies.props
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ and are generated based on the last package release.
<LatestPackageReference Include="NuGet.Frameworks" />
<LatestPackageReference Include="NuGet.Versioning" />
<LatestPackageReference Include="Photino.NET" />
<LatestPackageReference Include="PlaywrightSharp" />
<LatestPackageReference Include="Microsoft.Playwright" />
<LatestPackageReference Include="Polly" />
<LatestPackageReference Include="Polly.Extensions.Http" />
<LatestPackageReference Include="Selenium.Support" />
Expand Down
2 changes: 1 addition & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@
<NewtonsoftJsonVersion>13.0.1</NewtonsoftJsonVersion>
<NSwagApiDescriptionClientVersion>13.0.4</NSwagApiDescriptionClientVersion>
<PhotinoNETVersion>1.1.6</PhotinoNETVersion>
<PlaywrightSharpVersion>0.192.0</PlaywrightSharpVersion>
<MicrosoftPlaywrightVersion>1.17.3</MicrosoftPlaywrightVersion>
<PollyExtensionsHttpVersion>3.0.0</PollyExtensionsHttpVersion>
<PollyVersion>7.2.2</PollyVersion>
<SeleniumSupportVersion>4.3.0</SeleniumSupportVersion>
Expand Down
2 changes: 1 addition & 1 deletion eng/helix/content/RunTests/RunTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@

<ItemGroup>
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20158.1" />
<PackageReference Condition=" '$(InstallPlaywright)' == 'true' " Include="PlaywrightSharp" Version="0.192.0" />
<PackageReference Condition=" '$(InstallPlaywright)' == 'true' " Include="Microsoft.Playwright" Version="1.17.3" />
</ItemGroup>
</Project>
11 changes: 5 additions & 6 deletions eng/helix/content/RunTests/TestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
using System.Threading;
using System.Threading.Tasks;
#if INSTALLPLAYWRIGHT
using PlaywrightSharp;
using Microsoft.Playwright;
#endif

namespace RunTests
Expand Down Expand Up @@ -55,9 +55,6 @@ public bool SetupEnvironment()
var playwrightBrowsers = Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH");
ProcessUtil.PrintMessage($"Setting PLAYWRIGHT_BROWSERS_PATH: {playwrightBrowsers}");
EnvironmentVariables.Add("PLAYWRIGHT_BROWSERS_PATH", playwrightBrowsers);
var playrightDriver = Environment.GetEnvironmentVariable("PLAYWRIGHT_DRIVER_PATH");
ProcessUtil.PrintMessage($"Setting PLAYWRIGHT_DRIVER_PATH: {playrightDriver}");
EnvironmentVariables.Add("PLAYWRIGHT_DRIVER_PATH", playrightDriver);
#else
ProcessUtil.PrintMessage($"Skipping setting PLAYWRIGHT_BROWSERS_PATH");
#endif
Expand Down Expand Up @@ -112,8 +109,10 @@ public async Task<bool> InstallPlaywrightAsync()
{
try
{
ProcessUtil.PrintMessage($"Installing Playwright to Browsers: {Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH")} Driver: {Environment.GetEnvironmentVariable("PLAYWRIGHT_DRIVER_PATH")}");
await Playwright.InstallAsync(Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH"), Environment.GetEnvironmentVariable("PLAYWRIGHT_DRIVER_PATH"));
Console.WriteLine($"Installing Playwright Browsers to {Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH")}");

var exitCode = Microsoft.Playwright.Program.Main(new[] { "install" });

DisplayContents(Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH"));
return true;
}
Expand Down
1 change: 0 additions & 1 deletion eng/helix/content/runtests.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ set DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
set DOTNET_MULTILEVEL_LOOKUP=0
set InstallPlaywright=%$installPlaywright%
set PLAYWRIGHT_BROWSERS_PATH=%CD%\ms-playwright
set PLAYWRIGHT_DRIVER_PATH=%CD%\.playwright\win-x64\native\playwright.cmd

REM Avoid https://github.com/dotnet/aspnetcore/issues/41937 in current session.
set ASPNETCORE_ENVIRONMENT=
Expand Down
1 change: 0 additions & 1 deletion eng/helix/content/runtests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export PATH="$PATH:$DIR:$DIR/node/bin"
# Set playwright stuff
export PLAYWRIGHT_BROWSERS_PATH="$DIR/ms-playwright"
if [[ "$helixQueue" == *"OSX"* ]]; then
export PLAYWRIGHT_DRIVER_PATH="$DIR/.playwright/osx/native/playwright.sh"
PLAYWRIGHT_NODE_PATH=$DIR/.playwright/osx/native/node
else
export PLAYWRIGHT_DRIVER_PATH="$DIR/.playwright/unix/native/playwright.sh"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.BrowserTesting;
using Microsoft.AspNetCore.Testing;
using PlaywrightSharp;
using Microsoft.Playwright;
using ProjectTemplates.Tests.Infrastructure;
using Templates.Test.Helpers;
using Xunit;
Expand Down Expand Up @@ -137,20 +137,31 @@ public async Task BlazorServerTemplateWorks_IndividualAuth(BrowserKind browserKi

private async Task TestBasicNavigation(Project project, IPage page)
{
var socket = BrowserContextInfo.Pages[page].WebSockets.SingleOrDefault() ??
(await page.WaitForEventAsync(PageEvent.WebSocket)).WebSocket;
var socket = await page.WaitForWebSocketAsync();

var framesReceived = 0;
var framesSent = 0;

void FrameReceived(object sender, IWebSocketFrame frame) { framesReceived++; }
void FrameSent(object sender, IWebSocketFrame frame) { framesSent++; }

socket.FrameReceived += FrameReceived;
socket.FrameSent += FrameSent;

// Receive render batch
await socket.WaitForEventAsync(WebSocketEvent.FrameReceived);
await socket.WaitForEventAsync(WebSocketEvent.FrameSent);
await page.WaitForWebSocketAsync(new() { Predicate = (s) => framesReceived == 1 });
await page.WaitForWebSocketAsync(new() { Predicate = (s) => framesSent == 1 });

// JS interop call to intercept navigation
await socket.WaitForEventAsync(WebSocketEvent.FrameReceived);
await socket.WaitForEventAsync(WebSocketEvent.FrameSent);
await page.WaitForWebSocketAsync(new() { Predicate = (s) => framesReceived == 2 });
await page.WaitForWebSocketAsync(new() { Predicate = (s) => framesSent == 2 });

socket.FrameReceived -= FrameReceived;
socket.FrameSent -= FrameSent;

await page.WaitForSelectorAsync("nav");
// <title> element gets project ID injected into it during template execution
Assert.Equal("Index", (await page.GetTitleAsync()).Trim());
Assert.Equal("Index", (await page.TitleAsync()).Trim());

// Initially displays the home page
await page.WaitForSelectorAsync("h1 >> text=Hello, world!");
Expand All @@ -169,7 +180,7 @@ private async Task TestBasicNavigation(Project project, IPage page)

// Asynchronously loads and displays the table of weather forecasts
await page.WaitForSelectorAsync("table>tbody>tr");
Assert.Equal(5, (await page.QuerySelectorAllAsync("p+table>tbody>tr")).Count());
Assert.Equal(5, await page.Locator("p+table>tbody>tr").CountAsync());
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
<Reference Include="Microsoft.Extensions.Configuration.Json" />
<Reference Include="AngleSharp" />
<Reference Include="System.Net.Http" />
<Reference Include="PlaywrightSharp" Condition="'$(TargetOsName)' != 'linux-musl'" />
<Reference Include="PlaywrightSharp" ExcludeAssets="build" Condition="'$(TargetOsName)' == 'linux-musl'" />
<Reference Include="Microsoft.Playwright" Condition="'$(TargetOsName)' != 'linux-musl'" />
<Reference Include="Microsoft.Playwright" ExcludeAssets="build" Condition="'$(TargetOsName)' == 'linux-musl'" />
<ProjectReference Include="$(RepoRoot)src\Framework\App.Runtime\src\Microsoft.AspNetCore.App.Runtime.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.CommandLineUtils;
using Newtonsoft.Json.Linq;
using PlaywrightSharp;
using Microsoft.Playwright;
using Templates.Test.Helpers;
using Xunit;
using Xunit.Abstractions;
Expand Down Expand Up @@ -64,7 +64,7 @@ public async Task BlazorWasmStandaloneTemplate_Works(BrowserKind browserKind)
private async Task<IPage> NavigateToPage(IBrowserContext browser, string listeningUri)
{
var page = await browser.NewPageAsync();
await page.GoToAsync(listeningUri, LifecycleEvent.Networkidle);
await page.GotoAsync(listeningUri, new() { WaitUntil = WaitUntilState.NetworkIdle });
return page;
}

Expand Down Expand Up @@ -141,9 +141,9 @@ public async Task BlazorWasmStandalonePwaTemplate_Works(BrowserKind browserKind)

// The PWA template supports offline use. By now, the browser should have cached everything it needs,
// so we can continue working even without the server.
await page.GoToAsync("about:blank");
await page.GotoAsync("about:blank");
await browser.SetOfflineAsync(true);
await page.GoToAsync(listeningUri);
await page.GotoAsync(listeningUri);
await TestBasicNavigation(project.ProjectName, page, skipFetchData: true);
await page.CloseAsync();
}
Expand Down Expand Up @@ -189,9 +189,9 @@ public async Task BlazorWasmHostedPwaTemplate_Works(BrowserKind browserKind)
// The PWA template supports offline use. By now, the browser should have cached everything it needs,
// so we can continue working even without the server.
// Since this is the hosted project, backend APIs won't work offline, so we need to skip "fetchdata"
await page.GoToAsync("about:blank");
await page.GotoAsync("about:blank");
await browser.SetOfflineAsync(true);
await page.GoToAsync(listeningUri);
await page.GotoAsync(listeningUri);
await TestBasicNavigation(project.ProjectName, page, skipFetchData: true);
await page.CloseAsync();
}
Expand Down Expand Up @@ -424,11 +424,11 @@ private async Task TestBasicNavigation(string appName, IPage page, bool usesAuth
// Initially displays the home page
await page.WaitForSelectorAsync("h1 >> text=Hello, world!");

Assert.Equal("Index", (await page.GetTitleAsync()).Trim());
Assert.Equal("Index", (await page.TitleAsync()).Trim());

// Can navigate to the counter page
await Task.WhenAll(
page.WaitForNavigationAsync("**/counter"),
page.WaitForNavigationAsync(new() { UrlString = "**/counter" }),
page.WaitForSelectorAsync("h1 >> text=Counter"),
page.WaitForSelectorAsync("p >> text=Current count: 0"),
page.ClickAsync("a[href=counter]"));
Expand All @@ -441,12 +441,12 @@ private async Task TestBasicNavigation(string appName, IPage page, bool usesAuth
if (usesAuth)
{
await Task.WhenAll(
page.WaitForNavigationAsync("**/Identity/Account/Login**", LifecycleEvent.Networkidle),
page.WaitForNavigationAsync(new() { UrlString = "**/Identity/Account/Login**", WaitUntil = LifecycleEvent.Networkidle }),
page.ClickAsync("text=Log in"));

await Task.WhenAll(
page.WaitForSelectorAsync("[name=\"Input.Email\"]"),
page.WaitForNavigationAsync("**/Identity/Account/Register**", LifecycleEvent.Networkidle),
page.WaitForNavigationAsync(new() { UrlString = "**/Identity/Account/Register**", WaitUntil = LifecycleEvent.Networkidle }),
page.ClickAsync("text=Register as a new user"));

var userName = $"{Guid.NewGuid()}@example.com";
Expand All @@ -458,12 +458,12 @@ private async Task TestBasicNavigation(string appName, IPage page, bool usesAuth

// We will be redirected to the RegisterConfirmation
await Task.WhenAll(
page.WaitForNavigationAsync("**/Identity/Account/RegisterConfirmation**", LifecycleEvent.Networkidle),
page.WaitForNavigationAsync(new() { UrlString = "**/Identity/Account/RegisterConfirmation**", WaitUntil = LifecycleEvent.Networkidle }),
page.ClickAsync("#registerSubmit"));

// We will be redirected to the ConfirmEmail
await Task.WhenAll(
page.WaitForNavigationAsync("**/Identity/Account/ConfirmEmail**", LifecycleEvent.Networkidle),
page.WaitForNavigationAsync(new() { UrlString = "**/Identity/Account/ConfirmEmail**", WaitUntil = LifecycleEvent.Networkidle }),
page.ClickAsync("text=Click here to confirm your account"));

// Now we can login
Expand All @@ -474,21 +474,21 @@ private async Task TestBasicNavigation(string appName, IPage page, bool usesAuth
await page.ClickAsync("#login-submit");

// Need to navigate to fetch page
await page.GoToAsync(new Uri(page.Url).GetLeftPart(UriPartial.Authority));
Assert.Equal(appName.Trim(), (await page.GetTitleAsync()).Trim());
await page.GotoAsync(new Uri(page.Url).GetLeftPart(UriPartial.Authority));
Assert.Equal(appName.Trim(), (await page.TitleAsync()).Trim());
}

if (!skipFetchData)
{
// Can navigate to the 'fetch data' page
await Task.WhenAll(
page.WaitForNavigationAsync("**/fetchdata"),
page.WaitForNavigationAsync(new() { UrlString = "**/fetchdata" }),
page.WaitForSelectorAsync("h1 >> text=Weather forecast"),
page.ClickAsync("text=Fetch data"));

// Asynchronously loads and displays the table of weather forecasts
await page.WaitForSelectorAsync("table>tbody>tr");
Assert.Equal(5, (await page.QuerySelectorAllAsync("p+table>tbody>tr")).Count());
Assert.Equal(5, await page.Locator("p+table>tbody>tr").CountAsync());
}
}

Expand Down
15 changes: 3 additions & 12 deletions src/ProjectTemplates/BlazorTemplates.Tests/playwrightSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,18 @@
"BaseArtifactsFolder": ".",
"GlobalBrowserOptions": {
"ChromiumSandbox": true,
"DumpIO": true,
"IgnoreHTTPSErrors": true,
"Headless": true,
"Timeout": 30000
},
"GlobalContextOptions": {
"RecordVideo": {
"Dir": "videos"
},
"RecordHar": {
"Path": "har"
},
"RecordVideoDir": "videos",
"RecordHarPath": "har",
"IgnoreHTTPSErrors": true
},
"BrowserOptions": {
"Chromium": {
"BrowserKind": "Chromium",
"IsEnabled": true,
"Args": {
"--ignore-certificate-errors": true
}
"IsEnabled": true
},
"Firefox": {
"BrowserKind": "Firefox",
Expand Down
4 changes: 2 additions & 2 deletions src/ProjectTemplates/Shared/AspNetProcess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
using Microsoft.Extensions.CommandLineUtils;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using PlaywrightSharp;
using Microsoft.Playwright;
using Xunit;
using Xunit.Abstractions;

Expand Down Expand Up @@ -109,7 +109,7 @@ public class AspNetProcess : IDisposable
public async Task VisitInBrowserAsync(IPage page)
{
_output.WriteLine($"Opening browser at {ListeningUri}...");
await page.GoToAsync(ListeningUri.AbsoluteUri);
await page.GotoAsync(ListeningUri.AbsoluteUri);
}


Expand Down
21 changes: 7 additions & 14 deletions src/Shared/BrowserTesting/src/BrowserManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using PlaywrightSharp;
using Microsoft.Playwright;

namespace Microsoft.AspNetCore.BrowserTesting
{
Expand Down Expand Up @@ -47,20 +47,12 @@ private async Task InitializeAsync()

async Task InitializeCore()
{
var driverPath = Environment.GetEnvironmentVariable("PLAYWRIGHT_DRIVER_PATH");
if (!string.IsNullOrEmpty(driverPath))
{
Playwright = await PlaywrightSharp.Playwright.CreateAsync(_loggerFactory, driverExecutablePath: driverPath, debug: "pw:api");
}
else
{
Playwright = await PlaywrightSharp.Playwright.CreateAsync(_loggerFactory, debug: "pw:api");
}
Playwright = await Microsoft.Playwright.Playwright.CreateAsync();
foreach (var (browserName, options) in _browserManagerConfiguration.BrowserOptions)
{
if (!_launchBrowsers.ContainsKey(browserName))
{
var effectiveLaunchOptions = _browserManagerConfiguration.GetLaunchOptions(options.BrowserLaunchOptions);
var effectiveLaunchOptions = _browserManagerConfiguration.GetBrowserTypeLaunchOptions(options.BrowserLaunchOptions);

Check failure on line 55 in src/Shared/BrowserTesting/src/BrowserManager.cs

View check run for this annotation

Azure Pipelines / aspnetcore-ci (Build Test: Ubuntu x64)

src/Shared/BrowserTesting/src/BrowserManager.cs#L55

src/Shared/BrowserTesting/src/BrowserManager.cs(55,119): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'BrowserOptions' does not contain a definition for 'BrowserLaunchOptions' and no accessible extension method 'BrowserLaunchOptions' accepting a first argument of type 'BrowserOptions' could be found (are you missing a using directive or an assembly reference?)

var browser = options.BrowserKind switch
{
Expand Down Expand Up @@ -108,10 +100,10 @@ public Task<IBrowserContext> GetBrowserInstance(string browserInstance, string c
contextInfo);
}

public Task<IBrowserContext> GetBrowserInstance(BrowserKind browserInstance, string contextName, BrowserContextOptions options, ContextInformation contextInfo) =>
public Task<IBrowserContext> GetBrowserInstance(BrowserKind browserInstance, string contextName, BrowserNewContextOptions options, ContextInformation contextInfo) =>
GetBrowserInstance(browserInstance.ToString(), contextName, options, contextInfo);

public Task<IBrowserContext> GetBrowserInstance(string browserInstance, string contextName, BrowserContextOptions options, ContextInformation contextInfo)
public Task<IBrowserContext> GetBrowserInstance(string browserInstance, string contextName, BrowserNewContextOptions options, ContextInformation contextInfo)
{
if (_launchBrowsers.TryGetValue(browserInstance, out var browser))
{
Expand All @@ -126,9 +118,10 @@ public Task<IBrowserContext> GetBrowserInstance(string browserInstance, string c
private async Task<IBrowserContext> AttachContextInfo(Task<IBrowserContext> browserContextTask, ContextInformation contextInfo)
{
var context = await browserContextTask;
context.DefaultTimeout = HasFailedTests ?
var defaultTimeout = HasFailedTests ?
_browserManagerConfiguration.TimeoutAfterFirstFailureInMilliseconds:
_browserManagerConfiguration.TimeoutInMilliseconds;
context.SetDefaultTimeout(defaultTimeout);

contextInfo.Attach(context);
return context;
Expand Down
Loading

0 comments on commit a45498a

Please sign in to comment.