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

chore: improve the test reporter's messaging #5724

Merged
merged 27 commits into from
Sep 13, 2024
Merged

Conversation

galargh
Copy link
Member

@galargh galargh commented Sep 5, 2024

  • Because this PR includes a bug fix, relevant tests have been included.
  • Because this PR includes a new feature, the change was previously discussed on an Issue or with someone from the team.
  • I didn't do anything of this.

Please note that this PR is currently based on #5714

This PR implements improvements to our test reporter that were discussed in and around #5669 and #5692

Here's a breakdown of the proposed changes together with links to their UI diffs (if you prefer me to break the PR down into separate ones, please let me know):

  1. If there is an error in a suite, display it in the tree view. In particular, this is relevant to when a suite fails in before or describe. Previously, an issue like that was only displayed in the summary at the end. After the change, there will also be an indication of a failure in the tree view. This is useful because, in such cases, the failure in the suite tends to be the more interesting one. It is introduced in d9bca64
  2. Do not display top-level file passes. This tends to be an indication that we successfully imported a file and there are no tests defined in it. It seems to be a waste of space to display it. It is introduced in 3957b42
  3. Do not suggest that a user forgot to await a promise when file execution fails. Usually, the issue is different, e.g. the file throws, so the suggestion can be misleading. It is introduced in 15a5eab
  4. When displaying unused diagnostic messages, make sure they are unique. Also, make them hardhat specific. In particular, make sure the suggestion about rerunning only tests, uses the hardhat --only flag. It is introduced in 270f889
  5. Remove ERR_TEST_FAILURE from the formatted error details. Similarly to how we improve the assertion error message. It is introduced in bfb1415
  6. Do not show cancelled by parent errors in the summary. These can be resolved by fixing the issue in the parent. This is why I suggest to link to the details of the parent error from the test error instead. It is introduced in a698e68
  7. Show tests failing with cancelled by parent errors in grey. After introduction of 5., these tests duplicate failure index of parent errors. I think we should guide the user towards the parent error more by making the line of the test itself grey. It is introduced in bc0a738

Additionally, I removed the usage of async describe block from hardhat tests since it doesn't work well with node's test reporter even though it is supported (fee6fb5). We could think about making it into a linting rule, maybe?

Copy link

vercel bot commented Sep 5, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
hardhat ✅ Ready (Inspect) Visit Preview 💬 Add feedback Sep 11, 2024 9:54am

Copy link

changeset-bot bot commented Sep 5, 2024

⚠️ No Changeset found

Latest commit: b415497

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions github-actions bot added the status:ready This issue is ready to be worked on label Sep 5, 2024
@galargh galargh changed the title [WIP] chore: improve the test reporter's messaging chore: improve the test reporter's messaging Sep 8, 2024
@galargh galargh force-pushed the galargh/test-reporter-ui branch from a65bcb5 to bc0a738 Compare September 8, 2024 07:49
@galargh galargh marked this pull request as ready for review September 8, 2024 07:52
@galargh galargh requested a review from alcuadrado September 8, 2024 07:52
@alcuadrado
Copy link
Member

  1. If there is an error in a suite, display it in the tree view. In particular, this is relevant to when a suite fails in before or describe. Previously, an issue like that was only displayed in the summary at the end. After the change, there will also be an indication of a failure in the tree view. This is useful because, in such cases, the failure in the suite tends to be the more interesting one. It is introduced in d9bca64

This is a much better experience.

Do not display top-level file passes. This tends to be an indication that we successfully imported a file and there are no tests defined in it. It seems to be a waste of space to display it. It is introduced in 3957b42

yay!

Do not suggest that a user forgot to await a promise when file execution fails. Usually, the issue is different, e.g. the file throws, so the suggestion can be misleading. It is introduced in 15a5eab

Makes sense. See below my other comment about this.

When displaying unused diagnostic messages, make sure they are unique. Also, make them hardhat specific. In particular, make sure the suggestion about rerunning only tests, uses the hardhat --only flag. It is introduced in 270f889

I think this change is needed, but this implementation breaks the usage of this reporter outside of hardhat (e.g. in our own tests).

I think we can have two exports in the package:

  • One is the one that we already have, and can be used by non-hardhat tests.
  • The other one would be a function that constructs a reporter, and can receive params, like how the only flag is called.

This will be helpful in a comment below.

Remove ERR_TEST_FAILURE from the formatted error details. Similarly to how we improve the assertion error message. It is introduced in bfb1415

Makes sense

Do not show cancelled by parent errors in the summary. These can be resolved by fixing the issue in the parent. This is why I suggest to link to the details of the parent error from the test error instead. It is introduced in a698e68

This is great. Much cleaner.

Show tests failing with cancelled by parent errors in grey. After introduction of 5., these tests duplicate failure index of parent errors. I think we should guide the user towards the parent error more by making the line of the test itself grey. It is introduced in bc0a738

Great idea!

I removed the usage of async describe block from hardhat tests since it doesn't work well with node's test reporter even though it is supported (fee6fb5). We could think about making it into a linting rule, maybe?

Unfortunately, this doesn't work, and we need to support that case. The reason is that our users will definitely do that. For example:

describe("Testing contract Foo", async () => {
    const Foo = await getFooFactory();
    
    it(...);
})

This already happens in practice, I'm trying to get Mocha to show an error in those situations, as they don't support async describes, but node does.

I went deeper into the reporter's code, and I understand when this happens and how to detect it:

/**
 * Returns true the event represents a failure due to trying to create a subtest
 * when its parent has already finished.
 *
 * This normally happens if you are running in `only` and the parent is async,
 * as the parent gets cancelled but continues running an async operation, and
 * try to create a subtests after it.
 */
export function isSubtestCreationAbortedError(event: TestEvent): boolean {
  if (event.type !== "test:fail") {
    return false;
  }

  const error = event.data.details.error;

  if (!("code" in error) || !("failureType" in error)) {
    return false;
  }

  return (
    error.code === "ERR_TEST_FAILURE" &&
    error.failureType === "parentAlreadyFinished"
  );
}

It may also be generated when the users forget an await and/or call to it/test after some weird async behavior, so I don't think it's entirely safe to silence it.

What if we do this?

  • Expose a separate entry point with options for hardhat, as mentioned above.
  • Pass it a flag when running in only mode.
  • Ignore these events in only mode.
  • Print them otherwise.

(we would need to add tests for this)

@alcuadrado
Copy link
Member

Also, let's revert the change to our test that does that. If we are going to support it, it's better to dogfood it.

Copy link
Member

@alcuadrado alcuadrado left a comment

Choose a reason for hiding this comment

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

I just left a few comments

Comment on lines 117 to 137
// We need to subtract the number of tests/suites that we chose not to
// display from the summary
if (event.data.message.startsWith("tests")) {
const parts = event.data.message.split(" ");
const count =
parseInt(parts[1], 10) -
topLevelFilePassCount -
parentAlreadyFinishedFailureCount;
event.data.message = `${parts[0]} ${count}`;
}
if (event.data.message.startsWith("pass")) {
const parts = event.data.message.split(" ");
const count = parseInt(parts[1], 10) - topLevelFilePassCount;
event.data.message = `${parts[0]} ${count}`;
}
if (event.data.message.startsWith("fail")) {
const parts = event.data.message.split(" ");
const count =
parseInt(parts[1], 10) - parentAlreadyFinishedFailureCount;
event.data.message = `${parts[0]} ${count}`;
}
Copy link
Member

Choose a reason for hiding this comment

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

Maybe all this logic should go to processGlobalDiagnostics

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a good catch. I now moved it to after processGlobalDiagnostics which I think is much cleaner, see 8332321 (#5724)

Comment on lines 163 to 164
// We still display the failed suites, because failures for the nested
// tests (cancelled by parent errors) were already displayed.
Copy link
Member

@alcuadrado alcuadrado Sep 10, 2024

Choose a reason for hiding this comment

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

This doesn't work well, as it looks like an error. I think a good trade-off would be to detect that situation and maybe display those canceled tests/suites as a particular case in the summary at the end of the test run if needed.

This is a complex case, so we can continue addressing it in a follow up PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

I replied in a longer form in #5724 (comment) TLDR I removed any attempt to handle that case from this PR + the newest node makes the output for these cases a lot better (e.g. in hardhat package, test:only works as expected now).

@galargh
Copy link
Member Author

galargh commented Sep 10, 2024

I'll look closer at it tomorrow and prepare the PR for a re-review properly, but I reverted any custom handling for the async describe case and the diff from node v22.8.0 looks quite promising - 5599b92

Base automatically changed from galargh/test-reporter-stack-cleanup to v-next September 11, 2024 07:51
@galargh
Copy link
Member Author

galargh commented Sep 11, 2024

I think this change is needed, but this implementation breaks the usage of this reporter outside of hardhat (e.g. in our own tests).

I think we can have two exports in the package:

One is the one that we already have, and can be used by non-hardhat tests.
The other one would be a function that constructs a reporter, and can receive params, like how the only flag is called.

I think this was a great suggestion and I implemented it straight away. Now we have the following 2 exports:

  • hardhatTestReporter which accepts RunOptions and HardhatTestReporterConfig; the former will give us the ability to detect whether we're running with an only flag or not, for example; while the latter we can use to customise how the reporter works - to begin with, we can get a custom message to display when the runner encounters some .only tests
  • customReporter which is the default export and uses the defaults that should work for any node project

It may also be generated when the users forget an await and/or call to it/test after some weird async behavior, so I don't think it's entirely safe to silence it.

After the experimentation and discussions we had on Slack, I do agree that silencing might not be the way forward in this case. Actually, I don't think we should do that even when running in the only mode. I now reverted the changes related to that silencing "parent already finished" errors.

This doesn't work well, as it looks like an error. I think a good trade-off would be to detect that situation and maybe display those canceled tests/suites as a particular case in the summary at the end of the test run if needed.

This is a complex case, so we can continue addressing it in a follow up PR.

As agreed, this PR will not introduce any special behaviour for "parent already finished" errors as it's a complex issue without a clearly right way forward. We'll deal with that in a separate PR if needed.

One thing worth noting is that some of the issues we were dealing with were addressed in v22.8.0 release of Node 🥳 We can see that clearly in this diff - 5599b92

This should be the result of nodejs/node#54423 as far as I can tell. With that PR in place, we can only see the "parent already finished" errors in nested async describes. Something like:

describe("a suite", () => {
  // If we remove this, no tests will be executed and no failures will be reported.
  it.only("an only test", async () => {
  	assert.equal(1, 1);
  });

  describe("a nested suite with an async callback", async () => {
    const one = await new Promise((resolve) => setTimeout(() => resolve(1), 0));

    it("a nested test", async () => {
      assert.equal(one, 1);
    });

    it.only("a nested only test", async () => {
      assert.equal(one, 1);
    });
  });
});

The issue is also only visible (reported by the test runner) if there is some block marked as only at the same level as the nested async describe.

All in all, triggering the issue requires a muuuch more complex setup now. We could consider whether trying to handle that edge case is worth pursuing.


I would suggest re-reviewing the PR with whitespace changes hidden - https://github.com/NomicFoundation/hardhat/pull/5724/files?w=1 This is because of all the indentation changes in the reporter.ts.

@galargh galargh requested a review from alcuadrado September 11, 2024 09:56
@schaable schaable added the v-next A Hardhat v3 development task label Sep 12, 2024
Copy link
Member

@alcuadrado alcuadrado left a comment

Choose a reason for hiding this comment

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

Great news about 22.8.0. Let's merge this now, and we'll see how this progresses.

@galargh galargh added this pull request to the merge queue Sep 13, 2024
Merged via the queue into v-next with commit 2de8407 Sep 13, 2024
64 checks passed
@galargh galargh deleted the galargh/test-reporter-ui branch September 13, 2024 06:35
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 13, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status:ready This issue is ready to be worked on v-next A Hardhat v3 development task
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

3 participants