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 -}