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

OSOE-935: Upgrade to xUnit 3 and handling test cancellations gracefully #432

Open
wants to merge 23 commits into
base: dev
Choose a base branch
from

Conversation

Piedone
Copy link
Member

@Piedone Piedone commented Dec 22, 2024

OSOE-935
Fixes #430
Fixes #82

Test cancellation can be tried when running the exe of a test: run it from the CLI, wait like 10 seconds, hit Ctrl+C (only once), and you should see "Test execution was cancelled. Shutting down the test execution session." at one point (only once the tests actually started).

To be added to the release notes:

Upgraded xUnit to v3 with breaking changes

This version of the UI Testing Toolbox uses v3 of xUnit, which brings many updates. However, it's also a breaking version, requiring you to adapt your test projects, see the official guide.

Migrating UI test projects consuming the UI Testing Toolbox should be simpler, though, with you requiring to do roughly the following steps:

  1. Update the xunit.runner.visualstudio package reference to latest (currently 3.0.0).
  2. Convert test projects to executables, see docs (this will most possibly only need you to add <OutputType>Exe</OutputType> to the first PropertyGroup in the test project's csproj). These are all the projects with xunit.runner.visualstudio references.
  3. In all test projects, change xunit package references to xunit.v3 with the latest version (currently 1.0.0). If a test project lacks such a reference then add it (currently <PackageReference Include="xunit.v3" Version="1.0.0" />). Only test projects should reference xunit.
  4. Also update the Microsoft.NET.Test.Sdk references in the test projects to latest (currently 17.12.0) too while we're at it, or add it if it's missing (currently <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />).
  5. ITestOutputHelper is now in the Xunit namespace instead of Xunit.Abstractions. Fix the namespace imports in UITestBase classes first and then anywhere else; they'll show up as build errors.
  6. Clean up unused namespace imports. In Visual Studio, you can do this by right-clicking on the solution -> Analyze and Code Cleanup -> Run Code Cleanup (Profile 1).
  7. Run the tests to check if everything is still OK. If tests don't show up in the Visual Studio Test Explorer, or show up but don't start if you try to run them, check out the Tests pane of the Output Window for clues. Confirm that the Web project doesn't contain any xUnit references (even transitively, like by accidentally referencing UI test projects) but all test projects reference unit.v3. You might need to do a recursive git clean to be sure to start with a clean slate.
  8. Verify in CI that the tests are actually discovered and all run there too (the CI build being green is not enough, it might miss no tests being discovered).

@github-actions github-actions bot changed the title Upgrade to xUnit 3 and handling test cancellations gracefully OSOE-935: Upgrade to xUnit 3 and handling test cancellations gracefully Dec 22, 2024

// While there may be some common code between local and remote tests, they cannot be the same, and the common code must
// be in a project independent of the web app (which is not the case here for the sake of simplicity):
// - In local tests, you have a much lower-level access to the app: E.g., you can access the Orchard Core log, use
Copy link
Member

Choose a reason for hiding this comment

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

Did you mean "higher-level"?

Suggested change
// - In local tests, you have a much lower-level access to the app: E.g., you can access the Orchard Core log, use
// - In local tests, you have much higher-level access to the app: E.g., you can access the Orchard Core log, use

@@ -48,6 +48,8 @@ public static Task TestWorkflowsAsync(this UITestContext context) =>
By.XPath("//div[@class = 'jtk-endpoint jtk-endpoint-anchor jtk-draggable jtk-droppable']"), // #spell-check-ignore-line
By.XPath(taskXPath));

context.WaitElementToNotChange(By.ClassName("jtk-connector")); // #spell-check-ignore-line
Copy link
Member

Choose a reason for hiding this comment

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

Why this change is necessary?

public ITest XunitTest { get; }
public string Name => XunitTest?.DisplayName;
public ITest XunitTest => TestContext.Current.Test;
public string Name => XunitTest?.TestDisplayName;
Copy link
Member

Choose a reason for hiding this comment

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

Can TestContext.Current.Test null here?

public ITest XunitTest { get; }
public string Name => XunitTest?.DisplayName;
public ITest XunitTest => TestContext.Current.Test;
public string Name => XunitTest?.TestDisplayName;
public Func<UITestContext, Task> TestAsync { get; set; }
Copy link
Member

Choose a reason for hiding this comment

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

This can be a constructor parameter.
image

@@ -369,7 +369,7 @@ protected virtual async Task ExecuteTestAsync(
Func<UITestContext, Task<Uri>> setupOperation,
Func<OrchardCoreUITestExecutorConfiguration, Task> changeConfigurationAsync)
{
var testManifest = new UITestManifest(_testOutputHelper) { TestAsync = testAsync };
var testManifest = new UITestManifest { TestAsync = testAsync };
Copy link
Member

Choose a reason for hiding this comment

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

See my comment for UITestManifest.TestAsync.

@@ -61,7 +61,7 @@ async Task BaseUriVisitingTest(UITestContext context)
await testAsync(context);
}

var testManifest = new UITestManifest(_testOutputHelper) { TestAsync = BaseUriVisitingTest };
var testManifest = new UITestManifest { TestAsync = BaseUriVisitingTest };
Copy link
Member

Choose a reason for hiding this comment

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

See my comment for UITestManifest.TestAsync.

@@ -61,6 +61,12 @@ public UITestExecutionSession(

public async Task<bool> ExecuteAsync(int retryCount, string dumpRootPath)
{
_configuration.TestCancellationToken.Register(() =>
Copy link
Member

@dministro dministro Jan 16, 2025

Choose a reason for hiding this comment

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

I'm not sure, but I think System.Threading.CancellationTokenRegistration returned by CancellationToken.Register needs to be disposed.

Is this really necessary?

Testing _configuration.TestCancellationToken.IsCancellationRequested also wellcome before starting the whole ceremony.

Comment on lines +114 to +130
if (timeoutTask.IsCompleted)
{
// If the EnterInteractiveModeAsync() extension method has been used, then timeout should be ignored to
// make the debugging experience smoother. Note that EnterInteractiveModeAsync() should never be used in
// committed tests.
if (!ShortcutsUITestContextExtensions.InteractiveModeHasBeenUsed)
{
throw new TimeoutException($"The time allotted for the test ({timeout}) was exceeded.");
}

await testTask;
}

// Since the timeout task is not yet completed but the Task.WhenAny has finished, the test task is done in
// some way. So it's safe to await it here. It's also necessary to cleanly propagate any exceptions that may
// have been thrown inside it.
await testTask;
Copy link
Member

Choose a reason for hiding this comment

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

In case when a cancellation is requested on the _configuration.TestCancellationToken, the timeoutTask.IsCompleted will be true.

@@ -75,11 +60,6 @@ private static async Task ExecuteOrchardCoreTestInnerAsync(
{
Copy link
Member

Choose a reason for hiding this comment

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

The _configuration.TestCancellationToken.IsCancellationRequested can also stop the loop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Upgrade to xUnit 3 (OSOE-935) Handle cancellations gracefully (OSOE-362)
2 participants