refactor: migrate to shared eslint config#3661
Merged
Conversation
8ee63aa to
303d032
Compare
1 task
bcac179 to
4904a1c
Compare
This was referenced Apr 14, 2026
4904a1c to
3b6e983
Compare
8 tasks
- Rename test/helpers/runCommand.ts to legacy-run-command.ts for old-style tests - Replace local run-command.ts with shared implementation from @heroku-cli/test-utils - Update 226+ test files to import runCommand from @heroku-cli/test-utils - Rename helper files to kebab-case: testInstances.ts -> test-instances.ts, uxStub.ts -> ux-stub.ts - Consolidate test utilities to use shared @heroku-cli/test-utils package This reduces code duplication and ensures all tests use the same command runner implementation.
- Replace local test/helpers/utils/expectOutput.ts with shared implementation - Update 57 test files to import expectOutput from @heroku-cli/test-utils - Use named import syntax for consistency with other test-utils exports This continues the consolidation of test utilities into the shared package.
Remove eslint plugins that are now handled by shared config. Also fix URL construction in exec.ts to avoid duplicate slashes in the API path.
The shared eslint config requires eslint-import-resolver-typescript v4.x for ESLint 9 flat config compatibility. Without it explicitly installed, npm resolves to v3.x from eslint-config-oclif, which has an incompatible interface and causes "invalid interface loaded as resolver" errors.
The bin/run.js file imports from the dist folder, which needs to exist before linting can resolve those imports. Running build before lint ensures the TypeScript compiler generates the dist folder first.
Use ternary expression with explicit return to satisfy getter-return rule while avoiding no-useless-return. Added explicit return type annotation for clarity.
- Add semi: ['warn', 'never'] to eslint config for no semicolons preference - Fix unicorn/prefer-ternary warning in members/add.ts - Remove unnecessary no-var from eslint-disable comment - Use String.raw for better backslash escaping in tests - Reorder imports and alphabetize mock properties
e72a630 to
c4eb1d7
Compare
Replace try-catch blocks with error property destructuring from runCommand across 88 test cases in 23 test files. This simplifies error handling by using the error returned directly from runCommand instead of relying on catch blocks.
Fix 6 test files where error handling was incorrectly using expect.fail, try-catch blocks, or expect().to.be.rejected instead of properly checking the error property returned by runCommand. This resolves 9 test failures.
Import HTTPError type and cast error to access body property, resolving TypeScript compilation error.
Replace stdout-stderr package with captureOutput from @heroku-cli/test-utils for cleaner and more consistent test output handling. Converted 7 test files and removed the stdout-stderr dependency from package.json. Files converted: - lib/confirm-command.unit.test.ts - lib/spaces/peering.unit.test.ts - lib/spaces/spaces.unit.test.ts - lib/run/log-displayer.unit.test.ts - lib/spaces/hosts.unit.test.ts - lib/data/display-quota.unit.test.ts - lib/spaces/vpn-connections.unit.test.ts
The log-displayer tests that expect errors were wrapping displayer.display() in captureOutput, which was causing the tests to hang. Since these tests are only checking error messages and not stdout/stderr output, we can remove the captureOutput wrapper and catch the errors directly in try-catch blocks.
The MockEventSource was creating setTimeout calls that weren't being cleaned up. These orphaned timers kept the Node.js event loop alive, causing the test suite to hang with a 30+ second timeout. Now we track all timeout IDs and clear them in the close() method to ensure proper cleanup.
The container/release test was calling stdMocks.use() to hijack stdout/stderr but never calling stdMocks.restore(). This left stdout/stderr in a broken state, causing the test runner to malfunction and exit after the release tests completed, preventing subsequent test files from running. Added stdMocks.flush() and stdMocks.restore() calls to properly clean up after capturing output.
michaelmalave
approved these changes
Apr 16, 2026
Contributor
michaelmalave
left a comment
There was a problem hiding this comment.
Left one comment but otherwise this looks good.
The container/release test was using stdMocks.use() to capture stdout/stderr, but then checking the output from runCommand() which already captures output. This was redundant and the missing stdMocks.restore() was breaking the test runner by leaving stdout/stderr hijacked, causing the test suite to exit early. Removed: - stdMocks usage from container/release test since runCommand() handles capture - std-mocks dependency from package.json (no longer used anywhere)
The tests that expect errors to be thrown shouldn't use captureOutput because captureOutput doesn't return an error property. When an error is thrown inside captureOutput, it gets swallowed and the test fails with the expect.fail() message instead of properly catching the error. Removed captureOutput wrapper from the two tests that expect errors, since we don't need to capture stdout/stderr when we're just checking that an error is thrown.
Fixed various linting warnings including: - Adding explicit type imports (e.g., SinonStub) - Addressing other ESLint warnings - Cleaning up test file patterns Updated 65 test files across commands, lib, and unit test directories.
Fixed linting warnings related to sinon usage across test files: - Added explicit type imports for sinon types - Cleaned up sinon stub and spy patterns - Fixed other sinon-related ESLint warnings Updated 17 test files.
Fixed additional linting warnings related to sinon usage: - Added explicit type imports for sinon types - Cleaned up sinon stub, spy, and sandbox patterns - Fixed sinon-related ESLint warnings Updated 19 test files across commands, hooks, and lib directories.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Migrates the project from ESLint 8 with legacy
.eslintrc.cjsto ESLint 9 with flat config (eslint.config.js), adopting the shared eslint configuration from@heroku-cli/test-utils. This reduces duplication across Heroku CLI projects and ensures consistent linting rules.This PR primarily focuses on:
@heroku-cli/test-utils(runCommand, expectOutput, etc.)semi: ['warn', 'never']rule to enforce no-semicolon styleNote: Test helper, fixture, acceptance, and integration test linting changes are being handled in a separate PR (#3671).
Key changes:
.eslintrc.cjsand.eslintignorefileseslint.config.jsusing ESLint 9 flat config format@heroku-cli/test-utilsdependency for shared linting rules and test utilities@heroku-cli/test-utilsinstead of local implementationsType of Change
Patch Updates (patch semver update)
Testing
Notes:
Steps:
npm run lintto verify all linting rules passnpm testto ensure all tests pass