Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 73 additions & 15 deletions src/Playwright/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

using System;
using System.Diagnostics;
using System.Text;
using Microsoft.Playwright.Helpers;

namespace Microsoft.Playwright;
Expand All @@ -38,43 +39,100 @@ public static int Main(string[] args)

public int Run(string[] args)
{
Func<string?, string> getArgs;
string executablePath;
Process pwProcess;
try
{
(executablePath, getArgs) = Driver.GetExecutablePath();
pwProcess = CreateDriverProcess(args, captureOutput: false);
}
catch
{
return PrintError("Microsoft.Playwright assembly was found, but is missing required assets. Please ensure to build your project before running Playwright tool.");
}
using (pwProcess)
{
pwProcess.Start();
pwProcess.WaitForExit();
return pwProcess.ExitCode;
}
}

/// <summary>
/// Runs the Playwright driver with the given arguments and returns the captured stdout, stderr, and exit code.
/// Unlike <see cref="Run(string[])"/>, this does not inherit the calling process's stdio, so the output is
/// available to callers running under environments (e.g. xUnit) that don't surface inherited console output.
/// </summary>
/// <param name="args">The arguments to pass to the Playwright driver (e.g. <c>install</c>, <c>codegen</c>).</param>
/// <returns>The captured <see cref="RunResult"/>.</returns>
public RunResult RunWithResult(string[] args)
{
using var pwProcess = CreateDriverProcess(args, captureOutput: true);

var stdout = new StringBuilder();
var stderr = new StringBuilder();
pwProcess.OutputDataReceived += (_, e) =>
{
if (e.Data != null)
{
stdout.AppendLine(e.Data);
}
};
pwProcess.ErrorDataReceived += (_, e) =>
{
if (e.Data != null)
{
stderr.AppendLine(e.Data);
}
};

pwProcess.Start();
pwProcess.BeginOutputReadLine();
pwProcess.BeginErrorReadLine();
pwProcess.WaitForExit();

return new RunResult(pwProcess.ExitCode, stdout.ToString(), stderr.ToString());
}

var playwrightStartInfo = new ProcessStartInfo(executablePath, getArgs(args.Length > 0 ? "\"" + string.Join("\" \"", args) + "\"" : null))
private static Process CreateDriverProcess(string[] args, bool captureOutput)
{
var (executablePath, getArgs) = Driver.GetExecutablePath();
var startInfo = new ProcessStartInfo(executablePath, getArgs(args.Length > 0 ? "\"" + string.Join("\" \"", args) + "\"" : null))
{
UseShellExecute = false,
// This works after net8.0-preview-4
// https://github.com/dotnet/runtime/pull/82662
WindowStyle = ProcessWindowStyle.Hidden,
RedirectStandardOutput = captureOutput,
RedirectStandardError = captureOutput,
};
foreach (var pair in Driver.EnvironmentVariables)
{
playwrightStartInfo.EnvironmentVariables[pair.Key] = pair.Value;
startInfo.EnvironmentVariables[pair.Key] = pair.Value;
}

using var pwProcess = new Process()
{
StartInfo = playwrightStartInfo,
};

pwProcess.Start();

pwProcess.WaitForExit();
return pwProcess.ExitCode;
return new Process() { StartInfo = startInfo };
}

private static int PrintError(string error)
{
Console.Error.WriteLine("\x1b[91m" + error + "\x1b[0m");
return 1;
}

/// <summary>
/// Captured result of <see cref="RunWithResult(string[])"/>.
/// </summary>
public class RunResult
{
internal RunResult(int exitCode, string standardOutput, string standardError)
{
ExitCode = exitCode;
StandardOutput = standardOutput;
StandardError = standardError;
}

public int ExitCode { get; }

public string StandardOutput { get; }

public string StandardError { get; }
}
}
Loading