Add a few tests for generic JSInterop (#14626)
Fixes https://github.com/aspnet/AspNetCore/issues/9061
This commit is contained in:
parent
b9d0e61144
commit
9e84abec47
|
|
@ -11,6 +11,7 @@ using OpenQA.Selenium;
|
|||
using OpenQA.Selenium.Support.UI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||
{
|
||||
|
|
@ -68,6 +69,8 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
["testDtoAsync"] = "Same",
|
||||
["returnPrimitiveAsync"] = "123",
|
||||
["returnArrayAsync"] = "first,second",
|
||||
["syncGenericInstanceMethod"] = @"""Initial value""",
|
||||
["asyncGenericInstanceMethod"] = @"""Updated value 1""",
|
||||
};
|
||||
|
||||
var expectedSyncValues = new Dictionary<string, string>
|
||||
|
|
@ -102,6 +105,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
["testDtoSync"] = "Same",
|
||||
["returnPrimitive"] = "123",
|
||||
["returnArray"] = "first,second",
|
||||
["genericInstanceMethod"] = @"""Updated value 2""",
|
||||
};
|
||||
|
||||
// Include the sync assertions only when running under WebAssembly
|
||||
|
|
@ -132,13 +136,17 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
// Assert
|
||||
foreach (var expectedValue in expectedValues)
|
||||
{
|
||||
var actualValue = actualValues[expectedValue.Key];
|
||||
if (expectedValue.Key.Contains("Exception"))
|
||||
{
|
||||
Assert.StartsWith(expectedValue.Value, actualValues[expectedValue.Key]);
|
||||
Assert.StartsWith(expectedValue.Value, actualValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal(expectedValue.Value, actualValues[expectedValue.Key]);
|
||||
if (expectedValue.Value != actualValue)
|
||||
{
|
||||
throw new AssertActualExpectedException(expectedValue.Value, actualValue, $"Scenario '{expectedValue.Key}' failed. Expected '{expectedValue.Value}, Actual {actualValue}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,13 +70,15 @@
|
|||
var shouldSupportSyncInterop = RuntimeInformation.IsOSPlatform(OSPlatform.Create("WEBASSEMBLY"));
|
||||
var testDTOTOPassByRef = new TestDTO(nonSerializedValue: 123);
|
||||
var instanceMethodsTarget = new JavaScriptInterop();
|
||||
var genericType = new JavaScriptInterop.GenericType<string> { Value = "Initial value" };
|
||||
|
||||
Console.WriteLine("Starting interop invocations.");
|
||||
await JSRuntime.InvokeVoidAsync(
|
||||
"jsInteropTests.invokeDotNetInteropMethodsAsync",
|
||||
shouldSupportSyncInterop,
|
||||
DotNetObjectReference.Create(testDTOTOPassByRef),
|
||||
DotNetObjectReference.Create(instanceMethodsTarget));
|
||||
DotNetObjectReference.Create(instanceMethodsTarget),
|
||||
DotNetObjectReference.Create(genericType));
|
||||
|
||||
if (shouldSupportSyncInterop)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -462,5 +462,25 @@ namespace BasicTestApp.InteropTest
|
|||
|
||||
public DotNetObjectReference<TestDTO> OutgoingByRef { get; set; }
|
||||
}
|
||||
|
||||
public class GenericType<TValue>
|
||||
{
|
||||
public TValue Value { get; set; }
|
||||
|
||||
[JSInvokable]
|
||||
public TValue Update(TValue newValue)
|
||||
{
|
||||
var oldValue = Value;
|
||||
Value = newValue;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
[JSInvokable]
|
||||
public async Task<TValue> UpdateAsync(TValue newValue)
|
||||
{
|
||||
await Task.Yield();
|
||||
return Update(newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
var results = {};
|
||||
var assemblyName = 'BasicTestApp';
|
||||
|
||||
function invokeDotNetInteropMethodsAsync(shouldSupportSyncInterop, dotNetObjectByRef, instanceMethodsTarget) {
|
||||
async function invokeDotNetInteropMethodsAsync(shouldSupportSyncInterop, dotNetObjectByRef, instanceMethodsTarget, genericDotNetObjectByRef) {
|
||||
if (shouldSupportSyncInterop) {
|
||||
console.log('Invoking void sync methods.');
|
||||
DotNet.invokeMethod(assemblyName, 'VoidParameterless');
|
||||
|
|
@ -15,6 +15,7 @@ function invokeDotNetInteropMethodsAsync(shouldSupportSyncInterop, dotNetObjectB
|
|||
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));
|
||||
|
|
@ -40,75 +41,73 @@ function invokeDotNetInteropMethodsAsync(shouldSupportSyncInterop, dotNetObjectB
|
|||
}
|
||||
|
||||
console.log('Invoking void async methods.');
|
||||
return DotNet.invokeMethodAsync(assemblyName, 'VoidParameterlessAsync')
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithOneParameterAsync', ...createArgumentList(1, dotNetObjectByRef)))
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithTwoParametersAsync', ...createArgumentList(2, dotNetObjectByRef)))
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithThreeParametersAsync', ...createArgumentList(3, dotNetObjectByRef)))
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithFourParametersAsync', ...createArgumentList(4, dotNetObjectByRef)))
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithFiveParametersAsync', ...createArgumentList(5, dotNetObjectByRef)))
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithSixParametersAsync', ...createArgumentList(6, dotNetObjectByRef)))
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithSevenParametersAsync', ...createArgumentList(7, dotNetObjectByRef)))
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'VoidWithEightParametersAsync', ...createArgumentList(8, dotNetObjectByRef)))
|
||||
.then(() => {
|
||||
console.log('Invoking returning async methods.');
|
||||
return DotNet.invokeMethodAsync(assemblyName, 'ReturnArrayAsync')
|
||||
.then(r => results['result1Async'] = r)
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoOneParameterAsync', ...createArgumentList(1, dotNetObjectByRef)))
|
||||
.then(r => results['result2Async'] = r)
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoTwoParametersAsync', ...createArgumentList(2, dotNetObjectByRef)))
|
||||
.then(r => results['result3Async'] = r)
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoThreeParametersAsync', ...createArgumentList(3, dotNetObjectByRef)))
|
||||
.then(r => results['result4Async'] = r)
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoFourParametersAsync', ...createArgumentList(4, dotNetObjectByRef)))
|
||||
.then(r => results['result5Async'] = r)
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoFiveParametersAsync', ...createArgumentList(5, dotNetObjectByRef)))
|
||||
.then(r => results['result6Async'] = r)
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoSixParametersAsync', ...createArgumentList(6, dotNetObjectByRef)))
|
||||
.then(r => results['result7Async'] = r)
|
||||
.then(() => DotNet.invokeMethodAsync(assemblyName, 'EchoSevenParametersAsync', ...createArgumentList(7, dotNetObjectByRef)))
|
||||
.then(r => results['result8Async'] = r)
|
||||
.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'] = r;
|
||||
})
|
||||
.then(() => instanceMethodsTarget.invokeMethodAsync('InstanceMethodAsync', {
|
||||
stringValue: 'My string',
|
||||
dtoByRef: dotNetObjectByRef
|
||||
}))
|
||||
.then(r => {
|
||||
results['instanceMethodThisTypeNameAsync'] = r.thisTypeName;
|
||||
results['instanceMethodStringValueUpperAsync'] = r.stringValueUpper;
|
||||
results['instanceMethodIncomingByRefAsync'] = r.incomingByRef;
|
||||
return DotNet.invokeMethodAsync(assemblyName, 'ExtractNonSerializedValue', r.outgoingByRef);
|
||||
}).then(r => {
|
||||
results['instanceMethodOutgoingByRefAsync'] = r;
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
console.log('Invoking methods that throw exceptions');
|
||||
try {
|
||||
shouldSupportSyncInterop && DotNet.invokeMethod(assemblyName, 'ThrowException');
|
||||
} catch (e) {
|
||||
results['ThrowException'] = e.message;
|
||||
}
|
||||
|
||||
return DotNet.invokeMethodAsync(assemblyName, 'AsyncThrowSyncException')
|
||||
.catch(e => {
|
||||
results['AsyncThrowSyncException'] = e.message;
|
||||
await DotNet.invokeMethodAsync(assemblyName, 'VoidParameterlessAsync');
|
||||
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithOneParameterAsync', ...createArgumentList(1, dotNetObjectByRef));
|
||||
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithTwoParametersAsync', ...createArgumentList(2, dotNetObjectByRef));
|
||||
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithThreeParametersAsync', ...createArgumentList(3, dotNetObjectByRef));
|
||||
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithFourParametersAsync', ...createArgumentList(4, dotNetObjectByRef));
|
||||
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithFiveParametersAsync', ...createArgumentList(5, dotNetObjectByRef));
|
||||
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithSixParametersAsync', ...createArgumentList(6, dotNetObjectByRef));
|
||||
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithSevenParametersAsync', ...createArgumentList(7, dotNetObjectByRef));
|
||||
await DotNet.invokeMethodAsync(assemblyName, 'VoidWithEightParametersAsync', ...createArgumentList(8, dotNetObjectByRef));
|
||||
|
||||
return DotNet.invokeMethodAsync(assemblyName, 'AsyncThrowAsyncException');
|
||||
}).catch(e => {
|
||||
results['AsyncThrowAsyncException'] = e.message;
|
||||
console.log('Invoking returning async methods.');
|
||||
results['result1Async'] = await DotNet.invokeMethodAsync(assemblyName, 'ReturnArrayAsync');
|
||||
results['result2Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoOneParameterAsync', ...createArgumentList(1, dotNetObjectByRef));
|
||||
results['result3Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoTwoParametersAsync', ...createArgumentList(2, dotNetObjectByRef));
|
||||
results['result4Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoThreeParametersAsync', ...createArgumentList(3, dotNetObjectByRef));
|
||||
results['result5Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoFourParametersAsync', ...createArgumentList(4, dotNetObjectByRef));
|
||||
results['result6Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoFiveParametersAsync', ...createArgumentList(5, dotNetObjectByRef));
|
||||
results['result7Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoSixParametersAsync', ...createArgumentList(6, dotNetObjectByRef));
|
||||
results['result8Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoSevenParametersAsync', ...createArgumentList(7, dotNetObjectByRef));
|
||||
results['result9Async'] = await DotNet.invokeMethodAsync(assemblyName, 'EchoEightParametersAsync', ...createArgumentList(8, dotNetObjectByRef));
|
||||
|
||||
console.log('Done invoking interop methods');
|
||||
});
|
||||
});
|
||||
const returnDotNetObjectByRefAsync = await DotNet.invokeMethodAsync(assemblyName, 'ReturnDotNetObjectByRefAsync');
|
||||
results['resultReturnDotNetObjectByRefAsync'] = await DotNet.invokeMethodAsync(assemblyName, 'ExtractNonSerializedValue', returnDotNetObjectByRefAsync['Some async instance']);
|
||||
|
||||
const instanceMethodAsync = await instanceMethodsTarget.invokeMethodAsync('InstanceMethodAsync', {
|
||||
stringValue: 'My string',
|
||||
dtoByRef: dotNetObjectByRef
|
||||
});
|
||||
|
||||
results['instanceMethodThisTypeNameAsync'] = instanceMethodAsync.thisTypeName;
|
||||
results['instanceMethodStringValueUpperAsync'] = instanceMethodAsync.stringValueUpper;
|
||||
results['instanceMethodIncomingByRefAsync'] = instanceMethodAsync.incomingByRef;
|
||||
results['instanceMethodOutgoingByRefAsync'] = await DotNet.invokeMethodAsync(assemblyName, 'ExtractNonSerializedValue', instanceMethodAsync.outgoingByRef);
|
||||
|
||||
console.log('Invoking generic type instance methods.');
|
||||
|
||||
results['syncGenericInstanceMethod'] = await genericDotNetObjectByRef.invokeMethodAsync('Update', 'Updated value 1');
|
||||
results['asyncGenericInstanceMethod'] = await genericDotNetObjectByRef.invokeMethodAsync('UpdateAsync', 'Updated value 2');
|
||||
|
||||
if (shouldSupportSyncInterop) {
|
||||
results['genericInstanceMethod'] = genericDotNetObjectByRef.invokeMethod('Update', 'Updated Value 3');
|
||||
}
|
||||
|
||||
console.log('Invoking methods that throw exceptions');
|
||||
try {
|
||||
shouldSupportSyncInterop && DotNet.invokeMethod(assemblyName, 'ThrowException');
|
||||
} catch (e) {
|
||||
results['ThrowException'] = e.message;
|
||||
}
|
||||
|
||||
try {
|
||||
await DotNet.invokeMethodAsync(assemblyName, 'AsyncThrowSyncException');
|
||||
} catch (e) {
|
||||
results['AsyncThrowSyncException'] = e.message;
|
||||
}
|
||||
|
||||
try {
|
||||
await DotNet.invokeMethodAsync(assemblyName, 'AsyncThrowAsyncException');
|
||||
} catch (e) {
|
||||
results['AsyncThrowAsyncException'] = e.message;
|
||||
}
|
||||
|
||||
console.log('Done invoking interop methods');
|
||||
}
|
||||
|
||||
function createArgumentList(argumentNumber, dotNetObjectByRef){
|
||||
function createArgumentList(argumentNumber, dotNetObjectByRef) {
|
||||
const array = new Array(argumentNumber);
|
||||
if (argumentNumber === 0) {
|
||||
return [];
|
||||
|
|
@ -149,7 +148,7 @@ function createArgumentList(argumentNumber, dotNetObjectByRef){
|
|||
source: `Some random text with at least ${i} characters`,
|
||||
start: argumentNumber + 1,
|
||||
length: argumentNumber + 1
|
||||
}
|
||||
};
|
||||
break;
|
||||
default:
|
||||
console.log(i);
|
||||
|
|
@ -169,7 +168,7 @@ window.jsInteropTests = {
|
|||
returnPrimitive: returnPrimitive,
|
||||
returnPrimitiveAsync: returnPrimitiveAsync,
|
||||
receiveDotNetObjectByRef: receiveDotNetObjectByRef,
|
||||
receiveDotNetObjectByRefAsync: receiveDotNetObjectByRefAsync,
|
||||
receiveDotNetObjectByRefAsync: receiveDotNetObjectByRefAsync
|
||||
};
|
||||
|
||||
function returnPrimitive() {
|
||||
|
|
@ -211,9 +210,9 @@ function asyncFunctionThrowsAsyncException() {
|
|||
}
|
||||
|
||||
function asyncFunctionTakesLongerThanDefaultTimeoutToResolve() {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => resolve(undefined), 5000);
|
||||
});
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => resolve(undefined), 5000);
|
||||
});
|
||||
}
|
||||
|
||||
function collectInteropResults() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue