Skip to content

Wave 4: angular-eslint migration, remove protractor e2e, headless unit tests#418

Open
tobydrinkall wants to merge 3 commits into
devin/1782947720-angular20-core-upgradefrom
devin/wave4-test-lint
Open

Wave 4: angular-eslint migration, remove protractor e2e, headless unit tests#418
tobydrinkall wants to merge 3 commits into
devin/1782947720-angular20-core-upgradefrom
devin/wave4-test-lint

Conversation

@tobydrinkall

@tobydrinkall tobydrinkall commented Jul 1, 2026

Copy link
Copy Markdown

Summary

Wave 4 of the Angular 9→20 upgrade (test + lint tooling only), based on devin/1782947720-angular20-core-upgrade (#417).

  • tslint → angular-eslint: added flat eslint.config.js via ng add @angular-eslint/schematics, deleted tslint.json, replaced the lint architect target with @angular-eslint/builder:lint over src/**/*.{ts,html}. Rules requiring codebase-wide migrations are disabled rather than mass-editing code (prefer-standalone, prefer-inject, template/prefer-control-flow, a11y click/focus rules, prefer-const, no-empty-function, etc.). Two small code touches: SettingsService implements OnDestroy and an inline disable for the legacy item selector.
  • Protractor removal: deleted e2e/, the e2e architect target, and the e2e npm script (protractor is EOL).
  • Unit tests: new app.component.spec.ts (creation + settings wiring, using provideRouter([]) and CUSTOM_ELEMENTS_SCHEMA) and comment.pipe.spec.ts (discuss / singular / plural). karma.conf.js unchanged; run headlessly with npm test -- --watch=false --browsers=ChromeHeadless.

Verified locally (Node 22): npm run lint, npm run build, and npm test -- --watch=false --browsers=ChromeHeadless (6/6 SUCCESS) all pass. No rxjs or component template/style changes.

Link to Devin session: https://app.devin.ai/sessions/781947dcf306489e92d4ada10c3601aa
Requested by: @tobydrinkall


Devin Review

Status Commit
⚪ Not started

Run Devin Review

Open in Devin Review (Staging)
Open in Devin Review

…s unit tests

Co-Authored-By: Toby Drinkall <toby.drinkall@cognition.ai>
@tobydrinkall tobydrinkall self-assigned this Jul 1, 2026
@devin-ai-integration

Copy link
Copy Markdown

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 5 potential issues.

Open in Devin Review

Comment thread angular.json

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚩 Production build has sourceMap and namedChunks enabled

The production configuration in angular.json:46-47 has "sourceMap": true and "namedChunks": true. These are typically disabled in production builds for performance and bundle size reasons. This is pre-existing (not changed by this PR), but worth noting as it increases the production bundle size and exposes source code.

(Refers to lines 46-47)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread src/app/shared/services/settings.service.ts
Comment thread eslint.config.js
Comment on lines +37 to +42
"@angular-eslint/no-empty-lifecycle-method": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unsafe-function-type": "off",
"prefer-const": "off",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: ESLint config disables several useful lint rules

The new ESLint config disables a broad set of rules: @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-function-type, @typescript-eslint/no-empty-function, and prefer-const (eslint.config.js:37-42). While these are likely disabled to avoid a flood of errors on the existing codebase, they reduce the value of the linter going forward. Consider setting these to "warn" instead of "off" so new violations are surfaced without blocking the build.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Acknowledged — these are set to off deliberately to keep this wave scoped to tooling migration without mass code edits. Tightening them to warn/error is a good follow-up once the standalone/inject migrations land.

Comment thread src/app/app.component.spec.ts
providedIn: 'root'
})
export class SettingsService {
export class SettingsService implements OnDestroy {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: ngOnDestroy on a root-scoped service has minimal practical effect

The PR adds implements OnDestroy to SettingsService (src/app/shared/services/settings.service.ts:8), which is providedIn: 'root'. For root-scoped services, ngOnDestroy is only called when the application's root injector is destroyed (i.e., app shutdown). In a typical single-page app, this means the cleanup code effectively never runs during the app's useful lifetime. The addition is not harmful, but it may create a false sense that the media query listener is being properly managed during the app's lifecycle.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Co-Authored-By: Toby Drinkall <toby.drinkall@cognition.ai>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

Open in Devin Review

this.setTheme(theme);
}

private boundColorSchemeHandler = this.handleSystemPreferredColorSchemeChange.bind(this);

@devin-ai-integration devin-ai-integration Bot Jul 1, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: Field initialization order verified safe under useDefineForClassFields: false

The boundColorSchemeHandler field (src/app/shared/services/settings.service.ts:38) is declared textually after the constructor, which raises a question about whether it's initialized before the constructor body calls subscribeToSystemPreferredColorScheme() at line 20. Because tsconfig.json:13 sets useDefineForClassFields: false, TypeScript hoists ALL field initializers to the top of the constructor (before the explicit body). Verified by compiling a test case with the project's own tsc: the emitted JS places this.boundColorSchemeHandler = ... before the constructor body. This would also be safe under useDefineForClassFields: true (TC39 semantics), where all fields are initialized before the constructor body runs. However, the code's readability would benefit from moving the field declaration above the constructor, since this ordering dependency is non-obvious.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Moved the field declaration above the constructor in bdbb176.

Co-Authored-By: Toby Drinkall <toby.drinkall@cognition.ai>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

Open in Devin Review

Comment thread package.json

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: Protractor still appears in package-lock.json after e2e removal

The e2e directory, protractor config, and the e2e npm script were all removed, but protractor still appears as a transitive dependency in package-lock.json. This is likely pulled in by @angular-devkit/build-angular which historically depended on it. It's harmless dead weight but could be cleaned up by running npm prune or regenerating the lockfile after confirming no remaining references.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Checked: the only protractor references in package-lock.json are inside @angular-devkit/build-angular's optional peerDependencies declaration — protractor is not actually installed as a package (no node_modules/protractor entry). Nothing to prune.

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.

1 participant