From 76a6019c2792073717ca2200cda63b67c1fb3010 Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Thu, 31 Aug 2023 12:43:46 -0700 Subject: [PATCH 01/10] Support resolving IFormFile in complex form mapping --- .../FormMapping/Converters/FileConverter.cs | 49 ++++++++++++ .../Factories/FileConverterFactory.cs | 22 ++++++ .../src/FormMapping/FormDataMapperOptions.cs | 2 + .../Metadata/FormDataMetadataFactory.cs | 1 + .../FormMapping/Metadata/FormDataTypeKind.cs | 1 + .../src/RequestDelegateFactory.cs | 8 +- .../src/RequestDelegateFactoryContext.cs | 3 + ...RequestDelegateFactoryTests.FormMapping.cs | 75 +++++++++++++++++++ 8 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs create mode 100644 src/Components/Endpoints/src/FormMapping/Factories/FileConverterFactory.cs diff --git a/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs b/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs new file mode 100644 index 000000000000..6adb0fa2394f --- /dev/null +++ b/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping; + +internal sealed class FileConverter(HttpContext? httpContext) : FormDataConverter, ISingleValueConverter +{ + [RequiresDynamicCode(FormMappingHelpers.RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(FormMappingHelpers.RequiresUnreferencedCodeMessage)] + internal override bool TryRead(ref FormDataReader reader, Type type, FormDataMapperOptions options, out T? result, out bool found) + { + if (httpContext == null) + { + result = default; + found = false; + return true; + } + + if (typeof(T) == typeof(IFormFileCollection)) + { + result = (T)httpContext.Request.Form.Files; + found = true; + return true; + } + + var formFileCollection = httpContext.Request.Form.Files; + if (formFileCollection.Count == 0) + { + result = default; + found = false; + return true; + } + + var file = formFileCollection.GetFile(reader.CurrentPrefix.ToString()); + if (file != null) + { + result = (T)file; + found = true; + return true; + } + + result = default; + found = false; + return true; + } +} diff --git a/src/Components/Endpoints/src/FormMapping/Factories/FileConverterFactory.cs b/src/Components/Endpoints/src/FormMapping/Factories/FileConverterFactory.cs new file mode 100644 index 000000000000..c474dfe307d1 --- /dev/null +++ b/src/Components/Endpoints/src/FormMapping/Factories/FileConverterFactory.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping; + +internal sealed class FileConverterFactory(IHttpContextAccessor httpContextAccessor) : IFormDataConverterFactory +{ + [RequiresDynamicCode(FormMappingHelpers.RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(FormMappingHelpers.RequiresUnreferencedCodeMessage)] + public bool CanConvert(Type type, FormDataMapperOptions options) => type == typeof(IFormFile) || type == typeof(IFormFileCollection); + + [RequiresDynamicCode(FormMappingHelpers.RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(FormMappingHelpers.RequiresUnreferencedCodeMessage)] + public FormDataConverter CreateConverter(Type type, FormDataMapperOptions options) + { + return Activator.CreateInstance(typeof(FileConverter<>).MakeGenericType(type), httpContextAccessor.HttpContext) as FormDataConverter ?? + throw new InvalidOperationException($"Unable to create converter for '{type.FullName}'."); + } +} diff --git a/src/Components/Endpoints/src/FormMapping/FormDataMapperOptions.cs b/src/Components/Endpoints/src/FormMapping/FormDataMapperOptions.cs index 25cbc47cf2f0..70b671101ace 100644 --- a/src/Components/Endpoints/src/FormMapping/FormDataMapperOptions.cs +++ b/src/Components/Endpoints/src/FormMapping/FormDataMapperOptions.cs @@ -3,6 +3,7 @@ using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -27,6 +28,7 @@ public FormDataMapperOptions(ILoggerFactory loggerFactory) _converters = new(WellKnownConverters.Converters); _factories.Add(new ParsableConverterFactory()); _factories.Add(new EnumConverterFactory()); + _factories.Add(new FileConverterFactory()); _factories.Add(new NullableConverterFactory()); _factories.Add(new DictionaryConverterFactory()); _factories.Add(new CollectionConverterFactory()); diff --git a/src/Components/Endpoints/src/FormMapping/Metadata/FormDataMetadataFactory.cs b/src/Components/Endpoints/src/FormMapping/Metadata/FormDataMetadataFactory.cs index bba5501e347d..d29676583d29 100644 --- a/src/Components/Endpoints/src/FormMapping/Metadata/FormDataMetadataFactory.cs +++ b/src/Components/Endpoints/src/FormMapping/Metadata/FormDataMetadataFactory.cs @@ -17,6 +17,7 @@ internal partial class FormDataMetadataFactory(List f private readonly FormMetadataContext _context = new(); private readonly ParsableConverterFactory _parsableFactory = factories.OfType().Single(); private readonly DictionaryConverterFactory _dictionaryFactory = factories.OfType().Single(); + private readonly FileConverterFactory? _fileConverterFactory = factories.OfType().SingleOrDefault(); private readonly CollectionConverterFactory _collectionFactory = factories.OfType().Single(); private readonly ILogger _logger = loggerFactory.CreateLogger(); diff --git a/src/Components/Endpoints/src/FormMapping/Metadata/FormDataTypeKind.cs b/src/Components/Endpoints/src/FormMapping/Metadata/FormDataTypeKind.cs index 011244a7b25a..2b6a28deb5e0 100644 --- a/src/Components/Endpoints/src/FormMapping/Metadata/FormDataTypeKind.cs +++ b/src/Components/Endpoints/src/FormMapping/Metadata/FormDataTypeKind.cs @@ -6,6 +6,7 @@ namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping.Metadata; internal enum FormDataTypeKind { Primitive, + File, Collection, Dictionary, Object, diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs index 81c6d430f8b4..5289ae539b35 100644 --- a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs @@ -276,6 +276,9 @@ private static RequestDelegateFactoryContext CreateFactoryContext(RequestDelegat var serviceProvider = options?.ServiceProvider ?? options?.EndpointBuilder?.ApplicationServices ?? EmptyServiceProvider.Instance; var endpointBuilder = options?.EndpointBuilder ?? new RdfEndpointBuilder(serviceProvider); var jsonSerializerOptions = serviceProvider.GetService>()?.Value.SerializerOptions ?? JsonOptions.DefaultSerializerOptions; + var formDataMapperOptions = serviceProvider.GetService() is {} httpContextAccessor + ? new FormDataMapperOptions(httpContextAccessor) + : new FormDataMapperOptions(); var factoryContext = new RequestDelegateFactoryContext { @@ -288,6 +291,7 @@ private static RequestDelegateFactoryContext CreateFactoryContext(RequestDelegat EndpointBuilder = endpointBuilder, MetadataAlreadyInferred = metadataResult is not null, JsonSerializerOptions = jsonSerializerOptions, + FormDataMapperOptions = formDataMapperOptions }; return factoryContext; @@ -2054,7 +2058,7 @@ private static Expression BindComplexParameterFromFormItem( return formArgument; } - var formDataMapperOptions = new FormDataMapperOptions(); + var formDataMapperOptions = factoryContext.FormDataMapperOptions; var formMappingOptionsMetadatas = factoryContext.EndpointBuilder.Metadata.OfType(); foreach (var formMappingOptionsMetadata in formMappingOptionsMetadatas) { @@ -2073,7 +2077,7 @@ private static Expression BindComplexParameterFromFormItem( // ProcessForm(context.Request.Form, form_dict, form_buffer); var processFormExpr = Expression.Call(ProcessFormMethod, FormExpr, Expression.Constant(formDataMapperOptions.MaxKeyBufferSize), formDict, formBuffer); - // name_reader = new FormDataReader(form_dict, CultureInfo.InvariantCulture, form_buffer.AsMemory(0, FormDataMapperOptions.MaxKeyBufferSize)); + // name_reader = new FormDataReader(form_dict, CultureInfo.InvariantCulture, form_buffer.AsMemory(0, formDataMapperOptions.MaxKeyBufferSize)); var initializeReaderExpr = Expression.Assign( formReader, Expression.New(FormDataReaderConstructor, diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactoryContext.cs b/src/Http/Http.Extensions/src/RequestDelegateFactoryContext.cs index d3c793fbe642..aa87f10f915b 100644 --- a/src/Http/Http.Extensions/src/RequestDelegateFactoryContext.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactoryContext.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Text.Json; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Components.Endpoints.FormMapping; using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Http; @@ -59,4 +60,6 @@ internal sealed class RequestDelegateFactoryContext // Grab these options upfront to avoid the per request DI scope that would be made otherwise to get the options when writing Json public required JsonSerializerOptions JsonSerializerOptions { get; set; } + + public required FormDataMapperOptions FormDataMapperOptions { get; set; } } diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.FormMapping.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.FormMapping.cs index b1c740251adf..f9177bb12158 100644 --- a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.FormMapping.cs +++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.FormMapping.cs @@ -5,6 +5,8 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Testing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; @@ -278,7 +280,58 @@ public async Task SupportsRecursivePropertiesWithRecursionLimit() var exception = await Assert.ThrowsAsync(async () => await requestDelegate(httpContext)); Assert.Equal("The maximum recursion depth of '3' was exceeded for 'Manager.Manager.Manager.Name'.", exception.Message); + } + + [Fact] + public async Task SupportsFormFileSourcesInDto() + { + FormFileDto capturedArgument = default; + void TestAction([FromForm] FormFileDto args) { capturedArgument = args; }; + var httpContext = CreateHttpContext(); + var formFiles = new FormFileCollection + { + new FormFile(Stream.Null, 0, 10, "file", "file.txt"), + }; + httpContext.Request.Form = new FormCollection(new() { { "Description", "A test file" } }, formFiles); + var serviceCollection = new ServiceCollection(); + serviceCollection.TryAddSingleton(new HttpContextAccessor(httpContext)); + var options = new RequestDelegateFactoryOptions + { + ServiceProvider = serviceCollection.BuildServiceProvider() + }; + + var factoryResult = RequestDelegateFactory.Create(TestAction, options); + var requestDelegate = factoryResult.RequestDelegate; + + await requestDelegate(httpContext); + Assert.Equal("A test file", capturedArgument.Description); + Assert.Equal(formFiles["file"], capturedArgument.File); + } + + [Fact] + public async Task SupportsFormFileCollectionSourcesInDto() + { + FormFileCollectionDto capturedArgument = default; + void TestAction([FromForm] FormFileCollectionDto args) { capturedArgument = args; }; + var httpContext = CreateHttpContext(); + var formFiles = new FormFileCollection + { + new FormFile(Stream.Null, 0, 10, "file", "file.txt"), + }; + httpContext.Request.Form = new FormCollection(new() { { "Description", "A test file" } }, formFiles); + var serviceCollection = new ServiceCollection(); + serviceCollection.TryAddSingleton(new HttpContextAccessor(httpContext)); + var options = new RequestDelegateFactoryOptions + { + ServiceProvider = serviceCollection.BuildServiceProvider() + }; + var factoryResult = RequestDelegateFactory.Create(TestAction, options); + var requestDelegate = factoryResult.RequestDelegate; + + await requestDelegate(httpContext); + Assert.Equal("A test file", capturedArgument.Description); + Assert.Equal(formFiles, capturedArgument.FileCollection); } private record TodoRecord(int Id, string Name, bool IsCompleted); @@ -288,4 +341,26 @@ private class Employee public string Name { get; set; } public Employee Manager { get; set; } } + + private class FormFileDto + { + public string Description { get; set; } + public IFormFile File { get; set; } + } + + private class FormFileCollectionDto + { + public string Description { get; set; } + public IFormFileCollection FileCollection { get; set; } + } + + private class HttpContextAccessor(HttpContext httpContext) : IHttpContextAccessor + { + + public HttpContext HttpContext + { + get; + set; + } = httpContext; + } } From e5232bf6ee6089a31850949a83726a112283eeae Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Thu, 7 Sep 2023 21:43:13 -0700 Subject: [PATCH 02/10] Feedback --- .../FormMapping/Converters/FileConverter.cs | 8 +-- .../Factories/FileConverterFactory.cs | 4 +- .../src/FormMapping/FormDataMapperOptions.cs | 3 +- .../src/FormMapping/FormDataReader.cs | 11 +++- .../src/FormMapping/WellKnownConverters.cs | 5 +- .../test/Binding/FormDataMapperTests.cs | 52 +++++++++++++++++- .../src/RequestDelegateFactory.cs | 11 ++-- .../src/RequestDelegateFactoryContext.cs | 3 ++ ...RequestDelegateFactoryTests.FormMapping.cs | 54 ++++++++++--------- 9 files changed, 107 insertions(+), 44 deletions(-) diff --git a/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs b/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs index 6adb0fa2394f..14c5d220ccc3 100644 --- a/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs +++ b/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs @@ -6,13 +6,13 @@ namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping; -internal sealed class FileConverter(HttpContext? httpContext) : FormDataConverter, ISingleValueConverter +internal sealed class FileConverter : FormDataConverter, ISingleValueConverter { [RequiresDynamicCode(FormMappingHelpers.RequiresDynamicCodeMessage)] [RequiresUnreferencedCode(FormMappingHelpers.RequiresUnreferencedCodeMessage)] internal override bool TryRead(ref FormDataReader reader, Type type, FormDataMapperOptions options, out T? result, out bool found) { - if (httpContext == null) + if (reader.FormFileCollection == null) { result = default; found = false; @@ -21,12 +21,12 @@ internal override bool TryRead(ref FormDataReader reader, Type type, FormDataMap if (typeof(T) == typeof(IFormFileCollection)) { - result = (T)httpContext.Request.Form.Files; + result = (T)reader.FormFileCollection; found = true; return true; } - var formFileCollection = httpContext.Request.Form.Files; + var formFileCollection = reader.FormFileCollection; if (formFileCollection.Count == 0) { result = default; diff --git a/src/Components/Endpoints/src/FormMapping/Factories/FileConverterFactory.cs b/src/Components/Endpoints/src/FormMapping/Factories/FileConverterFactory.cs index c474dfe307d1..80b61870d029 100644 --- a/src/Components/Endpoints/src/FormMapping/Factories/FileConverterFactory.cs +++ b/src/Components/Endpoints/src/FormMapping/Factories/FileConverterFactory.cs @@ -6,7 +6,7 @@ namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping; -internal sealed class FileConverterFactory(IHttpContextAccessor httpContextAccessor) : IFormDataConverterFactory +internal sealed class FileConverterFactory : IFormDataConverterFactory { [RequiresDynamicCode(FormMappingHelpers.RequiresDynamicCodeMessage)] [RequiresUnreferencedCode(FormMappingHelpers.RequiresUnreferencedCodeMessage)] @@ -16,7 +16,7 @@ internal sealed class FileConverterFactory(IHttpContextAccessor httpContextAcces [RequiresUnreferencedCode(FormMappingHelpers.RequiresUnreferencedCodeMessage)] public FormDataConverter CreateConverter(Type type, FormDataMapperOptions options) { - return Activator.CreateInstance(typeof(FileConverter<>).MakeGenericType(type), httpContextAccessor.HttpContext) as FormDataConverter ?? + return Activator.CreateInstance(typeof(FileConverter<>).MakeGenericType(type)) as FormDataConverter ?? throw new InvalidOperationException($"Unable to create converter for '{type.FullName}'."); } } diff --git a/src/Components/Endpoints/src/FormMapping/FormDataMapperOptions.cs b/src/Components/Endpoints/src/FormMapping/FormDataMapperOptions.cs index 70b671101ace..12e626930a5f 100644 --- a/src/Components/Endpoints/src/FormMapping/FormDataMapperOptions.cs +++ b/src/Components/Endpoints/src/FormMapping/FormDataMapperOptions.cs @@ -3,7 +3,6 @@ using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -27,8 +26,8 @@ public FormDataMapperOptions(ILoggerFactory loggerFactory) { _converters = new(WellKnownConverters.Converters); _factories.Add(new ParsableConverterFactory()); - _factories.Add(new EnumConverterFactory()); _factories.Add(new FileConverterFactory()); + _factories.Add(new EnumConverterFactory()); _factories.Add(new NullableConverterFactory()); _factories.Add(new DictionaryConverterFactory()); _factories.Add(new CollectionConverterFactory()); diff --git a/src/Components/Endpoints/src/FormMapping/FormDataReader.cs b/src/Components/Endpoints/src/FormMapping/FormDataReader.cs index 1e062dd6bdba..85c65e363e93 100644 --- a/src/Components/Endpoints/src/FormMapping/FormDataReader.cs +++ b/src/Components/Endpoints/src/FormMapping/FormDataReader.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping; @@ -33,9 +34,17 @@ public FormDataReader(IReadOnlyDictionary formCollection, _prefixBuffer = buffer; } + public FormDataReader(IReadOnlyDictionary formCollection, CultureInfo culture, Memory buffer, IFormFileCollection formFileCollection) + : this(formCollection, culture, buffer) + { + FormFileCollection = formFileCollection; + } + internal ReadOnlyMemory CurrentPrefix => _currentPrefixBuffer; - public IFormatProvider Culture { get; internal set; } + public IFormatProvider Culture { get; } + + public IFormFileCollection? FormFileCollection { get; internal set; } public int MaxRecursionDepth { get; set; } = 64; diff --git a/src/Components/Endpoints/src/FormMapping/WellKnownConverters.cs b/src/Components/Endpoints/src/FormMapping/WellKnownConverters.cs index d5b6139f1a8e..25e05396af90 100644 --- a/src/Components/Endpoints/src/FormMapping/WellKnownConverters.cs +++ b/src/Components/Endpoints/src/FormMapping/WellKnownConverters.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping; internal static class WellKnownConverters @@ -37,7 +38,9 @@ static WellKnownConverters() { typeof(DateTimeOffset), new ParsableConverter() }, { typeof(TimeSpan), new ParsableConverter() }, { typeof(TimeOnly), new ParsableConverter() }, - { typeof(Guid), new ParsableConverter() } + { typeof(Guid), new ParsableConverter() }, + { typeof(IFormFileCollection), new FileConverter() }, + { typeof(IFormFile), new FileConverter() } }; converters.Add(typeof(char?), new NullableConverter((FormDataConverter)converters[typeof(char)])); diff --git a/src/Components/Endpoints/test/Binding/FormDataMapperTests.cs b/src/Components/Endpoints/test/Binding/FormDataMapperTests.cs index e82936aa8e1a..fb97d0dd4365 100644 --- a/src/Components/Endpoints/test/Binding/FormDataMapperTests.cs +++ b/src/Components/Endpoints/test/Binding/FormDataMapperTests.cs @@ -9,6 +9,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.Serialization; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping; @@ -72,14 +73,16 @@ public void CanDeserialize_NullableEnumTypes(string value, Colors expected) Assert.Equal(expected, result); } - private FormDataReader CreateFormDataReader(Dictionary collection, CultureInfo invariantCulture) + private FormDataReader CreateFormDataReader(Dictionary collection, CultureInfo invariantCulture, IFormFileCollection formFileCollection = null) { var dictionary = new Dictionary(collection.Count); foreach (var kvp in collection) { dictionary.Add(new FormKey(kvp.Key.AsMemory()), kvp.Value); } - return new FormDataReader(dictionary, CultureInfo.InvariantCulture, new char[2048]); + return formFileCollection is null + ? new FormDataReader(dictionary, CultureInfo.InvariantCulture, new char[2048]) + : new FormDataReader(dictionary, CultureInfo.InvariantCulture, new char[2048], formFileCollection); } [Theory] @@ -1849,6 +1852,51 @@ public void CanDeserialize_ComplexType_ThrowsFromConstructor() Assert.Equal("Value cannot be null. (Parameter 'key')", constructorError.Message.ToString(CultureInfo.InvariantCulture)); } + [Fact] + public void CanDeserialize_ComplexType_CanSerializerFormFile() + { + // Arrange + var expected = new FormFile(Stream.Null, 0, 10, "file", "file.txt"); + var formFileCollection = new FormFileCollection { expected }; + var data = new Dictionary(); + var reader = CreateFormDataReader(data, CultureInfo.InvariantCulture, formFileCollection); + var errors = new List(); + reader.ErrorHandler = (key, message, attemptedValue) => + { + errors.Add(new FormDataMappingError(key, message, attemptedValue)); + }; + reader.PushPrefix("file"); + var options = new FormDataMapperOptions(); + + // Act + var result = CallDeserialize(reader, options, typeof(IFormFile)); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void CanDeserialize_ComplexType_CanSerializerFormFileCollection() + { + // Arrange + var expected = new FormFileCollection { new FormFile(Stream.Null, 0, 10, "file", "file.txt") }; + var data = new Dictionary(); + var reader = CreateFormDataReader(data, CultureInfo.InvariantCulture, expected); + var errors = new List(); + reader.ErrorHandler = (key, message, attemptedValue) => + { + errors.Add(new FormDataMappingError(key, message, attemptedValue)); + }; + reader.PushPrefix("file"); + var options = new FormDataMapperOptions(); + + // Act + var result = CallDeserialize(reader, options, typeof(IFormFileCollection)); + + // Assert + Assert.Equal(expected, result); + } + [Fact] public void RecursiveTypes_Comparer_SortsValues_Correctly() { diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs index 5289ae539b35..82a882f7025a 100644 --- a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs @@ -120,7 +120,7 @@ public static partial class RequestDelegateFactory private static readonly MemberExpression FilterContextHttpContextStatusCodeExpr = Expression.Property(FilterContextHttpContextResponseExpr, typeof(HttpResponse).GetProperty(nameof(HttpResponse.StatusCode))!); private static readonly ParameterExpression InvokedFilterContextExpr = Expression.Parameter(typeof(EndpointFilterInvocationContext), "filterContext"); - private static readonly ConstructorInfo FormDataReaderConstructor = typeof(FormDataReader).GetConstructor(new[] { typeof(IReadOnlyDictionary), typeof(CultureInfo), typeof(Memory) })!; + private static readonly ConstructorInfo FormDataReaderConstructor = typeof(FormDataReader).GetConstructor(new[] { typeof(IReadOnlyDictionary), typeof(CultureInfo), typeof(Memory), typeof(IFormFileCollection) })!; private static readonly MethodInfo ProcessFormMethod = typeof(RequestDelegateFactory).GetMethod(nameof(ProcessForm), BindingFlags.Static | BindingFlags.NonPublic)!; private static readonly MethodInfo FormDataMapperMapMethod = typeof(FormDataMapper).GetMethod(nameof(FormDataMapper.Map))!; private static readonly MethodInfo AsMemoryMethod = new Func>(MemoryExtensions.AsMemory).Method; @@ -276,9 +276,7 @@ private static RequestDelegateFactoryContext CreateFactoryContext(RequestDelegat var serviceProvider = options?.ServiceProvider ?? options?.EndpointBuilder?.ApplicationServices ?? EmptyServiceProvider.Instance; var endpointBuilder = options?.EndpointBuilder ?? new RdfEndpointBuilder(serviceProvider); var jsonSerializerOptions = serviceProvider.GetService>()?.Value.SerializerOptions ?? JsonOptions.DefaultSerializerOptions; - var formDataMapperOptions = serviceProvider.GetService() is {} httpContextAccessor - ? new FormDataMapperOptions(httpContextAccessor) - : new FormDataMapperOptions(); + var formDataMapperOptions = new FormDataMapperOptions();; var factoryContext = new RequestDelegateFactoryContext { @@ -2077,13 +2075,14 @@ private static Expression BindComplexParameterFromFormItem( // ProcessForm(context.Request.Form, form_dict, form_buffer); var processFormExpr = Expression.Call(ProcessFormMethod, FormExpr, Expression.Constant(formDataMapperOptions.MaxKeyBufferSize), formDict, formBuffer); - // name_reader = new FormDataReader(form_dict, CultureInfo.InvariantCulture, form_buffer.AsMemory(0, formDataMapperOptions.MaxKeyBufferSize)); + // name_reader = new FormDataReader(form_dict, CultureInfo.InvariantCulture, form_buffer.AsMemory(0, formDataMapperOptions.MaxKeyBufferSize), httpContext.Request.Form.Files); var initializeReaderExpr = Expression.Assign( formReader, Expression.New(FormDataReaderConstructor, formDict, Expression.Constant(CultureInfo.InvariantCulture), - Expression.Call(AsMemoryMethod, formBuffer, Expression.Constant(0), Expression.Constant(formDataMapperOptions.MaxKeyBufferSize)))); + Expression.Call(AsMemoryMethod, formBuffer, Expression.Constant(0), Expression.Constant(formDataMapperOptions.MaxKeyBufferSize)), + FormFilesExpr)); // name_reader.MaxRecursionDepth = formDataMapperOptions.MaxRecursionDepth; var setMaxRecursionDepthExpr = Expression.Assign( Expression.Property(formReader, nameof(FormDataReader.MaxRecursionDepth)), diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactoryContext.cs b/src/Http/Http.Extensions/src/RequestDelegateFactoryContext.cs index aa87f10f915b..ff3010a68131 100644 --- a/src/Http/Http.Extensions/src/RequestDelegateFactoryContext.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactoryContext.cs @@ -46,6 +46,9 @@ internal sealed class RequestDelegateFactoryContext public NullabilityInfoContext NullabilityContext { get; } = new(); + // Used to invoke TryResolveFormAsync once per handler so that we can + // avoid the blocking code-path that occurs when `httpContext.Request.Form` + // is called. public bool ReadForm { get; set; } public bool ReadFormFile { get; set; } public ParameterInfo? FirstFormRequestBodyParameter { get; set; } diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.FormMapping.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.FormMapping.cs index f9177bb12158..5680e18cab5d 100644 --- a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.FormMapping.cs +++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.FormMapping.cs @@ -293,14 +293,8 @@ public async Task SupportsFormFileSourcesInDto() new FormFile(Stream.Null, 0, 10, "file", "file.txt"), }; httpContext.Request.Form = new FormCollection(new() { { "Description", "A test file" } }, formFiles); - var serviceCollection = new ServiceCollection(); - serviceCollection.TryAddSingleton(new HttpContextAccessor(httpContext)); - var options = new RequestDelegateFactoryOptions - { - ServiceProvider = serviceCollection.BuildServiceProvider() - }; - var factoryResult = RequestDelegateFactory.Create(TestAction, options); + var factoryResult = RequestDelegateFactory.Create(TestAction); var requestDelegate = factoryResult.RequestDelegate; await requestDelegate(httpContext); @@ -308,6 +302,23 @@ public async Task SupportsFormFileSourcesInDto() Assert.Equal(formFiles["file"], capturedArgument.File); } + [Fact] + public async Task SupportsNullableFormFileSourcesInDto() + { + NullableFormFileDto capturedArgument = default; + void TestAction([FromForm] NullableFormFileDto args) { capturedArgument = args; }; + var httpContext = CreateHttpContext(); + var formFiles = new FormFileCollection(); + httpContext.Request.Form = new FormCollection(new() { { "Description", "A test file" } }, formFiles); + + var factoryResult = RequestDelegateFactory.Create(TestAction); + var requestDelegate = factoryResult.RequestDelegate; + + await requestDelegate(httpContext); + Assert.Equal("A test file", capturedArgument.Description); + Assert.Null(capturedArgument.File); + } + [Fact] public async Task SupportsFormFileCollectionSourcesInDto() { @@ -319,14 +330,8 @@ public async Task SupportsFormFileCollectionSourcesInDto() new FormFile(Stream.Null, 0, 10, "file", "file.txt"), }; httpContext.Request.Form = new FormCollection(new() { { "Description", "A test file" } }, formFiles); - var serviceCollection = new ServiceCollection(); - serviceCollection.TryAddSingleton(new HttpContextAccessor(httpContext)); - var options = new RequestDelegateFactoryOptions - { - ServiceProvider = serviceCollection.BuildServiceProvider() - }; - var factoryResult = RequestDelegateFactory.Create(TestAction, options); + var factoryResult = RequestDelegateFactory.Create(TestAction); var requestDelegate = factoryResult.RequestDelegate; await requestDelegate(httpContext); @@ -341,26 +346,23 @@ private class Employee public string Name { get; set; } public Employee Manager { get; set; } } +#nullable enable private class FormFileDto { - public string Description { get; set; } - public IFormFile File { get; set; } + public string Description { get; set; } = String.Empty; + public required IFormFile File { get; set; } } - private class FormFileCollectionDto + private class NullableFormFileDto { - public string Description { get; set; } - public IFormFileCollection FileCollection { get; set; } + public string? Description { get; set; } + public IFormFile? File { get; set; } } - private class HttpContextAccessor(HttpContext httpContext) : IHttpContextAccessor + private class FormFileCollectionDto { - - public HttpContext HttpContext - { - get; - set; - } = httpContext; + public string Description { get; set; } = string.Empty; + public required IFormFileCollection FileCollection { get; set; } } } From 635e67d430b5dc72237f26a0782cd68b52da73d8 Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Wed, 13 Sep 2023 16:25:25 -0700 Subject: [PATCH 03/10] Fix up FormFile integration in Blazor --- .../FormMapping/BrowserFileFromFormFile.cs | 29 ++++++ .../FormMapping/Converters/FileConverter.cs | 24 +++++ .../Factories/FileConverterFactory.cs | 11 ++- .../HttpContextFormDataProvider.cs | 7 +- .../FormMapping/HttpContextFormValueMapper.cs | 12 ++- .../src/FormMapping/WellKnownConverters.cs | 10 +- ...oft.AspNetCore.Components.Endpoints.csproj | 1 + .../src/Rendering/EndpointHtmlRenderer.cs | 2 +- .../test/Binding/FormDataMapperTests.cs | 91 +++++++++++++++++++ .../test/HttpContextFormValueMapperTest.cs | 3 +- .../FormWithParentBindingContextTest.cs | 62 ++++++++++++- .../Pages/Forms/FormsWithFiles.razor | 57 ++++++++++++ ...icrosoft.AspNetCore.Http.Extensions.csproj | 1 + ...RequestDelegateFactoryTests.FormMapping.cs | 55 ++--------- 14 files changed, 306 insertions(+), 59 deletions(-) create mode 100644 src/Components/Endpoints/src/FormMapping/BrowserFileFromFormFile.cs create mode 100644 src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/FormsWithFiles.razor diff --git a/src/Components/Endpoints/src/FormMapping/BrowserFileFromFormFile.cs b/src/Components/Endpoints/src/FormMapping/BrowserFileFromFormFile.cs new file mode 100644 index 000000000000..f0300d75cc4f --- /dev/null +++ b/src/Components/Endpoints/src/FormMapping/BrowserFileFromFormFile.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Globalization; +using Microsoft.AspNetCore.Components.Forms; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping; + +internal sealed class BrowserFileFromFormFile(IFormFile formFile) : IBrowserFile +{ + public string Name => formFile.Name; + + public DateTimeOffset LastModified => DateTimeOffset.Parse(formFile.Headers.LastModified.ToString(), CultureInfo.InvariantCulture); + + public long Size => formFile.Length; + + public string ContentType => formFile.ContentType; + + public Stream OpenReadStream(long maxAllowedSize = 512000, CancellationToken cancellationToken = default) + { + if (Size > maxAllowedSize) + { + throw new IOException($"Supplied file with size {Size} bytes exceeds the maximum of {maxAllowedSize} bytes."); + } + + return formFile.OpenReadStream(); + } +} diff --git a/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs b/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs index 14c5d220ccc3..ca43bb377c3b 100644 --- a/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs +++ b/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs @@ -2,6 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; +#if COMPONENTS +using Microsoft.AspNetCore.Components.Forms; +#endif using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping; @@ -19,6 +22,27 @@ internal override bool TryRead(ref FormDataReader reader, Type type, FormDataMap return true; } +#if COMPONENTS + if (typeof(T) == typeof(IBrowserFile)) + { + var targetFile = reader.FormFileCollection.GetFile(reader.CurrentPrefix.ToString()); + if (targetFile != null) + { + var browserFile = new BrowserFileFromFormFile(targetFile); + result = (T)(IBrowserFile)browserFile; + found = true; + return true; + } + } +#endif + + if (typeof(T) == typeof(IReadOnlyList)) + { + result = (T)reader.FormFileCollection.GetFiles(reader.CurrentPrefix.ToString()); + found = true; + return true; + } + if (typeof(T) == typeof(IFormFileCollection)) { result = (T)reader.FormFileCollection; diff --git a/src/Components/Endpoints/src/FormMapping/Factories/FileConverterFactory.cs b/src/Components/Endpoints/src/FormMapping/Factories/FileConverterFactory.cs index 80b61870d029..511f1f809fa2 100644 --- a/src/Components/Endpoints/src/FormMapping/Factories/FileConverterFactory.cs +++ b/src/Components/Endpoints/src/FormMapping/Factories/FileConverterFactory.cs @@ -2,6 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; +#if COMPONENTS +using Microsoft.AspNetCore.Components.Forms; +#endif using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping; @@ -10,7 +13,13 @@ internal sealed class FileConverterFactory : IFormDataConverterFactory { [RequiresDynamicCode(FormMappingHelpers.RequiresDynamicCodeMessage)] [RequiresUnreferencedCode(FormMappingHelpers.RequiresUnreferencedCodeMessage)] - public bool CanConvert(Type type, FormDataMapperOptions options) => type == typeof(IFormFile) || type == typeof(IFormFileCollection); +#if COMPONENTS + public bool CanConvert(Type type, FormDataMapperOptions options) => CanConvertCommon(type) || type == typeof(IBrowserFile); +#else + public bool CanConvert(Type type, FormDataMapperOptions options) => CanConvertCommon(type); +#endif + + private static bool CanConvertCommon(Type type) => type == typeof(IFormFile) || type == typeof(IFormFileCollection) || type == typeof(IReadOnlyList); [RequiresDynamicCode(FormMappingHelpers.RequiresDynamicCodeMessage)] [RequiresUnreferencedCode(FormMappingHelpers.RequiresUnreferencedCodeMessage)] diff --git a/src/Components/Endpoints/src/FormMapping/HttpContextFormDataProvider.cs b/src/Components/Endpoints/src/FormMapping/HttpContextFormDataProvider.cs index 96193f2d3479..812e1a10a64d 100644 --- a/src/Components/Endpoints/src/FormMapping/HttpContextFormDataProvider.cs +++ b/src/Components/Endpoints/src/FormMapping/HttpContextFormDataProvider.cs @@ -3,6 +3,7 @@ using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Components.Endpoints; @@ -11,15 +12,19 @@ internal sealed class HttpContextFormDataProvider { private string? _incomingHandlerName; private IReadOnlyDictionary? _entries; + private IFormFileCollection? _formFiles; public string? IncomingHandlerName => _incomingHandlerName; public IReadOnlyDictionary Entries => _entries ?? ReadOnlyDictionary.Empty; - public void SetFormData(string incomingHandlerName, IReadOnlyDictionary form) + public IFormFileCollection FormFiles => _formFiles ?? (IFormFileCollection)FormCollection.Empty; + + public void SetFormData(string incomingHandlerName, IReadOnlyDictionary form, IFormFileCollection formFiles) { _incomingHandlerName = incomingHandlerName; _entries = form; + _formFiles = formFiles; } public bool TryGetIncomingHandlerName([NotNullWhen(true)] out string? incomingHandlerName) diff --git a/src/Components/Endpoints/src/FormMapping/HttpContextFormValueMapper.cs b/src/Components/Endpoints/src/FormMapping/HttpContextFormValueMapper.cs index cac78e732636..db1e9af301cf 100644 --- a/src/Components/Endpoints/src/FormMapping/HttpContextFormValueMapper.cs +++ b/src/Components/Endpoints/src/FormMapping/HttpContextFormValueMapper.cs @@ -8,6 +8,7 @@ using System.Globalization; using Microsoft.AspNetCore.Components.Endpoints.FormMapping; using Microsoft.AspNetCore.Components.Forms.Mapping; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; @@ -85,7 +86,7 @@ public void Map(FormValueMappingContext context) var deserializer = _cache.GetOrAdd(context.ValueType, CreateDeserializer); Debug.Assert(deserializer != null); - deserializer.Deserialize(context, _options, _formData.Entries); + deserializer.Deserialize(context, _options, _formData.Entries, _formData.FormFiles); } private FormValueSupplier CreateDeserializer(Type type) => @@ -99,7 +100,8 @@ internal abstract class FormValueSupplier public abstract void Deserialize( FormValueMappingContext context, FormDataMapperOptions options, - IReadOnlyDictionary form); + IReadOnlyDictionary form, + IFormFileCollection formFiles); } internal class FormValueSupplier : FormValueSupplier @@ -109,7 +111,8 @@ internal class FormValueSupplier : FormValueSupplier public override void Deserialize( FormValueMappingContext context, FormDataMapperOptions options, - IReadOnlyDictionary form) + IReadOnlyDictionary form, + IFormFileCollection formFiles) { if (form.Count == 0) { @@ -129,7 +132,8 @@ public override void Deserialize( using var reader = new FormDataReader( dictionary, CultureInfo.InvariantCulture, - buffer.AsMemory(0, options.MaxKeyBufferSize)) + buffer.AsMemory(0, options.MaxKeyBufferSize), + formFiles) { ErrorHandler = context.OnError, AttachInstanceToErrorsHandler = context.MapErrorToContainer, diff --git a/src/Components/Endpoints/src/FormMapping/WellKnownConverters.cs b/src/Components/Endpoints/src/FormMapping/WellKnownConverters.cs index 25e05396af90..f6c2b98eb744 100644 --- a/src/Components/Endpoints/src/FormMapping/WellKnownConverters.cs +++ b/src/Components/Endpoints/src/FormMapping/WellKnownConverters.cs @@ -1,7 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if COMPONENTS +using Microsoft.AspNetCore.Components.Forms; +#endif using Microsoft.AspNetCore.Http; + namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping; internal static class WellKnownConverters @@ -40,7 +44,11 @@ static WellKnownConverters() { typeof(TimeOnly), new ParsableConverter() }, { typeof(Guid), new ParsableConverter() }, { typeof(IFormFileCollection), new FileConverter() }, - { typeof(IFormFile), new FileConverter() } + { typeof(IFormFile), new FileConverter() }, + { typeof(IReadOnlyList), new FileConverter>() }, +#if COMPONENTS + { typeof(IBrowserFile), new FileConverter() } +#endif }; converters.Add(typeof(char?), new NullableConverter((FormDataConverter)converters[typeof(char)])); diff --git a/src/Components/Endpoints/src/Microsoft.AspNetCore.Components.Endpoints.csproj b/src/Components/Endpoints/src/Microsoft.AspNetCore.Components.Endpoints.csproj index 44101368b937..05eeca0222c1 100644 --- a/src/Components/Endpoints/src/Microsoft.AspNetCore.Components.Endpoints.csproj +++ b/src/Components/Endpoints/src/Microsoft.AspNetCore.Components.Endpoints.csproj @@ -10,6 +10,7 @@ false Microsoft.Extensions.FileProviders.Embedded.Manifest.xml enable + $(DefineConstants);COMPONENTS diff --git a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs index 0c46325988a1..8031ca9e268a 100644 --- a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs +++ b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs @@ -84,7 +84,7 @@ internal static async Task InitializeStandardComponentServicesAsync( if (handler != null && form != null) { httpContext.RequestServices.GetRequiredService() - .SetFormData(handler, new FormCollectionReadOnlyDictionary(form)); + .SetFormData(handler, new FormCollectionReadOnlyDictionary(form), form.Files); } if (httpContext.RequestServices.GetService() is EndpointAntiforgeryStateProvider antiforgery) diff --git a/src/Components/Endpoints/test/Binding/FormDataMapperTests.cs b/src/Components/Endpoints/test/Binding/FormDataMapperTests.cs index fb97d0dd4365..55c865f35547 100644 --- a/src/Components/Endpoints/test/Binding/FormDataMapperTests.cs +++ b/src/Components/Endpoints/test/Binding/FormDataMapperTests.cs @@ -9,6 +9,8 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.Serialization; +using System.Text; +using Microsoft.AspNetCore.Components.Forms; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; @@ -1875,6 +1877,67 @@ public void CanDeserialize_ComplexType_CanSerializerFormFile() Assert.Equal(expected, result); } + [Fact] + public void CanDeserialize_ComplexType_CanSerializerIReadOnlyListFormFile() + { + // Arrange + var formFileCollection = new FormFileCollection + { + new FormFile(Stream.Null, 0, 10, "file", "file-1.txt"), + new FormFile(Stream.Null, 0, 20, "file", "file-2.txt"), + new FormFile(Stream.Null, 0, 30, "file", "file-3.txt"), + new FormFile(Stream.Null, 0, 40, "oddOneOutFile", "file-4.txt"), + }; + var data = new Dictionary(); + var reader = CreateFormDataReader(data, CultureInfo.InvariantCulture, formFileCollection); + var errors = new List(); + reader.ErrorHandler = (key, message, attemptedValue) => + { + errors.Add(new FormDataMappingError(key, message, attemptedValue)); + }; + reader.PushPrefix("file"); + var options = new FormDataMapperOptions(); + + // Act + var result = CallDeserialize(reader, options, typeof(IReadOnlyList)); + + // Assert + var formFileResult = Assert.IsAssignableFrom>(result); + Assert.Collection(formFileResult, + element => Assert.Equal("file-1.txt", element.FileName), + element => Assert.Equal("file-2.txt", element.FileName), + element => Assert.Equal("file-3.txt", element.FileName) + ); + } + + [Fact] + public void CanDeserialize_ComplexType_ReturnsFirstFileForMultiples() + { + // Arrange + var formFileCollection = new FormFileCollection + { + new FormFile(Stream.Null, 0, 10, "file", "file-1.txt"), + new FormFile(Stream.Null, 0, 20, "file", "file-2.txt"), + new FormFile(Stream.Null, 0, 30, "file", "file-3.txt"), + new FormFile(Stream.Null, 0, 40, "oddOneOutFile", "file-4.txt"), + }; + var data = new Dictionary(); + var reader = CreateFormDataReader(data, CultureInfo.InvariantCulture, formFileCollection); + var errors = new List(); + reader.ErrorHandler = (key, message, attemptedValue) => + { + errors.Add(new FormDataMappingError(key, message, attemptedValue)); + }; + reader.PushPrefix("file"); + var options = new FormDataMapperOptions(); + + // Act + var result = CallDeserialize(reader, options, typeof(IFormFile)); + + // Assert + Assert.Equal(formFileCollection[0], result); + } + [Fact] public void CanDeserialize_ComplexType_CanSerializerFormFileCollection() { @@ -1897,6 +1960,34 @@ public void CanDeserialize_ComplexType_CanSerializerFormFileCollection() Assert.Equal(expected, result); } + [Fact] + public void CanDeserialize_ComplexType_CanSerializerBrowserFile() + { + // Arrange + var expectedString = "This is the contents of my text file."; + var expected = new FormFileCollection { new FormFile(new MemoryStream(Encoding.UTF8.GetBytes(expectedString)), 0, expectedString.Length, "file", "file.txt") }; + var data = new Dictionary(); + var reader = CreateFormDataReader(data, CultureInfo.InvariantCulture, expected); + var errors = new List(); + reader.ErrorHandler = (key, message, attemptedValue) => + { + errors.Add(new FormDataMappingError(key, message, attemptedValue)); + }; + reader.PushPrefix("file"); + var options = new FormDataMapperOptions(); + + // Act + var result = CallDeserialize(reader, options, typeof(IBrowserFile)); + + // Assert + var browserFile = Assert.IsAssignableFrom(result); + Assert.Equal("file", browserFile.Name); + Assert.Equal(expectedString.Length, browserFile.Size); + var buffer = new byte[browserFile.Size]; + browserFile.OpenReadStream().Read(buffer); + Assert.Equal(expectedString, Encoding.UTF8.GetString(buffer, 0, buffer.Length)); + } + [Fact] public void RecursiveTypes_Comparer_SortsValues_Correctly() { diff --git a/src/Components/Endpoints/test/HttpContextFormValueMapperTest.cs b/src/Components/Endpoints/test/HttpContextFormValueMapperTest.cs index 1b139fcf8549..5a0f30ddb163 100644 --- a/src/Components/Endpoints/test/HttpContextFormValueMapperTest.cs +++ b/src/Components/Endpoints/test/HttpContextFormValueMapperTest.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; @@ -34,7 +35,7 @@ public class HttpContextFormValueMapperTest public void CanMap_MatchesOnScopeAndFormName(bool expectedResult, string incomingFormName, string scopeName, string formNameOrNull) { var formData = new HttpContextFormDataProvider(); - formData.SetFormData(incomingFormName, new Dictionary()); + formData.SetFormData(incomingFormName, new Dictionary(), (IFormFileCollection)FormCollection.Empty); var mapper = new HttpContextFormValueMapper(formData, Options.Create(new())); diff --git a/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs index f9164075105b..af99f364ad6c 100644 --- a/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs +++ b/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs @@ -3,6 +3,7 @@ using System.Collections.ObjectModel; using System.Net.Http; +using System.Text; using Components.TestServer.RazorComponents; using Microsoft.AspNetCore.Components.E2ETest.Infrastructure; using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures; @@ -15,6 +16,8 @@ namespace Microsoft.AspNetCore.Components.E2ETests.ServerRenderingTests.FormHand public class FormWithParentBindingContextTest : ServerTestBase>> { + private string _tempDirectory; + public FormWithParentBindingContextTest( BrowserFixture browserFixture, BasicTestAppServerSiteFixture> serverFixture, @@ -24,7 +27,12 @@ public FormWithParentBindingContextTest( } public override Task InitializeAsync() - => InitializeAsync(BrowserFixture.StreamingContext); + { + _tempDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(_tempDirectory); + + return InitializeAsync(BrowserFixture.StreamingContext); + } [Theory] [InlineData(true)] @@ -1216,6 +1224,36 @@ public void PostingFormWithErrorsDoesNotExceedMaximumErrors() DispatchToFormCore(dispatchToForm); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void CanBindToFormWithFiles(bool suppressEnhancedNavigation) + { + var profilePicture = TempFile.Create(_tempDirectory, "txt", "This is a profile picture."); + var headerPhoto = TempFile.Create(_tempDirectory, "txt", "This is a header picture."); + var file1 = TempFile.Create(_tempDirectory, "txt", "This is file 1."); + var file2 = TempFile.Create(_tempDirectory, "txt", "This is file 2."); + var dispatchToForm = new DispatchToForm(this) + { + Url = "forms/with-files", + FormCssSelector = "form", + SuppressEnhancedNavigation = suppressEnhancedNavigation, + UpdateFormAction = () => + { + Browser.Exists(By.CssSelector("input[name='Model.ProfilePicture']")).SendKeys(profilePicture.Path); + Browser.Exists(By.CssSelector("input[name='Model.Documents']")).SendKeys(file1.Path); + Browser.Exists(By.CssSelector("input[name='Model.Documents']")).SendKeys(file2.Path); + Browser.Exists(By.CssSelector("input[name='Model.HeaderPhoto']")).SendKeys(headerPhoto.Path); + } + }; + DispatchToFormCore(dispatchToForm); + + Assert.Equal($"Profile Picture: {profilePicture.Name}", Browser.Exists(By.Id("profile-picture")).Text); + Assert.Equal("Documents: 2", Browser.Exists(By.Id("documents")).Text); + Assert.Equal("Header Photo: Model.HeaderPhoto", Browser.Exists(By.Id("header-photo")).Text); + Assert.Equal("Total: 4", Browser.Exists(By.Id("form-collection")).Text); + } + private void DispatchToFormCore(DispatchToForm dispatch) { SuppressEnhancedNavigation(dispatch.SuppressEnhancedNavigation); @@ -1345,4 +1383,26 @@ private void GoTo(string relativePath) { Navigate($"{ServerPathBase}/{relativePath}"); } + + private struct TempFile + { + public string Name { get; } + public string Path { get; } + public byte[] Contents { get; } + public string Text => Encoding.ASCII.GetString(Contents); + private TempFile(string tempDirectory, string extension, byte[] contents) + { + Name = $"{Guid.NewGuid():N}.{extension}"; + Path = System.IO.Path.Combine(tempDirectory, Name); + Contents = contents; + } + public static TempFile Create(string tempDirectory, string extension, byte[] contents) + { + var file = new TempFile(tempDirectory, extension, contents); + File.WriteAllBytes(file.Path, contents); + return file; + } + public static TempFile Create(string tempDirectory, string extension, string text) + => Create(tempDirectory, extension, Encoding.ASCII.GetBytes(text)); + } } diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/FormsWithFiles.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/FormsWithFiles.razor new file mode 100644 index 000000000000..a3d36e983918 --- /dev/null +++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/FormsWithFiles.razor @@ -0,0 +1,57 @@ +@page "/forms/with-files" +@using Microsoft.AspNetCore.Components.Forms + +

Forms With Files

+ + + +
+ + +
+
+ + +
+
+ + +
+ +
+ +@if(_shouldDisplaySuccess) +{ +

Profile Picture: @Model.ProfilePicture.FileName

+

Documents: @Model.Documents.Count()

+

Header Photo: @Model.HeaderPhoto.Name

+

Total: @Model.FormFiles.Count

+} + +@code +{ + bool _shouldDisplaySuccess = false; + + public void DisplaySuccess() => _shouldDisplaySuccess = true; + + [SupplyParameterFromForm] public FileContainer Model { get; set; } + + protected override void OnInitialized() => Model ??= new FileContainer(); + + public class FileContainer + { + public IFormFile ProfilePicture { get; set; } + public IReadOnlyList Documents { get; set; } + public IBrowserFile HeaderPhoto { get; set; } + public IFormFileCollection FormFiles { get; set; } + } +} diff --git a/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj b/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj index 381353c1903b..0f8c4b3a3bf4 100644 --- a/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj +++ b/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj @@ -34,6 +34,7 @@ + diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.FormMapping.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.FormMapping.cs index 5680e18cab5d..414173a55806 100644 --- a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.FormMapping.cs +++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.FormMapping.cs @@ -291,6 +291,8 @@ public async Task SupportsFormFileSourcesInDto() var formFiles = new FormFileCollection { new FormFile(Stream.Null, 0, 10, "file", "file.txt"), + new FormFile(Stream.Null, 0, 10, "formFiles", "file-1.txt"), + new FormFile(Stream.Null, 0, 10, "formFiles", "file-2.txt"), }; httpContext.Request.Form = new FormCollection(new() { { "Description", "A test file" } }, formFiles); @@ -300,43 +302,8 @@ public async Task SupportsFormFileSourcesInDto() await requestDelegate(httpContext); Assert.Equal("A test file", capturedArgument.Description); Assert.Equal(formFiles["file"], capturedArgument.File); - } - - [Fact] - public async Task SupportsNullableFormFileSourcesInDto() - { - NullableFormFileDto capturedArgument = default; - void TestAction([FromForm] NullableFormFileDto args) { capturedArgument = args; }; - var httpContext = CreateHttpContext(); - var formFiles = new FormFileCollection(); - httpContext.Request.Form = new FormCollection(new() { { "Description", "A test file" } }, formFiles); - - var factoryResult = RequestDelegateFactory.Create(TestAction); - var requestDelegate = factoryResult.RequestDelegate; - - await requestDelegate(httpContext); - Assert.Equal("A test file", capturedArgument.Description); - Assert.Null(capturedArgument.File); - } - - [Fact] - public async Task SupportsFormFileCollectionSourcesInDto() - { - FormFileCollectionDto capturedArgument = default; - void TestAction([FromForm] FormFileCollectionDto args) { capturedArgument = args; }; - var httpContext = CreateHttpContext(); - var formFiles = new FormFileCollection - { - new FormFile(Stream.Null, 0, 10, "file", "file.txt"), - }; - httpContext.Request.Form = new FormCollection(new() { { "Description", "A test file" } }, formFiles); - - var factoryResult = RequestDelegateFactory.Create(TestAction); - var requestDelegate = factoryResult.RequestDelegate; - - await requestDelegate(httpContext); - Assert.Equal("A test file", capturedArgument.Description); - Assert.Equal(formFiles, capturedArgument.FileCollection); + Assert.Equal(formFiles.GetFiles("formFiles"), capturedArgument.FormFiles); + Assert.Equal(formFiles, capturedArgument.FormFileCollection); } private record TodoRecord(int Id, string Name, bool IsCompleted); @@ -351,18 +318,8 @@ private class Employee private class FormFileDto { public string Description { get; set; } = String.Empty; - public required IFormFile File { get; set; } - } - - private class NullableFormFileDto - { - public string? Description { get; set; } public IFormFile? File { get; set; } - } - - private class FormFileCollectionDto - { - public string Description { get; set; } = string.Empty; - public required IFormFileCollection FileCollection { get; set; } + public IReadOnlyList? FormFiles { get; set; } + public IFormFileCollection? FormFileCollection { get; set; } } } From 3a2c2a888dfe3205aa0def0d2fe42a33781c2c98 Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Wed, 13 Sep 2023 17:01:00 -0700 Subject: [PATCH 04/10] Fix up FileConverter interfaces --- .../Endpoints/src/FormMapping/Converters/FileConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs b/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs index ca43bb377c3b..ed3de6c3e2f9 100644 --- a/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs +++ b/src/Components/Endpoints/src/FormMapping/Converters/FileConverter.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Components.Endpoints.FormMapping; -internal sealed class FileConverter : FormDataConverter, ISingleValueConverter +internal sealed class FileConverter : FormDataConverter { [RequiresDynamicCode(FormMappingHelpers.RequiresDynamicCodeMessage)] [RequiresUnreferencedCode(FormMappingHelpers.RequiresUnreferencedCodeMessage)] From b8e33a53eba63286c85d996b525e6c3a3653ada7 Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Wed, 13 Sep 2023 17:22:54 -0700 Subject: [PATCH 05/10] Fix build --- .../src/FormMapping/Metadata/FormDataMetadataFactory.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Components/Endpoints/src/FormMapping/Metadata/FormDataMetadataFactory.cs b/src/Components/Endpoints/src/FormMapping/Metadata/FormDataMetadataFactory.cs index d29676583d29..124cdf5ffd05 100644 --- a/src/Components/Endpoints/src/FormMapping/Metadata/FormDataMetadataFactory.cs +++ b/src/Components/Endpoints/src/FormMapping/Metadata/FormDataMetadataFactory.cs @@ -17,7 +17,7 @@ internal partial class FormDataMetadataFactory(List f private readonly FormMetadataContext _context = new(); private readonly ParsableConverterFactory _parsableFactory = factories.OfType().Single(); private readonly DictionaryConverterFactory _dictionaryFactory = factories.OfType().Single(); - private readonly FileConverterFactory? _fileConverterFactory = factories.OfType().SingleOrDefault(); + private readonly FileConverterFactory _fileConverterFactory = factories.OfType().Single(); private readonly CollectionConverterFactory _collectionFactory = factories.OfType().Single(); private readonly ILogger _logger = loggerFactory.CreateLogger(); @@ -87,6 +87,12 @@ internal partial class FormDataMetadataFactory(List f return result; } + if (_fileConverterFactory.CanConvert(type, options)) + { + result.Kind = FormDataTypeKind.File; + return result; + } + if (_dictionaryFactory.CanConvert(type, options)) { Log.DictionaryType(_logger, type); From a34d9fee3fa10a1515a8309bc6770aca72c6d3b3 Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Wed, 13 Sep 2023 23:02:15 -0700 Subject: [PATCH 06/10] Fix FormFileCollection initialization --- src/Components/Endpoints/test/HttpContextFormValueMapperTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Endpoints/test/HttpContextFormValueMapperTest.cs b/src/Components/Endpoints/test/HttpContextFormValueMapperTest.cs index 5a0f30ddb163..976fe112fe3b 100644 --- a/src/Components/Endpoints/test/HttpContextFormValueMapperTest.cs +++ b/src/Components/Endpoints/test/HttpContextFormValueMapperTest.cs @@ -35,7 +35,7 @@ public class HttpContextFormValueMapperTest public void CanMap_MatchesOnScopeAndFormName(bool expectedResult, string incomingFormName, string scopeName, string formNameOrNull) { var formData = new HttpContextFormDataProvider(); - formData.SetFormData(incomingFormName, new Dictionary(), (IFormFileCollection)FormCollection.Empty); + formData.SetFormData(incomingFormName, new Dictionary(), new FormFileCollection()); var mapper = new HttpContextFormValueMapper(formData, Options.Create(new())); From 78bf7d8337b2cc77a19617ba9b5ee61a43f33ea6 Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Thu, 14 Sep 2023 10:52:45 -0700 Subject: [PATCH 07/10] Revert "Revert "[Blazor] Update selenium versions (#50511)" (#50556)" This reverts commit 564a94dc513946d221c39accf98e2a70ed6f78e8. --- eng/Versions.props | 6 +- src/Components/test/E2ETest/package.json | 6 +- src/Components/test/E2ETest/yarn.lock | 397 ++++++++++++++---- .../test/Templates.Tests/package.json | 4 +- .../test/Templates.Tests/yarn.lock | 392 +++++++++++++---- src/Shared/E2ETesting/E2ETesting.targets | 2 +- .../E2ETesting/SeleniumStandaloneServer.cs | 11 +- src/Shared/E2ETesting/selenium-config.json | 3 +- 8 files changed, 638 insertions(+), 183 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index bc279ea66186..c1b707303925 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -310,9 +310,9 @@ 1.28.0 3.0.0 7.2.4 - 4.10.0 - 114.0.5735.9000 - 4.10.0 + 4.12.2 + 116.0.5845.9600 + 4.12.2 1.4.0 4.0.0 2.6.122 diff --git a/src/Components/test/E2ETest/package.json b/src/Components/test/E2ETest/package.json index 085a418e3a12..dce200a1f238 100644 --- a/src/Components/test/E2ETest/package.json +++ b/src/Components/test/E2ETest/package.json @@ -11,11 +11,9 @@ }, "author": "", "license": "MIT", - "dependencies": { - "sauce-connect-launcher": "^1.3.1", - "selenium-standalone": "^7.1.0" - }, "devDependencies": { + "sauce-connect-launcher": "^1.3.1", + "selenium-standalone": "^9.1.1", "@types/node": "^13.1.7", "ts-node": "^8.6.2", "typescript": "^3.7.5" diff --git a/src/Components/test/E2ETest/yarn.lock b/src/Components/test/E2ETest/yarn.lock index 59a3743df090..de678d2ae29e 100644 --- a/src/Components/test/E2ETest/yarn.lock +++ b/src/Components/test/E2ETest/yarn.lock @@ -65,11 +65,31 @@ agent-base@6: dependencies: debug "4" +aggregate-error@^3.1.0: + version "3.1.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha1-kmcP9Q9TWb23o+DUDQ7DDFc3aHo= + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha1-7dgDYornHATIWuegkG7a00tkiTc= + dependencies: + color-convert "^2.0.1" + arg@^4.1.0: version "4.1.3" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha1-Jp/HrVuOQstjyJbVZmAXJhwUQIk= +arrify@^2.0.1: + version "2.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha1-yWVekzHgq81YjSp8rX6ZVvZnAfo= + async@^2.1.2: version "2.6.4" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" @@ -77,25 +97,29 @@ async@^2.1.2: dependencies: lodash "^4.17.14" +asynckit@^0.4.0: + version "0.4.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +axios@^0.27.2: + version "0.27.2" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha1-IHZYzIYhYG5YbIXbS0GnUOdW2XI= + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + +b4a@^1.6.4: + version "1.6.4" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9" + integrity sha1-7xwUIsrlzmU17Bkbru11Z0Q/Nsk= + balanced-match@^1.0.0: version "1.0.2" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4= -base64-js@^1.3.1: - version "1.5.1" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha1-GxtEAWClv3rUC2UPCVljSBkDkwo= - -bl@^4.0.3: - version "4.1.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha1-RRU1JkGCvsL7vIOmKrmM8R2fezo= - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -114,14 +138,6 @@ buffer-from@^1.0.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha1-KxRqb9cugLT1XSVfNe1Zo6mkG9U= -buffer@^5.5.0: - version "5.7.1" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha1-umLnwTEzBTWCGXFghRqPZI6Z7tA= - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - cacheable-lookup@^5.0.3: version "5.0.4" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" @@ -140,6 +156,19 @@ cacheable-request@^7.0.2: normalize-url "^6.0.1" responselike "^2.0.0" +chalk@^4.0.0: + version "4.1.2" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha1-qsTit3NKdAhnrrFr8CqtVWoeegE= + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha1-7oRy27Ep5yezHooQpCfe6d/kAIs= + clone-response@^1.0.2: version "1.0.3" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" @@ -147,17 +176,41 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" -commander@^7.2.0: - version "7.2.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha1-o2y1fQtQHOEI5NIFWaFQo5HZerc= +color-convert@^2.0.1: + version "2.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM= + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha1-wqCah6y95pVD3m9j+jmVyCbFNqI= + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha1-w9RaizT9cwYxoRCoolIGgrMdWn8= + dependencies: + delayed-stream "~1.0.0" + +commander@^5.1.0: + version "5.1.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + integrity sha1-Rqu9FlL44Fm92u+Zu9yyrZzxea4= + +commander@^8.3.0: + version "8.3.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha1-SDfqGy2me5xhamevuw+v7lZ7ymY= concat-map@0.0.1: version "0.0.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha1-9zqFudXUHQRVUcF34ogtSshXKKY= @@ -166,7 +219,7 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -debug@4, debug@^4.3.1: +debug@4, debug@^4.1.1, debug@^4.3.1: version "4.3.4" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha1-Exn2V5NX8jONMzfSzdSRS7XcyGU= @@ -185,18 +238,59 @@ defer-to-connect@^2.0.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha1-gBa9tBQ+RjK3ejRJxiNid95SBYc= +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + diff@^4.0.1: version "4.0.2" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha1-YPOuy4nV+uUgwRqhnvwruYKq3n0= -end-of-stream@^1.1.0, end-of-stream@^1.4.1: +end-of-stream@^1.1.0: version "1.4.4" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha1-WuZKX0UFe682JuwU2gyl5LJDHrA= dependencies: once "^1.4.0" +execa@^3.3.0: + version "3.4.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89" + integrity sha1-wI7UVQ72XYWPrCaf/IVyRG8364k= + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + p-finally "^2.0.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +execa@^5.0.0, execa@^5.1.1: + version "5.1.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha1-+ArZy/Qpj3vR1MlVXCHpN0HEEd0= + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +fast-fifo@^1.1.0, fast-fifo@^1.2.0: + version "1.3.2" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" + integrity sha1-KG4x3pbrltOKl4mYFXQLoqTzZAw= + fd-slicer@~1.1.0: version "1.1.0" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -204,10 +298,41 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha1-a+Dem+mYzhavivwkSXue6bfM2a0= +find-process@^1.4.7: + version "1.4.7" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/find-process/-/find-process-1.4.7.tgz#8c76962259216c381ef1099371465b5b439ea121" + integrity sha1-jHaWIlkhbDge8QmTcUZbW0OeoSE= + dependencies: + chalk "^4.0.0" + commander "^5.1.0" + debug "^4.1.1" + +fkill@^7.2.1: + version "7.2.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fkill/-/fkill-7.2.1.tgz#7036200cd2edd28a6bc40f0defc1e159d9e24e64" + integrity sha1-cDYgDNLt0oprxA8N78HhWdniTmQ= + dependencies: + aggregate-error "^3.1.0" + arrify "^2.0.1" + execa "^5.0.0" + pid-port "^0.1.0" + process-exists "^4.0.0" + ps-list "^7.2.0" + taskkill "^3.1.0" + +follow-redirects@^1.14.9: + version "1.15.2" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha1-tGCGQUS6Y/JoEJbydMTlcCbaLBM= + +form-data@^4.0.0: + version "4.0.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha1-k5Gdrq82HuUpWEubMWZNwSyfpFI= + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" fs-extra@^10.0.0: version "10.1.0" @@ -223,13 +348,18 @@ fs.realpath@^1.0.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -get-stream@^5.1.0: +get-stream@^5.0.0, get-stream@^5.1.0: version "5.2.0" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" integrity sha1-SWaheV7lrOZecGxLe+txJX1uItM= dependencies: pump "^3.0.0" +get-stream@^6.0.0: + version "6.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha1-omLY7vZ6ztV8KFKtYWdSakPL97c= + glob@^7.1.3: version "7.2.3" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -264,6 +394,11 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha1-FH06AG2kyjzhRyjHrvwofDZ9emw= +has-flag@^4.0.0: + version "4.0.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s= + http-cache-semantics@^4.0.0: version "4.1.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" @@ -285,10 +420,20 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -ieee754@^1.1.13: - version "1.2.1" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha1-jrehCmP/8l0VpXsAFYbRd9Gw01I= +human-signals@^1.1.1: + version "1.1.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha1-xbHNFPUK6uCatsWf5jujOV/k36M= + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha1-3JH8ukLk0G5Kuu0zs+ejwC9RTqA= + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha1-Yk+PRJfWGbLZdoUx1Y9BIoVNclE= inflight@^1.0.4: version "1.0.6" @@ -298,7 +443,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@^2.0.4: +inherits@2: version "2.0.4" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w= @@ -308,6 +453,11 @@ is-port-reachable@^3.0.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/is-port-reachable/-/is-port-reachable-3.1.0.tgz#f6668d3bca9c36b07f737c48a8f875ab0653cd2b" integrity sha1-9maNO8qcNrB/c3xIqPh1qwZTzSs= +is-stream@^2.0.0: + version "2.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha1-+sHj1TuXrVqdCunO8jifWBClwHc= + isexe@^2.0.0: version "2.0.0" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -359,6 +509,28 @@ make-error@^1.1.1: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha1-LrLjfqm2fEiR9oShOUeZr0hM96I= +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A= + +mime-db@1.52.0: + version "1.52.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha1-u6vNwChZ9JhzAchW4zh85exDv3A= + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha1-OBqHG2KnNEUGYK497uRIE/cNlZo= + dependencies: + mime-db "1.52.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs= + mimic-response@^1.0.0: version "1.0.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" @@ -381,10 +553,10 @@ minimist@^1.2.5: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha1-waRk52kzAuCCoHXO4MBXdBrEdyw= -mkdirp@^1.0.4: - version "1.0.4" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha1-PrXtYmInVteaXw4qIh3+utdcL34= +mkdirp@^2.1.3: + version "2.1.6" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" + integrity sha1-lk+8sSstjF1vvGKpY6yVonPizBk= ms@2.1.2: version "2.1.2" @@ -396,6 +568,13 @@ normalize-url@^6.0.1: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" integrity sha1-QNCIW1Nd7/4/MUe+yHfQX+TFZoo= +npm-run-path@^4.0.0, npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha1-t+zR5e1T2o43pV4cImnguX7XSOo= + dependencies: + path-key "^3.0.0" + once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -403,17 +582,29 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4= + dependencies: + mimic-fn "^2.1.0" + p-cancelable@^2.0.0: version "2.1.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" integrity sha1-qrf71BZYL6MqPbSYWcEiSHxe0s8= +p-finally@^2.0.0: + version "2.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" + integrity sha1-vW/KqcVZoJa2gIBvTWV7Pw8kBWE= + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U= @@ -423,11 +614,35 @@ pend@~1.2.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= +pid-port@^0.1.0: + version "0.1.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/pid-port/-/pid-port-0.1.1.tgz#2ac86fa8a0e97ef2e7eb9e7e9567cdc1eda78098" + integrity sha1-KshvqKDpfvLn655+lWfNwe2ngJg= + dependencies: + execa "^5.0.0" + +process-exists@^4.0.0: + version "4.1.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/process-exists/-/process-exists-4.1.0.tgz#4132c516324c1da72d65896851cdbd8bbdf5b9d8" + integrity sha1-QTLFFjJMHactZYloUc29i731udg= + dependencies: + ps-list "^6.3.0" + progress@2.0.3: version "2.0.3" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha1-foz42PW48jnBvGi+tOt4Vn1XLvg= +ps-list@^6.3.0: + version "6.3.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ps-list/-/ps-list-6.3.0.tgz#a2b775c2db7d547a28fbaa3a05e4c281771259be" + integrity sha1-ord1wtt9VHoo+6o6BeTCgXcSWb4= + +ps-list@^7.2.0: + version "7.2.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ps-list/-/ps-list-7.2.0.tgz#3d110e1de8249a4b178c9b1cf2a215d1e4e42fc0" + integrity sha1-PREOHegkmksXjJsc8qIV0eTkL8A= + pump@^3.0.0: version "3.0.0" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -436,20 +651,16 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +queue-tick@^1.0.1: + version "1.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" + integrity sha1-9vB6yCwf1g+C4Ji0F6gOUvH0wUI= + quick-lru@^5.1.1: version "5.1.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha1-NmST5rPkKjpoheLpnRj4D7eoyTI= -readable-stream@^3.1.1, readable-stream@^3.4.0: - version "3.6.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha1-M3u9o63AcGvT4CRCaihtS0sskZg= - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - resolve-alpn@^1.0.0: version "1.2.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" @@ -469,11 +680,6 @@ rimraf@^2.5.4: dependencies: glob "^7.1.3" -safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY= - sauce-connect-launcher@^1.3.1: version "1.3.2" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/sauce-connect-launcher/-/sauce-connect-launcher-1.3.2.tgz#dfc675a258550809a8eaf457eb9162b943ddbaf0" @@ -485,23 +691,27 @@ sauce-connect-launcher@^1.3.1: lodash "^4.16.6" rimraf "^2.5.4" -selenium-standalone@^7.1.0: - version "7.1.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/selenium-standalone/-/selenium-standalone-7.1.0.tgz#1192a4ad84f114137dd5deadcb81b0f56afe054a" - integrity sha1-EZKkrYTxFBN91d6ty4Gw9Wr+BUo= +selenium-standalone@^9.1.1: + version "9.1.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/selenium-standalone/-/selenium-standalone-9.1.1.tgz#a37388309afa29bb232205bf3aeaa3c7db681449" + integrity sha1-o3OIMJr6KbsjIgW/Ouqjx9toFEk= dependencies: - commander "^7.2.0" + axios "^0.27.2" + commander "^8.3.0" cross-spawn "^7.0.3" debug "^4.3.1" + execa "^5.1.1" + find-process "^1.4.7" + fkill "^7.2.1" fs-extra "^10.0.0" got "^11.8.2" is-port-reachable "^3.0.0" lodash.mapvalues "^4.6.0" lodash.merge "^4.6.2" minimist "^1.2.5" - mkdirp "^1.0.4" + mkdirp "^2.1.3" progress "2.0.3" - tar-stream "2.2.0" + tar-stream "3.1.6" which "^2.0.2" yauzl "^2.10.0" @@ -517,6 +727,11 @@ shebang-regex@^3.0.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI= +signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.7" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha1-qaF2f4r4QVURTqq9c/mSc8j1mtk= + source-map-support@^0.5.17: version "0.5.21" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -530,23 +745,42 @@ source-map@^0.6.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha1-dHIq8y6WFOnCh6jQu95IteLxomM= -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha1-QvEUWUpGzxqOMLCoT1bHjD7awh4= +streamx@^2.15.0: + version "2.15.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/streamx/-/streamx-2.15.1.tgz#396ad286d8bc3eeef8f5cea3f029e81237c024c6" + integrity sha1-OWrShti8Pu749c6j8CnoEjfAJMY= dependencies: - safe-buffer "~5.2.0" + fast-fifo "^1.1.0" + queue-tick "^1.0.1" -tar-stream@2.2.0: - version "2.2.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" - integrity sha1-rK2EwoQTawYNw/qmRHSqmuvXcoc= +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha1-ibhS+y/L6Tb29LMYevsKEsGrWK0= + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha1-G33NyzK4E4gBs+R4umpRyqiWSNo= + dependencies: + has-flag "^4.0.0" + +tar-stream@3.1.6: + version "3.1.6" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/tar-stream/-/tar-stream-3.1.6.tgz#6520607b55a06f4a2e2e04db360ba7d338cc5bab" + integrity sha1-ZSBge1Wgb0ouLgTbNgun0zjMW6s= dependencies: - bl "^4.0.3" - end-of-stream "^1.4.1" - fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" + b4a "^1.6.4" + fast-fifo "^1.2.0" + streamx "^2.15.0" + +taskkill@^3.1.0: + version "3.1.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/taskkill/-/taskkill-3.1.0.tgz#28001339feb23bfae3f447902c4b4abcdd057680" + integrity sha1-KAATOf6yO/rj9EeQLEtKvN0FdoA= + dependencies: + arrify "^2.0.1" + execa "^3.3.0" ts-node@^8.6.2: version "8.10.2" @@ -569,11 +803,6 @@ universalify@^2.0.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha1-daSYTv7cSwiXXFrrc/Uw0C3yVxc= -util-deprecate@^1.0.1: - version "1.0.2" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" diff --git a/src/ProjectTemplates/test/Templates.Tests/package.json b/src/ProjectTemplates/test/Templates.Tests/package.json index cf27e5755093..c7c903162aeb 100644 --- a/src/ProjectTemplates/test/Templates.Tests/package.json +++ b/src/ProjectTemplates/test/Templates.Tests/package.json @@ -10,7 +10,7 @@ }, "author": "", "license": "MIT", - "dependencies": { - "selenium-standalone": "^7.1.0" + "devDependencies": { + "selenium-standalone": "^9.1.1" } } diff --git a/src/ProjectTemplates/test/Templates.Tests/yarn.lock b/src/ProjectTemplates/test/Templates.Tests/yarn.lock index e3cd167d5693..7a4aac770b3a 100644 --- a/src/ProjectTemplates/test/Templates.Tests/yarn.lock +++ b/src/ProjectTemplates/test/Templates.Tests/yarn.lock @@ -48,33 +48,49 @@ dependencies: "@types/node" "*" -base64-js@^1.3.1: - version "1.5.1" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha1-GxtEAWClv3rUC2UPCVljSBkDkwo= +aggregate-error@^3.1.0: + version "3.1.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha1-kmcP9Q9TWb23o+DUDQ7DDFc3aHo= + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" -bl@^4.0.3: - version "4.1.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha1-RRU1JkGCvsL7vIOmKrmM8R2fezo= +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha1-7dgDYornHATIWuegkG7a00tkiTc= + dependencies: + color-convert "^2.0.1" + +arrify@^2.0.1: + version "2.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha1-yWVekzHgq81YjSp8rX6ZVvZnAfo= + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +axios@^0.27.2: + version "0.27.2" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha1-IHZYzIYhYG5YbIXbS0GnUOdW2XI= dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" + follow-redirects "^1.14.9" + form-data "^4.0.0" + +b4a@^1.6.4: + version "1.6.4" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9" + integrity sha1-7xwUIsrlzmU17Bkbru11Z0Q/Nsk= buffer-crc32@~0.2.3: version "0.2.13" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= -buffer@^5.5.0: - version "5.7.1" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha1-umLnwTEzBTWCGXFghRqPZI6Z7tA= - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - cacheable-lookup@^5.0.3: version "5.0.4" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" @@ -93,6 +109,19 @@ cacheable-request@^7.0.2: normalize-url "^6.0.1" responselike "^2.0.0" +chalk@^4.0.0: + version "4.1.2" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha1-qsTit3NKdAhnrrFr8CqtVWoeegE= + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha1-7oRy27Ep5yezHooQpCfe6d/kAIs= + clone-response@^1.0.2: version "1.0.3" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" @@ -100,12 +129,36 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" -commander@^7.2.0: - version "7.2.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha1-o2y1fQtQHOEI5NIFWaFQo5HZerc= +color-convert@^2.0.1: + version "2.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM= + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha1-wqCah6y95pVD3m9j+jmVyCbFNqI= + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha1-w9RaizT9cwYxoRCoolIGgrMdWn8= + dependencies: + delayed-stream "~1.0.0" -cross-spawn@^7.0.3: +commander@^5.1.0: + version "5.1.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + integrity sha1-Rqu9FlL44Fm92u+Zu9yyrZzxea4= + +commander@^8.3.0: + version "8.3.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha1-SDfqGy2me5xhamevuw+v7lZ7ymY= + +cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha1-9zqFudXUHQRVUcF34ogtSshXKKY= @@ -114,7 +167,7 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -debug@^4.3.1: +debug@^4.1.1, debug@^4.3.1: version "4.3.4" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha1-Exn2V5NX8jONMzfSzdSRS7XcyGU= @@ -133,13 +186,54 @@ defer-to-connect@^2.0.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha1-gBa9tBQ+RjK3ejRJxiNid95SBYc= -end-of-stream@^1.1.0, end-of-stream@^1.4.1: +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +end-of-stream@^1.1.0: version "1.4.4" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha1-WuZKX0UFe682JuwU2gyl5LJDHrA= dependencies: once "^1.4.0" +execa@^3.3.0: + version "3.4.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89" + integrity sha1-wI7UVQ72XYWPrCaf/IVyRG8364k= + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + p-finally "^2.0.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +execa@^5.0.0, execa@^5.1.1: + version "5.1.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha1-+ArZy/Qpj3vR1MlVXCHpN0HEEd0= + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +fast-fifo@^1.1.0, fast-fifo@^1.2.0: + version "1.3.2" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" + integrity sha1-KG4x3pbrltOKl4mYFXQLoqTzZAw= + fd-slicer@~1.1.0: version "1.1.0" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -147,10 +241,41 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha1-a+Dem+mYzhavivwkSXue6bfM2a0= +find-process@^1.4.7: + version "1.4.7" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/find-process/-/find-process-1.4.7.tgz#8c76962259216c381ef1099371465b5b439ea121" + integrity sha1-jHaWIlkhbDge8QmTcUZbW0OeoSE= + dependencies: + chalk "^4.0.0" + commander "^5.1.0" + debug "^4.1.1" + +fkill@^7.2.1: + version "7.2.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fkill/-/fkill-7.2.1.tgz#7036200cd2edd28a6bc40f0defc1e159d9e24e64" + integrity sha1-cDYgDNLt0oprxA8N78HhWdniTmQ= + dependencies: + aggregate-error "^3.1.0" + arrify "^2.0.1" + execa "^5.0.0" + pid-port "^0.1.0" + process-exists "^4.0.0" + ps-list "^7.2.0" + taskkill "^3.1.0" + +follow-redirects@^1.14.9: + version "1.15.2" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha1-tGCGQUS6Y/JoEJbydMTlcCbaLBM= + +form-data@^4.0.0: + version "4.0.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha1-k5Gdrq82HuUpWEubMWZNwSyfpFI= + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" fs-extra@^10.0.0: version "10.1.0" @@ -161,13 +286,18 @@ fs-extra@^10.0.0: jsonfile "^6.0.1" universalify "^2.0.0" -get-stream@^5.1.0: +get-stream@^5.0.0, get-stream@^5.1.0: version "5.2.0" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" integrity sha1-SWaheV7lrOZecGxLe+txJX1uItM= dependencies: pump "^3.0.0" +get-stream@^6.0.0: + version "6.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha1-omLY7vZ6ztV8KFKtYWdSakPL97c= + got@^11.8.2: version "11.8.6" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" @@ -190,6 +320,11 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha1-FH06AG2kyjzhRyjHrvwofDZ9emw= +has-flag@^4.0.0: + version "4.0.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s= + http-cache-semantics@^4.0.0: version "4.1.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" @@ -203,21 +338,31 @@ http2-wrapper@^1.0.0-beta.5.2: quick-lru "^5.1.1" resolve-alpn "^1.0.0" -ieee754@^1.1.13: - version "1.2.1" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha1-jrehCmP/8l0VpXsAFYbRd9Gw01I= +human-signals@^1.1.1: + version "1.1.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha1-xbHNFPUK6uCatsWf5jujOV/k36M= -inherits@^2.0.3, inherits@^2.0.4: - version "2.0.4" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w= +human-signals@^2.1.0: + version "2.1.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha1-3JH8ukLk0G5Kuu0zs+ejwC9RTqA= + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha1-Yk+PRJfWGbLZdoUx1Y9BIoVNclE= is-port-reachable@^3.0.0: version "3.1.0" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/is-port-reachable/-/is-port-reachable-3.1.0.tgz#f6668d3bca9c36b07f737c48a8f875ab0653cd2b" integrity sha1-9maNO8qcNrB/c3xIqPh1qwZTzSs= +is-stream@^2.0.0: + version "2.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha1-+sHj1TuXrVqdCunO8jifWBClwHc= + isexe@^2.0.0: version "2.0.0" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -259,6 +404,28 @@ lowercase-keys@^2.0.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" integrity sha1-JgPni3tLAAbLyi+8yKMgJVislHk= +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A= + +mime-db@1.52.0: + version "1.52.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha1-u6vNwChZ9JhzAchW4zh85exDv3A= + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha1-OBqHG2KnNEUGYK497uRIE/cNlZo= + dependencies: + mime-db "1.52.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs= + mimic-response@^1.0.0: version "1.0.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" @@ -274,10 +441,10 @@ minimist@^1.2.5: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha1-waRk52kzAuCCoHXO4MBXdBrEdyw= -mkdirp@^1.0.4: - version "1.0.4" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha1-PrXtYmInVteaXw4qIh3+utdcL34= +mkdirp@^2.1.3: + version "2.1.6" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" + integrity sha1-lk+8sSstjF1vvGKpY6yVonPizBk= ms@2.1.2: version "2.1.2" @@ -289,6 +456,13 @@ normalize-url@^6.0.1: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" integrity sha1-QNCIW1Nd7/4/MUe+yHfQX+TFZoo= +npm-run-path@^4.0.0, npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha1-t+zR5e1T2o43pV4cImnguX7XSOo= + dependencies: + path-key "^3.0.0" + once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -296,12 +470,24 @@ once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4= + dependencies: + mimic-fn "^2.1.0" + p-cancelable@^2.0.0: version "2.1.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" integrity sha1-qrf71BZYL6MqPbSYWcEiSHxe0s8= -path-key@^3.1.0: +p-finally@^2.0.0: + version "2.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" + integrity sha1-vW/KqcVZoJa2gIBvTWV7Pw8kBWE= + +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U= @@ -311,11 +497,35 @@ pend@~1.2.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= +pid-port@^0.1.0: + version "0.1.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/pid-port/-/pid-port-0.1.1.tgz#2ac86fa8a0e97ef2e7eb9e7e9567cdc1eda78098" + integrity sha1-KshvqKDpfvLn655+lWfNwe2ngJg= + dependencies: + execa "^5.0.0" + +process-exists@^4.0.0: + version "4.1.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/process-exists/-/process-exists-4.1.0.tgz#4132c516324c1da72d65896851cdbd8bbdf5b9d8" + integrity sha1-QTLFFjJMHactZYloUc29i731udg= + dependencies: + ps-list "^6.3.0" + progress@2.0.3: version "2.0.3" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha1-foz42PW48jnBvGi+tOt4Vn1XLvg= +ps-list@^6.3.0: + version "6.3.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ps-list/-/ps-list-6.3.0.tgz#a2b775c2db7d547a28fbaa3a05e4c281771259be" + integrity sha1-ord1wtt9VHoo+6o6BeTCgXcSWb4= + +ps-list@^7.2.0: + version "7.2.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ps-list/-/ps-list-7.2.0.tgz#3d110e1de8249a4b178c9b1cf2a215d1e4e42fc0" + integrity sha1-PREOHegkmksXjJsc8qIV0eTkL8A= + pump@^3.0.0: version "3.0.0" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -324,20 +534,16 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +queue-tick@^1.0.1: + version "1.0.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" + integrity sha1-9vB6yCwf1g+C4Ji0F6gOUvH0wUI= + quick-lru@^5.1.1: version "5.1.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha1-NmST5rPkKjpoheLpnRj4D7eoyTI= -readable-stream@^3.1.1, readable-stream@^3.4.0: - version "3.6.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha1-M3u9o63AcGvT4CRCaihtS0sskZg= - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - resolve-alpn@^1.0.0: version "1.2.1" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" @@ -350,28 +556,27 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.0.0" -safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY= - -selenium-standalone@^7.1.0: - version "7.1.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/selenium-standalone/-/selenium-standalone-7.1.0.tgz#1192a4ad84f114137dd5deadcb81b0f56afe054a" - integrity sha1-EZKkrYTxFBN91d6ty4Gw9Wr+BUo= +selenium-standalone@^9.1.1: + version "9.1.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/selenium-standalone/-/selenium-standalone-9.1.1.tgz#a37388309afa29bb232205bf3aeaa3c7db681449" + integrity sha1-o3OIMJr6KbsjIgW/Ouqjx9toFEk= dependencies: - commander "^7.2.0" + axios "^0.27.2" + commander "^8.3.0" cross-spawn "^7.0.3" debug "^4.3.1" + execa "^5.1.1" + find-process "^1.4.7" + fkill "^7.2.1" fs-extra "^10.0.0" got "^11.8.2" is-port-reachable "^3.0.0" lodash.mapvalues "^4.6.0" lodash.merge "^4.6.2" minimist "^1.2.5" - mkdirp "^1.0.4" + mkdirp "^2.1.3" progress "2.0.3" - tar-stream "2.2.0" + tar-stream "3.1.6" which "^2.0.2" yauzl "^2.10.0" @@ -387,34 +592,53 @@ shebang-regex@^3.0.0: resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI= -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha1-QvEUWUpGzxqOMLCoT1bHjD7awh4= +signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.7" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha1-qaF2f4r4QVURTqq9c/mSc8j1mtk= + +streamx@^2.15.0: + version "2.15.1" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/streamx/-/streamx-2.15.1.tgz#396ad286d8bc3eeef8f5cea3f029e81237c024c6" + integrity sha1-OWrShti8Pu749c6j8CnoEjfAJMY= dependencies: - safe-buffer "~5.2.0" + fast-fifo "^1.1.0" + queue-tick "^1.0.1" -tar-stream@2.2.0: - version "2.2.0" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" - integrity sha1-rK2EwoQTawYNw/qmRHSqmuvXcoc= +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha1-ibhS+y/L6Tb29LMYevsKEsGrWK0= + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha1-G33NyzK4E4gBs+R4umpRyqiWSNo= dependencies: - bl "^4.0.3" - end-of-stream "^1.4.1" - fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" + has-flag "^4.0.0" + +tar-stream@3.1.6: + version "3.1.6" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/tar-stream/-/tar-stream-3.1.6.tgz#6520607b55a06f4a2e2e04db360ba7d338cc5bab" + integrity sha1-ZSBge1Wgb0ouLgTbNgun0zjMW6s= + dependencies: + b4a "^1.6.4" + fast-fifo "^1.2.0" + streamx "^2.15.0" + +taskkill@^3.1.0: + version "3.1.0" + resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/taskkill/-/taskkill-3.1.0.tgz#28001339feb23bfae3f447902c4b4abcdd057680" + integrity sha1-KAATOf6yO/rj9EeQLEtKvN0FdoA= + dependencies: + arrify "^2.0.1" + execa "^3.3.0" universalify@^2.0.0: version "2.0.0" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha1-daSYTv7cSwiXXFrrc/Uw0C3yVxc= -util-deprecate@^1.0.1: - version "1.0.2" - resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" diff --git a/src/Shared/E2ETesting/E2ETesting.targets b/src/Shared/E2ETesting/E2ETesting.targets index 1450520a79ed..ae07c367af58 100644 --- a/src/Shared/E2ETesting/E2ETesting.targets +++ b/src/Shared/E2ETesting/E2ETesting.targets @@ -51,7 +51,7 @@ <_PackageJsonLinesContent>@(_PackageJsonLines) - <_PackageJsonSeleniumPackage>"selenium-standalone": "^7.1.0" + <_PackageJsonSeleniumPackage>"selenium-standalone": "^9.1.1" GetInstanceAsync(ITestOutputH private static async Task InitializeInstance(ITestOutputHelper output) { var port = FindAvailablePort(); - var uri = new UriBuilder("http", SeleniumHost, port, "/wd/hub").Uri; + var uri = new UriBuilder("http", SeleniumHost, port).Uri; var seleniumConfigPath = typeof(SeleniumStandaloneServer).Assembly .GetCustomAttributes() @@ -100,22 +100,25 @@ private static async Task InitializeInstance(ITestOutputHelper output) // In AzDO, the path to the system chromedriver is in an env var called CHROMEWEBDRIVER // We want to use this because it should match the installed browser version // If the env var is not set, then we fall back on using whatever is in the Selenium config file - var chromeDriverArg = string.Empty; var chromeDriverPathEnvVar = Environment.GetEnvironmentVariable("CHROMEWEBDRIVER"); if (!string.IsNullOrEmpty(chromeDriverPathEnvVar)) { - chromeDriverArg = $"--javaArgs=-Dwebdriver.chrome.driver={chromeDriverPathEnvVar}/chromedriver"; output.WriteLine($"Using chromedriver at path {chromeDriverPathEnvVar}"); } var psi = new ProcessStartInfo { FileName = "npm", - Arguments = $"run selenium-standalone start -- --config \"{seleniumConfigPath}\" {chromeDriverArg} -- -host {SeleniumHost} -port {port}", + Arguments = $"run selenium-standalone start -- --config \"{seleniumConfigPath}\" -- --host {SeleniumHost} --port {port}", RedirectStandardOutput = true, RedirectStandardError = true, }; + if (!string.IsNullOrEmpty(chromeDriverPathEnvVar)) + { + psi.EnvironmentVariables["PATH"] = $"{psi.EnvironmentVariables["PATH"]}{Path.PathSeparator}{chromeDriverPathEnvVar}"; + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { psi.FileName = "cmd"; diff --git a/src/Shared/E2ETesting/selenium-config.json b/src/Shared/E2ETesting/selenium-config.json index 4b6ee654b211..1f2e6bd75fe3 100644 --- a/src/Shared/E2ETesting/selenium-config.json +++ b/src/Shared/E2ETesting/selenium-config.json @@ -1,7 +1,8 @@ { + "version": "4.12.0", "drivers": { "chrome": { - "version" : "114.0.5735.90" + "version" : "116.0.5845.96" } }, "ignoreExtraDrivers": true From 41e54ac3f88b6379c5df884bf3f96d2d2283cdc8 Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Thu, 14 Sep 2023 11:52:47 -0700 Subject: [PATCH 08/10] Update test for non-enhanced form --- .../FormHandlingTests/FormWithParentBindingContextTest.cs | 8 +++----- .../RazorComponents/Pages/Forms/FormsWithFiles.razor | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs index af99f364ad6c..c02197c40ee4 100644 --- a/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs +++ b/src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs @@ -1224,10 +1224,8 @@ public void PostingFormWithErrorsDoesNotExceedMaximumErrors() DispatchToFormCore(dispatchToForm); } - [Theory] - [InlineData(true)] - [InlineData(false)] - public void CanBindToFormWithFiles(bool suppressEnhancedNavigation) + [Fact] + public void CanBindToFormWithFiles() { var profilePicture = TempFile.Create(_tempDirectory, "txt", "This is a profile picture."); var headerPhoto = TempFile.Create(_tempDirectory, "txt", "This is a header picture."); @@ -1237,7 +1235,7 @@ public void CanBindToFormWithFiles(bool suppressEnhancedNavigation) { Url = "forms/with-files", FormCssSelector = "form", - SuppressEnhancedNavigation = suppressEnhancedNavigation, + FormIsEnhanced = false, UpdateFormAction = () => { Browser.Exists(By.CssSelector("input[name='Model.ProfilePicture']")).SendKeys(profilePicture.Path); diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/FormsWithFiles.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/FormsWithFiles.razor index a3d36e983918..277321ea4017 100644 --- a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/FormsWithFiles.razor +++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/FormsWithFiles.razor @@ -3,7 +3,7 @@

Forms With Files

- +