diff --git a/eng/Versions.props b/eng/Versions.props
index f86f08817349..cb79cb2a3082 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -313,9 +313,8 @@
1.28.0
3.0.0
7.2.4
- 4.10.0
- 114.0.5735.9000
- 4.10.0
+ 4.14.1
+ 4.14.1
1.4.0
4.0.0
2.6.122
diff --git a/src/Components/test/E2ETest/Infrastructure/AssemblyInfo.AssemblyFixtures.cs b/src/Components/test/E2ETest/Infrastructure/AssemblyInfo.AssemblyFixtures.cs
deleted file mode 100644
index 08c9ff4a895a..000000000000
--- a/src/Components/test/E2ETest/Infrastructure/AssemblyInfo.AssemblyFixtures.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-// 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.E2ETesting;
-using Microsoft.AspNetCore.Testing;
-
-[assembly: AssemblyFixture(typeof(SeleniumStandaloneServer))]
-[assembly: AssemblyFixture(typeof(SauceConnectServer))]
diff --git a/src/Components/test/E2ETest/package.json b/src/Components/test/E2ETest/package.json
deleted file mode 100644
index 085a418e3a12..000000000000
--- a/src/Components/test/E2ETest/package.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "name": "microsoft.aspnetcore.components.e2etest",
- "version": "0.0.1",
- "description": "Not a real package. This file exists only to declare dependencies.",
- "main": "index.js",
- "private": true,
- "scripts": {
- "selenium-standalone": "selenium-standalone",
- "prepare": "selenium-standalone install --config ../../../Shared/E2ETesting/selenium-config.json",
- "sauce": "ts-node ./scripts/sauce.ts"
- },
- "author": "",
- "license": "MIT",
- "dependencies": {
- "sauce-connect-launcher": "^1.3.1",
- "selenium-standalone": "^7.1.0"
- },
- "devDependencies": {
- "@types/node": "^13.1.7",
- "ts-node": "^8.6.2",
- "typescript": "^3.7.5"
- },
- "resolutions": {
- "lodash": ">=4.17.21"
- }
-}
diff --git a/src/Components/test/E2ETest/scripts/sauce.ts b/src/Components/test/E2ETest/scripts/sauce.ts
deleted file mode 100644
index 395d0c1324b8..000000000000
--- a/src/Components/test/E2ETest/scripts/sauce.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-import { EOL } from "os";
-import * as _fs from "fs";
-import { promisify } from "util";
-
-// Promisify things from fs we want to use.
-const fs = {
- createWriteStream: _fs.createWriteStream,
- exists: promisify(_fs.exists),
- mkdir: promisify(_fs.mkdir),
- appendFile: promisify(_fs.appendFile),
- readFile: promisify(_fs.readFile),
-};
-
-process.on("unhandledRejection", (reason) => {
- console.error(`Unhandled promise rejection: ${reason}`);
- process.exit(1);
-});
-
-let sauceUser = null;
-let sauceKey = null;
-let tunnelIdentifier = null;
-let hostName = null;
-
-for (let i = 0; i < process.argv.length; i += 1) {
- switch (process.argv[i]) {
- case "--sauce-user":
- i += 1;
- sauceUser = process.argv[i];
- break;
- case "--sauce-key":
- i += 1;
- sauceKey = process.argv[i];
- break;
- case "--sauce-tunnel":
- i += 1;
- tunnelIdentifier = process.argv[i];
- break;
- case "--use-hostname":
- i += 1;
- hostName = process.argv[i];
- break;
- }
-}
-
-const HOSTSFILE_PATH = process.platform === "win32" ? `${process.env.SystemRoot}\\System32\\drivers\\etc\\hosts` : null;
-
-(async () => {
-
- if (hostName) {
- // Register a custom hostname in the hosts file (requires Admin, but AzDO agents run as Admin)
- // Used to work around issues in Sauce Labs.
- if (process.platform !== "win32") {
- throw new Error("Can't use '--use-hostname' on non-Windows platform.");
- }
-
- try {
-
- console.log(`Updating Hosts file (${HOSTSFILE_PATH}) to register host name '${hostName}'`);
- await fs.appendFile(HOSTSFILE_PATH, `${EOL}127.0.0.1 ${hostName}${EOL}`);
-
- } catch (error) {
- console.log(`Unable to update hosts file at ${HOSTSFILE_PATH}. Error: ${error}`);
- }
- }
-
-
- // Creates a persistent proxy tunnel using Sauce Connect.
- var sauceConnectLauncher = require('sauce-connect-launcher');
-
- sauceConnectLauncher({
- username: sauceUser,
- accessKey: sauceKey,
- tunnelIdentifier: tunnelIdentifier,
- }, function (err, sauceConnectProcess) {
- if (err) {
- console.error(err.message);
- return;
- }
-
- console.log("Sauce Connect ready");
- });
-})();
diff --git a/src/Components/test/E2ETest/yarn.lock b/src/Components/test/E2ETest/yarn.lock
deleted file mode 100644
index 59a3743df090..000000000000
--- a/src/Components/test/E2ETest/yarn.lock
+++ /dev/null
@@ -1,600 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-"@sindresorhus/is@^4.0.0":
- version "4.6.0"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f"
- integrity sha1-PHycRuZ4/u/nouW7YJ09vWZf+z8=
-
-"@szmarczak/http-timer@^4.0.5":
- version "4.0.6"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807"
- integrity sha1-tKkUu2LnwnLU5Zif5EQPgSqx2Ac=
- dependencies:
- defer-to-connect "^2.0.0"
-
-"@types/cacheable-request@^6.0.1":
- version "6.0.3"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183"
- integrity sha1-pDCzJgRmyntcpb/XNWk7Nuep0YM=
- dependencies:
- "@types/http-cache-semantics" "*"
- "@types/keyv" "^3.1.4"
- "@types/node" "*"
- "@types/responselike" "^1.0.0"
-
-"@types/http-cache-semantics@*":
- version "4.0.1"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812"
- integrity sha1-Dqe2FJaQK5WJDcTDoRa2DLja6BI=
-
-"@types/keyv@^3.1.4":
- version "3.1.4"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6"
- integrity sha1-PM2xxnUbDH5SMAvNrNW8v4+qdbY=
- dependencies:
- "@types/node" "*"
-
-"@types/node@*":
- version "18.13.0"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/node/-/node-18.13.0.tgz#0400d1e6ce87e9d3032c19eb6c58205b0d3f7850"
- integrity sha1-BADR5s6H6dMDLBnrbFggWw0/eFA=
-
-"@types/node@^13.1.7":
- version "13.13.52"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/node/-/node-13.13.52.tgz#03c13be70b9031baaed79481c0c0cfb0045e53f7"
- integrity sha1-A8E75wuQMbqu15SBwMDPsAReU/c=
-
-"@types/responselike@^1.0.0":
- version "1.0.0"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
- integrity sha1-JR9P59FU0rrRJavhtCmyOv0mLik=
- dependencies:
- "@types/node" "*"
-
-adm-zip@~0.4.3:
- version "0.4.16"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365"
- integrity sha1-z0xQj9/6sCwmnLx/RxqHXwVXA2U=
-
-agent-base@6:
- version "6.0.2"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
- integrity sha1-Sf/1hXfP7j83F2/qtMIuAPhtf3c=
- dependencies:
- debug "4"
-
-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=
-
-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"
- integrity sha1-cGt/9ghGZM1+rnE/b5ZUM7VQQiE=
- dependencies:
- lodash "^4.17.14"
-
-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"
- integrity sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=
- dependencies:
- balanced-match "^1.0.0"
- concat-map "0.0.1"
-
-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-from@^1.0.0:
- version "1.1.2"
- 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"
- integrity sha1-WmuGWyxENXvj1evCpGewMnGacAU=
-
-cacheable-request@^7.0.2:
- version "7.0.2"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27"
- integrity sha1-6g0LiJNkolhUdXMByhKy2nf5HSc=
- dependencies:
- clone-response "^1.0.2"
- get-stream "^5.1.0"
- http-cache-semantics "^4.0.0"
- keyv "^4.0.0"
- lowercase-keys "^2.0.0"
- normalize-url "^6.0.1"
- responselike "^2.0.0"
-
-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"
- integrity sha1-ryAyqkeBY5nPXwodDbkC9ReruMM=
- 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=
-
-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:
- 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=
- dependencies:
- path-key "^3.1.0"
- shebang-command "^2.0.0"
- which "^2.0.1"
-
-debug@4, 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=
- dependencies:
- ms "2.1.2"
-
-decompress-response@^6.0.0:
- version "6.0.0"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
- integrity sha1-yjh2Et234QS9FthaqwDV7PCcZvw=
- dependencies:
- mimic-response "^3.1.0"
-
-defer-to-connect@^2.0.0:
- version "2.0.1"
- 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=
-
-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:
- 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"
-
-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"
- integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
- 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=
-
-fs-extra@^10.0.0:
- version "10.1.0"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
- integrity sha1-Aoc8+8QITd4SfqpfmQXu8jJdGr8=
- dependencies:
- graceful-fs "^4.2.0"
- jsonfile "^6.0.1"
- universalify "^2.0.0"
-
-fs.realpath@^1.0.0:
- version "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:
- 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"
-
-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"
- integrity sha1-uN8PuAK7+o6JvR2Ti04WV47UTys=
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.1.1"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-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"
- integrity sha1-J26Cfq2Hcu3bz8lxcFkLhBgjIzo=
- dependencies:
- "@sindresorhus/is" "^4.0.0"
- "@szmarczak/http-timer" "^4.0.5"
- "@types/cacheable-request" "^6.0.1"
- "@types/responselike" "^1.0.0"
- cacheable-lookup "^5.0.3"
- cacheable-request "^7.0.2"
- decompress-response "^6.0.0"
- http2-wrapper "^1.0.0-beta.5.2"
- lowercase-keys "^2.0.0"
- p-cancelable "^2.0.0"
- responselike "^2.0.0"
-
-graceful-fs@^4.1.6, graceful-fs@^4.2.0:
- version "4.2.10"
- 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=
-
-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"
- integrity sha1-q+AvyymFRgvwMjvmZENuw0dqbVo=
-
-http2-wrapper@^1.0.0-beta.5.2:
- version "1.0.3"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
- integrity sha1-uPVeDB8l1OvQizsMLAeflZCACz0=
- dependencies:
- quick-lru "^5.1.1"
- resolve-alpn "^1.0.0"
-
-https-proxy-agent@^5.0.0:
- version "5.0.1"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
- integrity sha1-xZ7yJKBP6LdU89sAY6Jeow0ABdY=
- dependencies:
- 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=
-
-inflight@^1.0.4:
- version "1.0.6"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
- integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
- dependencies:
- once "^1.3.0"
- wrappy "1"
-
-inherits@2, 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=
-
-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=
-
-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"
- integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
-
-json-buffer@3.0.1:
- version "3.0.1"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
- integrity sha1-kziAKjDTtmBfvgYT4JQAjKjAWhM=
-
-jsonfile@^6.0.1:
- version "6.1.0"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
- integrity sha1-vFWyY0eTxnnsZAMJTrE2mKbsCq4=
- dependencies:
- universalify "^2.0.0"
- optionalDependencies:
- graceful-fs "^4.1.6"
-
-keyv@^4.0.0:
- version "4.5.2"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/keyv/-/keyv-4.5.2.tgz#0e310ce73bf7851ec702f2eaf46ec4e3805cce56"
- integrity sha1-DjEM5zv3hR7HAvLq9G7E44BczlY=
- dependencies:
- json-buffer "3.0.1"
-
-lodash.mapvalues@^4.6.0:
- version "4.6.0"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c"
- integrity sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=
-
-lodash.merge@^4.6.2:
- version "4.6.2"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
- integrity sha1-VYqlO0O2YeGSWgr9+japoQhf5Xo=
-
-lodash@>=4.17.21, lodash@^4.16.6, lodash@^4.17.14:
- version "4.17.21"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
- integrity sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=
-
-lowercase-keys@^2.0.0:
- version "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=
-
-make-error@^1.1.1:
- version "1.3.6"
- 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=
-
-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"
- integrity sha1-SSNTiHju9CBjy4o+OweYeBSHqxs=
-
-mimic-response@^3.1.0:
- version "3.1.0"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
- integrity sha1-LR1Zr5wbEpgVrMwsRqAipc4fo8k=
-
-minimatch@^3.1.1:
- version "3.1.2"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
- integrity sha1-Gc0ZS/0+Qo8EmnCBfAONiatL41s=
- dependencies:
- brace-expansion "^1.1.7"
-
-minimist@^1.2.5:
- version "1.2.8"
- 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=
-
-ms@2.1.2:
- version "2.1.2"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
- integrity sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=
-
-normalize-url@^6.0.1:
- version "6.1.0"
- 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=
-
-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"
- integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
- dependencies:
- wrappy "1"
-
-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-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:
- 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=
-
-pend@~1.2.0:
- version "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=
-
-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=
-
-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"
- integrity sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=
- dependencies:
- end-of-stream "^1.1.0"
- once "^1.3.1"
-
-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"
- integrity sha1-t629rDVGqq7CC0Xn2CZZJwcnJvk=
-
-responselike@^2.0.0:
- version "2.0.1"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc"
- integrity sha1-mgvI/cJS8/scymiwFlkQWboUIrw=
- dependencies:
- lowercase-keys "^2.0.0"
-
-rimraf@^2.5.4:
- version "2.7.1"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
- integrity sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w=
- 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"
- integrity sha1-38Z1olhVCAmo6vRX65FiuUPduvA=
- dependencies:
- adm-zip "~0.4.3"
- async "^2.1.2"
- https-proxy-agent "^5.0.0"
- 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=
- dependencies:
- commander "^7.2.0"
- cross-spawn "^7.0.3"
- debug "^4.3.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"
- progress "2.0.3"
- tar-stream "2.2.0"
- which "^2.0.2"
- yauzl "^2.10.0"
-
-shebang-command@^2.0.0:
- version "2.0.0"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
- integrity sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo=
- dependencies:
- shebang-regex "^3.0.0"
-
-shebang-regex@^3.0.0:
- version "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=
-
-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"
- integrity sha1-BP58f54e0tZiIzwoyys1ufY/bk8=
- dependencies:
- buffer-from "^1.0.0"
- source-map "^0.6.0"
-
-source-map@^0.6.0:
- version "0.6.1"
- 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=
- dependencies:
- safe-buffer "~5.2.0"
-
-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=
- 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"
-
-ts-node@^8.6.2:
- version "8.10.2"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d"
- integrity sha1-7uA3ZGM7EjTd03+NuewQt17H+40=
- dependencies:
- arg "^4.1.0"
- diff "^4.0.1"
- make-error "^1.1.1"
- source-map-support "^0.5.17"
- yn "3.1.1"
-
-typescript@^3.7.5:
- version "3.9.10"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8"
- integrity sha1-cPORCselHta+952ngAaQsZv3eLg=
-
-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"
- integrity sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE=
- dependencies:
- isexe "^2.0.0"
-
-wrappy@1:
- version "1.0.2"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
- integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
-
-yauzl@^2.10.0:
- version "2.10.0"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
- integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
- dependencies:
- buffer-crc32 "~0.2.3"
- fd-slicer "~1.1.0"
-
-yn@3.1.1:
- version "3.1.1"
- resolved "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
- integrity sha1-HodAGgnXZ8HV6rJqbkwYUYLS61A=
diff --git a/src/Shared/E2ETesting/BrowserFixture.cs b/src/Shared/E2ETesting/BrowserFixture.cs
index 67ab36f443b8..309d0697ee71 100644
--- a/src/Shared/E2ETesting/BrowserFixture.cs
+++ b/src/Shared/E2ETesting/BrowserFixture.cs
@@ -1,21 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
using System.Collections.Concurrent;
using System.Diagnostics;
-using System.IO;
-using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
-using System.Threading.Tasks;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
-using OpenQA.Selenium.Edge;
-using OpenQA.Selenium.IE;
-using OpenQA.Selenium.Remote;
-using OpenQA.Selenium.Safari;
-using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNetCore.E2ETesting;
@@ -23,7 +14,7 @@ namespace Microsoft.AspNetCore.E2ETesting;
public class BrowserFixture : IAsyncLifetime
{
public static string StreamingContext { get; } = "streaming";
- private readonly ConcurrentDictionary> _browsers = new ConcurrentDictionary>();
+ private readonly ConcurrentDictionary _browsers = new();
public BrowserFixture(IMessageSink diagnosticsMessageSink)
{
@@ -72,7 +63,7 @@ public static bool IsHostAutomationSupported()
public async Task DisposeAsync()
{
- var browsers = await Task.WhenAll(_browsers.Values);
+ var browsers = _browsers.Values;
foreach (var (browser, _) in browsers)
{
browser?.Quit();
@@ -115,30 +106,20 @@ private async Task DeleteBrowserUserProfileDirectoriesAsync()
}
}
- public Task<(IWebDriver, ILogs)> GetOrCreateBrowserAsync(ITestOutputHelper output, string isolationContext = "")
+ public (IWebDriver, ILogs) GetOrCreateBrowser(ITestOutputHelper output, string isolationContext = "")
{
- Func> createBrowserFunc;
- if (E2ETestOptions.Instance.SauceTest)
+ if (!IsHostAutomationSupported())
{
- createBrowserFunc = CreateSauceBrowserAsync;
- }
- else
- {
- if (!IsHostAutomationSupported())
- {
- output.WriteLine($"{nameof(BrowserFixture)}: Host does not support browser automation.");
- return Task.FromResult<(IWebDriver, ILogs)>(default);
- }
-
- createBrowserFunc = CreateBrowserAsync;
+ output.WriteLine($"{nameof(BrowserFixture)}: Host does not support browser automation.");
+ return default;
}
- return _browsers.GetOrAdd(isolationContext, createBrowserFunc, output);
+ return _browsers.GetOrAdd(isolationContext, CreateBrowser, output);
}
public Task InitializeAsync() => Task.CompletedTask;
- private async Task<(IWebDriver browser, ILogs log)> CreateBrowserAsync(string context, ITestOutputHelper output)
+ private (IWebDriver browser, ILogs log) CreateBrowser(string context, ITestOutputHelper output)
{
var opts = new ChromeOptions();
@@ -183,8 +164,6 @@ private async Task DeleteBrowserUserProfileDirectoriesAsync()
opts.AddUserProfilePreference("download.default_directory", Path.Combine(userProfileDirectory, "Downloads"));
}
- var instance = await SeleniumStandaloneServer.GetInstanceAsync(output);
-
var attempt = 0;
const int maxAttempts = 3;
Exception innerException;
@@ -201,9 +180,9 @@ private async Task DeleteBrowserUserProfileDirectoriesAsync()
// Additionally, if we think the selenium server has become irresponsive, we could spin up
// replace the current selenium server instance and let a new instance take over for the
// remaining tests.
- var driver = new RemoteWebDriverWithLogs(
- instance.Uri,
- opts.ToCapabilities(),
+ var driver = new ChromeDriver(
+ CreateChromeDriverService(output),
+ opts,
TimeSpan.FromSeconds(60).Add(TimeSpan.FromSeconds(attempt * 60)));
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(1);
@@ -224,146 +203,32 @@ private async Task DeleteBrowserUserProfileDirectoriesAsync()
throw new InvalidOperationException("Couldn't create a Selenium remote driver client. The server is irresponsive", innerException);
}
- private static string UserProfileDirectory(string context)
+ private static ChromeDriverService CreateChromeDriverService(ITestOutputHelper output)
{
- if (string.IsNullOrEmpty(context))
- {
- return null;
- }
-
- return Path.Combine(Path.GetTempPath(), "BrowserFixtureUserProfiles", context);
- }
-
- private async Task<(IWebDriver browser, ILogs log)> CreateSauceBrowserAsync(string context, ITestOutputHelper output)
- {
- var sauce = E2ETestOptions.Instance.Sauce;
-
- if (sauce == null ||
- string.IsNullOrEmpty(sauce.TestName) ||
- string.IsNullOrEmpty(sauce.Username) ||
- string.IsNullOrEmpty(sauce.AccessKey) ||
- string.IsNullOrEmpty(sauce.TunnelIdentifier) ||
- string.IsNullOrEmpty(sauce.PlatformName) ||
- string.IsNullOrEmpty(sauce.BrowserName))
- {
- throw new InvalidOperationException("Required SauceLabs environment variables not set.");
- }
-
- var name = sauce.TestName;
- if (!string.IsNullOrEmpty(context))
- {
- name = $"{name} - {context}";
- }
-
- DriverOptions options;
-
- switch (sauce.BrowserName.ToLowerInvariant())
+ // 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 allowing Selenium Manager to download
+ // and use an up-to-date chromedriver
+ var chromeDriverPathEnvVar = Environment.GetEnvironmentVariable("CHROMEWEBDRIVER");
+ if (!string.IsNullOrEmpty(chromeDriverPathEnvVar))
{
- case "chrome":
- options = new ChromeOptions();
- break;
- case "safari":
- options = new SafariOptions();
- break;
- case "internet explorer":
- options = new InternetExplorerOptions();
- break;
- case "microsoftedge":
- options = new EdgeOptions();
- break;
- default:
- throw new InvalidOperationException($"Browser name {sauce.BrowserName} not recognized");
- }
-
- // Required config
- options.AddAdditionalOption("username", sauce.Username);
- options.AddAdditionalOption("accessKey", sauce.AccessKey);
- options.AddAdditionalOption("tunnelIdentifier", sauce.TunnelIdentifier);
- options.AddAdditionalOption("name", name);
-
- if (!string.IsNullOrEmpty(sauce.BrowserName))
- {
- options.AddAdditionalOption("browserName", sauce.BrowserName);
- }
-
- if (!string.IsNullOrEmpty(sauce.PlatformVersion))
- {
- options.PlatformName = sauce.PlatformName;
- options.AddAdditionalOption("platformVersion", sauce.PlatformVersion);
+ output.WriteLine($"Using chromedriver at path {chromeDriverPathEnvVar}");
+ return ChromeDriverService.CreateDefaultService(chromeDriverPathEnvVar);
}
else
{
- // In some cases (like macOS), SauceLabs expects us to set "platform" instead of "platformName".
- options.AddAdditionalOption("platform", sauce.PlatformName);
- }
-
- if (!string.IsNullOrEmpty(sauce.BrowserVersion))
- {
- options.BrowserVersion = sauce.BrowserVersion;
+ output.WriteLine($"Using default chromedriver from Selenium Manager");
+ return ChromeDriverService.CreateDefaultService();
}
-
- if (!string.IsNullOrEmpty(sauce.DeviceName))
- {
- options.AddAdditionalOption("deviceName", sauce.DeviceName);
- }
-
- if (!string.IsNullOrEmpty(sauce.DeviceOrientation))
- {
- options.AddAdditionalOption("deviceOrientation", sauce.DeviceOrientation);
- }
-
- if (!string.IsNullOrEmpty(sauce.AppiumVersion))
- {
- options.AddAdditionalOption("appiumVersion", sauce.AppiumVersion);
- }
-
- if (!string.IsNullOrEmpty(sauce.SeleniumVersion))
- {
- options.AddAdditionalOption("seleniumVersion", sauce.SeleniumVersion);
- }
-
- var capabilities = options.ToCapabilities();
-
- //await SauceConnectServer.StartAsync(output);
- await Task.Yield();
-
- var attempt = 0;
- const int maxAttempts = 3;
- do
- {
- try
- {
- // Attempt to create a new browser in SauceLabs.
- var driver = new RemoteWebDriver(
- new Uri("http://localhost:4445/wd/hub"),
- capabilities,
- TimeSpan.FromSeconds(60).Add(TimeSpan.FromSeconds(attempt * 60)));
-
- // Make sure implicit waits are disabled as they don't mix well with explicit waiting
- // see https://www.selenium.dev/documentation/en/webdriver/waits/#implicit-wait
- driver.Manage().Timeouts().ImplicitWait = TimeSpan.Zero;
- var logs = driver.Manage().Logs;
-
- return (driver, logs);
- }
- catch (Exception ex)
- {
- output.WriteLine($"Error initializing RemoteWebDriver: {ex.Message}");
- }
-
- attempt++;
-
- } while (attempt < maxAttempts);
-
- throw new InvalidOperationException("Couldn't create a SauceLabs remote driver client.");
}
- // This is a workaround for https://github.com/SeleniumHQ/selenium/issues/8229
- private sealed class RemoteWebDriverWithLogs : RemoteWebDriver, ISupportsLogs
+ private static string UserProfileDirectory(string context)
{
- public RemoteWebDriverWithLogs(Uri remoteAddress, ICapabilities desiredCapabilities, TimeSpan commandTimeout)
- : base(remoteAddress, desiredCapabilities, commandTimeout)
+ if (string.IsNullOrEmpty(context))
{
+ return null;
}
+
+ return Path.Combine(Path.GetTempPath(), "BrowserFixtureUserProfiles", context);
}
}
diff --git a/src/Shared/E2ETesting/BrowserTestBase.cs b/src/Shared/E2ETesting/BrowserTestBase.cs
index 47c91910f38b..7a1927fe22cf 100644
--- a/src/Shared/E2ETesting/BrowserTestBase.cs
+++ b/src/Shared/E2ETesting/BrowserTestBase.cs
@@ -1,12 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
using System.Runtime.ExceptionServices;
-using System.Threading;
-using System.Threading.Tasks;
using OpenQA.Selenium;
-using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNetCore.E2ETesting;
@@ -63,22 +59,22 @@ public virtual Task InitializeAsync()
return InitializeAsync("");
}
- public virtual async Task InitializeAsync(string isolationContext)
+ public virtual Task InitializeAsync(string isolationContext)
{
- await InitializeBrowser(isolationContext);
-
+ InitializeBrowser(isolationContext);
InitializeAsyncCore();
+ return Task.CompletedTask;
}
protected virtual void InitializeAsyncCore()
{
}
- protected async Task InitializeBrowser(string isolationContext)
+ protected void InitializeBrowser(string isolationContext)
{
try
{
- var (browser, logs) = await BrowserFixture.GetOrCreateBrowserAsync(Output, isolationContext);
+ var (browser, logs) = BrowserFixture.GetOrCreateBrowser(Output, isolationContext);
_asyncBrowser.Value = browser;
_logs.Value = logs;
diff --git a/src/Shared/E2ETesting/E2ETesting.props b/src/Shared/E2ETesting/E2ETesting.props
index d1600f06133f..e19e2f12afe6 100644
--- a/src/Shared/E2ETesting/E2ETesting.props
+++ b/src/Shared/E2ETesting/E2ETesting.props
@@ -7,9 +7,6 @@
true
$([MSBuild]::EnsureTrailingSlash('$(RepoRoot)'))artifacts\tmp\sauceconnect\
-
- $([MSBuild]::NormalizePath($(MSBuildThisFileDirectory)selenium-config.json))
-
true
diff --git a/src/Shared/E2ETesting/E2ETesting.targets b/src/Shared/E2ETesting/E2ETesting.targets
index 1450520a79ed..4603c70c6585 100644
--- a/src/Shared/E2ETesting/E2ETesting.targets
+++ b/src/Shared/E2ETesting/E2ETesting.targets
@@ -12,17 +12,6 @@
-
-
-
-
-
-
-
-
-
-
-
- <_PackageJson>$(MSBuildProjectDirectory)\package.json
-
-
+
-
-
-
-
-
-
-
-
- <_PackageJsonLinesContent>@(_PackageJsonLines)
- <_PackageJsonSeleniumPackage>"selenium-standalone": "^7.1.0"
-
-
-
@@ -104,12 +74,6 @@
<_Parameter1>Microsoft.AspNetCore.Testing.Selenium.Supported
<_Parameter2>$(_SeleniumE2ETestsSupportedAttributeValue)
-
-
- <_Parameter1>Microsoft.AspNetCore.Testing.SeleniumConfigPath
- <_Parameter2>$(SeleniumConfigPath)
-
diff --git a/src/Shared/E2ETesting/SeleniumStandaloneServer.cs b/src/Shared/E2ETesting/SeleniumStandaloneServer.cs
deleted file mode 100644
index a635d47f985d..000000000000
--- a/src/Shared/E2ETesting/SeleniumStandaloneServer.cs
+++ /dev/null
@@ -1,330 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.Collections.Concurrent;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Net.Sockets;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.E2ETesting;
-using Microsoft.Extensions.Internal;
-using Xunit.Abstractions;
-using Xunit.Sdk;
-
-namespace Microsoft.AspNetCore.E2ETesting;
-
-public class SeleniumStandaloneServer : IDisposable
-{
- private const string SeleniumHost = "127.0.0.1";
- private const int SeleniumProcessTimeout = 3600; // 1h 30 min
-
- private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
-
- private Process _process;
- private string _sentinelPath;
- private Process _sentinelProcess;
- private static IMessageSink _diagnosticsMessageSink;
-
- public SeleniumStandaloneServer(IMessageSink diagnosticsMessageSink)
- {
- if (Instance != null || _diagnosticsMessageSink != null)
- {
- throw new InvalidOperationException("Selenium standalone singleton already created.");
- }
-
- // The assembly level attribute AssemblyFixture takes care of this being being instantiated before tests run
- // and disposed after tests are run, gracefully shutting down the server when possible by calling Dispose on
- // the singleton.
- Instance = this;
- _diagnosticsMessageSink = diagnosticsMessageSink;
- }
-
- private void Initialize(
- Uri uri,
- Process process,
- string sentinelPath,
- Process sentinelProcess)
- {
- Uri = uri;
- _process = process;
- _sentinelPath = sentinelPath;
- _sentinelProcess = sentinelProcess;
- }
-
- public Uri Uri { get; private set; }
-
- internal static SeleniumStandaloneServer Instance { get; private set; }
-
- public static async Task GetInstanceAsync(ITestOutputHelper output)
- {
- try
- {
- await _semaphore.WaitAsync();
- if (Instance._process == null)
- {
- // No process was started, meaning the instance wasn't initialized.
- await InitializeInstance(output);
- }
- }
- finally
- {
- _semaphore.Release();
- }
-
- return Instance;
- }
-
- private static async Task InitializeInstance(ITestOutputHelper output)
- {
- var port = FindAvailablePort();
- var uri = new UriBuilder("http", SeleniumHost, port, "/wd/hub").Uri;
-
- var seleniumConfigPath = typeof(SeleniumStandaloneServer).Assembly
- .GetCustomAttributes()
- .FirstOrDefault(k => k.Key == "Microsoft.AspNetCore.Testing.SeleniumConfigPath")
- ?.Value;
-
- if (seleniumConfigPath == null)
- {
- throw new InvalidOperationException("Selenium config path not configured. Does this project import the E2ETesting.targets?");
- }
-
- // 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}",
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- };
-
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- psi.FileName = "cmd";
- psi.Arguments = $"/c npm {psi.Arguments}";
- }
-
- // It's important that we get the folder value before we start the process to prevent
- // untracked processes when the tracking folder is not correctly configure.
- var trackingFolder = GetProcessTrackingFolder();
- if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("helix")))
- {
- // Just create a random tracking folder on helix
- trackingFolder = Path.Combine(Directory.GetCurrentDirectory(), Path.GetRandomFileName());
- Directory.CreateDirectory(trackingFolder);
- }
-
- if (!Directory.Exists(trackingFolder))
- {
- throw new InvalidOperationException($"Invalid tracking folder. Set the 'SeleniumProcessTrackingFolder' MSBuild property to a valid folder.");
- }
-
- Process process = null;
- Process sentinel = null;
- string pidFilePath = null;
- try
- {
- process = Process.Start(psi);
- pidFilePath = await WriteTrackingFileAsync(output, trackingFolder, process);
-
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- sentinel = StartSentinelProcess(process, pidFilePath, SeleniumProcessTimeout);
- }
- }
- catch
- {
- ProcessCleanup(process, pidFilePath);
-
- if (sentinel is not null)
- {
- ProcessCleanup(sentinel, pidFilePath: null);
- }
-
- throw;
- }
-
- // Log output for selenium standalone process.
- // This is for the case where the server fails to launch.
- var logOutput = new BlockingCollection();
-
- process.OutputDataReceived += LogOutput;
- process.ErrorDataReceived += LogOutput;
-
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
-
- // The Selenium sever has to be up for the entirety of the tests and is only shutdown when the application (i.e. the test) exits.
- // AppDomain.CurrentDomain.ProcessExit += (sender, args) => ProcessCleanup(process, pidFilePath);
-
- // Log
- void LogOutput(object sender, DataReceivedEventArgs e)
- {
- try
- {
- logOutput.TryAdd(e.Data);
- }
- catch (Exception)
- {
- }
-
- // We avoid logging on the output here because it is unreliable. We can only log in the diagnostics sink.
- lock (_diagnosticsMessageSink)
- {
- _diagnosticsMessageSink.OnMessage(new DiagnosticMessage(e.Data));
- }
- }
-
- var httpClient = new HttpClient
- {
- Timeout = TimeSpan.FromSeconds(1),
- };
-
- var retries = 0;
- do
- {
- await Task.Delay(1000);
- try
- {
- var response = await httpClient.GetAsync(uri);
- if (response.StatusCode == HttpStatusCode.OK)
- {
- output = null;
- Instance.Initialize(uri, process, pidFilePath, sentinel);
- return;
- }
- }
- catch (OperationCanceledException)
- {
- }
- catch (HttpRequestException)
- {
- }
-
- retries++;
- } while (retries < 30);
-
- // Make output null so that we stop logging to it.
- output = null;
- logOutput.CompleteAdding();
- var exitCodeString = process.HasExited ? process.ExitCode.ToString(CultureInfo.InvariantCulture) : "Process has not yet exited.";
- var message = $@"Failed to launch the server.
-ExitCode: {exitCodeString}
-Captured output lines:
-{string.Join(Environment.NewLine, logOutput.GetConsumingEnumerable())}.";
-
- // If we got here, we couldn't launch Selenium or get it to respond. So shut it down.
- ProcessCleanup(process, pidFilePath);
- throw new InvalidOperationException(message);
- }
-
- private static Process StartSentinelProcess(Process process, string sentinelFile, int timeout)
- {
- // This sentinel process will start and will kill any rouge selenium server that want' torn down
- // via normal means.
- var psi = new ProcessStartInfo
- {
- FileName = "powershell",
- Arguments = $"-NoProfile -NonInteractive -Command \"Start-Sleep {timeout}; " +
- $"if(Test-Path {sentinelFile}){{ " +
- $"Write-Output 'Stopping process {process.Id}'; Stop-Process {process.Id}; }}" +
- $"else{{ Write-Output 'Sentinel file {sentinelFile} not found.'}}",
- };
-
- return Process.Start(psi);
- }
-
- private static void ProcessCleanup(Process process, string pidFilePath)
- {
- try
- {
- if (process?.HasExited == false)
- {
- try
- {
- process?.KillTree(TimeSpan.FromSeconds(10));
- process?.Dispose();
- }
- catch
- {
- // Ignore errors here since we can't do anything
- }
- }
- if (pidFilePath != null && File.Exists(pidFilePath))
- {
- File.Delete(pidFilePath);
- }
- }
- catch
- {
- // Ignore errors here since we can't do anything
- }
- }
-
- private static async Task WriteTrackingFileAsync(ITestOutputHelper output, string trackingFolder, Process process)
- {
- var pidFile = Path.Combine(trackingFolder, $"{process.Id}.{Guid.NewGuid()}.pid");
- for (var i = 0; i < 3; i++)
- {
- try
- {
- await File.WriteAllTextAsync(pidFile, process.Id.ToString(CultureInfo.InvariantCulture));
- return pidFile;
- }
- catch
- {
- output.WriteLine($"Can't write file to process tracking folder: {trackingFolder}");
- }
- }
-
- throw new InvalidOperationException($"Failed to write file for process {process.Id}");
- }
-
- static int FindAvailablePort()
- {
- var listener = new TcpListener(IPAddress.Loopback, 0);
-
- try
- {
- listener.Start();
- return ((IPEndPoint)listener.LocalEndpoint).Port;
- }
- finally
- {
- listener.Stop();
- }
- }
-
- private static string GetProcessTrackingFolder() =>
- typeof(SeleniumStandaloneServer).Assembly
- .GetCustomAttributes()
- .Single(a => a.Key == "Microsoft.AspNetCore.Testing.Selenium.ProcessTracking").Value;
-
- public void Dispose()
- {
- ProcessCleanup(_process, _sentinelPath);
-
- if (_sentinelProcess is not null)
- {
- ProcessCleanup(_sentinelProcess, pidFilePath: null);
- }
- }
-}
diff --git a/src/Shared/E2ETesting/selenium-config.json b/src/Shared/E2ETesting/selenium-config.json
deleted file mode 100644
index 4b6ee654b211..000000000000
--- a/src/Shared/E2ETesting/selenium-config.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "drivers": {
- "chrome": {
- "version" : "114.0.5735.90"
- }
- },
- "ignoreExtraDrivers": true
-}