microsoft / playwright-dotnet

.NET version of the Playwright testing and automation library.
https://playwright.dev/dotnet/
MIT License
2.47k stars 235 forks source link

[BUG] Exception thrown when using playwright in a single-file published program #2255

Closed jeroenpelgrims closed 4 months ago

jeroenpelgrims commented 2 years ago

Context:

Code Snippet

See code to reproduce this bug here: https://github.com/resurge/PlaywrightSingleFilePathError

Describe the bug When publishing a project as single file and running the published executable the following error will be shown:

Unhandled exception. System.ArgumentException: The path is empty. (Parameter 'path')
   at System.IO.Path.GetFullPath(String path)
   at System.IO.FileInfo..ctor(String originalPath, String fullPath, String fileName, Boolean isNormalized)
   at System.IO.FileInfo..ctor(String fileName)
   at Microsoft.Playwright.Helpers.Driver.GetExecutablePath() in /_/src/Playwright/Helpers/Driver.cs:line 41
   at Microsoft.Playwright.Transport.StdIOTransport.GetProcess() in /_/src/Playwright/Transport/StdIOTransport.cs:line 119
   at Microsoft.Playwright.Transport.StdIOTransport..ctor() in /_/src/Playwright/Transport/StdIOTransport.cs:line 44
   at Microsoft.Playwright.Playwright.CreateAsync() in /_/src/Playwright/Playwright.cs:line 44
   at Program.<Main>$(String[] args) in C:\Users\jeroe\Documents\repos\PlaywrightSingleFilePathError\Program.cs:line 3
   at Program.<Main>(String[] args)

I would expect the program to behave the same way as a regular Debug or Release build.
But choosing to publish as a single file causes the behaviour of the executable to change. (And not work)

The following tickets were about the same bug but were closed because of no code to reproduce:

EDIT: Some other issues I found relating to this bug:

kblok commented 2 years ago

My two cents here. I don't think an end-to-end testing library needs to support single-file publishing.

jeroenpelgrims commented 2 years ago

While that seems to be the initial reason Playwright was created it is used for more that that.
I myself use it for scraping or transforming html to PDF. I would like to be able to share a single executable with users instead of having to make a zip file or installer as release.

I agree more with the description that is written in the README of this repo.
(Browser automation in general, not just specifically for testing)

Playwright for .NET is the official language port of Playwright, the library to automate Chromium, Firefox and WebKit with a single API.

The linked issues show that there is a need for this type of publishing.
EDIT: I found some more tickets about people using it this way, I added them above.

travisnielsen commented 1 year ago

Echoing @jeroenpelgrims comments. We're using Playwright for generating .png files as part of the Azure PlantUML project and it would be great if we could offer a single executable to users who wish to generate their own diagram sprites.

ianis58 commented 1 year ago

@kblok do you still have a patch for the issue #2493 ? I think it's the same issue as this one.

kblok commented 1 year ago

@mxschmitt, the solution I was using was saving the driver in a shared location, LocalApplicationData. I don't know if that's what we'd want to do here.

vmeganathan81 commented 1 year ago

Hi @kblok ,

Is this issue referred in #2493 ... done?

kblok commented 1 year ago

@vmeganathan81 I bet so.

vmeganathan81 commented 1 year ago

Any ETA on this?

vmeganathan81 commented 1 year ago

@vmeganathan81 I bet so.

Okay, let me test with latest version... thanks

vmeganathan81 commented 1 year ago

@jeroenpelgrims ... Are we going to resolve this or it would take more time?

jeroenpelgrims commented 1 year ago

@jeroenpelgrims ... Are we going to resolve this or it would take more time?

I'll try to test tomorrow. I actually haven't worked on the project this was for since the creation of this issue.

You verified it working on your end?

EDIT: Still doesn't seem to work although I get a clearer error message now.

Unhandled exception. System.NotSupportedException: CodeBase is not supported on assemblies loaded from a single-file bundle.
   at System.Reflection.RuntimeAssembly.get_CodeBase()
   at Microsoft.Playwright.Helpers.Driver.GetExecutablePath() in /_/src/Playwright/Helpers/Driver.cs:line 47
   at Microsoft.Playwright.Transport.StdIOTransport.GetProcess() in /_/src/Playwright/Transport/StdIOTransport.cs:line 114
   at Microsoft.Playwright.Transport.StdIOTransport..ctor() in /_/src/Playwright/Transport/StdIOTransport.cs:line 44
   at Microsoft.Playwright.Playwright.CreateAsync() in /_/src/Playwright/Playwright.cs:line 44
   at ResumeBuilder.Pdf.PdfBuilder.SavePdf(String htmlPath, String outputFile) in C:\Users\....\PdfBuilder.cs:line 9
   at Program.<Main>$(String[] args) in C:\Users\...\Program.cs:line 11
   at Program.<Main>(String[] args)

Same result when publishing self contained or framework dependent.

vmeganathan81 commented 1 year ago

@mxschmitt ,

The solution @kblok mentioned is that merged and available with latest version?

vmeganathan81 commented 1 year ago

@mxschmitt any update on this open issue?

lonix1 commented 1 year ago

Same issue here. We publish a single-file self-contained executable in a docker image, alongside the playwright stuff.

When dealing with docker images that is significantly more convenient and eliminates many dependency problems (which is why it is such a popular approach in the docker world).

But playwright conflicts with that deployment model.

jsoctocat commented 8 months ago

This issue still persist as of this comment (version 1.41.2)

mxschmitt commented 6 months ago

Starting from v1.44 (will be released in 3-4 weeks) this should be fixed: https://github.com/microsoft/playwright-dotnet/pull/2909

Browsers need to be installed via Microsoft.Playwright.Program.Main(["install"]);

matthewteeter commented 5 months ago

I still get this issue using v1.44 when running Microsoft.Playwright.Program.Main(["install"]).

Docker build error:

[final 3/4] RUN /app/PayPowerBill install: 1.565 Unhandled Exception: System.NotSupportedException: CodeBase is not supported on assemblies loaded from a single-file bundle. 1.565 at System.Reflection.Runtime.Assemblies.RuntimeAssemblyInfo.get_CodeBase() + 0x27 1.565 at Microsoft.Playwright.Helpers.Driver.GetExecutablePath() + 0xa8 1.565 at Microsoft.Playwright.Transport.StdIOTransport.GetProcess(String) + 0x36 1.565 at Microsoft.Playwright.Transport.StdIOTransport..ctor() + 0x62 1.565 at Microsoft.Playwright.Playwright.d0.MoveNext() + 0x4f 1.565 --- End of stack trace from previous location --- 1.565 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x1c 1.565 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xbe 1.565 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4e 1.565 at Program.<

$>d0.MoveNext() + 0xe5 1.565 --- End of stack trace from previous location --- 1.565 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x1c 1.565 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xbe 1.565 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4e 1.565 at Program.
(String[] args) + 0x24 1.565 at PayPowerBill!+0x4f86bc

Dockerfile:

FROM mcr.microsoft.com/dotnet/runtime:8.0-jammy AS base
USER app
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0 as build
# Install NativeAOT build prerequisites
USER root
RUN apt-get update && apt-get install -y --no-install-recommends clang zlib1g-dev

WORKDIR /src
COPY ["PayPowerBill.csproj", "."]
RUN dotnet restore "./PayPowerBill.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "PayPowerBill.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "PayPowerBill.csproj" -c Release -o /app/publish -r linux-x64 

FROM base AS final
USER root
WORKDIR /app
COPY --from=publish /app/publish .
##Need to trigger Playwright install thru code to avoid dependency on sdk in final image - see www.meziantou.net/distributing-applications-that-depend-on-microsoft-playwright.htm
RUN /app/PayPowerBill install
RUN <<-DEPS
    apt-get update &&
    apt-get -y install libasound2 libx11-xcb1 libxcursor1 libgtk-3-0 libpangocairo-1.0-0 libcairo-gobject2 libgdk-pixbuf-2.0-0 libdbus-glib-1-2 &&
    rm -rf /var/lib/apt/lists/* &&
    echo "workaround"
DEPS
ENTRYPOINT ["PayPowerBill"]

How the program calls install at startup:

using var playwright = await Playwright.CreateAsync();
var b = playwright.Firefox;
if (args.Any() && args?[0] == "install")
{
    Environment.Exit(Microsoft.Playwright.Program.Main(new[] { "install" }));//, b.Name }));
}
...
mxschmitt commented 5 months ago

@matthewteeter we need a full repro, ideally via a small git repository.

matthewteeter commented 4 months ago

Here is a full repro: https://github.com/matthewteeter/Playwright1.44AotRepro Running the program as normal throws an exception on the first line in Program.cs. Trying to install the browsers by invoking it with "install" (as shown by the Dockerfile) fails with:


0.816 Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
0.816    at Microsoft.Playwright.Transport.Connection.<WrapApiCallAsync>d__52`1.MoveNext() + 0x223
0.816 --- End of stack trace from previous location ---
0.816    at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x1c
0.816    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xbe
0.816    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4e
0.816    at Microsoft.Playwright.Transport.Connection.<InitializePlaywrightAsync>d__43.MoveNext() + 0x11b
0.816 --- End of stack trace from previous location ---
0.816    at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x1c
0.816    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xbe
0.816    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4e
0.816    at Microsoft.Playwright.Playwright.<CreateAsync>d__0.MoveNext() + 0x21d
0.816 --- End of stack trace from previous location ---
0.816    at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x1c
0.816    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xbe
0.816    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4e
0.816    at Program.<<Main>$>d__0.MoveNext() + 0xdf
0.816 --- End of stack trace from previous location ---
0.816    at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x1c
0.816    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xbe
0.816    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4e
0.816    at Program.<Main>(String[] args) + 0x24
0.816    at PayPowerBill!<BaseAddress>+0x2c672c```
mxschmitt commented 4 months ago

@matthewteeter AOT is not supported yet see here: https://github.com/microsoft/playwright-dotnet/issues/2714

mxschmitt commented 4 months ago

I'll close this issue, since this issue (sigle-file published program) has been resolved. See https://github.com/microsoft/playwright-dotnet/issues/2255#issuecomment-2056544386 for notes.