Run E2E tests for server execution as well as WebAssembly. Fixes several
server-execution bugs uncovered by the E2E tests.
This commit is contained in:
Родитель
4708aa4f06
Коммит
90cf6ce5a7
|
@ -17,7 +17,7 @@ function boot() {
|
|||
});
|
||||
|
||||
connection = new signalR.HubConnectionBuilder()
|
||||
.withUrl('/_blazor')
|
||||
.withUrl('_blazor')
|
||||
.withHubProtocol(new MessagePackHubProtocol())
|
||||
.configureLogging(signalR.LogLevel.Information)
|
||||
.build();
|
||||
|
|
|
@ -118,7 +118,8 @@ class OutOfProcessRenderTreeFrameReader implements RenderTreeFrameReader {
|
|||
}
|
||||
|
||||
elementReferenceCaptureId(frame: RenderTreeFrame) {
|
||||
return readInt32LE(this.batchDataUint8, frame as any + 4); // 2nd int
|
||||
const stringIndex = readInt32LE(this.batchDataUint8, frame as any + 4); // 2nd int
|
||||
return this.stringReader.readString(stringIndex);
|
||||
}
|
||||
|
||||
componentId(frame: RenderTreeFrame) {
|
||||
|
@ -159,14 +160,15 @@ class OutOfProcessStringReader {
|
|||
}
|
||||
|
||||
readString(index: number): string | null {
|
||||
const stringTableEntry = readInt32LE(this.batchDataUint8, this.stringTableStartIndex + index * stringTableEntryLength);
|
||||
if (stringTableEntry === -1) { // Special value encodes 'null'
|
||||
if (index === -1) { // Special value encodes 'null'
|
||||
return null;
|
||||
} else {
|
||||
const stringTableEntryPos = readInt32LE(this.batchDataUint8, this.stringTableStartIndex + index * stringTableEntryLength);
|
||||
|
||||
// By default, .NET's BinaryWriter gives LEB128-length-prefixed UTF-8 data.
|
||||
// This is convenient enough to decode in JavaScript.
|
||||
const numUtf8Bytes = readLEB128(this.batchDataUint8, stringTableEntry);
|
||||
const charsStart = stringTableEntry + numLEB128Bytes(numUtf8Bytes);
|
||||
const numUtf8Bytes = readLEB128(this.batchDataUint8, stringTableEntryPos);
|
||||
const charsStart = stringTableEntryPos + numLEB128Bytes(numUtf8Bytes);
|
||||
const utf8Data = new DataView(
|
||||
this.batchDataUint8.buffer,
|
||||
this.batchDataUint8.byteOffset + charsStart,
|
||||
|
|
|
@ -138,7 +138,21 @@ namespace Microsoft.AspNetCore.Blazor.Server.Circuits
|
|||
{
|
||||
case RenderTreeFrameType.Attribute:
|
||||
WriteString(frame.AttributeName);
|
||||
WriteString(frame.AttributeValue as string);
|
||||
if (frame.AttributeValue is bool boolValue)
|
||||
{
|
||||
// Encoding the bool as either "" or null is pretty odd, but avoids
|
||||
// having to pack any "what type of thing is this" info into the same
|
||||
// 4 bytes as the string table index. If, later, we need a way of
|
||||
// distinguishing whether an attribute value is really a bool or a string
|
||||
// or something else, we'll need a different encoding mechanism. Since there
|
||||
// would never be more than (say) 2^28 (268 million) distinct string table
|
||||
// entries, we could use the first 4 bits to encode the value type.
|
||||
WriteString(boolValue ? string.Empty : null);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteString(frame.AttributeValue as string);
|
||||
}
|
||||
_binaryWriter.Write(frame.AttributeEventHandlerId);
|
||||
break;
|
||||
case RenderTreeFrameType.Component:
|
||||
|
|
|
@ -72,14 +72,25 @@ namespace Microsoft.JSInterop
|
|||
? null
|
||||
: jsRuntimeBaseInstance.ArgSerializerStrategy.FindDotNetObject(dotNetObjectId);
|
||||
|
||||
var syncResult = InvokeSynchronously(assemblyName, methodIdentifier, targetInstance, argsJson);
|
||||
object syncResult = null;
|
||||
Exception syncException = null;
|
||||
|
||||
try
|
||||
{
|
||||
syncResult = InvokeSynchronously(assemblyName, methodIdentifier, targetInstance, argsJson);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
syncException = ex;
|
||||
}
|
||||
|
||||
// If there was no callId, the caller does not want to be notified about the result
|
||||
if (callId != null)
|
||||
{
|
||||
// Invoke and coerce the result to a Task so the caller can use the same async API
|
||||
// for both synchronous and asynchronous methods
|
||||
var task = syncResult is Task syncResultTask ? syncResultTask : Task.FromResult(syncResult);
|
||||
var task = CoerceToTask(syncResult, syncException);
|
||||
|
||||
task.ContinueWith(completedTask =>
|
||||
{
|
||||
try
|
||||
|
@ -96,6 +107,22 @@ namespace Microsoft.JSInterop
|
|||
}
|
||||
}
|
||||
|
||||
private static Task CoerceToTask(object syncResult, Exception syncException)
|
||||
{
|
||||
if (syncException != null)
|
||||
{
|
||||
return Task.FromException(syncException);
|
||||
}
|
||||
else if (syncResult is Task syncResultTask)
|
||||
{
|
||||
return syncResultTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Task.FromResult(syncResult);
|
||||
}
|
||||
}
|
||||
|
||||
private static object InvokeSynchronously(string assemblyName, string methodIdentifier, object targetInstance, string argsJson)
|
||||
{
|
||||
if (targetInstance != null)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using BasicTestApp;
|
||||
|
@ -11,13 +11,14 @@ using Xunit.Abstractions;
|
|||
|
||||
namespace Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure
|
||||
{
|
||||
public class BasicTestAppTestBase : ServerTestBase<DevHostServerFixture<Program>>
|
||||
public class BasicTestAppTestBase : ServerTestBase<ToggleExecutionModeServerFixture<Program>>
|
||||
{
|
||||
public const string ServerPathBase = "/subdir";
|
||||
public string ServerPathBase
|
||||
=> "/subdir" + (_serverFixture.UsingAspNetHost ? "#server" : "");
|
||||
|
||||
public BasicTestAppTestBase(
|
||||
BrowserFixture browserFixture,
|
||||
DevHostServerFixture<Program> serverFixture,
|
||||
ToggleExecutionModeServerFixture<Program> serverFixture,
|
||||
ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture, output)
|
||||
{
|
||||
|
@ -27,19 +28,18 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure
|
|||
protected IWebElement MountTestComponent<TComponent>() where TComponent : IComponent
|
||||
{
|
||||
var componentTypeName = typeof(TComponent).FullName;
|
||||
WaitUntilDotNetRunningInBrowser();
|
||||
((IJavaScriptExecutor)Browser).ExecuteScript(
|
||||
$"mountTestComponent('{componentTypeName}')");
|
||||
var testSelector = WaitUntilTestSelectorReady();
|
||||
testSelector.SelectByValue("none");
|
||||
testSelector.SelectByValue(componentTypeName);
|
||||
return Browser.FindElement(By.TagName("app"));
|
||||
}
|
||||
|
||||
protected void WaitUntilDotNetRunningInBrowser()
|
||||
protected SelectElement WaitUntilTestSelectorReady()
|
||||
{
|
||||
new WebDriverWait(Browser, TimeSpan.FromSeconds(30)).Until(driver =>
|
||||
{
|
||||
return ((IJavaScriptExecutor)driver)
|
||||
.ExecuteScript("return window.isTestReady;");
|
||||
});
|
||||
var elemToFind = By.CssSelector("#test-selector > select");
|
||||
new WebDriverWait(Browser, TimeSpan.FromSeconds(30)).Until(
|
||||
driver => driver.FindElement(elemToFind) != null);
|
||||
return new SelectElement(Browser.FindElement(elemToFind));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure
|
|||
try
|
||||
{
|
||||
var driver = new RemoteWebDriver(opts);
|
||||
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(1);
|
||||
Browser = driver;
|
||||
Logs = new RemoteLogs(driver);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure.ServerFixtures
|
||||
{
|
||||
public class ToggleExecutionModeServerFixture<TClientProgram>
|
||||
: ServerFixture
|
||||
{
|
||||
public string PathBase { get; set; }
|
||||
public bool UsingAspNetHost { get; private set; }
|
||||
|
||||
private AspNetSiteServerFixture.BuildWebHost _buildWebHostMethod;
|
||||
private IDisposable _serverToDispose;
|
||||
|
||||
public void UseAspNetHost(AspNetSiteServerFixture.BuildWebHost buildWebHostMethod)
|
||||
{
|
||||
_buildWebHostMethod = buildWebHostMethod
|
||||
?? throw new ArgumentNullException(nameof(buildWebHostMethod));
|
||||
UsingAspNetHost = true;
|
||||
}
|
||||
|
||||
protected override string StartAndGetRootUri()
|
||||
{
|
||||
if (_buildWebHostMethod == null)
|
||||
{
|
||||
// Use Blazor's dev host server
|
||||
var underlying = new DevHostServerFixture<TClientProgram>();
|
||||
underlying.PathBase = PathBase;
|
||||
_serverToDispose = underlying;
|
||||
return underlying.RootUri.AbsoluteUri;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use specified ASP.NET host server
|
||||
var underlying = new AspNetSiteServerFixture();
|
||||
underlying.BuildWebHostMethod = _buildWebHostMethod;
|
||||
_serverToDispose = underlying;
|
||||
return underlying.RootUri.AbsoluteUri;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_serverToDispose.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure.ServerFixtures;
|
||||
|
@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure
|
|||
: BrowserTestBase, IClassFixture<TServerFixture>
|
||||
where TServerFixture: ServerFixture
|
||||
{
|
||||
private readonly TServerFixture _serverFixture;
|
||||
protected readonly TServerFixture _serverFixture;
|
||||
|
||||
public ServerTestBase(BrowserFixture browserFixture, TServerFixture serverFixture, ITestOutputHelper output)
|
||||
: base(browserFixture, output)
|
||||
|
@ -33,6 +33,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure
|
|||
}
|
||||
}
|
||||
|
||||
Browser.Navigate().GoToUrl("about:blank");
|
||||
Browser.Navigate().GoToUrl(absoluteUrl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure
|
||||
{
|
||||
// XUnit assertions, but hooked into Selenium's polling mechanism
|
||||
|
||||
public class WaitAssert
|
||||
{
|
||||
private readonly static TimeSpan DefaultTimeout = TimeSpan.FromSeconds(1);
|
||||
|
||||
public static void Equal<T>(T expected, Func<T> actual)
|
||||
=> WaitAssertCore(() => Assert.Equal(expected, actual()));
|
||||
|
||||
public static void True(Func<bool> actual)
|
||||
=> WaitAssertCore(() => Assert.True(actual()));
|
||||
|
||||
public static void False(Func<bool> actual)
|
||||
=> WaitAssertCore(() => Assert.False(actual()));
|
||||
|
||||
public static void Contains(string expectedSubstring, Func<string> actualString)
|
||||
=> WaitAssertCore(() => Assert.Contains(expectedSubstring, actualString()));
|
||||
|
||||
public static void Collection<T>(Func<IEnumerable<T>> actualValues, params Action<T>[] elementInspectors)
|
||||
=> WaitAssertCore(() => Assert.Collection(actualValues(), elementInspectors));
|
||||
|
||||
public static void Empty(Func<IEnumerable> actualValues)
|
||||
=> WaitAssertCore(() => Assert.Empty(actualValues()));
|
||||
|
||||
public static void Single(Func<IEnumerable> actualValues)
|
||||
=> WaitAssertCore(() => Assert.Single(actualValues()));
|
||||
|
||||
private static void WaitAssertCore(Action assertion, TimeSpan timeout = default)
|
||||
{
|
||||
if (timeout == default)
|
||||
{
|
||||
timeout = DefaultTimeout;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
new WebDriverWait(BrowserTestBase.Browser, timeout).Until(_ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
assertion();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (WebDriverTimeoutException)
|
||||
{
|
||||
// Instead of reporting it as a timeout, report the Xunit exception
|
||||
assertion();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure.ServerFixtures;
|
||||
|
||||
namespace Microsoft.AspNetCore.Blazor.E2ETest.ServerExecutionTests
|
||||
{
|
||||
internal static class ServerExecutionTestExtensions
|
||||
{
|
||||
public static ToggleExecutionModeServerFixture<T> WithServerExecution<T>(this ToggleExecutionModeServerFixture<T> serverFixture)
|
||||
{
|
||||
serverFixture.UseAspNetHost(TestServer.Program.BuildWebHost);
|
||||
return serverFixture;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,23 +10,20 @@ using System.Linq;
|
|||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
||||
namespace Microsoft.AspNetCore.Blazor.E2ETest.ServerExecutionTests
|
||||
{
|
||||
public class ServerSideBlazorTest : ServerTestBase<AspNetSiteServerFixture>, IDisposable
|
||||
public class ServerSideAppTest : ServerTestBase<AspNetSiteServerFixture>
|
||||
{
|
||||
private readonly AspNetSiteServerFixture _serverFixture;
|
||||
|
||||
public ServerSideBlazorTest(
|
||||
public ServerSideAppTest(
|
||||
BrowserFixture browserFixture,
|
||||
AspNetSiteServerFixture serverFixture,
|
||||
ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture, output)
|
||||
{
|
||||
_serverFixture = serverFixture;
|
||||
_serverFixture.Environment = AspNetEnvironment.Development;
|
||||
_serverFixture.BuildWebHostMethod = ServerSideBlazor.Server.Program.BuildWebHost;
|
||||
|
||||
Navigate("/", noReload: true);
|
||||
Navigate("/", noReload: false);
|
||||
WaitUntilLoaded();
|
||||
}
|
||||
|
||||
|
@ -58,13 +55,13 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
Browser.FindElement(By.LinkText("Counter")).Click();
|
||||
|
||||
// Verify we're now on the counter page, with that nav link (only) highlighted
|
||||
Assert.Equal("Counter", Browser.FindElement(mainHeaderSelector).Text);
|
||||
WaitAssert.Equal("Counter", () => Browser.FindElement(mainHeaderSelector).Text);
|
||||
Assert.Collection(Browser.FindElements(activeNavLinksSelector),
|
||||
item => Assert.Equal("Counter", item.Text));
|
||||
|
||||
// Verify we can navigate back to home too
|
||||
Browser.FindElement(By.LinkText("Home")).Click();
|
||||
Assert.Equal("Hello, world!", Browser.FindElement(mainHeaderSelector).Text);
|
||||
WaitAssert.Equal("Hello, world!", () => Browser.FindElement(mainHeaderSelector).Text);
|
||||
Assert.Collection(Browser.FindElements(activeNavLinksSelector),
|
||||
item => Assert.Equal("Home", item.Text));
|
||||
}
|
||||
|
@ -74,7 +71,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
{
|
||||
// Navigate to "Counter"
|
||||
Browser.FindElement(By.LinkText("Counter")).Click();
|
||||
Assert.Equal("Counter", Browser.FindElement(By.TagName("h1")).Text);
|
||||
WaitAssert.Equal("Counter", () => Browser.FindElement(By.TagName("h1")).Text);
|
||||
|
||||
// Observe the initial value is zero
|
||||
var countDisplayElement = Browser.FindElement(By.CssSelector("h1 + p"));
|
||||
|
@ -83,17 +80,19 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// Click the button; see it counts
|
||||
var button = Browser.FindElement(By.CssSelector(".main button"));
|
||||
button.Click();
|
||||
WaitAssert.Equal("Current count: 1", () => countDisplayElement.Text);
|
||||
button.Click();
|
||||
WaitAssert.Equal("Current count: 2", () => countDisplayElement.Text);
|
||||
button.Click();
|
||||
Assert.Equal("Current count: 3", countDisplayElement.Text);
|
||||
WaitAssert.Equal("Current count: 3", () => countDisplayElement.Text);
|
||||
}
|
||||
|
||||
[Fact(Skip = "This is failing and I don't know why")]
|
||||
[Fact]
|
||||
public void HasFetchDataPage()
|
||||
{
|
||||
// Navigate to "Fetch Data"
|
||||
Browser.FindElement(By.LinkText("Fetch data")).Click();
|
||||
Assert.Equal("Weather forecast", Browser.FindElement(By.TagName("h1")).Text);
|
||||
WaitAssert.Equal("Weather forecast", () => Browser.FindElement(By.TagName("h1")).Text);
|
||||
|
||||
// Wait until loaded
|
||||
var tableSelector = By.CssSelector("table.table");
|
||||
|
@ -115,12 +114,5 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
new WebDriverWait(Browser, TimeSpan.FromSeconds(30)).Until(
|
||||
driver => driver.FindElement(By.TagName("app")).Text != "Loading...");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Make the tests run faster by navigating back to the home page when we are done
|
||||
// If we don't, then the next test will reload the whole page before it starts
|
||||
Browser.FindElement(By.LinkText("Home")).Click();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using BasicTestApp;
|
||||
using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure;
|
||||
using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure.ServerFixtures;
|
||||
using Microsoft.AspNetCore.Blazor.E2ETest.Tests;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNetCore.Blazor.E2ETest.ServerExecutionTests
|
||||
{
|
||||
public class ServerComponentRenderingTest : ComponentRenderingTest
|
||||
{
|
||||
public ServerComponentRenderingTest(BrowserFixture browserFixture, ToggleExecutionModeServerFixture<Program> serverFixture, ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture.WithServerExecution(), output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerBindTest : BindTest
|
||||
{
|
||||
public ServerBindTest(BrowserFixture browserFixture, ToggleExecutionModeServerFixture<Program> serverFixture, ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture.WithServerExecution(), output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerEventBubblingTest : EventBubblingTest
|
||||
{
|
||||
public ServerEventBubblingTest(BrowserFixture browserFixture, ToggleExecutionModeServerFixture<Program> serverFixture, ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture.WithServerExecution(), output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerEventTest : EventTest
|
||||
{
|
||||
public ServerEventTest(BrowserFixture browserFixture, ToggleExecutionModeServerFixture<Program> serverFixture, ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture.WithServerExecution(), output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerInteropTest : InteropTest
|
||||
{
|
||||
public ServerInteropTest(BrowserFixture browserFixture, ToggleExecutionModeServerFixture<Program> serverFixture, ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture.WithServerExecution(), output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerRoutingTest : RoutingTest
|
||||
{
|
||||
public ServerRoutingTest(BrowserFixture browserFixture, ToggleExecutionModeServerFixture<Program> serverFixture, ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture.WithServerExecution(), output)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using BasicTestApp.HttpClientTest;
|
||||
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
public BinaryHttpClientTest(
|
||||
BrowserFixture browserFixture,
|
||||
DevHostServerFixture<BasicTestApp.Program> devHostServerFixture,
|
||||
ToggleExecutionModeServerFixture<BasicTestApp.Program> devHostServerFixture,
|
||||
AspNetSiteServerFixture apiServerFixture,
|
||||
ITestOutputHelper output)
|
||||
: base(browserFixture, devHostServerFixture, output)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using BasicTestApp;
|
||||
|
@ -14,12 +14,13 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
public class BindTest : BasicTestAppTestBase
|
||||
{
|
||||
public BindTest(
|
||||
BrowserFixture browserFixture,
|
||||
DevHostServerFixture<Program> serverFixture,
|
||||
BrowserFixture browserFixture,
|
||||
ToggleExecutionModeServerFixture<Program> serverFixture,
|
||||
ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture, output)
|
||||
{
|
||||
Navigate(ServerPathBase, noReload: true);
|
||||
// On WebAssembly, page reloads are expensive so skip if possible
|
||||
Navigate(ServerPathBase, noReload: !serverFixture.UsingAspNetHost);
|
||||
MountTestComponent<BindCasesComponent>();
|
||||
}
|
||||
|
||||
|
@ -39,12 +40,12 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
Assert.Equal(string.Empty, boundValue.Text); // Doesn't update until change event
|
||||
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
|
||||
target.SendKeys("\t");
|
||||
Assert.Equal("Changed value", boundValue.Text);
|
||||
WaitAssert.Equal("Changed value", () => boundValue.Text);
|
||||
Assert.Equal("Changed value", mirrorValue.GetAttribute("value"));
|
||||
|
||||
// Remove the value altogether
|
||||
setNullButton.Click();
|
||||
Assert.Equal(string.Empty, target.GetAttribute("value"));
|
||||
WaitAssert.Equal(string.Empty, () => target.GetAttribute("value"));
|
||||
Assert.Equal(string.Empty, boundValue.Text);
|
||||
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
|
||||
}
|
||||
|
@ -63,12 +64,12 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||
target.Clear();
|
||||
target.SendKeys("Changed value\t");
|
||||
Assert.Equal("Changed value", boundValue.Text);
|
||||
WaitAssert.Equal("Changed value", () => boundValue.Text);
|
||||
Assert.Equal("Changed value", mirrorValue.GetAttribute("value"));
|
||||
|
||||
// Remove the value altogether
|
||||
setNullButton.Click();
|
||||
Assert.Equal(string.Empty, target.GetAttribute("value"));
|
||||
WaitAssert.Equal(string.Empty, () => target.GetAttribute("value"));
|
||||
Assert.Equal(string.Empty, boundValue.Text);
|
||||
Assert.Equal(string.Empty, mirrorValue.GetAttribute("value"));
|
||||
}
|
||||
|
@ -85,7 +86,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
target.SendKeys("Changed value");
|
||||
Assert.Equal(string.Empty, boundValue.Text); // Don't update as there's no change event fired yet.
|
||||
target.SendKeys("\t");
|
||||
Assert.Equal("Changed value", boundValue.Text);
|
||||
WaitAssert.Equal("Changed value", () => boundValue.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -99,7 +100,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// Modify target; verify value is updated
|
||||
target.Clear();
|
||||
target.SendKeys("Changed value\t");
|
||||
Assert.Equal("Changed value", boundValue.Text);
|
||||
WaitAssert.Equal("Changed value", () => boundValue.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -113,12 +114,12 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
// Modify target; verify value is updated
|
||||
target.Click();
|
||||
Assert.True(target.Selected);
|
||||
WaitAssert.True(() => target.Selected);
|
||||
Assert.Equal("True", boundValue.Text);
|
||||
|
||||
// Modify data; verify checkbox is updated
|
||||
invertButton.Click();
|
||||
Assert.False(target.Selected);
|
||||
WaitAssert.False(() => target.Selected);
|
||||
Assert.Equal("False", boundValue.Text);
|
||||
}
|
||||
|
||||
|
@ -133,12 +134,12 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
// Modify target; verify value is updated
|
||||
target.Click();
|
||||
Assert.False(target.Selected);
|
||||
WaitAssert.False(() => target.Selected);
|
||||
Assert.Equal("False", boundValue.Text);
|
||||
|
||||
// Modify data; verify checkbox is updated
|
||||
invertButton.Click();
|
||||
Assert.True(target.Selected);
|
||||
WaitAssert.True(() => target.Selected);
|
||||
Assert.Equal("True", boundValue.Text);
|
||||
}
|
||||
|
||||
|
@ -152,13 +153,13 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
// Modify target; verify value is updated
|
||||
target.SelectByText("Third choice");
|
||||
Assert.Equal("Third", boundValue.Text);
|
||||
WaitAssert.Equal("Third", () => boundValue.Text);
|
||||
|
||||
// Also verify we can add and select new options atomically
|
||||
// Don't move this into a separate test, because then the previous assertions
|
||||
// would be dependent on test execution order (or would require a full page reload)
|
||||
Browser.FindElement(By.Id("select-box-add-option")).Click();
|
||||
Assert.Equal("Fourth", boundValue.Text);
|
||||
WaitAssert.Equal("Fourth", () => boundValue.Text);
|
||||
Assert.Equal("Fourth choice", target.SelectedOption.Text);
|
||||
}
|
||||
|
||||
|
@ -175,7 +176,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||
target.Clear();
|
||||
target.SendKeys("42\t");
|
||||
Assert.Equal("42", boundValue.Text);
|
||||
WaitAssert.Equal("42", () => boundValue.Text);
|
||||
Assert.Equal("42", mirrorValue.GetAttribute("value"));
|
||||
}
|
||||
|
||||
|
@ -192,7 +193,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||
target.Clear();
|
||||
target.SendKeys("-3000000000\t");
|
||||
Assert.Equal("-3000000000", boundValue.Text);
|
||||
WaitAssert.Equal("-3000000000", () => boundValue.Text);
|
||||
Assert.Equal("-3000000000", mirrorValue.GetAttribute("value"));
|
||||
}
|
||||
|
||||
|
@ -209,7 +210,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||
target.Clear();
|
||||
target.SendKeys("-3.141\t");
|
||||
Assert.Equal("-3.141", boundValue.Text);
|
||||
WaitAssert.Equal("-3.141", () => boundValue.Text);
|
||||
Assert.Equal("-3.141", mirrorValue.GetAttribute("value"));
|
||||
}
|
||||
|
||||
|
@ -226,14 +227,14 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||
target.Clear();
|
||||
target.SendKeys("-3.14159265359\t");
|
||||
Assert.Equal("-3.14159265359", boundValue.Text);
|
||||
WaitAssert.Equal("-3.14159265359", () => boundValue.Text);
|
||||
Assert.Equal("-3.14159265359", mirrorValue.GetAttribute("value"));
|
||||
|
||||
// Modify target; verify value is updated and that textboxes linked to the same data are updated
|
||||
// Double shouldn't preserve trailing zeros
|
||||
target.Clear();
|
||||
target.SendKeys("0.010\t");
|
||||
Assert.Equal("0.01", boundValue.Text);
|
||||
WaitAssert.Equal("0.01", () => boundValue.Text);
|
||||
Assert.Equal("0.01", mirrorValue.GetAttribute("value"));
|
||||
}
|
||||
|
||||
|
@ -251,7 +252,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// Decimal should preserve trailing zeros
|
||||
target.Clear();
|
||||
target.SendKeys("0.010\t");
|
||||
Assert.Equal("0.010", boundValue.Text);
|
||||
WaitAssert.Equal("0.010", () => boundValue.Text);
|
||||
Assert.Equal("0.010", mirrorValue.GetAttribute("value"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ using BasicTestApp.HierarchicalImportsTest.Subdir;
|
|||
using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure;
|
||||
using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure.ServerFixtures;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
@ -20,11 +21,11 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
{
|
||||
public ComponentRenderingTest(
|
||||
BrowserFixture browserFixture,
|
||||
DevHostServerFixture<Program> serverFixture,
|
||||
ToggleExecutionModeServerFixture<Program> serverFixture,
|
||||
ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture, output)
|
||||
{
|
||||
Navigate(ServerPathBase, noReload: true);
|
||||
Navigate(ServerPathBase, noReload: !serverFixture.UsingAspNetHost);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -71,7 +72,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
// Clicking button increments count
|
||||
appElement.FindElement(By.TagName("button")).Click();
|
||||
Assert.Equal("Current count: 1", countDisplayElement.Text);
|
||||
WaitAssert.Equal("Current count: 1", () => countDisplayElement.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -84,11 +85,11 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
// Clicking 'tick' changes the state, and starts a task
|
||||
appElement.FindElement(By.Id("tick")).Click();
|
||||
Assert.Equal("Started", stateElement.Text);
|
||||
WaitAssert.Equal("Started", () => stateElement.Text);
|
||||
|
||||
// Clicking 'tock' completes the task, which updates the state
|
||||
appElement.FindElement(By.Id("tock")).Click();
|
||||
Assert.Equal("Stopped", stateElement.Text);
|
||||
WaitAssert.Equal("Stopped", () => stateElement.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -103,12 +104,12 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
// Typing adds element
|
||||
inputElement.SendKeys("a");
|
||||
Assert.Collection(liElements(),
|
||||
WaitAssert.Collection(liElements,
|
||||
li => Assert.Equal("a", li.Text));
|
||||
|
||||
// Typing again adds another element
|
||||
inputElement.SendKeys("b");
|
||||
Assert.Collection(liElements(),
|
||||
WaitAssert.Collection(liElements,
|
||||
li => Assert.Equal("a", li.Text),
|
||||
li => Assert.Equal("b", li.Text));
|
||||
|
||||
|
@ -127,17 +128,19 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// Initial count is zero; clicking button increments count
|
||||
Assert.Equal("Current count: 0", countDisplayElement.Text);
|
||||
incrementButton.Click();
|
||||
Assert.Equal("Current count: 1", countDisplayElement.Text);
|
||||
WaitAssert.Equal("Current count: 1", () => countDisplayElement.Text);
|
||||
|
||||
// We can remove an event handler
|
||||
toggleClickHandlerCheckbox.Click();
|
||||
WaitAssert.Empty(() => appElement.FindElements(By.Id("listening-message")));
|
||||
incrementButton.Click();
|
||||
Assert.Equal("Current count: 1", countDisplayElement.Text);
|
||||
WaitAssert.Equal("Current count: 1", () => countDisplayElement.Text);
|
||||
|
||||
// We can add an event handler
|
||||
toggleClickHandlerCheckbox.Click();
|
||||
appElement.FindElement(By.Id("listening-message"));
|
||||
incrementButton.Click();
|
||||
Assert.Equal("Current count: 2", countDisplayElement.Text);
|
||||
WaitAssert.Equal("Current count: 2", () => countDisplayElement.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -164,7 +167,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
// Clicking increments count in child component
|
||||
appElement.FindElement(By.TagName("button")).Click();
|
||||
Assert.Equal("Current count: 1", counterDisplay.Text);
|
||||
WaitAssert.Equal("Current count: 1", () => counterDisplay.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -179,7 +182,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
// Clicking increments count in child element
|
||||
appElement.FindElement(By.TagName("button")).Click();
|
||||
Assert.Equal("1", messageElementInChild.Text);
|
||||
WaitAssert.Equal("1", () => messageElementInChild.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -192,12 +195,22 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
Func<IEnumerable<IWebElement>> childComponentWrappers = () => appElement.FindElements(By.TagName("p"));
|
||||
Assert.Empty(childComponentWrappers());
|
||||
|
||||
// Click to add some child components
|
||||
// Click to add/remove some child components
|
||||
addButton.Click();
|
||||
WaitAssert.Collection(childComponentWrappers,
|
||||
elem => Assert.Equal("Child 1", elem.FindElement(By.ClassName("message")).Text));
|
||||
|
||||
addButton.Click();
|
||||
WaitAssert.Collection(childComponentWrappers,
|
||||
elem => Assert.Equal("Child 1", elem.FindElement(By.ClassName("message")).Text),
|
||||
elem => Assert.Equal("Child 2", elem.FindElement(By.ClassName("message")).Text));
|
||||
|
||||
removeButton.Click();
|
||||
WaitAssert.Collection(childComponentWrappers,
|
||||
elem => Assert.Equal("Child 1", elem.FindElement(By.ClassName("message")).Text));
|
||||
|
||||
addButton.Click();
|
||||
Assert.Collection(childComponentWrappers(),
|
||||
WaitAssert.Collection(childComponentWrappers,
|
||||
elem => Assert.Equal("Child 1", elem.FindElement(By.ClassName("message")).Text),
|
||||
elem => Assert.Equal("Child 3", elem.FindElement(By.ClassName("message")).Text));
|
||||
}
|
||||
|
@ -215,7 +228,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
// When property changes, child is renotified before rerender
|
||||
incrementButton.Click();
|
||||
Assert.Equal("You supplied: 101", suppliedValueElement.Text);
|
||||
WaitAssert.Equal("You supplied: 101", () => suppliedValueElement.Text);
|
||||
Assert.Equal("I computed: 202", computedValueElement.Text);
|
||||
}
|
||||
|
||||
|
@ -225,8 +238,8 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// Initially, the region isn't shown
|
||||
var appElement = MountTestComponent<RenderFragmentToggler>();
|
||||
var originalButton = appElement.FindElement(By.TagName("button"));
|
||||
var fragmentElements = appElement.FindElements(By.CssSelector("p[name=fragment-element]"));
|
||||
Assert.Empty(fragmentElements);
|
||||
Func<IEnumerable<IWebElement>> fragmentElements = () => appElement.FindElements(By.CssSelector("p[name=fragment-element]"));
|
||||
Assert.Empty(fragmentElements());
|
||||
|
||||
// The JS-side DOM builder handles regions correctly, placing elements
|
||||
// after the region after the corresponding elements
|
||||
|
@ -234,13 +247,11 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
// When we click the button, the region is shown
|
||||
originalButton.Click();
|
||||
fragmentElements = appElement.FindElements(By.CssSelector("p[name=fragment-element]"));
|
||||
Assert.Single(fragmentElements);
|
||||
WaitAssert.Single(fragmentElements);
|
||||
|
||||
// The button itself was preserved, so we can click it again and see the effect
|
||||
originalButton.Click();
|
||||
fragmentElements = appElement.FindElements(By.CssSelector("p[name=fragment-element]"));
|
||||
Assert.Empty(fragmentElements);
|
||||
WaitAssert.Empty(fragmentElements);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -263,11 +274,13 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// .NET code access to browser APIs
|
||||
var showPromptButton = appElement.FindElements(By.TagName("button")).First();
|
||||
showPromptButton.Click();
|
||||
var modal = Browser.SwitchTo().Alert();
|
||||
|
||||
var modal = new WebDriverWait(Browser, TimeSpan.FromSeconds(3))
|
||||
.Until(SwitchToAlert);
|
||||
modal.SendKeys("Some value from test");
|
||||
modal.Accept();
|
||||
var promptResult = appElement.FindElement(By.TagName("strong"));
|
||||
Assert.Equal("Some value from test", promptResult.Text);
|
||||
WaitAssert.Equal("Some value from test", () => promptResult.Text);
|
||||
|
||||
// NuGet packages can also embed entire Blazor components (themselves
|
||||
// authored as Razor files), including static content. The CSS value
|
||||
|
@ -280,7 +293,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
var externalComponentButton = specialStyleDiv.FindElement(By.TagName("button"));
|
||||
Assert.Equal("Click me", externalComponentButton.Text);
|
||||
externalComponentButton.Click();
|
||||
Assert.Equal("It works", externalComponentButton.Text);
|
||||
WaitAssert.Equal("It works", () => externalComponentButton.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -324,9 +337,9 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
Assert.Equal(string.Empty, inputElement.GetAttribute("value"));
|
||||
|
||||
buttonElement.Click();
|
||||
Assert.Equal("Clicks: 1", inputElement.GetAttribute("value"));
|
||||
WaitAssert.Equal("Clicks: 1", () => inputElement.GetAttribute("value"));
|
||||
buttonElement.Click();
|
||||
Assert.Equal("Clicks: 2", inputElement.GetAttribute("value"));
|
||||
WaitAssert.Equal("Clicks: 2", () => inputElement.GetAttribute("value"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -342,17 +355,16 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
// Remove the captured element
|
||||
checkbox.Click();
|
||||
Assert.Empty(appElement.FindElements(By.Id("capturedElement")));
|
||||
WaitAssert.Empty(() => appElement.FindElements(By.Id("capturedElement")));
|
||||
|
||||
// Re-add it; observe it starts empty again
|
||||
checkbox.Click();
|
||||
var inputElement = appElement.FindElement(By.Id("capturedElement"));
|
||||
Assert.NotNull(inputElement);
|
||||
Assert.Equal(string.Empty, inputElement.GetAttribute("value"));
|
||||
|
||||
// See that the capture variable was automatically updated to reference the new instance
|
||||
buttonElement.Click();
|
||||
Assert.Equal("Clicks: 1", inputElement.GetAttribute("value"));
|
||||
WaitAssert.Equal("Clicks: 1", () => inputElement.GetAttribute("value"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -363,26 +375,27 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
var currentCountTextSelector = By.CssSelector("#child-component p:first-of-type");
|
||||
var resetButton = appElement.FindElement(By.Id("reset-child"));
|
||||
var toggleChildCheckbox = appElement.FindElement(By.Id("toggle-child"));
|
||||
Func<string> currentCountText = () => appElement.FindElement(currentCountTextSelector).Text;
|
||||
|
||||
// Verify the reference was captured initially
|
||||
appElement.FindElement(incrementButtonSelector).Click();
|
||||
Assert.Equal("Current count: 1", appElement.FindElement(currentCountTextSelector).Text);
|
||||
WaitAssert.Equal("Current count: 1", currentCountText);
|
||||
resetButton.Click();
|
||||
Assert.Equal("Current count: 0", appElement.FindElement(currentCountTextSelector).Text);
|
||||
WaitAssert.Equal("Current count: 0", currentCountText);
|
||||
appElement.FindElement(incrementButtonSelector).Click();
|
||||
Assert.Equal("Current count: 1", appElement.FindElement(currentCountTextSelector).Text);
|
||||
WaitAssert.Equal("Current count: 1", currentCountText);
|
||||
|
||||
// Remove and re-add a new instance of the child, checking the text was reset
|
||||
toggleChildCheckbox.Click();
|
||||
Assert.Empty(appElement.FindElements(incrementButtonSelector));
|
||||
WaitAssert.Empty(() => appElement.FindElements(incrementButtonSelector));
|
||||
toggleChildCheckbox.Click();
|
||||
Assert.Equal("Current count: 0", appElement.FindElement(currentCountTextSelector).Text);
|
||||
WaitAssert.Equal("Current count: 0", currentCountText);
|
||||
|
||||
// Verify we have a new working reference
|
||||
appElement.FindElement(incrementButtonSelector).Click();
|
||||
Assert.Equal("Current count: 1", appElement.FindElement(currentCountTextSelector).Text);
|
||||
WaitAssert.Equal("Current count: 1", currentCountText);
|
||||
resetButton.Click();
|
||||
Assert.Equal("Current count: 0", appElement.FindElement(currentCountTextSelector).Text);
|
||||
WaitAssert.Equal("Current count: 0", currentCountText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -392,5 +405,17 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
var inputElement = appElement.FindElement(By.TagName("input"));
|
||||
Assert.Equal("Value set after render", inputElement.GetAttribute("value"));
|
||||
}
|
||||
|
||||
static IAlert SwitchToAlert(IWebDriver driver)
|
||||
{
|
||||
try
|
||||
{
|
||||
return driver.SwitchTo().Alert();
|
||||
}
|
||||
catch (NoAlertPresentException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using BasicTestApp;
|
||||
|
@ -20,12 +20,12 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// the one that doesn't match the 'bubbles' flag on the received event object.
|
||||
|
||||
public EventBubblingTest(
|
||||
BrowserFixture browserFixture,
|
||||
DevHostServerFixture<Program> serverFixture,
|
||||
BrowserFixture browserFixture,
|
||||
ToggleExecutionModeServerFixture<Program> serverFixture,
|
||||
ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture, output)
|
||||
{
|
||||
Navigate(ServerPathBase, noReload: true);
|
||||
Navigate(ServerPathBase, noReload: !serverFixture.UsingAspNetHost);
|
||||
MountTestComponent<EventBubblingComponent>();
|
||||
}
|
||||
|
||||
|
@ -35,9 +35,9 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
Browser.FindElement(By.Id("button-with-onclick")).Click();
|
||||
|
||||
// Triggers event on target and ancestors with handler in upwards direction
|
||||
Assert.Equal(
|
||||
WaitAssert.Equal(
|
||||
new[] { "target onclick", "parent onclick" },
|
||||
GetLogLines());
|
||||
GetLogLines);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -46,9 +46,9 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
Browser.FindElement(By.Id("button-without-onclick")).Click();
|
||||
|
||||
// Triggers event on ancestors with handler in upwards direction
|
||||
Assert.Equal(
|
||||
WaitAssert.Equal(
|
||||
new[] { "parent onclick" },
|
||||
GetLogLines());
|
||||
GetLogLines);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -57,9 +57,9 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
TriggerCustomBubblingEvent("element-with-onsneeze", "sneeze");
|
||||
|
||||
// Triggers event on target and ancestors with handler in upwards direction
|
||||
Assert.Equal(
|
||||
WaitAssert.Equal(
|
||||
new[] { "target onsneeze", "parent onsneeze" },
|
||||
GetLogLines());
|
||||
GetLogLines);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -68,9 +68,9 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
TriggerCustomBubblingEvent("element-without-onsneeze", "sneeze");
|
||||
|
||||
// Triggers event on ancestors with handler in upwards direction
|
||||
Assert.Equal(
|
||||
WaitAssert.Equal(
|
||||
new[] { "parent onsneeze" },
|
||||
GetLogLines());
|
||||
GetLogLines);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -79,7 +79,9 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
Browser.FindElement(By.Id("input-with-onfocus")).Click();
|
||||
|
||||
// Triggers event only on target, not other ancestors with event handler
|
||||
Assert.Equal(new[] { "target onfocus" }, GetLogLines());
|
||||
WaitAssert.Equal(
|
||||
new[] { "target onfocus" },
|
||||
GetLogLines);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -88,7 +90,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
Browser.FindElement(By.Id("input-without-onfocus")).Click();
|
||||
|
||||
// Triggers no event
|
||||
Assert.Empty(GetLogLines());
|
||||
WaitAssert.Empty(GetLogLines);
|
||||
}
|
||||
|
||||
private string[] GetLogLines()
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using BasicTestApp;
|
||||
using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure;
|
||||
using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure.ServerFixtures;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Interactions;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
@ -16,8 +14,8 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
public class EventTest : BasicTestAppTestBase
|
||||
{
|
||||
public EventTest(
|
||||
BrowserFixture browserFixture,
|
||||
DevHostServerFixture<Program> serverFixture,
|
||||
BrowserFixture browserFixture,
|
||||
ToggleExecutionModeServerFixture<Program> serverFixture,
|
||||
ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture, output)
|
||||
{
|
||||
|
@ -38,13 +36,13 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// Focus the target, verify onfocusin is fired
|
||||
input.Click();
|
||||
|
||||
Assert.Equal("onfocus,onfocusin,", output.Text);
|
||||
WaitAssert.Equal("onfocus,onfocusin,", () => output.Text);
|
||||
|
||||
// Focus something else, verify onfocusout is also fired
|
||||
var other = Browser.FindElement(By.Id("other"));
|
||||
other.Click();
|
||||
|
||||
Assert.Equal("onfocus,onfocusin,onblur,onfocusout,", output.Text);
|
||||
WaitAssert.Equal("onfocus,onfocusin,onblur,onfocusout,", () => output.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -65,7 +63,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
.MoveToElement(other);
|
||||
|
||||
actions.Perform();
|
||||
Assert.Equal("onmouseover,onmouseout,", output.Text);
|
||||
WaitAssert.Equal("onmouseover,onmouseout,", () => output.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -84,7 +82,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
.MoveToElement(input, 10, 10);
|
||||
|
||||
actions.Perform();
|
||||
Assert.Contains("onmousemove,", output.Text);
|
||||
WaitAssert.Contains("onmousemove,", () => output.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -103,12 +101,12 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
var actions = new Actions(Browser).ClickAndHold(input);
|
||||
|
||||
actions.Perform();
|
||||
Assert.Equal("onmousedown,", output.Text);
|
||||
WaitAssert.Equal("onmousedown,", () => output.Text);
|
||||
|
||||
actions = new Actions(Browser).Release(input);
|
||||
|
||||
actions.Perform();
|
||||
Assert.Equal("onmousedown,onmouseup,", output.Text);
|
||||
WaitAssert.Equal("onmousedown,onmouseup,", () => output.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using BasicTestApp.HttpClientTest;
|
||||
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
public HttpClientTest(
|
||||
BrowserFixture browserFixture,
|
||||
DevHostServerFixture<BasicTestApp.Program> devHostServerFixture,
|
||||
ToggleExecutionModeServerFixture<BasicTestApp.Program> devHostServerFixture,
|
||||
AspNetSiteServerFixture apiServerFixture,
|
||||
ITestOutputHelper output)
|
||||
: base(browserFixture, devHostServerFixture, output)
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
{
|
||||
public InteropTest(
|
||||
BrowserFixture browserFixture,
|
||||
DevHostServerFixture<Program> serverFixture,
|
||||
ToggleExecutionModeServerFixture<Program> serverFixture,
|
||||
ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture, output)
|
||||
{
|
||||
|
@ -26,7 +26,42 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
public void CanInvokeDotNetMethods()
|
||||
{
|
||||
// Arrange
|
||||
var expectedValues = new Dictionary<string, string>
|
||||
var expectedAsyncValues = new Dictionary<string, string>
|
||||
{
|
||||
["VoidParameterlessAsync"] = "[]",
|
||||
["VoidWithOneParameterAsync"] = @"[{""id"":1,""isValid"":false,""data"":{""source"":""Some random text with at least 1 characters"",""start"":1,""length"":1}}]",
|
||||
["VoidWithTwoParametersAsync"] = @"[{""id"":2,""isValid"":true,""data"":{""source"":""Some random text with at least 2 characters"",""start"":2,""length"":2}},2]",
|
||||
["VoidWithThreeParametersAsync"] = @"[{""id"":3,""isValid"":false,""data"":{""source"":""Some random text with at least 3 characters"",""start"":3,""length"":3}},3,123]",
|
||||
["VoidWithFourParametersAsync"] = @"[{""id"":4,""isValid"":true,""data"":{""source"":""Some random text with at least 4 characters"",""start"":4,""length"":4}},4,123,16]",
|
||||
["VoidWithFiveParametersAsync"] = @"[{""id"":5,""isValid"":false,""data"":{""source"":""Some random text with at least 5 characters"",""start"":5,""length"":5}},5,123,20,40]",
|
||||
["VoidWithSixParametersAsync"] = @"[{""id"":6,""isValid"":true,""data"":{""source"":""Some random text with at least 6 characters"",""start"":6,""length"":6}},6,123,24,48,6.25]",
|
||||
["VoidWithSevenParametersAsync"] = @"[{""id"":7,""isValid"":false,""data"":{""source"":""Some random text with at least 7 characters"",""start"":7,""length"":7}},7,123,28,56,7.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5]]",
|
||||
["VoidWithEightParametersAsync"] = @"[{""id"":8,""isValid"":true,""data"":{""source"":""Some random text with at least 8 characters"",""start"":8,""length"":8}},8,123,32,64,8.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5],{""source"":""Some random text with at least 7 characters"",""start"":9,""length"":9}]",
|
||||
["result1Async"] = @"[0.1,0.2]",
|
||||
["result2Async"] = @"[{""id"":1,""isValid"":false,""data"":{""source"":""Some random text with at least 1 characters"",""start"":1,""length"":1}}]",
|
||||
["result3Async"] = @"[{""id"":2,""isValid"":true,""data"":{""source"":""Some random text with at least 2 characters"",""start"":2,""length"":2}},2]",
|
||||
["result4Async"] = @"[{""id"":3,""isValid"":false,""data"":{""source"":""Some random text with at least 3 characters"",""start"":3,""length"":3}},3,123]",
|
||||
["result5Async"] = @"[{""id"":4,""isValid"":true,""data"":{""source"":""Some random text with at least 4 characters"",""start"":4,""length"":4}},4,123,16]",
|
||||
["result6Async"] = @"[{""id"":5,""isValid"":false,""data"":{""source"":""Some random text with at least 5 characters"",""start"":5,""length"":5}},5,123,20,40]",
|
||||
["result7Async"] = @"[{""id"":6,""isValid"":true,""data"":{""source"":""Some random text with at least 6 characters"",""start"":6,""length"":6}},6,123,24,48,6.25]",
|
||||
["result8Async"] = @"[{""id"":7,""isValid"":false,""data"":{""source"":""Some random text with at least 7 characters"",""start"":7,""length"":7}},7,123,28,56,7.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5]]",
|
||||
["result9Async"] = @"[{""id"":8,""isValid"":true,""data"":{""source"":""Some random text with at least 8 characters"",""start"":8,""length"":8}},8,123,32,64,8.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5],{""source"":""Some random text with at least 7 characters"",""start"":9,""length"":9}]",
|
||||
["AsyncThrowSyncException"] = @"""System.InvalidOperationException: Threw a sync exception!",
|
||||
["AsyncThrowAsyncException"] = @"""System.InvalidOperationException: Threw an async exception!",
|
||||
["SyncExceptionFromAsyncMethod"] = "Function threw a sync exception!",
|
||||
["AsyncExceptionFromAsyncMethod"] = "Function threw an async exception!",
|
||||
["resultReturnDotNetObjectByRefAsync"] = "1001",
|
||||
["instanceMethodThisTypeNameAsync"] = @"""JavaScriptInterop""",
|
||||
["instanceMethodStringValueUpperAsync"] = @"""MY STRING""",
|
||||
["instanceMethodIncomingByRefAsync"] = "123",
|
||||
["instanceMethodOutgoingByRefAsync"] = "1234",
|
||||
["stringValueUpperAsync"] = "MY STRING",
|
||||
["testDtoNonSerializedValueAsync"] = "99999",
|
||||
["testDtoAsync"] = "Same",
|
||||
["returnPrimitiveAsync"] = "123",
|
||||
};
|
||||
|
||||
var expectedSyncValues = new Dictionary<string, string>
|
||||
{
|
||||
["VoidParameterless"] = "[]",
|
||||
["VoidWithOneParameter"] = @"[{""id"":1,""isValid"":false,""data"":{""source"":""Some random text with at least 1 characters"",""start"":1,""length"":1}}]",
|
||||
|
@ -37,15 +72,6 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
["VoidWithSixParameters"] = @"[{""id"":6,""isValid"":true,""data"":{""source"":""Some random text with at least 6 characters"",""start"":6,""length"":6}},6,123,24,48,6.25]",
|
||||
["VoidWithSevenParameters"] = @"[{""id"":7,""isValid"":false,""data"":{""source"":""Some random text with at least 7 characters"",""start"":7,""length"":7}},7,123,28,56,7.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5]]",
|
||||
["VoidWithEightParameters"] = @"[{""id"":8,""isValid"":true,""data"":{""source"":""Some random text with at least 8 characters"",""start"":8,""length"":8}},8,123,32,64,8.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5],{""source"":""Some random text with at least 7 characters"",""start"":9,""length"":9}]",
|
||||
["VoidParameterlessAsync"] = "[]",
|
||||
["VoidWithOneParameterAsync"] = @"[{""id"":1,""isValid"":false,""data"":{""source"":""Some random text with at least 1 characters"",""start"":1,""length"":1}}]",
|
||||
["VoidWithTwoParametersAsync"] = @"[{""id"":2,""isValid"":true,""data"":{""source"":""Some random text with at least 2 characters"",""start"":2,""length"":2}},2]",
|
||||
["VoidWithThreeParametersAsync"] = @"[{""id"":3,""isValid"":false,""data"":{""source"":""Some random text with at least 3 characters"",""start"":3,""length"":3}},3,123]",
|
||||
["VoidWithFourParametersAsync"] = @"[{""id"":4,""isValid"":true,""data"":{""source"":""Some random text with at least 4 characters"",""start"":4,""length"":4}},4,123,16]",
|
||||
["VoidWithFiveParametersAsync"] = @"[{""id"":5,""isValid"":false,""data"":{""source"":""Some random text with at least 5 characters"",""start"":5,""length"":5}},5,123,20,40]",
|
||||
["VoidWithSixParametersAsync"] = @"[{""id"":6,""isValid"":true,""data"":{""source"":""Some random text with at least 6 characters"",""start"":6,""length"":6}},6,123,24,48,6.25]",
|
||||
["VoidWithSevenParametersAsync"] = @"[{""id"":7,""isValid"":false,""data"":{""source"":""Some random text with at least 7 characters"",""start"":7,""length"":7}},7,123,28,56,7.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5]]",
|
||||
["VoidWithEightParametersAsync"] = @"[{""id"":8,""isValid"":true,""data"":{""source"":""Some random text with at least 8 characters"",""start"":8,""length"":8}},8,123,32,64,8.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5],{""source"":""Some random text with at least 7 characters"",""start"":9,""length"":9}]",
|
||||
["result1"] = @"[0.1,0.2]",
|
||||
["result2"] = @"[{""id"":1,""isValid"":false,""data"":{""source"":""Some random text with at least 1 characters"",""start"":1,""length"":1}}]",
|
||||
["result3"] = @"[{""id"":2,""isValid"":true,""data"":{""source"":""Some random text with at least 2 characters"",""start"":2,""length"":2}},2]",
|
||||
|
@ -55,40 +81,29 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
["result7"] = @"[{""id"":6,""isValid"":true,""data"":{""source"":""Some random text with at least 6 characters"",""start"":6,""length"":6}},6,123,24,48,6.25]",
|
||||
["result8"] = @"[{""id"":7,""isValid"":false,""data"":{""source"":""Some random text with at least 7 characters"",""start"":7,""length"":7}},7,123,28,56,7.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5]]",
|
||||
["result9"] = @"[{""id"":8,""isValid"":true,""data"":{""source"":""Some random text with at least 8 characters"",""start"":8,""length"":8}},8,123,32,64,8.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5],{""source"":""Some random text with at least 7 characters"",""start"":9,""length"":9}]",
|
||||
["result1Async"] = @"[0.1,0.2]",
|
||||
["result2Async"] = @"[{""id"":1,""isValid"":false,""data"":{""source"":""Some random text with at least 1 characters"",""start"":1,""length"":1}}]",
|
||||
["result3Async"] = @"[{""id"":2,""isValid"":true,""data"":{""source"":""Some random text with at least 2 characters"",""start"":2,""length"":2}},2]",
|
||||
["result4Async"] = @"[{""id"":3,""isValid"":false,""data"":{""source"":""Some random text with at least 3 characters"",""start"":3,""length"":3}},3,123]",
|
||||
["result5Async"] = @"[{""id"":4,""isValid"":true,""data"":{""source"":""Some random text with at least 4 characters"",""start"":4,""length"":4}},4,123,16]",
|
||||
["result6Async"] = @"[{""id"":5,""isValid"":false,""data"":{""source"":""Some random text with at least 5 characters"",""start"":5,""length"":5}},5,123,20,40]",
|
||||
["result7Async"] = @"[{""id"":6,""isValid"":true,""data"":{""source"":""Some random text with at least 6 characters"",""start"":6,""length"":6}},6,123,24,48,6.25]",
|
||||
["result8Async"] = @"[{""id"":7,""isValid"":false,""data"":{""source"":""Some random text with at least 7 characters"",""start"":7,""length"":7}},7,123,28,56,7.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5]]",
|
||||
["result9Async"] = @"[{""id"":8,""isValid"":true,""data"":{""source"":""Some random text with at least 8 characters"",""start"":8,""length"":8}},8,123,32,64,8.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5],{""source"":""Some random text with at least 7 characters"",""start"":9,""length"":9}]",
|
||||
["ThrowException"] = @"""System.InvalidOperationException: Threw an exception!",
|
||||
["AsyncThrowSyncException"] = @"""System.InvalidOperationException: Threw a sync exception!",
|
||||
["AsyncThrowAsyncException"] = @"""System.InvalidOperationException: Threw an async exception!",
|
||||
["ExceptionFromSyncMethod"] = "Function threw an exception!",
|
||||
["SyncExceptionFromAsyncMethod"] = "Function threw a sync exception!",
|
||||
["AsyncExceptionFromAsyncMethod"] = "Function threw an async exception!",
|
||||
["resultReturnDotNetObjectByRefSync"] = "1000",
|
||||
["resultReturnDotNetObjectByRefAsync"] = "1001",
|
||||
["instanceMethodThisTypeName"] = @"""JavaScriptInterop""",
|
||||
["instanceMethodStringValueUpper"] = @"""MY STRING""",
|
||||
["instanceMethodIncomingByRef"] = "123",
|
||||
["instanceMethodOutgoingByRef"] = "1234",
|
||||
["instanceMethodThisTypeNameAsync"] = @"""JavaScriptInterop""",
|
||||
["instanceMethodStringValueUpperAsync"] = @"""MY STRING""",
|
||||
["instanceMethodIncomingByRefAsync"] = "123",
|
||||
["instanceMethodOutgoingByRefAsync"] = "1234",
|
||||
["stringValueUpperSync"] = "MY STRING",
|
||||
["testDtoNonSerializedValueSync"] = "99999",
|
||||
["testDtoSync"] = "Same",
|
||||
["stringValueUpperAsync"] = "MY STRING",
|
||||
["testDtoNonSerializedValueAsync"] = "99999",
|
||||
["testDtoAsync"] = "Same",
|
||||
["returnPrimitive"] = "123",
|
||||
["returnPrimitiveAsync"] = "123",
|
||||
};
|
||||
|
||||
// Include the sync assertions only when running under WebAssembly
|
||||
var expectedValues = expectedAsyncValues;
|
||||
if (!_serverFixture.UsingAspNetHost)
|
||||
{
|
||||
foreach (var kvp in expectedSyncValues)
|
||||
{
|
||||
expectedValues.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
var actualValues = new Dictionary<string, string>();
|
||||
|
||||
// Act
|
||||
|
|
|
@ -15,25 +15,22 @@ using Xunit.Abstractions;
|
|||
|
||||
namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
||||
{
|
||||
public class RoutingTest : BasicTestAppTestBase, IDisposable
|
||||
public class RoutingTest : BasicTestAppTestBase
|
||||
{
|
||||
private readonly ServerFixture _server;
|
||||
|
||||
public RoutingTest(
|
||||
BrowserFixture browserFixture,
|
||||
DevHostServerFixture<Program> serverFixture,
|
||||
BrowserFixture browserFixture,
|
||||
ToggleExecutionModeServerFixture<Program> serverFixture,
|
||||
ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture, output)
|
||||
{
|
||||
_server = serverFixture;
|
||||
Navigate(ServerPathBase, noReload: true);
|
||||
WaitUntilDotNetRunningInBrowser();
|
||||
Navigate(ServerPathBase, noReload: false);
|
||||
WaitUntilTestSelectorReady();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanArriveAtDefaultPage()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/");
|
||||
SetUrlViaPushState("/");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
Assert.Equal("This is the default page.", app.FindElement(By.Id("test-info")).Text);
|
||||
|
@ -47,7 +44,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
// servers to enforce a canonical URL (with trailing slash) for the homepage.
|
||||
// But in case they don't want to, we need to handle it the same as if the URL does
|
||||
// have a trailing slash.
|
||||
SetUrlViaPushState($"{ServerPathBase}");
|
||||
SetUrlViaPushState("");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
Assert.Equal("This is the default page.", app.FindElement(By.Id("test-info")).Text);
|
||||
|
@ -57,7 +54,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
[Fact]
|
||||
public void CanArriveAtPageWithParameters()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/WithParameters/Name/Ghi/LastName/O'Jkl");
|
||||
SetUrlViaPushState("/WithParameters/Name/Ghi/LastName/O'Jkl");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
Assert.Equal("Your full name is Ghi O'Jkl.", app.FindElement(By.Id("test-info")).Text);
|
||||
|
@ -67,7 +64,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
[Fact]
|
||||
public void CanArriveAtNonDefaultPage()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/Other");
|
||||
SetUrlViaPushState("/Other");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
Assert.Equal("This is another page.", app.FindElement(By.Id("test-info")).Text);
|
||||
|
@ -77,11 +74,11 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
[Fact]
|
||||
public void CanFollowLinkToOtherPage()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/");
|
||||
SetUrlViaPushState("/");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
app.FindElement(By.LinkText("Other")).Click();
|
||||
Assert.Equal("This is another page.", app.FindElement(By.Id("test-info")).Text);
|
||||
WaitAssert.Equal("This is another page.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
AssertHighlightedLinks("Other", "Other with base-relative URL (matches all)");
|
||||
}
|
||||
|
||||
|
@ -93,20 +90,20 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
|
||||
try
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/");
|
||||
SetUrlViaPushState("/");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
var button = app.FindElement(By.LinkText("Other"));
|
||||
|
||||
new Actions(Browser).KeyDown(key).Click(button).Build().Perform();
|
||||
|
||||
Assert.Equal(2, Browser.WindowHandles.Count);
|
||||
WaitAssert.Equal(2, () => Browser.WindowHandles.Count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Leaving the ctrl key up
|
||||
new Actions(Browser).KeyUp(key).Build().Perform();
|
||||
|
||||
|
||||
// Closing newly opened windows if a new one was opened
|
||||
while (Browser.WindowHandles.Count > 1)
|
||||
{
|
||||
|
@ -123,7 +120,7 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
[Fact]
|
||||
public void CanFollowLinkToOtherPageDoesNotOpenNewWindow()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/");
|
||||
SetUrlViaPushState("/");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
|
||||
|
@ -135,106 +132,106 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
[Fact]
|
||||
public void CanFollowLinkToOtherPageWithBaseRelativeUrl()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/");
|
||||
SetUrlViaPushState("/");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
app.FindElement(By.LinkText("Other with base-relative URL (matches all)")).Click();
|
||||
Assert.Equal("This is another page.", app.FindElement(By.Id("test-info")).Text);
|
||||
WaitAssert.Equal("This is another page.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
AssertHighlightedLinks("Other", "Other with base-relative URL (matches all)");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanFollowLinkToEmptyStringHrefAsBaseRelativeUrl()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/Other");
|
||||
SetUrlViaPushState("/Other");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
app.FindElement(By.LinkText("Default with base-relative URL (matches all)")).Click();
|
||||
Assert.Equal("This is the default page.", app.FindElement(By.Id("test-info")).Text);
|
||||
WaitAssert.Equal("This is the default page.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
AssertHighlightedLinks("Default (matches all)", "Default with base-relative URL (matches all)");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanFollowLinkToPageWithParameters()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/Other");
|
||||
SetUrlViaPushState("/Other");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
app.FindElement(By.LinkText("With parameters")).Click();
|
||||
Assert.Equal("Your full name is Abc McDef.", app.FindElement(By.Id("test-info")).Text);
|
||||
WaitAssert.Equal("Your full name is Abc McDef.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
AssertHighlightedLinks("With parameters");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanFollowLinkToDefaultPage()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/Other");
|
||||
SetUrlViaPushState("/Other");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
app.FindElement(By.LinkText("Default (matches all)")).Click();
|
||||
Assert.Equal("This is the default page.", app.FindElement(By.Id("test-info")).Text);
|
||||
WaitAssert.Equal("This is the default page.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
AssertHighlightedLinks("Default (matches all)", "Default with base-relative URL (matches all)");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanFollowLinkToOtherPageWithQueryString()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/");
|
||||
SetUrlViaPushState("/");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
app.FindElement(By.LinkText("Other with query")).Click();
|
||||
Assert.Equal("This is another page.", app.FindElement(By.Id("test-info")).Text);
|
||||
WaitAssert.Equal("This is another page.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
AssertHighlightedLinks("Other", "Other with query");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanFollowLinkToDefaultPageWithQueryString()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/Other");
|
||||
SetUrlViaPushState("/Other");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
app.FindElement(By.LinkText("Default with query")).Click();
|
||||
Assert.Equal("This is the default page.", app.FindElement(By.Id("test-info")).Text);
|
||||
WaitAssert.Equal("This is the default page.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
AssertHighlightedLinks("Default with query");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanFollowLinkToOtherPageWithHash()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/");
|
||||
SetUrlViaPushState("/");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
app.FindElement(By.LinkText("Other with hash")).Click();
|
||||
Assert.Equal("This is another page.", app.FindElement(By.Id("test-info")).Text);
|
||||
WaitAssert.Equal("This is another page.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
AssertHighlightedLinks("Other", "Other with hash");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanFollowLinkToDefaultPageWithHash()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/Other");
|
||||
SetUrlViaPushState("/Other");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
app.FindElement(By.LinkText("Default with hash")).Click();
|
||||
Assert.Equal("This is the default page.", app.FindElement(By.Id("test-info")).Text);
|
||||
WaitAssert.Equal("This is the default page.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
AssertHighlightedLinks("Default with hash");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanNavigateProgrammatically()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/");
|
||||
SetUrlViaPushState("/");
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
app.FindElement(By.TagName("button")).Click();
|
||||
Assert.Equal("This is another page.", app.FindElement(By.Id("test-info")).Text);
|
||||
WaitAssert.Equal("This is another page.", () => app.FindElement(By.Id("test-info")).Text);
|
||||
AssertHighlightedLinks("Other", "Other with base-relative URL (matches all)");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClickingAnchorWithNoHrefShouldNotNavigate()
|
||||
{
|
||||
SetUrlViaPushState($"{ServerPathBase}/");
|
||||
SetUrlViaPushState("/");
|
||||
var initialUrl = Browser.Url;
|
||||
|
||||
var app = MountTestComponent<TestRouter>();
|
||||
|
@ -244,25 +241,19 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
AssertHighlightedLinks("Default (matches all)", "Default with base-relative URL (matches all)");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Clear any existing state
|
||||
SetUrlViaPushState(ServerPathBase);
|
||||
MountTestComponent<TextOnlyComponent>();
|
||||
}
|
||||
|
||||
private void SetUrlViaPushState(string relativeUri)
|
||||
{
|
||||
var pathBaseWithoutHash = ServerPathBase.Split('#')[0];
|
||||
var jsExecutor = (IJavaScriptExecutor)Browser;
|
||||
var absoluteUri = new Uri(_server.RootUri, relativeUri);
|
||||
var absoluteUri = new Uri(_serverFixture.RootUri, $"{pathBaseWithoutHash}{relativeUri}");
|
||||
jsExecutor.ExecuteScript($"Blazor.navigateTo('{absoluteUri.ToString().Replace("'", "\\'")}')");
|
||||
}
|
||||
|
||||
private void AssertHighlightedLinks(params string[] linkTexts)
|
||||
{
|
||||
var actual = Browser.FindElements(By.CssSelector("a.active"));
|
||||
var actualTexts = actual.Select(x => x.Text);
|
||||
Assert.Equal(linkTexts, actualTexts);
|
||||
WaitAssert.Equal(linkTexts, () => Browser
|
||||
.FindElements(By.CssSelector("a.active"))
|
||||
.Select(x => x.Text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,15 +15,12 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
public class StandaloneAppTest
|
||||
: ServerTestBase<DevHostServerFixture<StandaloneApp.Program>>, IDisposable
|
||||
{
|
||||
private readonly ServerFixture _serverFixture;
|
||||
|
||||
public StandaloneAppTest(
|
||||
BrowserFixture browserFixture,
|
||||
DevHostServerFixture<StandaloneApp.Program> serverFixture,
|
||||
ITestOutputHelper output)
|
||||
: base(browserFixture, serverFixture, output)
|
||||
{
|
||||
_serverFixture = serverFixture;
|
||||
Navigate("/", noReload: true);
|
||||
WaitUntilLoaded();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<h1>Counter</h1>
|
||||
<h1>Counter</h1>
|
||||
<p>Current count: @currentCount</p>
|
||||
<p><button onclick="@((handleClicks ? (Action)IncrementCount : null))">Click me</button></p>
|
||||
|
||||
|
@ -7,6 +7,11 @@
|
|||
Toggle click handler registration
|
||||
</label>
|
||||
|
||||
@if (handleClicks)
|
||||
{
|
||||
<p id="listening-message">Listening</p>
|
||||
}
|
||||
|
||||
@functions {
|
||||
int currentCount = 0;
|
||||
bool handleClicks = true;
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
@using Microsoft.AspNetCore.Blazor.RenderTree
|
||||
<div id="test-selector">
|
||||
Select test:
|
||||
<select bind=@SelectedComponentTypeName>
|
||||
<option value="none">Choose...</option>
|
||||
<option value="BasicTestApp.InteropComponent">Interop component</option>
|
||||
<option value="BasicTestApp.AsyncEventHandlerComponent">Async event handlers</option>
|
||||
<option value="BasicTestApp.AddRemoveChildComponents">Add/remove child components</option>
|
||||
<option value="BasicTestApp.CounterComponent">Counter</option>
|
||||
<option value="BasicTestApp.CounterComponentUsingChild">Counter using child component</option>
|
||||
<option value="BasicTestApp.CounterComponentWrapper">Counter wrapped in parent</option>
|
||||
<option value="BasicTestApp.FocusEventComponent">Focus events</option>
|
||||
<option value="BasicTestApp.KeyPressEventComponent">Key press event</option>
|
||||
<option value="BasicTestApp.MouseEventComponent">Mouse events</option>
|
||||
<option value="BasicTestApp.TouchEventComponent">Touch events</option>
|
||||
<option value="BasicTestApp.ParentChildComponent">Parent component with child</option>
|
||||
<option value="BasicTestApp.PropertiesChangedHandlerParent">Parent component that changes parameters on child</option>
|
||||
<option value="BasicTestApp.RedTextComponent">Red text</option>
|
||||
<option value="BasicTestApp.RenderFragmentToggler">Render fragment renderer</option>
|
||||
<option value="BasicTestApp.TextOnlyComponent">Plain text</option>
|
||||
<option value="BasicTestApp.HierarchicalImportsTest.Subdir.ComponentUsingImports">Imports statement</option>
|
||||
<option value="BasicTestApp.HttpClientTest.HttpRequestsComponent">HttpClient tester</option>
|
||||
<option value="BasicTestApp.HttpClientTest.BinaryHttpRequestsComponent">Binary HttpClient tester</option>
|
||||
<option value="BasicTestApp.HttpClientTest.CookieCounterComponent">HttpClient cookies</option>
|
||||
<option value="BasicTestApp.BindCasesComponent">bind cases</option>
|
||||
<option value="BasicTestApp.DataDashComponent">data-* attribute rendering</option>
|
||||
<option value="BasicTestApp.ExternalContentPackage">External content package</option>
|
||||
<option value="BasicTestApp.SvgComponent">SVG</option>
|
||||
<option value="BasicTestApp.SvgWithChildComponent">SVG with child component</option>
|
||||
<option value="BasicTestApp.LogicalElementInsertionCases">Logical element insertion cases</option>
|
||||
<option value="BasicTestApp.ElementRefComponent">Element ref component</option>
|
||||
<option value="BasicTestApp.ComponentRefComponent">Component ref component</option>
|
||||
<option value="BasicTestApp.AfterRenderInteropComponent">After-render interop component</option>
|
||||
<option value="BasicTestApp.EventCasesComponent">Event cases</option>
|
||||
<option value="BasicTestApp.EventBubblingComponent">Event bubbling</option>
|
||||
<option value="BasicTestApp.RouterTest.TestRouter">Router</option>
|
||||
</select>
|
||||
|
||||
@if (SelectedComponentType != null)
|
||||
{
|
||||
<span id="source-info"><code><tt>@(SelectedComponentType.Name.Replace(".", "/")).cshtml</tt></code></span>
|
||||
}
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<app>
|
||||
@((RenderFragment)RenderSelectedComponent)
|
||||
</app>
|
||||
|
||||
@functions {
|
||||
string SelectedComponentTypeName { get; set; } = "none";
|
||||
|
||||
Type SelectedComponentType
|
||||
=> SelectedComponentTypeName == "none" ? null : Type.GetType(SelectedComponentTypeName);
|
||||
|
||||
void RenderSelectedComponent(RenderTreeBuilder builder)
|
||||
{
|
||||
if (SelectedComponentType != null)
|
||||
{
|
||||
builder.OpenComponent(0, SelectedComponentType);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
@using Microsoft.JSInterop
|
||||
@using BasicTestApp.InteropTest
|
||||
@using System.Runtime.InteropServices
|
||||
|
||||
<button id="btn-interop" onclick="@InvokeInteropAsync">Invoke interop!</button>
|
||||
|
||||
|
@ -65,18 +66,24 @@
|
|||
|
||||
public async Task InvokeInteropAsync()
|
||||
{
|
||||
var inProcRuntime = ((IJSInProcessRuntime)JSRuntime.Current);
|
||||
var shouldSupportSyncInterop = RuntimeInformation.IsOSPlatform(OSPlatform.Create("WEBASSEMBLY"));
|
||||
var testDTOTOPassByRef = new TestDTO(nonSerializedValue: 123);
|
||||
|
||||
var instanceMethodsTarget = new JavaScriptInterop();
|
||||
|
||||
Console.WriteLine("Starting interop invocations.");
|
||||
await JSRuntime.Current.InvokeAsync<object>(
|
||||
"jsInteropTests.invokeDotNetInteropMethodsAsync",
|
||||
shouldSupportSyncInterop,
|
||||
new DotNetObjectRef(testDTOTOPassByRef),
|
||||
new DotNetObjectRef(instanceMethodsTarget));
|
||||
|
||||
if (shouldSupportSyncInterop)
|
||||
{
|
||||
InvokeInProcessInterop();
|
||||
}
|
||||
|
||||
Console.WriteLine("Showing interop invocation results.");
|
||||
var collectResults = inProcRuntime.Invoke<Dictionary<string,string>>("jsInteropTests.collectInteropResults");
|
||||
var collectResults = await JSRuntime.Current.InvokeAsync<Dictionary<string,string>>("jsInteropTests.collectInteropResults");
|
||||
|
||||
ReturnValues = collectResults.ToDictionary(kvp => kvp.Key,kvp => System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(kvp.Value)));
|
||||
|
||||
|
@ -87,15 +94,6 @@
|
|||
invocations[interopResult.Key] = interopResultValue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
inProcRuntime.Invoke<object>("jsInteropTests.functionThrowsException");
|
||||
}
|
||||
catch (JSException e)
|
||||
{
|
||||
ExceptionFromSyncMethod = e;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await JSRuntime.Current.InvokeAsync<object>("jsInteropTests.asyncFunctionThrowsSyncException");
|
||||
|
@ -120,15 +118,39 @@
|
|||
{ "stringValue", "My string" },
|
||||
{ "testDto", new DotNetObjectRef(passDotNetObjectByRef) },
|
||||
};
|
||||
ReceiveDotNetObjectByRefResult = inProcRuntime.Invoke<Dictionary<string, object>>("receiveDotNetObjectByRef", passDotNetObjectByRefArg);
|
||||
ReceiveDotNetObjectByRefAsyncResult = await JSRuntime.Current.InvokeAsync<Dictionary<string, object>>("receiveDotNetObjectByRefAsync", passDotNetObjectByRefArg);
|
||||
ReceiveDotNetObjectByRefResult["testDto"] = ReceiveDotNetObjectByRefResult["testDto"] == passDotNetObjectByRef ? "Same" : "Different";
|
||||
ReceiveDotNetObjectByRefAsyncResult["testDto"] = ReceiveDotNetObjectByRefAsyncResult["testDto"] == passDotNetObjectByRef ? "Same" : "Different";
|
||||
|
||||
ReturnValues["returnPrimitive"] = inProcRuntime.Invoke<int>("returnPrimitive").ToString();
|
||||
ReturnValues["returnPrimitiveAsync"] = (await JSRuntime.Current.InvokeAsync<int>("returnPrimitiveAsync")).ToString();
|
||||
if (shouldSupportSyncInterop)
|
||||
{
|
||||
ReturnValues["returnPrimitive"] = ((IJSInProcessRuntime)JSRuntime.Current).Invoke<int>("returnPrimitive").ToString();
|
||||
}
|
||||
|
||||
Invocations = invocations;
|
||||
DoneWithInterop = true;
|
||||
}
|
||||
|
||||
public void InvokeInProcessInterop()
|
||||
{
|
||||
var inProcRuntime = ((IJSInProcessRuntime)JSRuntime.Current);
|
||||
|
||||
try
|
||||
{
|
||||
inProcRuntime.Invoke<object>("jsInteropTests.functionThrowsException");
|
||||
}
|
||||
catch (JSException e)
|
||||
{
|
||||
ExceptionFromSyncMethod = e;
|
||||
}
|
||||
|
||||
var passDotNetObjectByRef = new TestDTO(99999);
|
||||
var passDotNetObjectByRefArg = new Dictionary<string, object>
|
||||
{
|
||||
{ "stringValue", "My string" },
|
||||
{ "testDto", new DotNetObjectRef(passDotNetObjectByRef) },
|
||||
};
|
||||
ReceiveDotNetObjectByRefResult = inProcRuntime.Invoke<Dictionary<string, object>>("receiveDotNetObjectByRef", passDotNetObjectByRefArg);
|
||||
ReceiveDotNetObjectByRefResult["testDto"] = ReceiveDotNetObjectByRefResult["testDto"] == passDotNetObjectByRef ? "Same" : "Different";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,19 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Blazor.Browser.Http;
|
||||
using Microsoft.AspNetCore.Blazor.Browser.Rendering;
|
||||
using Microsoft.AspNetCore.Blazor.Browser.Services;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Blazor.Hosting;
|
||||
|
||||
namespace BasicTestApp
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Needed because the test server runs on a different port than the client app,
|
||||
// and we want to test sending/receiving cookies undering this config
|
||||
BrowserHttpMessageHandler.DefaultCredentials = FetchCredentialsOption.Include;
|
||||
|
||||
// Signal to tests that we're ready
|
||||
GC.KeepAlive(ActivateMonoJSRuntime.EnsureActivated());
|
||||
JSRuntime.Current.InvokeAsync<object>("testReady");
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
[JSInvokable(nameof(MountTestComponent))]
|
||||
public static void MountTestComponent(string componentTypeName)
|
||||
{
|
||||
var componentType = Type.GetType(componentTypeName);
|
||||
new BrowserRenderer().AddComponent(componentType, "app");
|
||||
}
|
||||
public static IWebAssemblyHostBuilder CreateHostBuilder(string[] args) =>
|
||||
BlazorWebAssemblyHost.CreateDefaultBuilder()
|
||||
.UseBlazorStartup<Startup>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Blazor.Browser.Http;
|
||||
using Microsoft.AspNetCore.Blazor.Browser.Services;
|
||||
using Microsoft.AspNetCore.Blazor.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BasicTestApp
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
}
|
||||
|
||||
public void Configure(IBlazorApplicationBuilder app)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("WEBASSEMBLY")))
|
||||
{
|
||||
// Needed because the test server runs on a different port than the client app,
|
||||
// and we want to test sending/receiving cookies undering this config
|
||||
BrowserHttpMessageHandler.DefaultCredentials = FetchCredentialsOption.Include;
|
||||
|
||||
GC.KeepAlive(ActivateMonoJSRuntime.EnsureActivated());
|
||||
}
|
||||
|
||||
app.AddComponent<Index>("root");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,71 +6,26 @@
|
|||
<base href="/subdir/" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="test-selector" style="display: none;">
|
||||
Select test:
|
||||
<select onchange="mountTestComponent(event.target.value)">
|
||||
<option value="">Choose...</option>
|
||||
<option value="BasicTestApp.InteropComponent">Interop component</option>
|
||||
<option value="BasicTestApp.AsyncEventHandlerComponent">Async event handlers</option>
|
||||
<option value="BasicTestApp.AddRemoveChildComponents">Add/remove child components</option>
|
||||
<option value="BasicTestApp.CounterComponent">Counter</option>
|
||||
<option value="BasicTestApp.CounterComponentUsingChild">Counter using child component</option>
|
||||
<option value="BasicTestApp.CounterComponentWrapper">Counter wrapped in parent</option>
|
||||
<option value="BasicTestApp.FocusEventComponent">Focus events</option>
|
||||
<option value="BasicTestApp.KeyPressEventComponent">Key press event</option>
|
||||
<option value="BasicTestApp.MouseEventComponent">Mouse events</option>
|
||||
<option value="BasicTestApp.TouchEventComponent">Touch events</option>
|
||||
<option value="BasicTestApp.ParentChildComponent">Parent component with child</option>
|
||||
<option value="BasicTestApp.PropertiesChangedHandlerParent">Parent component that changes parameters on child</option>
|
||||
<option value="BasicTestApp.RedTextComponent">Red text</option>
|
||||
<option value="BasicTestApp.RenderFragmentToggler">Render fragment renderer</option>
|
||||
<option value="BasicTestApp.TextOnlyComponent">Plain text</option>
|
||||
<option value="BasicTestApp.HierarchicalImportsTest.Subdir.ComponentUsingImports">Imports statement</option>
|
||||
<option value="BasicTestApp.HttpClientTest.HttpRequestsComponent">HttpClient tester</option>
|
||||
<option value="BasicTestApp.HttpClientTest.BinaryHttpRequestsComponent">Binary HttpClient tester</option>
|
||||
<option value="BasicTestApp.HttpClientTest.CookieCounterComponent">HttpClient cookies</option>
|
||||
<option value="BasicTestApp.BindCasesComponent">@bind cases</option>
|
||||
<option value="BasicTestApp.ExternalContentPackage">External content package</option>
|
||||
<option value="BasicTestApp.SvgComponent">SVG</option>
|
||||
<option value="BasicTestApp.SvgWithChildComponent">SVG with child component</option>
|
||||
<option value="BasicTestApp.LogicalElementInsertionCases">Logical element insertion cases</option>
|
||||
<option value="BasicTestApp.ElementRefComponent">Element ref component</option>
|
||||
<option value="BasicTestApp.ComponentRefComponent">Component ref component</option>
|
||||
<option value="BasicTestApp.AfterRenderInteropComponent">After-render interop component</option>
|
||||
<option value="BasicTestApp.EventCasesComponent">Event cases</option>
|
||||
<!--<option value="BasicTestApp.RouterTest.Default">Router</option> Excluded because it requires additional setup to work correctly when loaded manually -->
|
||||
</select>
|
||||
|
||||
<span id="source-info"></span>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<app>Loading...</app>
|
||||
|
||||
<script src="_framework/blazor.webassembly.js"></script>
|
||||
<root>Loading...</root>
|
||||
|
||||
<!-- Used for testing interop scenarios between JS and .NET -->
|
||||
<script src="js/jsinteroptests.js"></script>
|
||||
|
||||
<script>
|
||||
// The client-side .NET code calls this when it is ready to be called from test code
|
||||
// The Xunit test code polls until it sees the flag is set
|
||||
function testReady() {
|
||||
window.isTestReady = true;
|
||||
document.getElementsByTagName('APP')[0].textContent = '';
|
||||
document.getElementById('test-selector').style.display = 'block';
|
||||
}
|
||||
|
||||
// The Xunit test code calls this when setting up tests for specific components
|
||||
function mountTestComponent(typeName) {
|
||||
document.getElementById('source-info').innerHTML = '<code><tt>' + typeName.replace(/\./g, '/') + '.cshtml</code></strong>';
|
||||
DotNet.invokeMethodAsync('BasicTestApp', 'MountTestComponent', typeName);
|
||||
}
|
||||
|
||||
// Used by ElementRefComponent
|
||||
function setElementValue(element, newValue) {
|
||||
element.value = newValue;
|
||||
}
|
||||
|
||||
(function () {
|
||||
// Load either blazor.webassembly.js or blazor.server.js depending
|
||||
// on the hash part of the URL. This is just to give a way for the
|
||||
// test runner to make the selection.
|
||||
var src = location.hash === '#server'
|
||||
? 'blazor.server.js'
|
||||
: 'blazor.webassembly.js';
|
||||
document.write('<script src="_framework/' + src + '"><' + '/script>');
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -4,40 +4,42 @@
|
|||
var results = {};
|
||||
var assemblyName = 'BasicTestApp';
|
||||
|
||||
function invokeDotNetInteropMethodsAsync(dotNetObjectByRef, instanceMethodsTarget) {
|
||||
console.log('Invoking void sync methods.');
|
||||
DotNet.invokeMethod(assemblyName, 'VoidParameterless');
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithOneParameter', ...createArgumentList(1, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithTwoParameters', ...createArgumentList(2, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithThreeParameters', ...createArgumentList(3, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithFourParameters', ...createArgumentList(4, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithFiveParameters', ...createArgumentList(5, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithSixParameters', ...createArgumentList(6, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithSevenParameters', ...createArgumentList(7, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithEightParameters', ...createArgumentList(8, dotNetObjectByRef));
|
||||
function invokeDotNetInteropMethodsAsync(shouldSupportSyncInterop, dotNetObjectByRef, instanceMethodsTarget) {
|
||||
if (shouldSupportSyncInterop) {
|
||||
console.log('Invoking void sync methods.');
|
||||
DotNet.invokeMethod(assemblyName, 'VoidParameterless');
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithOneParameter', ...createArgumentList(1, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithTwoParameters', ...createArgumentList(2, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithThreeParameters', ...createArgumentList(3, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithFourParameters', ...createArgumentList(4, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithFiveParameters', ...createArgumentList(5, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithSixParameters', ...createArgumentList(6, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithSevenParameters', ...createArgumentList(7, dotNetObjectByRef));
|
||||
DotNet.invokeMethod(assemblyName, 'VoidWithEightParameters', ...createArgumentList(8, dotNetObjectByRef));
|
||||
|
||||
console.log('Invoking returning sync methods.');
|
||||
results['result1'] = DotNet.invokeMethod(assemblyName, 'ReturnArray');
|
||||
results['result2'] = DotNet.invokeMethod(assemblyName, 'EchoOneParameter', ...createArgumentList(1, dotNetObjectByRef));
|
||||
results['result3'] = DotNet.invokeMethod(assemblyName, 'EchoTwoParameters', ...createArgumentList(2, dotNetObjectByRef));
|
||||
results['result4'] = DotNet.invokeMethod(assemblyName, 'EchoThreeParameters', ...createArgumentList(3, dotNetObjectByRef));
|
||||
results['result5'] = DotNet.invokeMethod(assemblyName, 'EchoFourParameters', ...createArgumentList(4, dotNetObjectByRef));
|
||||
results['result6'] = DotNet.invokeMethod(assemblyName, 'EchoFiveParameters', ...createArgumentList(5, dotNetObjectByRef));
|
||||
results['result7'] = DotNet.invokeMethod(assemblyName, 'EchoSixParameters', ...createArgumentList(6, dotNetObjectByRef));
|
||||
results['result8'] = DotNet.invokeMethod(assemblyName, 'EchoSevenParameters', ...createArgumentList(7, dotNetObjectByRef));
|
||||
results['result9'] = DotNet.invokeMethod(assemblyName, 'EchoEightParameters', ...createArgumentList(8, dotNetObjectByRef));
|
||||
console.log('Invoking returning sync methods.');
|
||||
results['result1'] = DotNet.invokeMethod(assemblyName, 'ReturnArray');
|
||||
results['result2'] = DotNet.invokeMethod(assemblyName, 'EchoOneParameter', ...createArgumentList(1, dotNetObjectByRef));
|
||||
results['result3'] = DotNet.invokeMethod(assemblyName, 'EchoTwoParameters', ...createArgumentList(2, dotNetObjectByRef));
|
||||
results['result4'] = DotNet.invokeMethod(assemblyName, 'EchoThreeParameters', ...createArgumentList(3, dotNetObjectByRef));
|
||||
results['result5'] = DotNet.invokeMethod(assemblyName, 'EchoFourParameters', ...createArgumentList(4, dotNetObjectByRef));
|
||||
results['result6'] = DotNet.invokeMethod(assemblyName, 'EchoFiveParameters', ...createArgumentList(5, dotNetObjectByRef));
|
||||
results['result7'] = DotNet.invokeMethod(assemblyName, 'EchoSixParameters', ...createArgumentList(6, dotNetObjectByRef));
|
||||
results['result8'] = DotNet.invokeMethod(assemblyName, 'EchoSevenParameters', ...createArgumentList(7, dotNetObjectByRef));
|
||||
results['result9'] = DotNet.invokeMethod(assemblyName, 'EchoEightParameters', ...createArgumentList(8, dotNetObjectByRef));
|
||||
|
||||
var returnDotNetObjectByRefResult = DotNet.invokeMethod(assemblyName, 'ReturnDotNetObjectByRef');
|
||||
results['resultReturnDotNetObjectByRefSync'] = DotNet.invokeMethod(assemblyName, 'ExtractNonSerializedValue', returnDotNetObjectByRefResult['Some sync instance']);
|
||||
var returnDotNetObjectByRefResult = DotNet.invokeMethod(assemblyName, 'ReturnDotNetObjectByRef');
|
||||
results['resultReturnDotNetObjectByRefSync'] = DotNet.invokeMethod(assemblyName, 'ExtractNonSerializedValue', returnDotNetObjectByRefResult['Some sync instance']);
|
||||
|
||||
var instanceMethodResult = instanceMethodsTarget.invokeMethod('InstanceMethod', {
|
||||
stringValue: 'My string',
|
||||
dtoByRef: dotNetObjectByRef
|
||||
});
|
||||
results['instanceMethodThisTypeName'] = instanceMethodResult.thisTypeName;
|
||||
results['instanceMethodStringValueUpper'] = instanceMethodResult.stringValueUpper;
|
||||
results['instanceMethodIncomingByRef'] = instanceMethodResult.incomingByRef;
|
||||
results['instanceMethodOutgoingByRef'] = DotNet.invokeMethod(assemblyName, 'ExtractNonSerializedValue', instanceMethodResult.outgoingByRef);
|
||||
var instanceMethodResult = instanceMethodsTarget.invokeMethod('InstanceMethod', {
|
||||
stringValue: 'My string',
|
||||
dtoByRef: dotNetObjectByRef
|
||||
});
|
||||
results['instanceMethodThisTypeName'] = instanceMethodResult.thisTypeName;
|
||||
results['instanceMethodStringValueUpper'] = instanceMethodResult.stringValueUpper;
|
||||
results['instanceMethodIncomingByRef'] = instanceMethodResult.incomingByRef;
|
||||
results['instanceMethodOutgoingByRef'] = DotNet.invokeMethod(assemblyName, 'ExtractNonSerializedValue', instanceMethodResult.outgoingByRef);
|
||||
}
|
||||
|
||||
console.log('Invoking void async methods.');
|
||||
return DotNet.invokeMethodAsync(assemblyName, 'VoidParameterlessAsync')
|
||||
|
@ -70,8 +72,9 @@ function invokeDotNetInteropMethodsAsync(dotNetObjectByRef, instanceMethodsTarge
|
|||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoEightParametersAsync', ...createArgumentList(8, dotNetObjectByRef)))
|
||||
.then(r => results['result9Async'] = r)
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'ReturnDotNetObjectByRefAsync'))
|
||||
.then(r => DotNet.invokeMethodAsync(assemblyName, 'ExtractNonSerializedValue', r['Some async instance']))
|
||||
.then(r => {
|
||||
results['resultReturnDotNetObjectByRefAsync'] = DotNet.invokeMethod(assemblyName, 'ExtractNonSerializedValue', r['Some async instance']);
|
||||
results['resultReturnDotNetObjectByRefAsync'] = r;
|
||||
})
|
||||
.then(() => instanceMethodsTarget.invokeMethodAsync('InstanceMethodAsync', {
|
||||
stringValue: 'My string',
|
||||
|
@ -81,13 +84,15 @@ function invokeDotNetInteropMethodsAsync(dotNetObjectByRef, instanceMethodsTarge
|
|||
results['instanceMethodThisTypeNameAsync'] = r.thisTypeName;
|
||||
results['instanceMethodStringValueUpperAsync'] = r.stringValueUpper;
|
||||
results['instanceMethodIncomingByRefAsync'] = r.incomingByRef;
|
||||
results['instanceMethodOutgoingByRefAsync'] = DotNet.invokeMethod(assemblyName, 'ExtractNonSerializedValue', r.outgoingByRef);
|
||||
return DotNet.invokeMethodAsync(assemblyName, 'ExtractNonSerializedValue', r.outgoingByRef);
|
||||
}).then(r => {
|
||||
results['instanceMethodOutgoingByRefAsync'] = r;
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
console.log('Invoking methods that throw exceptions');
|
||||
try {
|
||||
DotNet.invokeMethod(assemblyName, 'ThrowException');
|
||||
shouldSupportSyncInterop && DotNet.invokeMethod(assemblyName, 'ThrowException');
|
||||
} catch (e) {
|
||||
results['ThrowException'] = e.message;
|
||||
}
|
||||
|
@ -224,10 +229,18 @@ function receiveDotNetObjectByRef(incomingData) {
|
|||
}
|
||||
|
||||
function receiveDotNetObjectByRefAsync(incomingData) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(function () {
|
||||
const promiseResult = receiveDotNetObjectByRef(incomingData);
|
||||
resolve(promiseResult);
|
||||
}, 100);
|
||||
const stringValue = incomingData.stringValue;
|
||||
const testDto = incomingData.testDto;
|
||||
|
||||
// To verify we received a proper reference to testDto, pass it back into .NET
|
||||
// to have it evaluate something that only .NET can know
|
||||
return DotNet.invokeMethodAsync(assemblyName, 'ExtractNonSerializedValue', testDto).then(testDtoNonSerializedValue => {
|
||||
// To show we can return a .NET object by ref anywhere in a complex structure,
|
||||
// return it among other values
|
||||
return {
|
||||
stringValueUpper: stringValue.toUpperCase(),
|
||||
testDtoNonSerializedValue: testDtoNonSerializedValue,
|
||||
testDto: testDto
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
@ -22,6 +22,7 @@ namespace TestServer
|
|||
{
|
||||
options.AddPolicy("AllowAll", _ => { /* Controlled below */ });
|
||||
});
|
||||
services.AddServerSideBlazor<BasicTestApp.Startup>();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
@ -34,6 +35,12 @@ namespace TestServer
|
|||
|
||||
AllowCorsForAnyLocalhostPort(app);
|
||||
app.UseMvc();
|
||||
|
||||
// Mount the server-side Blazor app on /subdir
|
||||
app.Map("/subdir", subdirApp =>
|
||||
{
|
||||
subdirApp.UseServerSideBlazor<BasicTestApp.Startup>();
|
||||
});
|
||||
}
|
||||
|
||||
private static void AllowCorsForAnyLocalhostPort(IApplicationBuilder app)
|
||||
|
|
|
@ -7,4 +7,9 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="$(AspNetCorePackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Microsoft.AspNetCore.Blazor.Server\Microsoft.AspNetCore.Blazor.Server.csproj" />
|
||||
<ProjectReference Include="..\BasicTestApp\BasicTestApp.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
Загрузка…
Ссылка в новой задаче