-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Add Playwright E2E tests for role-based navigation #112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| // ============================================ | ||
| // Copyright (c) 2026. All rights reserved. | ||
| // File Name : PlaywrightCollection.cs | ||
| // Company : mpaulosky | ||
| // Author : Matthew Paulosky | ||
| // Solution Name : IssueManager | ||
| // Project Name : AppHost.Tests.E2E | ||
| // ============================================= | ||
|
|
||
| namespace AppHost.Tests.E2E.Fixtures; | ||
|
|
||
| /// <summary> | ||
| /// Defines the PlaywrightE2E collection, backed by a shared PlaywrightFixture. | ||
| /// Tests in this collection share one Aspire host + Playwright browser instance. | ||
| /// </summary> | ||
| [ExcludeFromCodeCoverage] | ||
| [CollectionDefinition("PlaywrightE2E")] | ||
| public sealed class PlaywrightCollection : ICollectionFixture<PlaywrightFixture>; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| // ============================================ | ||
| // Copyright (c) 2026. All rights reserved. | ||
| // File Name : PlaywrightFixture.cs | ||
| // Company : mpaulosky | ||
| // Author : Matthew Paulosky | ||
| // Solution Name : IssueManager | ||
| // Project Name : AppHost.Tests.E2E | ||
| // ============================================= | ||
|
|
||
| namespace AppHost.Tests.E2E.Fixtures; | ||
|
|
||
| /// <summary> | ||
| /// Playwright fixture that hosts the Aspire AppHost for end-to-end tests. | ||
| /// Initializes Playwright and provides browser/page instances for E2E tests. | ||
| /// Starts the Aspire AppHost and captures the Web app URL for browser navigation. | ||
| /// </summary> | ||
| [ExcludeFromCodeCoverage] | ||
| public sealed class PlaywrightFixture : IAsyncLifetime | ||
| { | ||
| private IPlaywright? _playwright; | ||
| private IBrowser? _browser; | ||
| private IDistributedApplicationTestingBuilder? _builder; | ||
| private DistributedApplication? _app; | ||
| private string? _webUrl; | ||
| private ResourceNotificationService? _notificationService; | ||
|
|
||
| /// <summary> | ||
| /// Gets the Playwright instance. | ||
| /// </summary> | ||
| public IPlaywright Playwright => | ||
| _playwright ?? throw new InvalidOperationException("Playwright not initialized. Check IsAvailable."); | ||
|
|
||
| /// <summary> | ||
| /// Gets the browser instance. | ||
| /// </summary> | ||
| public IBrowser Browser => | ||
| _browser ?? throw new InvalidOperationException("Browser not initialized. Check IsAvailable."); | ||
|
|
||
| /// <summary> | ||
| /// Gets the base URL of the web application. | ||
| /// </summary> | ||
| public string WebUrl => | ||
| _webUrl ?? throw new InvalidOperationException("Web URL not available. Check IsAvailable."); | ||
|
|
||
| /// <summary> | ||
| /// Gets the Aspire app instance. | ||
| /// </summary> | ||
| public DistributedApplication App => | ||
| _app ?? throw new InvalidOperationException("Aspire app not initialized. Check IsAvailable."); | ||
|
|
||
| /// <summary> | ||
| /// True if the fixture was successfully initialized. | ||
| /// </summary> | ||
| public bool IsAvailable { get; private set; } | ||
|
|
||
| /// <summary> | ||
| /// The reason initialization was skipped or failed, if IsAvailable is false. | ||
| /// </summary> | ||
| public string? UnavailableReason { get; private set; } | ||
|
|
||
| /// <summary> | ||
| /// Creates a new browser context with isolated state for test isolation. | ||
| /// </summary> | ||
| public async Task<IBrowserContext> NewContextAsync(BrowserNewContextOptions? options = null) | ||
| { | ||
| return await Browser.NewContextAsync(options ?? new BrowserNewContextOptions | ||
| { | ||
| IgnoreHTTPSErrors = true | ||
| }); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Creates a new page in a fresh browser context for test isolation. | ||
| /// </summary> | ||
| public async Task<IPage> NewPageAsync() | ||
| { | ||
| var context = await NewContextAsync(); | ||
| return await context.NewPageAsync(); | ||
| } | ||
|
|
||
| public async ValueTask InitializeAsync() | ||
| { | ||
| try | ||
| { | ||
| // Step 1: Initialize Aspire AppHost | ||
| _builder = await DistributedApplicationTestingBuilder | ||
| .CreateAsync<Projects.AppHost>(CancellationToken.None); | ||
|
|
||
| _builder.Services.ConfigureHttpClientDefaults(clientBuilder => | ||
| { | ||
| clientBuilder.AddStandardResilienceHandler(); | ||
| }); | ||
|
|
||
| _app = await _builder.BuildAsync(CancellationToken.None); | ||
|
|
||
| _notificationService = _app.Services.GetRequiredService<ResourceNotificationService>(); | ||
|
|
||
| // Start the distributed application | ||
| await _app.StartAsync(CancellationToken.None); | ||
|
|
||
| // Wait for the web app to be running | ||
| await _notificationService.WaitForResourceAsync( | ||
| Website, | ||
| KnownResourceStates.Running, | ||
| CancellationToken.None).WaitAsync(TimeSpan.FromMinutes(3)); | ||
|
|
||
| // Get the web app URL | ||
| _webUrl = _app.GetEndpoint(Website, "https")?.ToString() | ||
| ?? _app.GetEndpoint(Website, "http")?.ToString(); | ||
|
|
||
| if (string.IsNullOrEmpty(_webUrl)) | ||
| { | ||
| IsAvailable = false; | ||
| UnavailableReason = "Could not get web app endpoint URL"; | ||
| return; | ||
| } | ||
|
|
||
| // Step 2: Initialize Playwright | ||
| _playwright = await Microsoft.Playwright.Playwright.CreateAsync(); | ||
|
|
||
| // Launch Chromium in headless mode | ||
| _browser = await _playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions | ||
| { | ||
| Headless = true | ||
| }); | ||
|
|
||
| IsAvailable = true; | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| IsAvailable = false; | ||
| UnavailableReason = $"Fixture initialization failed: {ex.Message}"; | ||
| } | ||
| } | ||
|
|
||
| public async ValueTask DisposeAsync() | ||
| { | ||
| if (_browser is not null) | ||
| { | ||
| await _browser.CloseAsync(); | ||
| } | ||
|
|
||
| _playwright?.Dispose(); | ||
|
|
||
| if (_app is not null) | ||
| { | ||
| await _app.StopAsync(); | ||
| await _app.DisposeAsync(); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,134 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ============================================ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Copyright (c) 2026. All rights reserved. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // File Name : Auth0LoginHelper.cs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Company : mpaulosky | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Author : Matthew Paulosky | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Solution Name : IssueManager | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Project Name : AppHost.Tests.E2E | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ============================================= | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| namespace AppHost.Tests.E2E.Helpers; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Helper for authenticating with Auth0 via browser-based OIDC flow in Playwright tests. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Test credentials are read from environment variables for security. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [ExcludeFromCodeCoverage] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public static class Auth0LoginHelper | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Gets test credentials from environment variables. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public static (string Email, string Password)? GetTestCredentials(string role) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var suffix = role.ToUpperInvariant(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var email = Environment.GetEnvironmentVariable($"E2E_TEST_{suffix}_EMAIL"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var password = Environment.GetEnvironmentVariable($"E2E_TEST_{suffix}_PASSWORD"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return (email, password); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Performs Auth0 login via the browser-based OIDC flow. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Navigates to /auth/login, fills Auth0 form, and waits for redirect back. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <param name="page">The Playwright page instance.</param> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <param name="baseUrl">The application base URL.</param> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <param name="email">The test user email.</param> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <param name="password">The test user password.</param> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <param name="timeout">Timeout for waiting operations (default 30 seconds).</param> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <returns>True if login succeeded, false otherwise.</returns> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public static async Task<bool> LoginAsync( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IPage page, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| string baseUrl, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| string email, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| string password, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int timeout = 30000) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Navigate to the login endpoint which triggers Auth0 redirect | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.GotoAsync($"{baseUrl.TrimEnd('/')}/auth/login", new PageGotoOptions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WaitUntil = WaitUntilState.NetworkIdle, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Timeout = timeout | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Wait for Auth0 login page | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.WaitForURLAsync("**/u/login**", new PageWaitForURLOptions { Timeout = timeout }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Fill in the Auth0 Universal Login form | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.FillAsync("input[name='username'], input[name='email'], input#username, input[type='email']", email); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.FillAsync("input[name='password'], input#password, input[type='password']", password); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Click the submit button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.ClickAsync("button[type='submit'], button[name='action'], button[data-action-button-primary='true']"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Wait for redirect back to our app (should redirect to home or return URL) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.WaitForURLAsync(url => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| url.Contains(new Uri(baseUrl).Host) && !url.Contains("auth0.com"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new PageWaitForURLOptions { Timeout = timeout }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Wait for the page to stabilize | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.WaitForLoadStateAsync(LoadState.NetworkIdle); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| catch (TimeoutException) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| catch (PlaywrightException) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+53
to
+89
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try | |
| { | |
| // Navigate to the login endpoint which triggers Auth0 redirect | |
| await page.GotoAsync($"{baseUrl.TrimEnd('/')}/auth/login", new PageGotoOptions | |
| { | |
| WaitUntil = WaitUntilState.NetworkIdle, | |
| Timeout = timeout | |
| }); | |
| // Wait for Auth0 login page | |
| await page.WaitForURLAsync("**/u/login**", new PageWaitForURLOptions { Timeout = timeout }); | |
| // Fill in the Auth0 Universal Login form | |
| await page.FillAsync("input[name='username'], input[name='email'], input#username, input[type='email']", email); | |
| await page.FillAsync("input[name='password'], input#password, input[type='password']", password); | |
| // Click the submit button | |
| await page.ClickAsync("button[type='submit'], button[name='action'], button[data-action-button-primary='true']"); | |
| // Wait for redirect back to our app (should redirect to home or return URL) | |
| await page.WaitForURLAsync(url => | |
| url.Contains(new Uri(baseUrl).Host) && !url.Contains("auth0.com"), | |
| new PageWaitForURLOptions { Timeout = timeout }); | |
| // Wait for the page to stabilize | |
| await page.WaitForLoadStateAsync(LoadState.NetworkIdle); | |
| return true; | |
| } | |
| catch (TimeoutException) | |
| { | |
| return false; | |
| } | |
| catch (PlaywrightException) | |
| { | |
| return false; | |
| } | |
| // Navigate to the login endpoint which triggers Auth0 redirect | |
| await page.GotoAsync($"{baseUrl.TrimEnd('/')}/auth/login", new PageGotoOptions | |
| { | |
| WaitUntil = WaitUntilState.NetworkIdle, | |
| Timeout = timeout | |
| }); | |
| // Wait for Auth0 login page | |
| await page.WaitForURLAsync("**/u/login**", new PageWaitForURLOptions { Timeout = timeout }); | |
| // Fill in the Auth0 Universal Login form | |
| await page.FillAsync("input[name='username'], input[name='email'], input#username, input[type='email']", email); | |
| await page.FillAsync("input[name='password'], input#password, input[type='password']", password); | |
| // Click the submit button | |
| await page.ClickAsync("button[type='submit'], button[name='action'], button[data-action-button-primary='true']"); | |
| // Wait for redirect back to our app (should redirect to home or return URL) | |
| await page.WaitForURLAsync(url => | |
| url.Contains(new Uri(baseUrl).Host) && !url.Contains("auth0.com"), | |
| new PageWaitForURLOptions { Timeout = timeout }); | |
| // Wait for the page to stabilize | |
| await page.WaitForLoadStateAsync(LoadState.NetworkIdle); | |
| return true; |
Check warning on line 121 in tests/AppHost.Tests.E2E/Helpers/Auth0LoginHelper.cs
GitHub Actions / Build Solution
'LocatorIsVisibleOptions.Timeout' is obsolete
Check warning on line 121 in tests/AppHost.Tests.E2E/Helpers/Auth0LoginHelper.cs
GitHub Actions / Build and Test / Build Solution
'LocatorIsVisibleOptions.Timeout' is obsolete
Check warning on line 121 in tests/AppHost.Tests.E2E/Helpers/Auth0LoginHelper.cs
GitHub Actions / AppHost.Tests.E2E
'LocatorIsVisibleOptions.Timeout' is obsolete
Check warning on line 132 in tests/AppHost.Tests.E2E/Helpers/Auth0LoginHelper.cs
GitHub Actions / Build Solution
'LocatorIsVisibleOptions.Timeout' is obsolete
Check warning on line 132 in tests/AppHost.Tests.E2E/Helpers/Auth0LoginHelper.cs
GitHub Actions / Build and Test / Build Solution
'LocatorIsVisibleOptions.Timeout' is obsolete
Check warning on line 132 in tests/AppHost.Tests.E2E/Helpers/Auth0LoginHelper.cs
GitHub Actions / AppHost.Tests.E2E
'LocatorIsVisibleOptions.Timeout' is obsolete
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to the resource-name mismatch:
_app.GetEndpoint("web", ...)uses the same incorrect resource name. This will yield a null endpoint and causeWebUrlto be unavailable even if the app started. Use the same resource name the AppHost registers for the Web project (e.g.,Website/ "WebApp").