Before the tool list — a quick thing that genuinely matters.
Most "AngularJS tools 2025" articles are actually about Angular (v2 onward), not AngularJS (v1, deprecated December 2021). These are different frameworks. Different architecture, different language, different tooling, different everything. The naming overlap is a historical accident that's confused people for nine years.
Why does this matter for tooling? Because some tools — Augury, Batarang, Protractor — either originated in the AngularJS era or haven't been updated to work with modern Angular's internals. They keep appearing in tooling guides because articles reference each other without checking. Using them on a current Angular project doesn't just fail to help — in some cases it actively gives you wrong information about your application.
I'll flag which tools fall into that category, and more importantly, what replaced them.
Angular CLI — You're Using 40% of It
The basics everyone knows: ng new, ng serve, ng build, ng generate. The parts worth actually understanding:
# Standalone component — the default in Angular 17+
ng generate component features/checkout --standalone
# Functional guard — cleaner than the old class-based approach
ng generate guard core/guards/auth --functional
# Apply migration schematics before a major version upgrade
ng update @angular/core @angular/cli
# Production build with bundle stats for analysis
ng build --configuration production --stats-json
npx webpack-bundle-analyzer dist/my-app/stats.json
# Lint with auto-fix
ng lint --fix
The ng update command is the one I'd push hardest on. Angular releases a major version every six months. Each one ships migration schematics — automated code transformations that rewrite your code for breaking changes. Deprecated API usages, changed import paths, modified decorator syntax — the schematics handle the mechanical parts automatically. The first time you run it on a large codebase instead of manually migrating, the time difference is significant.
Angular 17 swapped the default build engine from webpack to esbuild. If you're already on 17+, you noticed — dev server startup got faster, hot reload is snappier. If you're still on 15 or 16 with sluggish builds, upgrading might fix your build performance before you touch any configuration.
Angular DevTools — Not Augury
Augury: third-party Chrome extension, last meaningfully updated before Angular's Ivy renderer shipped in 2020, doesn't support Signals, shows incomplete information on modern Angular codebases. Still appearing in tooling lists because nobody checked.
Angular DevTools: official extension from the Angular team, ships updates when Angular ships updates, supports Ivy, supports Signals. This is the one to install.
What it actually does that's useful:
// Angular DevTools catches this kind of thing:
@Component({
template: `<li *ngFor="let item of getFilteredItems()">{{ item.name }}</li>`
})
export class ListComponent {
// Called on every change detection cycle — potentially hundreds of times per second
getFilteredItems() {
return this.items.filter(i => i.active && i.category === this.selectedCategory);
}
}
// The change detection profiler shows this component firing constantly.
// Fix:
@Component({
template: `<li *ngFor="let item of filteredItems()">{{ item.name }}</li>`
})
export class ListComponent {
private items = signal<Item[]>([]);
private selectedCategory = signal('');
// Computed only re-runs when its signal dependencies change
filteredItems = computed(() =>
this.items().filter(i => i.active && i.category === this.selectedCategory())
);
}
The change detection profiler is what makes this tool worth keeping open. Record a session, look at which components triggered the most detection cycles. That list tells you exactly where to start when an Angular app is sluggish. It's not guesswork — it's instrumented data.
The Signals dependency graph is newer and increasingly useful. As codebases move toward signal-based reactivity, being able to see which signals a component depends on and what their current values are is legitimately helpful for debugging reactive behavior that isn't obvious from the code.
VS Code + Angular Language Service
Most Angular developers use VS Code. WebStorm is capable and worth considering for teams that want a pre-configured environment, but the Angular Language Service extension closes most of the gap for free.
Without it:
<!-- Editor sees this as a string. No errors flagged. -->
<p>{{ user.naem }}</p>
<app-user-card [userId]="user.id.toString()"></app-user-card>
<app-product-card></app-product-card>
With it:
<!-- "Property 'naem' does not exist on type 'User'. Did you mean 'name'?" -->
<p>{{ user.naem }}</p>
<!-- "Argument of type 'string' is not assignable to parameter of type 'number'" -->
<app-user-card [userId]="user.id.toString()"></app-user-card>
<!-- "Required input 'product' from component ProductCardComponent must be specified" -->
<app-product-card></app-product-card>
That last error — missing required inputs — relies on @Input({ required: true }) from Angular 16. If you're using it (you should be), the Language Service enforces it at edit time rather than runtime. On a large project with many components, this catches real bugs during development, not after.
ESLint with @angular-eslint for linting — TSLint has been deprecated since 2019:
ng add @angular-eslint/schematics
{
"rules": {
"@angular-eslint/component-selector": [
"error",
{ "type": "element", "prefix": "app", "style": "kebab-case" }
],
"@angular-eslint/no-empty-lifecycle-method": "error",
"@angular-eslint/no-input-rename": "error",
"@angular-eslint/use-lifecycle-interface": "error"
}
}
no-input-rename is the rule I see violated most — developers aliasing component inputs with a public name that differs from the internal property. It's confusing for component consumers and the rule prevents it. Worth having on.
Testing: The Karma Migration Isn't Optional Anymore
Karma is deprecated. Angular 16, officially. It's been removed from new project scaffolding. You can still run it, but you're running a test runner without active maintenance on a framework that ships breaking changes every six months. The compatibility risk is real.
Jest migration — less painful than it sounds:
# Remove Karma
npm uninstall karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter
# Add Jest
npm install --save-dev jest jest-preset-angular @types/jest
// jest.config.ts
export default {
preset: 'jest-preset-angular',
setupFilesAfterFramework: ['<rootDir>/setup-jest.ts'],
transform: {
'^.+\\.(ts|mjs|js|html)$': [
'jest-preset-angular',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$',
},
],
},
};
// setup-jest.ts
import 'jest-preset-angular/setup-jest';
Your actual tests don't change. describe, it, expect, TestBed.configureTestingModule, ComponentFixture — all of it works with Jest. The migration is configuration, not test rewriting. Payoff: faster execution (no browser startup), parallel runs, better failure output.
For E2E: Playwright or Cypress. Not Protractor.
Protractor was deprecated in Angular 12, support ended with Angular 15. Any article recommending it in 2025 is wrong.
// Playwright E2E — what modern Angular E2E testing looks like
import { test, expect } from '@playwright/test';
test('checkout flow completes successfully', async ({ page }) => {
await page.goto('/products/42');
await page.getByRole('button', { name: 'Add to Cart' }).click();
await expect(page.getByTestId('cart-badge')).toHaveText('1');
await page.goto('/checkout');
await page.getByLabel('Email').fill('user@example.com');
await page.getByRole('button', { name: 'Place Order' }).click();
await expect(page.getByText('Order confirmed')).toBeVisible();
});
Playwright: cross-browser (Chromium, Firefox, WebKit) from one API, excellent trace viewer for debugging failures, strong parallel execution. Cypress: better Angular-specific documentation, more tutorials. Both are actively maintained and either is a significant improvement over Protractor.
RxJS Debugging: Two Tools Worth Knowing
Most Angular apps are deep into RxJS, and debugging observable chains is genuinely awkward. The problem isn't complexity — it's that pipelines don't produce inspectable artifacts by default.
rxjs-spy adds named tags to observables, making them inspectable from the browser console:
import { tag } from 'rxjs-spy/operators';
// During development:
this.productService.getProducts(filters).pipe(
tag('products-filtered'), // Now visible in console
map(products => products.slice(0, 20))
).subscribe();
// Browser console:
// spy.show('products-filtered') — current value, subscriber count
// spy.log('products-filtered') — log every emission
// spy.pause('products-filtered') — pause emissions for inspection
No permanent console.log in production code. Remove the tags before shipping.
NgRx DevTools + Redux DevTools extension: if you're using NgRx, install this. Time-travel debugging — stepping backward through dispatched actions to understand how state got broken — is one of those features that sounds interesting until you're actually debugging a complex state problem at 11pm, and then it becomes essential.
BrowserStack: Honest About When It's Worth It
Playwright handles Chromium, Firefox, and WebKit. For teams whose cross-browser concern is desktop coverage, Playwright alone gets you there without a third-party subscription.
BrowserStack earns its cost in two scenarios. Real mobile device testing — actual iPhones running mobile Safari, actual Android devices running Chrome — where emulator behavior diverges from real devices in ways that matter (touch events, viewport handling, certain rendering behaviors). And organizational requirements for documented cross-browser test results, which some enterprise and compliance contexts require.
If neither scenario applies, Playwright covers you.
The Deprecation Summary
| Tool | Status | Replacement |
|---|---|---|
| Angular CLI | Current, essential | — |
| Angular DevTools | Current, official | — |
| Angular Language Service | Current, essential | — |
| Jest + jest-preset-angular | Current standard | — |
| Playwright / Cypress | Current standard | — |
| ESLint + @angular-eslint | Current standard | — |
| Karma | Deprecated Angular 16 | Jest |
| Protractor | Deprecated Angular 12/15 | Playwright / Cypress |
| Augury | Abandoned, incompatible | Angular DevTools |
| TSLint | Deprecated 2019 | ESLint |
| Batarang | AngularJS-only, irrelevant | Angular DevTools |
At Innostax, we build Angular applications and have dealt with most of the migrations on this list in real production codebases. If you're working through a Karma-to-Jest migration or a broader Angular modernization, reach out here.
Originally published on the Innostax Engineering Blog.
Top comments (0)