Skip to content

Commit b42a399

Browse files
committed
Run Blazor E2E tests on SauceLabs
1 parent c7e6bee commit b42a399

15 files changed

+662
-14
lines changed

src/Components/test/E2ETest/Infrastructure/AssemblyInfo.AssemblyFixtures.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66

77
[assembly: TestFramework("Microsoft.AspNetCore.E2ETesting.XunitTestFrameworkWithAssemblyFixture", "Microsoft.AspNetCore.Components.E2ETests")]
88
[assembly: AssemblyFixture(typeof(SeleniumStandaloneServer))]
9+
[assembly: AssemblyFixture(typeof(SauceConnectServer))]

src/Components/test/E2ETest/Infrastructure/ServerFixtures/AspNetSiteServerFixture.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.IO;
77
using System.Linq;
88
using System.Reflection;
9+
using Microsoft.AspNetCore.E2ETesting;
910
using Microsoft.AspNetCore.Hosting;
1011
using Microsoft.Extensions.Hosting;
1112

@@ -34,9 +35,15 @@ protected override IHost CreateWebHost()
3435
var assembly = ApplicationAssembly ?? BuildWebHostMethod.Method.DeclaringType.Assembly;
3536
var sampleSitePath = FindSampleOrTestSitePath(assembly.FullName);
3637

38+
var host = "127.0.0.1";
39+
if (E2ETestOptions.Instance.SauceTest)
40+
{
41+
host = E2ETestOptions.Instance.Sauce.HostName;
42+
}
43+
3744
return BuildWebHostMethod(new[]
3845
{
39-
"--urls", "http://127.0.0.1:0",
46+
"--urls", $"http://{host}:0",
4047
"--contentroot", sampleSitePath,
4148
"--environment", Environment.ToString(),
4249
}.Concat(AdditionalArguments).ToArray());

src/Components/test/E2ETest/Infrastructure/ServerFixtures/DevHostServerFixture.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using Microsoft.AspNetCore.E2ETesting;
45
using Microsoft.AspNetCore.Hosting;
56
using Microsoft.AspNetCore.Hosting.Server;
67
using Microsoft.AspNetCore.Http.Features;
@@ -24,9 +25,15 @@ protected override IHost CreateWebHost()
2425
ContentRoot = FindSampleOrTestSitePath(
2526
typeof(TProgram).Assembly.FullName);
2627

28+
var host = "127.0.0.1";
29+
if (E2ETestOptions.Instance.SauceTest)
30+
{
31+
host = E2ETestOptions.Instance.Sauce.HostName;
32+
}
33+
2734
var args = new List<string>
2835
{
29-
"--urls", "http://127.0.0.1:0",
36+
"--urls", $"http://{host}:0",
3037
"--contentroot", ContentRoot,
3138
"--pathbase", PathBase,
3239
"--applicationpath", typeof(TProgram).Assembly.Location,

src/Components/test/E2ETest/Infrastructure/ServerFixtures/ServerFixture.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Reflection;
99
using System.Runtime.ExceptionServices;
1010
using System.Threading;
11+
using Microsoft.AspNetCore.E2ETesting;
1112

1213
namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures
1314
{
@@ -22,7 +23,15 @@ public abstract class ServerFixture : IDisposable
2223
public ServerFixture()
2324
{
2425
_rootUriInitializer = new Lazy<Uri>(() =>
25-
new Uri(StartAndGetRootUri()));
26+
{
27+
var uri = new Uri(StartAndGetRootUri());
28+
if (E2ETestOptions.Instance.SauceTest)
29+
{
30+
uri = new UriBuilder(uri.Scheme, E2ETestOptions.Instance.Sauce.HostName, uri.Port).Uri;
31+
}
32+
33+
return uri;
34+
});
2635
}
2736

2837
public abstract void Dispose();

src/Components/test/E2ETest/Infrastructure/ServerFixtures/StaticSiteServerFixture.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.IO;
66
using Microsoft.AspNetCore.Builder;
7+
using Microsoft.AspNetCore.E2ETesting;
78
using Microsoft.AspNetCore.Hosting;
89
using Microsoft.Extensions.Hosting;
910

@@ -26,13 +27,19 @@ protected override IHost CreateWebHost()
2627

2728
var sampleSitePath = FindSampleOrTestSitePath(SampleSiteName);
2829

30+
var host = "127.0.0.1";
31+
if (E2ETestOptions.Instance.SauceTest)
32+
{
33+
host = E2ETestOptions.Instance.Sauce.HostName;
34+
}
35+
2936
return new HostBuilder()
3037
.ConfigureWebHost(webHostBuilder => webHostBuilder
3138
.UseKestrel()
3239
.UseContentRoot(sampleSitePath)
3340
.UseWebRoot(string.Empty)
3441
.UseStartup<StaticSiteStartup>()
35-
.UseUrls("http://127.0.0.1:0"))
42+
.UseUrls($"http://{host}:0"))
3643
.Build();
3744
}
3845

src/Components/test/E2ETest/Tests/StandaloneAppTest.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using OpenQA.Selenium.Support.UI;
99
using System;
1010
using System.Linq;
11-
using System.Threading.Tasks;
1211
using Xunit;
1312
using Xunit.Abstractions;
1413

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
{
22
"DefaultWaitTimeoutInSeconds": 20,
3-
"ScreenShotsPath": "../../screenshots"
3+
"ScreenShotsPath": "../../screenshots",
4+
"SauceTest": true,
5+
"Sauce": {
6+
"Username": "placeholder",
7+
"AccessKey": "placeholder",
8+
"TunnelIdentifier": "blazor-e2e-sc-proxy-tunnel",
9+
"HostName": "sauce.local"
10+
}
411
}

src/Components/test/E2ETest/package.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,18 @@
66
"private": true,
77
"scripts": {
88
"selenium-standalone": "selenium-standalone",
9-
"prepare": "selenium-standalone install"
9+
"prepare": "selenium-standalone install",
10+
"sauce": "ts-node ./scripts/sauce.ts"
1011
},
1112
"author": "",
1213
"license": "Apache-2.0",
1314
"dependencies": {
15+
"sauce-connect-launcher": "^1.3.1",
1416
"selenium-standalone": "^6.15.4"
17+
},
18+
"devDependencies": {
19+
"@types/node": "^13.1.7",
20+
"ts-node": "^8.6.2",
21+
"typescript": "^3.7.5"
1522
}
1623
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { EOL } from "os";
2+
import * as _fs from "fs";
3+
import { promisify } from "util";
4+
5+
// Promisify things from fs we want to use.
6+
const fs = {
7+
createWriteStream: _fs.createWriteStream,
8+
exists: promisify(_fs.exists),
9+
mkdir: promisify(_fs.mkdir),
10+
appendFile: promisify(_fs.appendFile),
11+
readFile: promisify(_fs.readFile),
12+
};
13+
14+
process.on("unhandledRejection", (reason) => {
15+
console.error(`Unhandled promise rejection: ${reason}`);
16+
process.exit(1);
17+
});
18+
19+
let sauceUser = null;
20+
let sauceKey = null;
21+
let tunnelIdentifier = null;
22+
let hostName = null;
23+
24+
for (let i = 0; i < process.argv.length; i += 1) {
25+
switch (process.argv[i]) {
26+
case "--sauce-user":
27+
i += 1;
28+
sauceUser = process.argv[i];
29+
break;
30+
case "--sauce-key":
31+
i += 1;
32+
sauceKey = process.argv[i];
33+
break;
34+
case "--sauce-tunnel":
35+
i += 1;
36+
tunnelIdentifier = process.argv[i];
37+
break;
38+
case "--use-hostname":
39+
i += 1;
40+
hostName = process.argv[i];
41+
break;
42+
}
43+
}
44+
45+
const HOSTSFILE_PATH = process.platform === "win32" ? `${process.env.SystemRoot}\\System32\\drivers\\etc\\hosts` : null;
46+
47+
(async () => {
48+
49+
if (hostName) {
50+
// Register a custom hostname in the hosts file (requires Admin, but AzDO agents run as Admin)
51+
// Used to work around issues in Sauce Labs.
52+
if (process.platform !== "win32") {
53+
throw new Error("Can't use '--use-hostname' on non-Windows platform.");
54+
}
55+
56+
try {
57+
58+
console.log(`Updating Hosts file (${HOSTSFILE_PATH}) to register host name '${hostName}'`);
59+
await fs.appendFile(HOSTSFILE_PATH, `${EOL}127.0.0.1 ${hostName}${EOL}`);
60+
61+
} catch (error) {
62+
console.log(`Unable to update hosts file at ${HOSTSFILE_PATH}. Error: ${error}`);
63+
}
64+
}
65+
66+
67+
// Creates a persistent proxy tunnel using Sauce Connect.
68+
var sauceConnectLauncher = require('sauce-connect-launcher');
69+
70+
sauceConnectLauncher({
71+
username: sauceUser,
72+
accessKey: sauceKey,
73+
tunnelIdentifier: tunnelIdentifier,
74+
}, function (err, sauceConnectProcess) {
75+
if (err) {
76+
console.error(err.message);
77+
return;
78+
}
79+
80+
console.log("Sauce Connect ready");
81+
});
82+
})();

0 commit comments

Comments
 (0)