Skip to content

Commit 871809c

Browse files
committed
added Ui test for multiple API sample
1 parent 3753b78 commit 871809c

File tree

5 files changed

+205
-4
lines changed

5 files changed

+205
-4
lines changed

UiTests/Common/UiTestHelpers.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public static async Task NavigateToWebApp(string uri, IPage page)
3434
await Task.Delay(1000);
3535
InitialConnectionRetryCount--;
3636
if (InitialConnectionRetryCount == 0)
37-
{ throw; }
37+
{ throw; }
3838
}
3939
}
4040
}
@@ -421,6 +421,7 @@ public static bool StartAndVerifyProcessesAreRunning(List<ProcessStartOptions> p
421421
{
422422
if (!UiTestHelpers.ProcessesAreAlive(processes.Values.ToList())) { RestartProcesses(processes, processDataEntries); }
423423
else { break; }
424+
}
424425
}
425426

426427
if (!UiTestHelpers.ProcessesAreAlive(processes.Values.ToList()))

UiTests/Directory.Build.props

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
<SystemTextJsonVersion>8.0.4</SystemTextJsonVersion>
1818
<XunitAssertVersion>2.9.1</XunitAssertVersion>
1919
<XunitExtensibilityCoreVersion>2.9.1</XunitExtensibilityCoreVersion>
20-
<XunitRunnerVisualStudioVersion>2.8.2</XunitRunnerVisualStudioVersion>
21-
<XunitVersion>2.9.1</XunitVersion>
20+
<XunitRunnerVisualStudioVersion>2.8.2</XunitRunnerVisualStudioVersion>
21+
<XunitVersion>2.9.1</XunitVersion>
2222
</PropertyGroup>
23-
23+
2424
</Project>

UiTests/UiTests/MultiApiTest.cs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Runtime.Versioning;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
using Common;
11+
using Microsoft.Identity.Lab.Api;
12+
using Microsoft.Playwright;
13+
using Xunit;
14+
using Xunit.Abstractions;
15+
using Process = System.Diagnostics.Process;
16+
using TC = Common.TestConstants;
17+
using TH = Common.UiTestHelpers;
18+
19+
namespace MultipleApiUiTest
20+
{
21+
public class MultiApiTest : IClassFixture<InstallPlaywrightBrowserFixture>
22+
{
23+
private const string SignOutPageUriPath = @"/MicrosoftIdentity/Account/SignedOut";
24+
private const uint ClientPort = 44321;
25+
private const string TraceFileClassName = "OpenIDConnect";
26+
private readonly LocatorAssertionsToBeVisibleOptions _assertVisibleOptions = new() { Timeout = 5000 };
27+
private readonly string _sampleAppPath = "3-WebApp-multi-APIs" + Path.DirectorySeparatorChar.ToString();
28+
private readonly string _testAssemblyLocation = typeof(MultiApiTest).Assembly.Location;
29+
private readonly ITestOutputHelper _output;
30+
31+
public MultiApiTest(ITestOutputHelper output)
32+
{
33+
_output = output;
34+
}
35+
36+
[Fact]
37+
[SupportedOSPlatform("windows")]
38+
public async Task ChallengeUser_MicrosoftIdFlow_LocalApp_ValidEmailPasswordCreds_LoginLogout()
39+
{
40+
// Setup web app and api environmental variables.
41+
var clientEnvVars = new Dictionary<string, string>
42+
{
43+
{"ASPNETCORE_ENVIRONMENT", "Development"},
44+
{TC.KestrelEndpointEnvVar, TC.HttpsStarColon + ClientPort}
45+
};
46+
47+
Dictionary<string, Process>? processes = null;
48+
49+
// Arrange Playwright setup, to see the browser UI set Headless = false.
50+
const string TraceFileName = TraceFileClassName + "_LoginLogout";
51+
using IPlaywright playwright = await Playwright.CreateAsync();
52+
IBrowser browser = await playwright.Chromium.LaunchAsync(new() { Headless = false });
53+
IBrowserContext context = await browser.NewContextAsync(new BrowserNewContextOptions { IgnoreHTTPSErrors = true });
54+
await context.Tracing.StartAsync(new() { Screenshots = true, Snapshots = true, Sources = true });
55+
IPage page = await context.NewPageAsync();
56+
string uriWithPort = TC.LocalhostUrl + ClientPort;
57+
58+
try
59+
{
60+
// Start the web app and api processes.
61+
// The delay before starting client prevents transient devbox issue where the client fails to load the first time after rebuilding
62+
var clientProcessOptions = new ProcessStartOptions(_testAssemblyLocation, _sampleAppPath, TC.s_oidcWebAppExe, clientEnvVars);
63+
64+
bool areProcessesRunning = TH.StartAndVerifyProcessesAreRunning([clientProcessOptions], out processes);
65+
66+
if (!areProcessesRunning)
67+
{
68+
_output.WriteLine("Process not started after 3 attempts.");
69+
StringBuilder runningProcesses = new StringBuilder();
70+
foreach (var process in processes)
71+
{
72+
#pragma warning disable CA1305 // Specify IFormatProvider
73+
runningProcesses.AppendLine($"Is {process.Key} running: {TH.ProcessIsAlive(process.Value)}");
74+
#pragma warning restore CA1305 // Specify IFormatProvider
75+
}
76+
Assert.Fail(TC.WebAppCrashedString + " " + runningProcesses.ToString());
77+
}
78+
79+
LabResponse labResponse = await LabUserHelper.GetSpecificUserAsync(TC.OIDCUser);
80+
81+
// Initial sign in
82+
_output.WriteLine("Starting web app sign-in flow.");
83+
string email = labResponse.User.Upn;
84+
await TH.NavigateToWebApp(uriWithPort, page);
85+
await TH.EnterEmailAsync(page, email, _output);
86+
await TH.EnterPasswordAsync(page, labResponse.User.GetOrFetchPassword(), _output);
87+
await Assertions.Expect(page.GetByText("Integrating Azure AD V2")).ToBeVisibleAsync(_assertVisibleOptions);
88+
await Assertions.Expect(page.GetByText(email)).ToBeVisibleAsync(_assertVisibleOptions);
89+
_output.WriteLine("Web app sign-in flow successful.");
90+
91+
// Sign out
92+
_output.WriteLine("Starting web app sign-out flow.");
93+
await page.GetByRole(AriaRole.Link, new() { Name = "Sign out" }).ClickAsync();
94+
await TH.PerformSignOut_MicrosoftIdFlow(page, email, TC.LocalhostUrl + ClientPort + SignOutPageUriPath, _output);
95+
_output.WriteLine("Web app sign out successful.");
96+
}
97+
catch (Exception ex)
98+
{
99+
//Adding guid incase of multiple test runs. This will allow screenshots to be matched to their appropriet test runs.
100+
var guid = Guid.NewGuid().ToString();
101+
try
102+
{
103+
if (page != null)
104+
{
105+
await page.ScreenshotAsync(new PageScreenshotOptions() { Path = $"ChallengeUser_MicrosoftIdFlow_LocalApp_ValidEmailPasswordCreds_TodoAppFunctionsCorrectlyScreenshotFail{guid}.png", FullPage = true });
106+
}
107+
}
108+
catch
109+
{
110+
_output.WriteLine("No Screenshot.");
111+
}
112+
113+
string runningProcesses = TH.GetRunningProcessAsString(processes);
114+
Assert.Fail($"the UI automation failed: {ex} output: {ex.Message}.\n{runningProcesses}\nTest run: {guid}");
115+
}
116+
finally
117+
{
118+
// Add the following to make sure all processes and their children are stopped.
119+
TH.EndProcesses(processes);
120+
121+
// Stop tracing and export it into a zip archive.
122+
string path = TH.GetTracePath(_testAssemblyLocation, TraceFileName);
123+
await context.Tracing.StopAsync(new() { Path = path });
124+
_output.WriteLine($"Trace data for {TraceFileName} recorded to {path}.");
125+
126+
// Close the browser and stop Playwright.
127+
await browser.CloseAsync();
128+
playwright.Dispose();
129+
}
130+
}
131+
132+
}
133+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>net8.0</TargetFrameworks>
5+
<!--<TargetFrameworks Condition="'$(TargetNet9)'== 'True'">$(TargetFrameworks); net9.0</TargetFrameworks>-->
6+
<IsPackable>false</IsPackable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="$(MicrosoftAspNetCoreMvcTestingVersion)" />
11+
<PackageReference Include="Microsoft.Identity.Lab.Api" Version="$(MicrosoftIdentityLabApiVersion)" />
12+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNetTestSdkVersion)" />
13+
<PackageReference Include="Microsoft.Playwright" Version="$(MicrosoftPlaywrightVersion)" />
14+
<PackageReference Include="System.Management" Version="$(SystemManagementVersion)" />
15+
<PackageReference Include="System.Text.Json" Version="$(SystemTextJsonVersion)" />
16+
<PackageReference Include="xunit" Version="$(XunitVersion)" />
17+
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioVersion)">
18+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
19+
<PrivateAssets>all</PrivateAssets>
20+
</PackageReference>
21+
<PackageReference Include="coverlet.collector" Version="$(CoverletCollectorVersion)">
22+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
23+
<PrivateAssets>all</PrivateAssets>
24+
</PackageReference>
25+
</ItemGroup>
26+
27+
<ItemGroup>
28+
<ProjectReference Include="..\Common\Common.csproj" />
29+
</ItemGroup>
30+
31+
</Project>

UiTests/UiTests/UiTests.sln

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.11.35303.130
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultipleApiUiTest", "MultipleApiUiTest.csproj", "{2B42751A-8650-4DE4-9B46-B01C21825EB1}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "..\Common\Common.csproj", "{3074B729-52E8-408E-8BBC-815FE9217385}"
9+
EndProject
10+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6A8B8F57-DBC6-43E2-84E7-16D24E54157B}"
11+
ProjectSection(SolutionItems) = preProject
12+
..\Directory.Build.props = ..\Directory.Build.props
13+
EndProjectSection
14+
EndProject
15+
Global
16+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
17+
Debug|Any CPU = Debug|Any CPU
18+
Release|Any CPU = Release|Any CPU
19+
EndGlobalSection
20+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
21+
{2B42751A-8650-4DE4-9B46-B01C21825EB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22+
{2B42751A-8650-4DE4-9B46-B01C21825EB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
23+
{2B42751A-8650-4DE4-9B46-B01C21825EB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
24+
{2B42751A-8650-4DE4-9B46-B01C21825EB1}.Release|Any CPU.Build.0 = Release|Any CPU
25+
{3074B729-52E8-408E-8BBC-815FE9217385}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26+
{3074B729-52E8-408E-8BBC-815FE9217385}.Debug|Any CPU.Build.0 = Debug|Any CPU
27+
{3074B729-52E8-408E-8BBC-815FE9217385}.Release|Any CPU.ActiveCfg = Release|Any CPU
28+
{3074B729-52E8-408E-8BBC-815FE9217385}.Release|Any CPU.Build.0 = Release|Any CPU
29+
EndGlobalSection
30+
GlobalSection(SolutionProperties) = preSolution
31+
HideSolutionNode = FALSE
32+
EndGlobalSection
33+
GlobalSection(ExtensibilityGlobals) = postSolution
34+
SolutionGuid = {F7161FC1-9BC2-4CE4-B59C-504328CA6C7F}
35+
EndGlobalSection
36+
EndGlobal

0 commit comments

Comments
 (0)