Skip to content
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

Add playwright test for changing theme #4154

Closed

Conversation

adamint
Copy link
Member

@adamint adamint commented May 10, 2024

Aspire.Hosting.Tests/Dashboard may not be the best place to put this test long-term. I made it local only for now.

I was unable to access the dashboard frontend from a browser when trying the approach in Aspire.Dashboard.Tests of just creating the dashboard frontend app - it would not connect. If anyone has an idea why that might be, I'm all ears.

I also ran into gRPC issues after orchestrating. Also seeking feedback on that, but in the meantime I injected a mock dashboard service so that there is no grpc connection.

Microsoft Reviewers: Open in CodeFlow

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-components Issues pertaining to Aspire Component packages label May 10, 2024
Copy link
Member

@tlmii tlmii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree on the confusion of why it didn't work the way you originally tried it. It'd also be nice to get some feedback from the Hosting folks about pulling in the dashboard ref here. Just test code, so probably fine, but an ack would be nice.

@@ -161,4 +162,4 @@
<PackageVersion Include="Newtonsoft.Json.Schema" Version="3.0.15" />
<!-- Introduced by Microsoft.Azure.Cosmos, https://github.com/Azure/azure-cosmos-dotnet-v3/issues/4302 -->
</ItemGroup>
</Project>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inadvertent change?

public Task<ResourceViewModelSubscription> SubscribeResourcesAsync(CancellationToken cancellationToken) => throw new NotImplementedException();
}

public async Task<(string DashboardUrl, IPage Page)> SetupDashboardForPlaywrightAsync()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a huge fan of tuples in a public surface. But it's test code so probably OK.

catch (Exception)
{
await Task.Delay(1000, cts.Token);
await WaitUntilDashboardReadyAsync();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be a point at which this bails out?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also probably a loop rather than recursion

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, looks like that's the 1 minute timeout on the cts. still, feels like a loop

@radical
Copy link
Member

radical commented May 10, 2024

FYI, I'm adding some playwright based tests in #3270 . But in that I'm using dotnet run to start up a real app, and then interact with it.

This waits for the dashboard to become available, and uses resiliency to handle retries - https://github.com/radical/aspire/blob/5a900f1f44018a84e6741c45c4d632a1b6e35090/tests/Shared/WorkloadTesting/AspireProject.cs#L408-L427 .

And this connects with playwright, and verifies that the expected resources show up on the dashboard.

{
await page.GotoAsync(url);
}
catch (Exception)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to retry on any exception type other than PlaywrightException ?

}
catch (Exception)
{
await Task.Delay(1000, cts.Token);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is 1000 reasonable? say, pages typically take 1100 ms to be ready, then it's adding 900ms delay on every test, and perhaps we end with 100 tests.

sometimes in these cases you see a backoff strategy. So starting with brief delays (or just calling GotoAsync again immediately) so the happy path on a machine where it's available fast has no delay. Then backing off progressively the delay for slower machines to release resources for the pages to actually start.


public async Task DisposeAsync()
{
await Browser.DisposeAsync();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Browser.CloseAsync() seems canonical in their examples

public async Task DisposeAsync()
{
await Browser.DisposeAsync();
PlaywrightInstance.Dispose();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it need disposing? I can't find in the docs.

I think in general you don't dispose Task<T> without a reason
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.dispose?view=net-8.0#system-threading-tasks-task-dispose


namespace Aspire.Hosting.Tests.Dashboard;

public class AppbarTests : IClassFixture<PlaywrightFixture>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this the Fluent AppBar? In which case it should be capitalized AppBar

await settingsButton.ClickAsync();
var darkThemeCheckbox = page.GetByRole(AriaRole.Radio).And(page.GetByText("Dark")).First;
await darkThemeCheckbox.ClickAsync();
Assert.Equal("dark", await page.Locator("html").First.GetAttributeAsync("data-theme"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert it's not dark before you click the box?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and click again and assert it's light again?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also will this fail if the OS is set to dark theme up front (prefers-color-scheme: dark) ? if so it should instead test for what it is, click the box, check it changed, click the box, check it changed again.

var (_, page) = await _playwrightFixture.SetupDashboardForPlaywrightAsync();
var settingsButton = page.GetByRole(AriaRole.Button, new()
{
Name = "Launch settings"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is matching the English string, right? Is there a way to find this button on any locale, as we want to test all localized builds. Perhaps via a class or id ?

Name = "Launch settings"
});
await settingsButton.ClickAsync();
var darkThemeCheckbox = page.GetByRole(AriaRole.Radio).And(page.GetByText("Dark")).First;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same issue with assuming English.

public async Task<(string DashboardUrl, IPage Page)> SetupDashboardForPlaywrightAsync()
{

var url = "http://localhost:1234";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it need a port at all?

using var testProgram = TestProgram.Create<PlaywrightFixture>(
args,
includeIntegrationServices: false,
disableDashboard: false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this includeNodeApp actually?

public static TestProgram Create<T>(
string[]? args = null,
bool includeIntegrationServices = false,
bool includeNodeApp = false,
bool disableDashboard = true,
bool allowUnsecuredTransport = true,
bool randomizePorts = true)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm but if that's so how is the named param compiling? I must be missing an overload

{
try
{
await page.GotoAsync(url);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking to see whether there's a way to pass in the cts. But one can only pass a timeout (via PageGotoOptions) which is otherwise 30 seconds .. so I guess no reason to change that.

@adamint adamint closed this May 21, 2024
@kvenkatrajan
Copy link
Member

Was this closed by accident?

@adamint
Copy link
Member Author

adamint commented May 21, 2024

@kvenkatrajan we are going to use Ankit’s e2e infrastructure so 90% of this pr content will be replaced :)

@danmoseley
Copy link
Member

thanks for working together on this, sounds like we'll end up with a single infrastructure and it will be easier for everyone.

(when you have your new PR could you check whether any of the feedback above still applies?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-components Issues pertaining to Aspire Component packages
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants