diff --git a/lib/CLAUDE.md b/lib/CLAUDE.md
index 864b18161..754ff46cc 100644
--- a/lib/CLAUDE.md
+++ b/lib/CLAUDE.md
@@ -14,6 +14,12 @@ You are allowed to run git commands to update these repositories locally.
- Original Puppeteer repository: ../../puppeteer/puppeteer. Every time "upstream" is mentioned we are referring to this code.
- Bidi Driver: ../../webdriverbidi-net/webdriverbidi-net
+## Upstream code structure
+
+- Code in upstream puppeteer-core/src/api/* are our abstract class. For instance our public abstract class Frame.
+- Code in upstream puppeteer-core/src/bidi/* are our Bidi* classes.
+- Code in upstream puppeteer-core/src/cdp/* are our Cdp* classes.
+
## Project Structure
```
@@ -380,6 +386,7 @@ Test directory structure demonstrates comprehensive coverage:
- Headless mode variations (headless, headful, headless-shell)
- Local and upstream expectation merging
- Tests should always match the code in upstream. Tests should never be changed to match the code local code.
+
#### Test Server (`PuppeteerSharp.TestServer/`)
- ASP.NET Core server for hosting test pages
- wwwroot directory with test fixtures
diff --git a/lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json b/lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json
index c93e1c722..fc49af62c 100644
--- a/lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json
+++ b/lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json
@@ -900,21 +900,6 @@
"FAIL"
]
},
- {
- "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
- "testIdPattern": "[page.spec] *Page.addScriptTag*",
- "platforms": [
- "darwin",
- "linux",
- "win32"
- ],
- "parameters": [
- "webDriverBiDi"
- ],
- "expectations": [
- "FAIL"
- ]
- },
{
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
"testIdPattern": "[page.spec] *addStyleTag*",
diff --git a/lib/PuppeteerSharp.Tests/PageTests/AddScriptTagTests.cs b/lib/PuppeteerSharp.Tests/PageTests/AddScriptTagTests.cs
index 80f805533..6a71a0010 100644
--- a/lib/PuppeteerSharp.Tests/PageTests/AddScriptTagTests.cs
+++ b/lib/PuppeteerSharp.Tests/PageTests/AddScriptTagTests.cs
@@ -8,10 +8,6 @@ namespace PuppeteerSharp.Tests.PageTests
{
public class AddScriptTagTests : PuppeteerPageBaseTest
{
- public AddScriptTagTests() : base()
- {
- }
-
[Test, PuppeteerTest("page.spec", "Page Page.addScriptTag", "should throw an error if no options are provided")]
public void ShouldThrowAnErrorIfNoOptionsAreProvided()
{
diff --git a/lib/PuppeteerSharp/Bidi/BidiFrame.cs b/lib/PuppeteerSharp/Bidi/BidiFrame.cs
index bc98d2e54..55884a540 100644
--- a/lib/PuppeteerSharp/Bidi/BidiFrame.cs
+++ b/lib/PuppeteerSharp/Bidi/BidiFrame.cs
@@ -97,9 +97,6 @@ internal BidiPage BidiPage
///
public override Task AddStyleTagAsync(AddTagOptions options) => throw new System.NotImplementedException();
- ///
- public override Task AddScriptTagAsync(AddTagOptions options) => throw new System.NotImplementedException();
-
///
public override async Task SetContentAsync(string html, NavigationOptions options = null)
{
diff --git a/lib/PuppeteerSharp/Bidi/BidiRealm.cs b/lib/PuppeteerSharp/Bidi/BidiRealm.cs
index ef316647d..6c503bcb1 100644
--- a/lib/PuppeteerSharp/Bidi/BidiRealm.cs
+++ b/lib/PuppeteerSharp/Bidi/BidiRealm.cs
@@ -214,7 +214,7 @@ private async Task EvaluateAsync(bool returnByValue, bool
if (result.ResultType == EvaluateResultType.Exception)
{
// TODO: Improve text details
- throw new EvaluateException(((EvaluateResultException)result).ExceptionDetails.Text);
+ throw new EvaluationFailedException(((EvaluateResultException)result).ExceptionDetails.Text);
}
return result as EvaluateResultSuccess;
diff --git a/lib/PuppeteerSharp/Cdp/CdpFrame.cs b/lib/PuppeteerSharp/Cdp/CdpFrame.cs
index e84c47d1a..d25032bef 100644
--- a/lib/PuppeteerSharp/Cdp/CdpFrame.cs
+++ b/lib/PuppeteerSharp/Cdp/CdpFrame.cs
@@ -243,72 +243,6 @@ public override async Task AddStyleTagAsync(AddTagOptions option
return (await MainRealm.TransferHandleAsync(handle).ConfigureAwait(false)) as IElementHandle;
}
- ///
- public override async Task AddScriptTagAsync(AddTagOptions options)
- {
- if (options == null)
- {
- throw new ArgumentNullException(nameof(options));
- }
-
- if (string.IsNullOrEmpty(options.Url) && string.IsNullOrEmpty(options.Path) &&
- string.IsNullOrEmpty(options.Content))
- {
- throw new ArgumentException("Provide options with a `Url`, `Path` or `Content` property");
- }
-
- var content = options.Content;
-
- if (!string.IsNullOrEmpty(options.Path))
- {
- content = await AsyncFileHelper.ReadAllText(options.Path).ConfigureAwait(false);
- content += "//# sourceURL=" + options.Path.Replace("\n", string.Empty);
- }
-
- var handle = await IsolatedRealm.EvaluateFunctionHandleAsync(
- @"async (puppeteerUtil, url, id, type, content) => {
- const createDeferredPromise = puppeteerUtil.createDeferredPromise;
- const promise = createDeferredPromise();
- const script = document.createElement('script');
- script.type = type;
- script.text = content;
- if (url) {
- script.src = url;
- script.addEventListener(
- 'load',
- () => {
- return promise.resolve();
- },
- {once: true}
- );
- script.addEventListener(
- 'error',
- event => {
- promise.reject(
- new Error(event.message ?? 'Could not load script')
- );
- },
- {once: true}
- );
- } else {
- promise.resolve();
- }
- if (id) {
- script.id = id;
- }
- document.head.appendChild(script);
- await promise;
- return script;
- }",
- new LazyArg(async context => await context.GetPuppeteerUtilAsync().ConfigureAwait(false)),
- options.Url,
- options.Id,
- options.Type,
- content).ConfigureAwait(false);
-
- return (await MainRealm.TransferHandleAsync(handle).ConfigureAwait(false)) as IElementHandle;
- }
-
internal void UpdateClient(CDPSession client, bool keepWorlds = false)
{
Client = client;
diff --git a/lib/PuppeteerSharp/Frame.cs b/lib/PuppeteerSharp/Frame.cs
index c96b3d6f6..273cae4fc 100644
--- a/lib/PuppeteerSharp/Frame.cs
+++ b/lib/PuppeteerSharp/Frame.cs
@@ -3,6 +3,7 @@
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
+using PuppeteerSharp.Helpers;
using PuppeteerSharp.Input;
using PuppeteerSharp.QueryHandlers;
@@ -196,14 +197,77 @@ public async Task XPathAsync(string expression)
}
///
- public Task WaitForDevicePromptAsync(WaitForOptions options = default)
+ public Task WaitForDevicePromptAsync(WaitForOptions options = null)
=> GetDeviceRequestPromptManager().WaitForDevicePromptAsync(options);
///
public abstract Task AddStyleTagAsync(AddTagOptions options);
///
- public abstract Task AddScriptTagAsync(AddTagOptions options);
+ public async Task AddScriptTagAsync(AddTagOptions options)
+ {
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ if (string.IsNullOrEmpty(options.Url) && string.IsNullOrEmpty(options.Path) &&
+ string.IsNullOrEmpty(options.Content))
+ {
+ throw new ArgumentException("Provide options with a `Url`, `Path` or `Content` property");
+ }
+
+ var content = options.Content;
+
+ if (!string.IsNullOrEmpty(options.Path))
+ {
+ content = await AsyncFileHelper.ReadAllText(options.Path).ConfigureAwait(false);
+ content += "//# sourceURL=" + options.Path.Replace("\n", string.Empty);
+ }
+
+ var handle = await IsolatedRealm.EvaluateFunctionHandleAsync(
+ @"async (puppeteerUtil, url, id, type, content) => {
+ const createDeferredPromise = puppeteerUtil.createDeferredPromise;
+ const promise = createDeferredPromise();
+ const script = document.createElement('script');
+ script.type = type;
+ script.text = content;
+ if (url) {
+ script.src = url;
+ script.addEventListener(
+ 'load',
+ () => {
+ return promise.resolve();
+ },
+ {once: true}
+ );
+ script.addEventListener(
+ 'error',
+ event => {
+ promise.reject(
+ new Error(event.message ?? 'Could not load script')
+ );
+ },
+ {once: true}
+ );
+ } else {
+ promise.resolve();
+ }
+ if (id) {
+ script.id = id;
+ }
+ document.head.appendChild(script);
+ await promise;
+ return script;
+ }",
+ new LazyArg(async context => await context.GetPuppeteerUtilAsync().ConfigureAwait(false)),
+ options.Url,
+ options.Id,
+ options.Type,
+ content).ConfigureAwait(false);
+
+ return (await MainRealm.TransferHandleAsync(handle).ConfigureAwait(false)) as IElementHandle;
+ }
///
public Task GetContentAsync(GetContentOptions options = null)