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

[Question]: How to set up a custom driver path? (Does not work with ASP.NET 4.8) #1842

Closed smitbmx closed 2 years ago

smitbmx commented 2 years ago

Your question

Hi, I use the Playwright 1.16.1 with an ASP.NET NET Application (.NET Framework 4.8) on the WIndows machine. I would like to ship my application together with the next entities in the App_Data folder:

  1. A bundled browser - OK. I can set up a custom path via ExecutablePath of the BrowserTypeLaunchOptions class.
  2. Playwright driver - I don't see a needed API that allows me to set up a custom path for the Playwright driver (the .playwright folder).

Question: How to have a custom path for the .playwright folder?

What I tried: I see the BrowserTypeLaunchOptions class also contains the Env key-value property. I've tried to add the PLAYWRIGHT_DRIVER_PATH key with a custom path value but looks like it doesn't work.

Problem and what I can see: I have debugged the Playwright tool itself and discovered the next things:

The responsible class for the driver path is Microsoft.Playwright.Helpers.Patch which has the GetExecutablePath method. Please check the code with the 1-4 comments below:

internal static class Paths
    {
        internal static string GetExecutablePath()
        {
            //1 - The AppContexts.BaseDirectory for me is the root of the ASP.NET solution, at this level I can see the App_Data, bin folders etc.
            DirectoryInfo assemblyDirectory = new(AppContext.BaseDirectory);
            //2 - then there is a check which looking for the Microsoft.Playwright.dll at the previously mentioned path, but there is no such Playwright dll, because it's under the bin folder.
            if (!assemblyDirectory.Exists || !File.Exists(Path.Combine(assemblyDirectory.FullName, "Microsoft.Playwright.dll")))
            {
                //3 - the dll haven't found at the root of website and now code looking for the type. 
                //The type was found under the Temporary ASP.NET Files (the path is: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\13163ddd\37e5e286\assembly\dl3\.playwright\node).
                var assemblyLocation = typeof(Playwright).Assembly.Location;
                //4 - then the rest of the code relies on the assemblyDirectory variable which is the Temporary ASP.NET Files.
                // If manually add the .playwright folder there, my application works but I would like to avoid manually put the driver here.
                assemblyDirectory = new FileInfo(assemblyLocation).Directory;
            }

            string executableFile = GetPath(assemblyDirectory.FullName);
            if (File.Exists(executableFile))
            {
                return executableFile;
            }

            // if the above fails, we can assume we're in the nuget registry
            executableFile = GetPath(assemblyDirectory.Parent.Parent.FullName);
            if (File.Exists(executableFile))
            {
                return executableFile;
            }

            throw new PlaywrightException($"Driver not found: {executableFile}");
        }

Should this class be more flexible? Is there any other approach that I don't see? Thank you in advance! :) Please let me know if I should clarify something more.

pavelfeldman commented 2 years ago

Playwright will be looking for the driver next to the assembly. Does that not work for you?

smitbmx commented 2 years ago

Hi, @pavelfeldman, the problem is where the assembly is located, because Playwright looks for the assembly at the website root (Microsoft.Playwright.Helpers.Patch LIne 36: AppContext.BaseDirectory this is website root path for me), but not in the bin folder. Then it cannot find the Playwright assembly there, and via typeof(Playwright).Assembly.Location looks at the Temporary ASP.NET Files, hence if I put the .playwright folder there, it works, but I would like to avoid storing the folder under the ASP.NET Temporary folder.

So, in theory, I can put the Playwright.dll to the website root, but this is not the right approach I believe :)

mxschmitt commented 2 years ago

@smitbmx sorry for the late reply. Would it be possible that you could create a small demo project for us which demonstrates this issue in form of a GitHub repository? Thanks! Then its easier for us to dig into it.

smitbmx commented 2 years ago

Hi @mxschmitt, sure, I'll make it and let you know when it's ready.

smitbmx commented 2 years ago

Hi, @mxschmitt, there is the sample project as you've asked: https://github.com/smitbmx/DemoPlaywrightASPNET48

As I described previously, there is a workaround to add the .playwright folder under the Temporary ASP.NET Files, but I strongly would like to avoid it. It would be really nice to have a customizable path for the Playwright driver as if was done for the bundled browsers via ExecutablePath variable of the BrowserTypeLaunchOptions class. Then it gives the ability to keep the driver somewhere under the App_Data folder of the ASP.NET solutions. Please let me know if you have additional questions.

Jojoshua commented 2 years ago

I am checking out playright again(6 months later) after several failed attempts using it in NET 4.8 (https://github.com/microsoft/playwright-dotnet/issues/1694)

I am no longer getting the Microsoft.Bcl.AsyncInterfaces error but on a clean 4.8 console project, the app still fails to run.

_Microsoft.Playwright.PlaywrightException: 'Driver not found: C:\Users\user\Source\Repos\PlaywriteTest2.playwright\node\win32x64\playwright.cmd'

I did copy the .playright folder from packages\Microsoft.Playwright.1.18.1 into the root of the console app and it started working but we can't move forward with that solution. Being able to specify a custom driver path might be a nice to have but at a minimum on NET 4.8 this needs to by default reference the installed location under packages or wherever the nuget restore/install resides.

As a side note, I went to https://playwright.dev/dotnet/docs/intro#first-project to see if I was missing a step and there is no acknowledgement of a 4.8 install

vandre commented 2 years ago

I am checking out playright again(6 months later) after several failed attempts using it in NET 4.8 (#1694)

I am no longer getting the Microsoft.Bcl.AsyncInterfaces error but on a clean 4.8 console project, the app still fails to run.

_Microsoft.Playwright.PlaywrightException: 'Driver not found: C:\Users\user\Source\Repos\PlaywriteTest2.playwright\node\win32x64\playwright.cmd'

I did copy the .playright folder from packages\Microsoft.Playwright.1.18.1 into the root of the console app and it started working but we can't move forward with that solution. Being able to specify a custom driver path might be a nice to have but at a minimum on NET 4.8 this needs to by default reference the installed location under packages or wherever the nuget restore/install resides.

As a side note, I went to https://playwright.dev/dotnet/docs/intro#first-project to see if I was missing a step and there is no acknowledgement of a 4.8 install

@Jojoshua I got Playwright working with .Net 4.8 Take a look at my comments on this issue (#1797):

https://github.com/microsoft/playwright-dotnet/issues/1797#issuecomment-982841808

Basically to be able to use Playwright in 4.8 you need to use PackageReference instead of packages.config as well as convert your .CSProj file to the SDK-style Project format

vandre commented 2 years ago

+1 for the ability to specify a custom driver path, similarly to how we can specify the browser's binaries path with $env:PLAYWRIGHT_BROWSERS_PATH="c:\common\pw-browsers"

Something like:

$env:PLAYWRIGHT_DRIVER_PATH="c:\common\pw-driver"

My use-case is leveraging Playwright to generate custom PDF reports in a sandbox-like environment. Everytime a new report is generated a new sandbox is set-up and it is impractical to copy hundreds of megabytes every time.

Jojoshua commented 2 years ago

I am checking out playright again(6 months later) after several failed attempts using it in NET 4.8 (#1694) I am no longer getting the Microsoft.Bcl.AsyncInterfaces error but on a clean 4.8 console project, the app still fails to run. _Microsoft.Playwright.PlaywrightException: 'Driver not found: C:\Users\user\Source\Repos\PlaywriteTest2.playwright\node\win32x64\playwright.cmd' I did copy the .playright folder from packages\Microsoft.Playwright.1.18.1 into the root of the console app and it started working but we can't move forward with that solution. Being able to specify a custom driver path might be a nice to have but at a minimum on NET 4.8 this needs to by default reference the installed location under packages or wherever the nuget restore/install resides. As a side note, I went to https://playwright.dev/dotnet/docs/intro#first-project to see if I was missing a step and there is no acknowledgement of a 4.8 install

@Jojoshua I got Playwright working with .Net 4.8 Take a look at my comments on this issue (#1797):

#1797 (comment)

Basically to be able to use Playwright in 4.8 you need to use PackageReference instead of packages.config as well as convert your .CSProj file to the SDK-style Project format

Thanks for this tip @vandre . That did work for my test project but I am afraid my real (years old) application can't migrate to use the PackageReference. Since this seems to be a specific oversight in the tooling I will create a new issue.

KyleCrowley commented 2 years ago

Is there any update on this issue? I'm currently using PlaywrightSharp, but as noted in the NuGet page for the PlaywrightSharp, it has been deprecated in favor of Microsoft.Playwright.

Previously I was able to specify the driver executable path like so:

var playwright = Playwright.CreateAsync(driverExecutablePath: "...");

Without the ability to specify a driver executable path, unfortunately, I'm blocked from migrating to Microsoft.Playwright.

mxschmitt commented 2 years ago

Closing since it seem stale.

The logic how the driver gets terminated and where it gets placed has been reworked over the last few months. So it should not yield into that anymore.

If you still encounter issues, please file a new issue with a repro attached in form of a GitHub repository.

BeniFreitag commented 2 years ago

Just tested Playwright v1.24.1 with ASP.Net 4.8 on Windows 11 and Windows Server 2019, it still looks for the .playwright folder in Temporary ASP.NET Files. When I copy the .playwright to there, it works.

Exception:

Driver not found: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\2a24f152\658d0bda\assembly\dl3\.playwright\node\win32_x64\playwright.cmd
   at Microsoft.Playwright.Helpers.Driver.GetExecutablePath() in /_/src/Playwright/Helpers/Driver.cs:line 57
   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>d__0.MoveNext() in /_/src/Playwright/Playwright.cs:line 44
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at ToReserve.Services.PdfService.<GetPdfAsync>d__3.MoveNext() in C:\Projects\2reserve Universal\ToReserve\Services\PdfService.cs:line 20