Skip to content

Conversation

@steliosmavro
Copy link

Summary

Adds a new ESLint rule scout_max_one_describe that enforces a maximum of one describe block per test type in Scout tests to maintain consistent test structure.

What it does

Scout tests support multiple test fixtures (apiTest, test, spaceTest), and each fixture type should only have one top-level describe block per file. This rule prevents multiple describe blocks for the same test type, which can lead to fragmented test organization.

Invalid:

test.describe('first suite', () => {
  test('test 1', () => {});
});

test.describe('second suite', () => {  // ❌ Second test.describe() not allowed
  test('test 2', () => {});
});

Valid:

test.describe('my test suite', () => {  // ✅ Only one test.describe()
  test('test 1', () => {});
  test('test 2', () => {});
});

Features

  • Tracks apiTest.describe(), test.describe(), and spaceTest.describe() calls independently
  • Reports errors immediately on second occurrence for each test type
  • Allows 0 or 1 describe block per test type (not required, but max once if present)

Changes

  • Added rule implementation with comprehensive test suite (12 test cases)
  • Registered rule in plugin and enabled as error for Scout test files in .eslintrc.js
  • Uses efficient single-pass tracking with immediate error reporting

@steliosmavro steliosmavro self-assigned this Dec 6, 2025
@steliosmavro steliosmavro requested a review from a team as a code owner December 6, 2025 16:08
@steliosmavro steliosmavro added release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting labels Dec 6, 2025
@steliosmavro
Copy link
Author

  • I will need your insights on the file paths the rule should apply for. It's supposed to run for api tests, ui tests and space tests.
  • The rule checks for describe calls per test type, but doesn't encourage multiple test types in the same file. Another rule can be introduced, discouraging multiple test types in the same file. Separation of concerns, each rule checks for its own thing. Although the introduction of such a rule might be redundant.
  • Where should I add comments like this? Straight on the PR? Or on the project issue/task?

Comment on lines +29 to +37
// No describe blocks at all
{
code: dedent`
test('should work', () => {
expect(true).toBe(true);
});
`,
},
Copy link
Member

Choose a reason for hiding this comment

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

tbh not sure about it, but let's leave it as is for now

Comment on lines 86 to 92
test.describe('outer suite', () => {
describe('inner suite', () => {
test('should work', () => {
expect(true).toBe(true);
});
});
});
Copy link
Member

@dmlemeshko dmlemeshko Dec 8, 2025

Choose a reason for hiding this comment

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

This test case is not valid: describe in global namespace is the Jest one, playwright Playwright.

Playwright/Scout nested describes already covered by the existing rules:

image

What is not covered is multiple top level describe in the same spec file.

Comment on lines 98 to 96
describe('my test suite', () => {
describe('nested suite', () => {
test('should work', () => {
expect(true).toBe(true);
});
});
});
Copy link
Member

Choose a reason for hiding this comment

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

Afaik this is will be interpreted as Jest test suites. Please double check

Comment on lines +113 to +111
apiTest.describe('first suite', () => {
apiTest('test 1', () => {});
});

apiTest.describe('second suite', () => {
apiTest('test 2', () => {});
});
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 exactly the problem we try to detect!

/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.CallExpression} CallExpression */
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.MemberExpression} MemberExpression */

const ERROR_MSG = 'Only one describe block is allowed per test type (apiTest, test, or spaceTest).';
Copy link
Member

@dmlemeshko dmlemeshko Dec 8, 2025

Choose a reason for hiding this comment

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

I think we need to explain it is required for auto-skip functionality in CI. This argument should hopefully minimize interest to disable the rule.

Copy link
Member

@dmlemeshko dmlemeshko left a comment

Choose a reason for hiding this comment

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

I left few nits 👏

@dmlemeshko dmlemeshko added backport:all-open Backport to all branches that could still receive a release test:scout and removed backport:skip This PR does not require backporting labels Dec 8, 2025
@steliosmavro steliosmavro force-pushed the eslint-max-one-describe-rule branch from d82fa37 to 08e195b Compare December 8, 2025 18:23
@steliosmavro steliosmavro force-pushed the eslint-max-one-describe-rule branch from 08e195b to c52fe40 Compare December 8, 2025 19:19
@elasticmachine
Copy link
Contributor

elasticmachine commented Dec 8, 2025

💔 Build Failed

Failed CI Steps

History

cc @steliosmavro

@steliosmavro
Copy link
Author

I wasn't sure if I should include rule-violation fixes in this PR, so I decided to make a separate PR fixing 1 rule foundation that was found.

I suppose I should wait for the "rule-violation fixes" PR to be completed before moving on with this one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:all-open Backport to all branches that could still receive a release release_note:skip Skip the PR/issue when compiling release notes test:scout

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants