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

feat!: Stricter rule test validations #17654

Merged

Conversation

DMartens
Copy link
Contributor

@DMartens DMartens commented Oct 16, 2023

Prerequisites checklist

What is the purpose of this pull request? (put an "X" next to an item)

Implements part of RFC 84, refs #15104.
As the responding issue is closed, but still planned for v9, I decided to create a draft PR with only the first check implemented.
If this PR is unwanted, free feel to close it.
My plan, if this PR is accepted, is to create one commit per check only for RuleTester, then add documentation as some details may change and at last port the changes to FlatRuleTester.

[ ] Documentation update
[ ] Bug fix (template)
[ ] New rule (template)
[ ] Changes an existing rule (template)
[ ] Add autofix to a rule
[ ] Add a CLI option
[ ] Add something to the core
[x] Other, please explain: Rule Tester

What changes did you make? (Give an overview)

Assertions added to invalid test case error objects:

  • Must contain suggestions if the test case produces suggestions
  • Must contain the violation message (message or messageId, but not both)

Assertions added to invalid test case suggestion objects:

  • Must contain the suggestion code output
  • Must contain the suggestion message (messageId or desc, but not both)
  • The suggestion code output must differ from the test case code

Assertions added to all test cases:

  • Any autofix output must differ from the test case code
  • Cannot have identical test cases (feat!: detect duplicate test cases #17955)
  • The optional filename property must be a string
  • The optional only property must be a boolean

Is there anything you'd like reviewers to focus on?

How should the added suggestion matchers for existing core rule be handled?
For the suggestion existence check there are currently 18 missing suggestions from 2 rules.
Should I put them in the same commit as the check, as a separate commit or fix them all at the end?

@eslint-github-bot eslint-github-bot bot added breaking This change is backwards-incompatible feature This change adds a new feature to ESLint labels Oct 16, 2023
@netlify
Copy link

netlify bot commented Oct 16, 2023

Deploy Preview for docs-eslint canceled.

Name Link
🔨 Latest commit 80d190f
🔍 Latest deploy log https://app.netlify.com/sites/docs-eslint/deploys/65bb9367af776e000892589c

@bmish
Copy link
Sponsor Member

bmish commented Oct 17, 2023

Note that I do have more of this implemented in: https://github.com/bmish/eslint/tree/RFC-84

@DMartens
Copy link
Contributor Author

Added the second check for requiring a message or messageId assuming this PR is welcome.
This made the check for data without messageId useless as message checks there is no data, so there has to be a data property as then messageId is required.
Currently I just fixed up the rule tester test cases and not the test cases for the rules.
How do you want me to structure this PR (e.g. one commit for rule tester and one for updating rule tests), so that you can review it more easily?

Copy link

Hi everyone, it looks like we lost track of this pull request. Please review and see what the next steps are. This pull request will auto-close in 7 days without an update.

@github-actions github-actions bot added Stale and removed Stale labels Nov 12, 2023
Copy link

Hi everyone, it looks like we lost track of this pull request. Please review and see what the next steps are. This pull request will auto-close in 7 days without an update.

@github-actions github-actions bot added the Stale label Nov 24, 2023
Copy link

github-actions bot commented Dec 1, 2023

This pull request was auto-closed due to inactivity. While we wish we could keep working on every request, we unfortunately don't have the bandwidth to continue here and need to focus on other things. You can resubmit this pull request if you would like to continue working on it.

@github-actions github-actions bot closed this Dec 1, 2023
@mdjermanovic mdjermanovic reopened this Dec 2, 2023
@mdjermanovic mdjermanovic removed the Stale label Dec 2, 2023
@bmish
Copy link
Sponsor Member

bmish commented Dec 3, 2023

@DMartens good progress on this PR. Are you still working on it? We should try to finish it up soon for ESLint v9.

  1. You can pull some of the documentation needed for this PR from my branch main...bmish:eslint:RFC-84
  2. I would recommend saving the task Cannot have identical test cases for a separate PR since it's a much more complex check to get right and shouldn't block the rest of the trivial checks.
  3. You shouldn't worry about what commit each change is in.

Let me know if you're stuck on anything.

@DMartens
Copy link
Contributor Author

DMartens commented Dec 3, 2023

Yes, I am still working on this. I was just waiting for feedback but with the PR reopened I guess this PR is wanted.
If you split off the "identical test case" then only the following tasks are left:

  • updating documentation (thanks for the link)
  • checking that output uses "null" if no fix is applied
  • fixing violations in the core rules
  • copying changes to the flat rule tester
    I should be able to finish this in the coming week.

@bmish
Copy link
Sponsor Member

bmish commented Dec 3, 2023

Excellent, yes definitely eager to see this PR completed, thanks!

@DMartens
Copy link
Contributor Author

DMartens commented Dec 4, 2023

Did everything except copying the assertions / tests for flat rule tester (and the duplicate test case detection (should this be a separate PR?)).
I would prefer a review before doing this to avoid unnecessary additional work copying the fixes.
Some notes:

  • documentation: also added a note for data that is required if messageId is used and its message has placeholders and for output: null that the fixer did not produce a fix
  • fixing found errors for builtin rules: preferred the messageId over desc for suggestion

Copy link
Sponsor Member

@bmish bmish left a comment

Choose a reason for hiding this comment

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

Looking pretty good so far.

I would definitely leave "duplicate test case detection" to a separate PR, as it's much more complicated as described in the RFC, and I personally ran into a lot of edge cases with it and trouble getting it perfect when implementing it for a similar linter.

@@ -1153,6 +1160,7 @@ class RuleTester {
);
} else {
assert.strictEqual(result.output, item.output, "Output is incorrect.");
assert.notStrictEqual(item.code, item.output, "Use 'output: null' if the rule does not fix this case instead of copying the code.");
Copy link
Sponsor Member

Choose a reason for hiding this comment

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

Omit 'output' is my first recommendation to fix. Also could simplify wording:

Suggested change
assert.notStrictEqual(item.code, item.output, "Use 'output: null' if the rule does not fix this case instead of copying the code.");
assert.notStrictEqual(item.code, item.output, "Omit 'output' or use 'output: null' if there is no autofix.");

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this is a preference (maybe a case for eslint-plugin-eslint-plugin?) as personally I try to be as explicit as possible. As the developer copied the code to output I think they want to keep the output property as there would've been no error forcing them to add the output property.

Copy link
Sponsor Member

Choose a reason for hiding this comment

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

If people want to be explicit, that's fine. But I do think we should mention that the property can be omitted as one option. Similar to how schema: [] can be omitted from rules starting in ESLint v9.

Copy link
Sponsor Member

@bmish bmish Jan 13, 2024

Choose a reason for hiding this comment

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

This doesn't seem to be addressed yet.

tests/lib/rule-tester/rule-tester.js Show resolved Hide resolved
docs/src/integrate/nodejs-api.md Outdated Show resolved Hide resolved
Copy link

Hi everyone, it looks like we lost track of this pull request. Please review and see what the next steps are. This pull request will auto-close in 7 days without an update.

@mdjermanovic
Copy link
Member

My plan, if this PR is accepted, is to create one commit per check only for RuleTester, then add documentation as some details may change and at last port the changes to FlatRuleTester.

We're going to remove RuleTester soon, so all changes should be done in FlatRuleTester only.

@bmish
Copy link
Sponsor Member

bmish commented Dec 31, 2023

Now that the alpha is out, it should be a good time to address these merge conflicts. @DMartens are you able to fix this up in the next week? Want to make sure this is ready for the beta.

@DMartens
Copy link
Contributor Author

DMartens commented Jan 2, 2024

I should be able to fix those merge issues this week.
Would it be better to start off a new PR as the prior flat-rule-tester.js is now named rule-tester.js and that is the main part of the PR?

@bmish
Copy link
Sponsor Member

bmish commented Jan 2, 2024

Great. No need for a new PR. Can just fix the merge conflicts so that the correct file is updated.

@bmish bmish mentioned this pull request Jan 4, 2024
3 tasks
@bmish
Copy link
Sponsor Member

bmish commented Jan 4, 2024

I've started on the duplicate test case detection here:

So we'll need to have both of these PRs ready for the beta in a week.

@DMartens
Copy link
Contributor Author

DMartens commented Jan 20, 2024

Thanks for the code reviews. I should have addressed all raised points in their own commit.
Also I split up the test for the explicit testing of missing suggestions.
Further I have an ideas which I think should be part of this PR (but which are not part of the RFC):
If data is not specified for an error or suggestion, then the rule tester should test whether the placeholders are available in the message. For example this would be caught when tested with the rule tester:

export default {
	messages: {
		id: "{{ expected }}"
	},
	create(context) {
		context.report({ messageId: "id", data: { actual: true });
	},
}

This is makes sure that all placeholders can be replaced (especially now that message and messageId cannot be specified for the same error/suggestion.

@mdjermanovic
Copy link
Member

Looks like one test is failing now.

 1) RuleTester
       should throw an error when the expected output is not null and the output does not differ from the code:
     AssertionError: expected [Function] to throw error matching /Use 'output: null' if the rule does …/u but got 'Either omit the \'output\' property o…'

@mdjermanovic
Copy link
Member

Further I have an ideas which I think should be part of this PR (but which are not part of the RFC): If data is not specified for an error or suggestion, then the rule tester should test whether the placeholders are available in the message. For example this would be caught when tested with the rule tester:

export default {
	messages: {
		id: "{{ expected }}"
	},
	create(context) {
		context.report({ messageId: "id", data: { actual: true });
	},
}

This is makes sure that all placeholders can be replaced (especially now that message and messageId cannot be specified for the same error/suggestion.

I think this would need another RFC. Could you please open a separate issue to discuss this?

@nzakas nzakas linked an issue Jan 25, 2024 that may be closed by this pull request
1 task
@DMartens
Copy link
Contributor Author

Sorry for the delay. I fixed up the mentioned error messages and added a test case for when the suggestions property is neither an array or number which was missing.

lib/rule-tester/rule-tester.js Outdated Show resolved Hide resolved
lib/rule-tester/rule-tester.js Outdated Show resolved Hide resolved
@mdjermanovic
Copy link
Member

I think the case described in #17654 (comment) hasn't been addressed.

docs/src/integrate/nodejs-api.md Outdated Show resolved Hide resolved
Comment on lines 999 to 1003
if (!message.suggestions) {
assert.ok(!error.suggestions || (Array.isArray(error.suggestions) && error.suggestions.length === 0), `Error should have suggestions on error with message: "${message.message}"`);
} else if (!error.suggestions || Array.isArray(error.suggestions) && error.suggestions.length === 0) {
assert.ok(message.suggestions.length === 0, `Error should have no suggestions on error with message: "${message.message}"`);
} else {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (!message.suggestions) {
assert.ok(!error.suggestions || (Array.isArray(error.suggestions) && error.suggestions.length === 0), `Error should have suggestions on error with message: "${message.message}"`);
} else if (!error.suggestions || Array.isArray(error.suggestions) && error.suggestions.length === 0) {
assert.ok(message.suggestions.length === 0, `Error should have no suggestions on error with message: "${message.message}"`);
} else {
if (!error.suggestions || (Array.isArray(error.suggestions) && error.suggestions.length === 0)) {
if (message.suggestions) {
assert.fail(`Error should have no suggestions on error with message: "${message.message}"`);
}
} else {
if (!message.suggestions) {
assert.fail(`Error should have suggestions on error with message: "${message.message}"`);
}

I think we can simplify this to avoid duplicating the !error.suggestions || (Array.isArray(error.suggestions) && error.suggestions.length === 0 condition.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought some more about it and I think assigning a hasSuggestions + expectSuggestions variables and collapsing the second branch is easier to understand (see the new commits).

@mdjermanovic
Copy link
Member

Looks good so far. I think the only remaining thing is to check if the received message has suggestions in this case:

if (typeof error === "string" || error instanceof RegExp) {
// Just an error message.
assertMessageMatches(message.message, error);

@@ -916,6 +920,7 @@ class RuleTester {

// Just an error message.
assertMessageMatches(message.message, error);
assert.ok(message.suggestions === void 0 || message.suggestions.length === 0, `The message has untested. suggestions. Please convert the error at index ${i} into an object by assigning this message to a 'message' property.`);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
assert.ok(message.suggestions === void 0 || message.suggestions.length === 0, `The message has untested. suggestions. Please convert the error at index ${i} into an object by assigning this message to a 'message' property.`);
assert.ok(message.suggestions === void 0, `Error at index ${i} has suggestions. Please convert the test error into an object and specify 'suggestions' property on it to test suggestions.`);

For consistency with the check and the error message in the other case.

Copy link
Member

@mdjermanovic mdjermanovic left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@mdjermanovic mdjermanovic merged commit 47e60f8 into eslint:main Feb 1, 2024
18 checks passed
@bmish
Copy link
Sponsor Member

bmish commented Feb 1, 2024

Great work on this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion breaking This change is backwards-incompatible contributor pool feature This change adds a new feature to ESLint
Projects
Status: Complete
Development

Successfully merging this pull request may close these issues.

Change Request: Stricter rule test validation
4 participants