-
-
Notifications
You must be signed in to change notification settings - Fork 439
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce file chooser interception (#1244)
* Some progress * Some progress * Feature complete * cr * cr * Add missing ConfigureAwait
- Loading branch information
Showing
14 changed files
with
628 additions
and
19 deletions.
There are no files selected for viewing
33 changes: 33 additions & 0 deletions
33
lib/PuppeteerSharp.Tests/ChromiumSpecificTests/PageWaitForFileChooserTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Http; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace PuppeteerSharp.Tests.ChromiumSpecificTests | ||
{ | ||
[Collection("PuppeteerLoaderFixture collection")] | ||
public class PageWaitForFileChooserTests : PuppeteerPageBaseTest | ||
{ | ||
public PageWaitForFileChooserTests(ITestOutputHelper output) : base(output) | ||
{ | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldFailGracefullyWhenTryingToWorkWithFilechoosersWithinMultipleConnections() | ||
{ | ||
// 1. Launch a browser and connect to all pages. | ||
var originalBrowser = await Puppeteer.LaunchAsync(TestConstants.DefaultBrowserOptions()); | ||
await originalBrowser.PagesAsync(); | ||
// 2. Connect a remote browser and connect to first page. | ||
var remoteBrowser = await Puppeteer.ConnectAsync(new ConnectOptions | ||
{ | ||
BrowserWSEndpoint = originalBrowser.WebSocketEndpoint | ||
}); | ||
var page = (await remoteBrowser.PagesAsync())[0]; | ||
// 3. Make sure |page.waitForFileChooser()| does not work with multiclient. | ||
var ex = await Assert.ThrowsAsync<PuppeteerException>(() => page.WaitForFileChooserAsync()); | ||
Assert.Equal("File chooser handling does not work with multiple connections to the same page", ex.Message); | ||
await originalBrowser.CloseAsync(); | ||
} | ||
} | ||
} |
129 changes: 129 additions & 0 deletions
129
lib/PuppeteerSharp.Tests/InputTests/FileChooserAcceptTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using PuppeteerSharp.Mobile; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace PuppeteerSharp.Tests.InputTests | ||
{ | ||
[Collection("PuppeteerLoaderFixture collection")] | ||
public class FileChooserAcceptTests : PuppeteerPageBaseTest | ||
{ | ||
public FileChooserAcceptTests(ITestOutputHelper output) : base(output) | ||
{ | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldWorkWhenFileInputIsAttachedToDOM() | ||
{ | ||
await Page.SetContentAsync("<input type=file>"); | ||
var waitForTask = Page.WaitForFileChooserAsync(); | ||
|
||
await Task.WhenAll( | ||
waitForTask, | ||
Page.ClickAsync("input")); | ||
|
||
Assert.NotNull(waitForTask.Result); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldAcceptSingleFile() | ||
{ | ||
await Page.SetContentAsync("<input type=file oninput='javascript:console.timeStamp()'>"); | ||
var waitForTask = Page.WaitForFileChooserAsync(); | ||
var metricsTcs = new TaskCompletionSource<bool>(); | ||
|
||
await Task.WhenAll( | ||
waitForTask, | ||
Page.ClickAsync("input")); | ||
|
||
Page.Metrics += (sender, e) => metricsTcs.TrySetResult(true); | ||
|
||
await Task.WhenAll( | ||
waitForTask.Result.AcceptAsync(TestConstants.FileToUpload), | ||
metricsTcs.Task); | ||
|
||
Assert.Equal(1, await Page.QuerySelectorAsync("input").EvaluateFunctionAsync<int>("input => input.files.length")); | ||
Assert.Equal( | ||
"file-to-upload.txt", | ||
await Page.QuerySelectorAsync("input").EvaluateFunctionAsync<string>("input => input.files[0].name")); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldBeAbleToReadSelectedFile() | ||
{ | ||
await Page.SetContentAsync("<input type=file>"); | ||
_ = Page.WaitForFileChooserAsync().ContinueWith(t => t.Result.AcceptAsync(TestConstants.FileToUpload)); | ||
|
||
Assert.Equal( | ||
"contents of the file", | ||
await Page.QuerySelectorAsync("input").EvaluateFunctionAsync<string>(@"async picker => | ||
{ | ||
picker.click(); | ||
await new Promise(x => picker.oninput = x); | ||
const reader = new FileReader(); | ||
const promise = new Promise(fulfill => reader.onload = fulfill); | ||
reader.readAsText(picker.files[0]); | ||
return promise.then(() => reader.result); | ||
}")); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldBeAbleToResetSelectedFilesWithEmptyFileList() | ||
{ | ||
await Page.SetContentAsync("<input type=file>"); | ||
_ = Page.WaitForFileChooserAsync().ContinueWith(t => t.Result.AcceptAsync(TestConstants.FileToUpload)); | ||
|
||
Assert.Equal( | ||
1, | ||
await Page.QuerySelectorAsync("input").EvaluateFunctionAsync<int>(@"async picker => | ||
{ | ||
picker.click(); | ||
await new Promise(x => picker.oninput = x); | ||
return picker.files.length; | ||
}")); | ||
|
||
_ = Page.WaitForFileChooserAsync().ContinueWith(t => t.Result.AcceptAsync()); | ||
|
||
Assert.Equal( | ||
0, | ||
await Page.QuerySelectorAsync("input").EvaluateFunctionAsync<int>(@"async picker => | ||
{ | ||
picker.click(); | ||
await new Promise(x => picker.oninput = x); | ||
return picker.files.length; | ||
}")); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldNotAcceptMultipleFilesForSingleFileInput() | ||
{ | ||
await Page.SetContentAsync("<input type=file>"); | ||
var waitForTask = Page.WaitForFileChooserAsync(); | ||
|
||
await Task.WhenAll( | ||
waitForTask, | ||
Page.ClickAsync("input")); | ||
|
||
var ex = await Assert.ThrowsAsync<MessageException>(() => waitForTask.Result.AcceptAsync( | ||
"./assets/file-to-upload.txt", | ||
"./assets/pptr.png")); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldFailWhenAcceptingFileChooserTwice() | ||
{ | ||
await Page.SetContentAsync("<input type=file>"); | ||
var waitForTask = Page.WaitForFileChooserAsync(); | ||
|
||
await Task.WhenAll( | ||
waitForTask, | ||
Page.ClickAsync("input")); | ||
|
||
var fileChooser = waitForTask.Result; | ||
await fileChooser.AcceptAsync(); | ||
var ex = await Assert.ThrowsAsync<PuppeteerException>(() => waitForTask.Result.AcceptAsync()); | ||
Assert.Equal("Cannot accept FileChooser which is already handled!", ex.Message); | ||
} | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
lib/PuppeteerSharp.Tests/InputTests/FileChooserCancelTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using PuppeteerSharp.Mobile; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace PuppeteerSharp.Tests.InputTests | ||
{ | ||
[Collection("PuppeteerLoaderFixture collection")] | ||
public class FileChooserCancelTests : PuppeteerPageBaseTest | ||
{ | ||
public FileChooserCancelTests(ITestOutputHelper output) : base(output) | ||
{ | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldCancelDialog() | ||
{ | ||
// Consider file chooser canceled if we can summon another one. | ||
// There's no reliable way in WebPlatform to see that FileChooser was | ||
// canceled. | ||
await Page.SetContentAsync("<input type=file>"); | ||
var waitForTask = Page.WaitForFileChooserAsync(); | ||
|
||
await Task.WhenAll( | ||
waitForTask, | ||
Page.ClickAsync("input")); | ||
|
||
var fileChooser = waitForTask.Result; | ||
await fileChooser.CancelAsync(); | ||
|
||
await Task.WhenAll( | ||
Page.WaitForFileChooserAsync(), | ||
Page.ClickAsync("input")); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldFailWhenCancelingFileChooserTwice() | ||
{ | ||
await Page.SetContentAsync("<input type=file>"); | ||
var waitForTask = Page.WaitForFileChooserAsync(); | ||
|
||
await Task.WhenAll( | ||
waitForTask, | ||
Page.ClickAsync("input")); | ||
|
||
var fileChooser = waitForTask.Result; | ||
await fileChooser.CancelAsync(); | ||
|
||
var ex = await Assert.ThrowsAsync<PuppeteerException>(() => fileChooser.CancelAsync()); | ||
Assert.Equal("Cannot accept FileChooser which is already handled!", ex.Message); | ||
} | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
lib/PuppeteerSharp.Tests/InputTests/FileChooserIsMultipleTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using PuppeteerSharp.Mobile; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace PuppeteerSharp.Tests.InputTests | ||
{ | ||
[Collection("PuppeteerLoaderFixture collection")] | ||
public class FileChooserIsMultipleTests : PuppeteerPageBaseTest | ||
{ | ||
public FileChooserIsMultipleTests(ITestOutputHelper output) : base(output) | ||
{ | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldWorkForSingleFilePick() | ||
{ | ||
await Page.SetContentAsync("<input type=file>"); | ||
var waitForTask = Page.WaitForFileChooserAsync(); | ||
|
||
await Task.WhenAll( | ||
waitForTask, | ||
Page.ClickAsync("input")); | ||
|
||
Assert.False(waitForTask.Result.IsMultiple); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldWorkForMultiple() | ||
{ | ||
await Page.SetContentAsync("<input type=file multiple>"); | ||
var waitForTask = Page.WaitForFileChooserAsync(); | ||
|
||
await Task.WhenAll( | ||
waitForTask, | ||
Page.ClickAsync("input")); | ||
|
||
Assert.True(waitForTask.Result.IsMultiple); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldWorkForWebkitDirectory() | ||
{ | ||
await Page.SetContentAsync("<input type=file multiple webkitdirectory>"); | ||
var waitForTask = Page.WaitForFileChooserAsync(); | ||
|
||
await Task.WhenAll( | ||
waitForTask, | ||
Page.ClickAsync("input")); | ||
|
||
Assert.True(waitForTask.Result.IsMultiple); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
102 changes: 102 additions & 0 deletions
102
lib/PuppeteerSharp.Tests/InputTests/PageWaitForFileChooserTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using PuppeteerSharp.Mobile; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace PuppeteerSharp.Tests.InputTests | ||
{ | ||
[Collection("PuppeteerLoaderFixture collection")] | ||
public class PageWaitForFileChooserTests : PuppeteerPageBaseTest | ||
{ | ||
public PageWaitForFileChooserTests(ITestOutputHelper output) : base(output) | ||
{ | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldWorkWhenFileInputIsAttachedToDOM() | ||
{ | ||
await Page.SetContentAsync("<input type=file>"); | ||
var waitForTask = Page.WaitForFileChooserAsync(); | ||
|
||
await Task.WhenAll( | ||
waitForTask, | ||
Page.ClickAsync("input")); | ||
|
||
Assert.NotNull(waitForTask.Result); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldWorkWhenFileInputIsNotAttachedToDOM() | ||
{ | ||
var waitForTask = Page.WaitForFileChooserAsync(); | ||
|
||
await Task.WhenAll( | ||
waitForTask, | ||
Page.EvaluateFunctionAsync(@"() => | ||
{ | ||
const el = document.createElement('input'); | ||
el.type = 'file'; | ||
el.click(); | ||
}")); | ||
|
||
Assert.NotNull(waitForTask.Result); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldRespectTimeout() | ||
{ | ||
var ex = await Assert.ThrowsAsync<TimeoutException>(() => Page.WaitForFileChooserAsync(new WaitForFileChooserOptions | ||
{ | ||
Timeout = 1 | ||
})); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldRespectTimeoutWhenThereIsNoCustomTimeout() | ||
{ | ||
Page.DefaultTimeout = 1; | ||
var ex = await Assert.ThrowsAsync<TimeoutException>(() => Page.WaitForFileChooserAsync()); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldPrioritizeExactTimeoutOverDefaultTimeout() | ||
{ | ||
Page.DefaultTimeout = 0; | ||
var ex = await Assert.ThrowsAsync<TimeoutException>(() => Page.WaitForFileChooserAsync(new WaitForFileChooserOptions | ||
{ | ||
Timeout = 1 | ||
})); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldWorkWithNoTimeout() | ||
{ | ||
var waitForTask = Page.WaitForFileChooserAsync(new WaitForFileChooserOptions { Timeout = 0 }); | ||
|
||
await Task.WhenAll( | ||
waitForTask, | ||
Page.EvaluateFunctionAsync(@"() => setTimeout(() => | ||
{ | ||
const el = document.createElement('input'); | ||
el.type = 'file'; | ||
el.click(); | ||
}, 50)")); | ||
Assert.NotNull(waitForTask.Result); | ||
} | ||
|
||
[Fact] | ||
public async Task ShouldReturnTheSameFileChooserWhenThereAreManyWatchdogsSimultaneously() | ||
{ | ||
await Page.SetContentAsync("<input type=file>"); | ||
var fileChooserTask1 = Page.WaitForFileChooserAsync(); | ||
var fileChooserTask2 = Page.WaitForFileChooserAsync(); | ||
|
||
await Task.WhenAll( | ||
fileChooserTask1, | ||
fileChooserTask2, | ||
Page.QuerySelectorAsync("input").EvaluateFunctionAsync("input => input.click()")); | ||
Assert.Same(fileChooserTask1.Result, fileChooserTask2.Result); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.