とんかつ時々あんどーなつ

〜たとえ低空でも飛行していられるように〜

2022 年振り返り & 2023 年の抱負

2022 年振り返り

仕事

転職が一大イベントだった。 前職ではコロナ禍以降 2 年くらいフルリモートだったが、現職は週 2 くらいで出社している。 久しく忘れていた通勤電車に体力を奪われつつ、オフラインコミュニケーションの良さを思い出している。

まだ試用期間なので、頑張って貢献していきたい。

プライベート

家庭内が忙しかったり、転職活動をしたりして慌ただしかった… それもあってか余暇時間をなかなかうまく使えていなかった気がする。

個人ブログでのアウトプットもたった 3 件と心の余裕のなさがわかる。

そんな中でも本は読むようにしていた。去年こんな記事を書いていたが、レジュメはあまり残せていない…

kasaharu.hatenablog.com

それでも 10 冊は読み切ったので努力賞といったところである。

Angular コミュニティ周りでは引き続き ng-japan OnAir に参加する機会があったので、可能な限り参加した。また公式ドキュメントの翻訳も数ページおこなった。

小さいかもしれないが、来年も自分なりにコミュニティへの貢献を続けたいと思う。

2023 年の抱負

毎年来年に向けていくつかの目標を立てるところであるが、環境が変わったりしているので、2023 年は改めて余裕を作り自分なりのリズムを見直すことを目標にしたいと思う。

Angular アプリケーションに Testing Library を導入する

はじめに

これは Angular Advent Calendar 2022 1 日目の記事です。

今回は Angular アプリケーションに Testing Library を導入してみたので紹介します。

Testing Library とは

Testing Library | Testing Library

ユーザーがページ上で要素を見つけるのと同じように DOM node を見つけ操作することを可能にするライブラリです。つまり、実際にユーザーがアプリケーションを使うようにテストをすることができるということです。

また、Testing Library 自体は Angular 専用ではなく多くのフレームワークで使用することができます。

導入方法はパッケージをインストールするだけなので、公式ページを参照することをオススメします。Angular Testing Library | Testing Library

検証用のアプリケーションを用意

今回は Tour of Heroes - download example の完成形となるコードをダウンロードして使用しています。

この記事で対象にしたコンポーネントのコードも示しておきます。

// src/app/dashboard/dashboard.component.ts

import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';

@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: [ './dashboard.component.css' ]
})
export class DashboardComponent implements OnInit {
  heroes: Hero[] = [];

  constructor(private heroService: HeroService) { }

  ngOnInit(): void {
    this.getHeroes();
  }

  getHeroes(): void {
    this.heroService.getHeroes()
      .subscribe(heroes => this.heroes = heroes.slice(1, 5));
  }
}
<!-- src/app/dashboard/dashboard.component.html -->

<h2>Top Heroes</h2>
<div class="heroes-menu">
  <a *ngFor="let hero of heroes"
      routerLink="/detail/{{hero.id}}">
      {{hero.name}}
  </a>
</div>

<app-hero-search></app-hero-search>

既存テストの確認

// src/app/dashboard/dashboard.component.spec.ts

import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { of } from 'rxjs';

import { HeroSearchComponent } from '../hero-search/hero-search.component';
import { HeroService } from '../hero.service';
import { HEROES } from '../mock-heroes';

import { DashboardComponent } from './dashboard.component';

describe('DashboardComponent', () => {
  let component: DashboardComponent;
  let fixture: ComponentFixture<DashboardComponent>;
  let heroService;
  let getHeroesSpy: jasmine.Spy;

  beforeEach(waitForAsync(() => {
    heroService = jasmine.createSpyObj('HeroService', ['getHeroes']);
    getHeroesSpy = heroService.getHeroes.and.returnValue(of(HEROES));
    TestBed
        .configureTestingModule({
          declarations: [DashboardComponent, HeroSearchComponent],
          imports: [RouterTestingModule.withRoutes([])],
          providers: [{provide: HeroService, useValue: heroService}]
        })
        .compileComponents();

    fixture = TestBed.createComponent(DashboardComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  }));

  it('should be created', () => {
    expect(component).toBeTruthy();
  });

  it('should display "Top Heroes" as headline', () => {
    expect(fixture.nativeElement.querySelector('h2').textContent).toEqual('Top Heroes');
  });

  it('should call heroService', waitForAsync(() => {
       expect(getHeroesSpy.calls.any()).toBe(true);
     }));

  it('should display 4 links', waitForAsync(() => {
       expect(fixture.nativeElement.querySelectorAll('a').length).toEqual(4);
     }));
});

既存のコードでは以下 4 つのテストケースがあります。

  • コンポーネントが作成されていること
  • h2 タグで "Top Heroes" が表示されていること
  • HeroService::getHeroes() が呼ばれていること
  • a タグが 4 つあること

Testing Library で書き換える

事前準備

テストをおこなうには、まず対象のコンポーネントレンダリングする必要があり、Testing Library では render() を使用します。 対象のコンポーネントが依存しているサービスや子コンポーネントがあるなら TestBed.configureTestingModule() に渡すように render() の第 2 引数としてオブジェクトで渡すことができます。

また render() の返り値には DOM ノードが RenderResult として返り fixture などを取り出すことができます。

  let component: DashboardComponent;
  let fixture: ComponentFixture<DashboardComponent>;
  const heroService = jasmine.createSpyObj('HeroService', ['getHeroes']);
  const getHeroesSpy = heroService.getHeroes.and.returnValue(of(HEROES));

  beforeEach(async () => {
    const renderResult = await render(DashboardComponent, {
      declarations: [HeroSearchComponent],
      providers: [{ provide: HeroService, useValue: heroService }],
    });

    fixture = renderResult.fixture;
    component = fixture.componentInstance;
  });
});

Angular のテスト用 API である TestBed を使わず記述できるようになるのが特徴です。

テストケースの作成

コンポーネントが作成されていること

render() の返り値から componentInstance を取り出せるため、このテストケースは特に変更なく、そのままとなります。

h2 タグで "Top Heroes" が表示されていること

もともとのテストケースを再掲します。

it('should display "Top Heroes" as headline', () => {
  expect(fixture.nativeElement.querySelector('h2').textContent).toEqual('Top Heroes');
});

Testing Library では role を指定することで対象の要素を見つけることができます。 画面上から 'Top Heroes' と書かれた heading role を探し、その存在を確認するテストケースが以下になります。

it('should display "Top Heroes" as headline', () => {
  expect(screen.getByRole('heading', { name: 'Top Heroes' })).toBeTruthy();
});

今回は getByRole() を使っていますが、どのメソッドを使うのが適切かわからない場合は、まず getByText() を使って対象のテキストがあるかを探します。

it('should display "Top Heroes" as headline', () => {
  expect(screen.getByText('Top Heroes')).toBeTruthy();
});

各メソッドの第 2 引数には MatcherOptions を渡すことができますが、その際に suggest を指定することでよりよいメソッドが提案されます。

it('should display "Top Heroes" as headline', () => {
  expect(screen.getByText('Top Heroes', { suggest: true })).toBeTruthy();
});

これを使って積極的によりよいメソッドを使えると良さそうです。

HeroService::getHeroes() が呼ばれていること

これは Testing Library を使っても変わるところがないので割愛します。

a タグが 4 つあること

既存のテストケースは a タグが 4 つあることを確認しています。 このままテストしてもいいですが、どのような a タグなのかを示せたほうがテストケースとしてはより有用だと考えられます。

今回の場合は「Bombasto, Celeritas, Magneta, RubberMan と書かれたリンクがあること」をそれぞれ確認するテストケースに変更します。

it('should display 4 links', () => {
  expect(screen.getByRole('link', { name: /Bombasto/i })).toBeTruthy();
  expect(screen.getByRole('link', { name: /Celeritas/i })).toBeTruthy();
  expect(screen.getByRole('link', { name: /Magneta/i })).toBeTruthy();
  expect(screen.getByRole('link', { name: /RubberMan/i })).toBeTruthy();
});

このようなテストケースも簡単にかけます。

まとめ

今回は導入ということで、簡単なコンポーネントについてテストを書いてみましたが、比較的直感的に書けることがわかりました。 後回しにしがちな view のテストも書いていきたい気持ちになったのではないでしょうか?

明日は nontangent さんです!

Standalone based Tour of Heroes

はじめに

これは Angular チュートリアル Tour of Heroes を今話題の Standalone base で書いたときのメモです。 angular/core のバージョンは v14.2.5 です。

Standalone とはなにかについては以下を見たほうがわかるので割愛します。

standalone への修正

コンポーネント

v14 では何も設定しないと CLI で作ったコンポーネントは standalone true になっていない。すべて standalone component で作るつもりであれば angular.json で設定を変更しておいたほうが楽になる。

"projectType": "application",
  "schematics": {
    "@schematics/angular:component": {
      "standalone": true
    },
    ...
  }
  ...
}

この設定を入れることで CLI で作ったコンポーネントは standalone true で作成される。

AppComponent

AppComponent を standalone component にする手順は以前 Angular v14 standalone component を試す - とんかつ時々あんどーなつ にも書いた。 再掲するが修正が必要になるのは main.ts であり、今まで bootstrapModule() を使っていた部分を修正する。

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

修正後は以下になる。

bootstrapApplication(AppComponent);

これにより AppModule が不要になるのでアプリケーションから削除することができる。

ルーティング

次はルーティングの設定を NgModule を使わない形に修正する。まずは従来の設定をおさらいする。RouterModule を使っている場合の src/app/routes.ts、src/app/app-routing.module.ts、src/main.ts は次のようになる。

// src/app/routes.ts

import { Routes } from '@angular/router';
import { DashboardPageComponent } from './features/dashboard/pages/dashboard/dashboard.component';
import { HeroDetailPageComponent } from './features/hero-detail/pages/hero-detail/hero-detail.component';
import { HeroesPageComponent } from './features/heroes/pages/heroes/heroes.component';

export const routes: Routes = [
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
  { path: 'dashboard', component: DashboardPageComponent },
  { path: 'detail/:id', component: HeroDetailPageComponent },
  { path: 'heroes', component: HeroesPageComponent },
];
// src/app/app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { routes } from './routes';

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}
// src/main.ts

...
bootstrapApplication(AppComponent, {
  providers: [
    importProvidersFrom(AppRoutingModule),
  ],
});

ここから RouterModule を外していく。v14.2 で RouterModule.forRoot() の代わりになる provideRouter() という API が追加された。provideRouter() の詳細を知るには Angular: provideRouter によるルーティング設定 (v14.2) | lacolaco/tech を見ていただくのがよい。 provideRouter() を使うと main.ts が以下のように変更でき、app-routing.module.ts が不要になる。

// src/main.ts

...
bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(routes),
  ],
});

router directive

RouterModule はルーティングの設定以外に <router-outlet>routerLink を使う際にも必要となる。そのためすべての RouterModule をアプリケーションから削除するにはもうひと手間必要となる。

router の API には RouterOutletRouterLinkWithHref などのディレクティブが存在するが、これらが v14.2 で standalone として提供されるようになっている。 よって、これらのディレクティブを必要なコンポーネントで import することで、すべての RouterModule をアプリケーションから削除することができる。

common directive / common pipe

おおよそすべてのコンポーネントで import されている CommonModule がある。最後にこれを削除する。CommonModule は頻繁に使用することになる NgIfNgForOf などのディレクティブや AsyncPipe などの組み込みパイプを提供している。これらのディレクティブやパイプも v14.1 で standalone として提供されているので、置き換えることができる。

ただし、想像以上に CommonModule がいろんなディレクティブ / パイプを一括で import していたので、これを外すのは無理しなくてもよさそう。 COMMON_DIRECTIVESAPI として提供されるのを待ちたいところである。

standalone にできなかったもの

ここまで修正してきた Tour of Heroes アプリケーションの中にはまだ NgModule が残っている。HttpClientModule と FormsModule である。provideRouter() のような API を期待したが angular/CHANGELOG.md at main · angular/angular · GitHub を見てもまだそれらしい変更はなかった。

※ 10/11 追記: provideHttpClient() は v15 で入りそう(https://github.com/angular/angular/pull/47502)

まとめ

Angular チュートリアルの Tour of Heroes を Standalone base で書き直してみました。コンポーネントをすべて standalone で書くことは何も不都合はなく NgModule がなくなったことで、依存の把握がしやすくなったように思います。 ルーティングの設定に関しても provideRouter() を使うことでかなりシンプルに書けるようになったので積極的に置き換える意味がありそうです。

一方で HttpClient や Forms で見たようにすべての API が standalone に対応しているわけではないのと CommonModule がに基本的なディレクティブやパイプを一括で import していたお手軽さなどを考慮すると、無理に NgModule を外すというよりは使いたいと思ったところから standalone にしていくのがよさそうです。

今回試したコード: GitHub - kasaharu/angular-architecture at standalone-based

Angular v14 standalone component を試す

standalone component は Angular 学習の複雑さを上げている要因の NgModule の必要性を減らすことを目的としている。 その standalone component が v14 で開発者プレビューとして使えるようになったので、試してみる。

なお、開発者プレビューであるため後のアップデートで変更される可能性がある。

standalone component の作り方

まずは Angular v14 を使ったアプリケーションを用意する。新しいコンポーネントで作る場合は以下のように --standalone フラグを付けるだけでよい。

$ yarn ng g c top-bar --standalone

すると以下のようなコンポーネントが作成される。

import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-top-bar',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './top-bar.component.html',
  styleUrls: ['./top-bar.component.scss']
})
export class TopBarComponent implements OnInit {

  constructor() { }

  ngOnInit(): void {
  }

}

注目すべき点は 2 つありは 1 つは standalone: true である。対象のコンポーネントが standalone component かどうかはこのフラグが決めており、既存のコンポーネントを standalone component にするときも standalone: true を追加すれば良い。

2 つ目は imports である。NgModule を使わないので依存関係は自分で解決する必要がある。従来の NgModule の他に新たに作った別の standalone component も指定できる。

angular.json でデフォルトのフラグを変更

新規につくるコンポーネントは standalone component を中心に作っていくと決めた場合は angular.json でデフォルトの設定を変えることもできる。 設定は以下の通り。

"projectType": "application",
  "schematics": {
    "@schematics/angular:component": {
      "standalone": true
    },
    ...
  }
  ...
}

ルートコンポーネントを standalone component にしてブートストラップする

ルートコンポーネントである AppComponent も standalone component にすることができる。

まずは AppComponent に standalone: true を追加する。上でも触れたがコンポーネント自体はこれで standalone component になる。 次に修正が必要なのは main.ts である。従来は NgModule が起点になっていたため以下のようにアプリケーションを起動していた。

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

対象が standalone component になることで、専用のブートストラップ API を使う必要があるので下記のように書き換える必要がある。

bootstrapApplication(AppComponent);

AppModule で解決していた依存関係は直接 AppComponent の imports に書くことができる。 しかし RouterModule のように一部の既存 module は NgModule に依存しているものがあるので、それらは standalone component にではなく以下のようにブートストラップ時に指定しなければならない。

bootstrapApplication(AppComponent, {
  providers: [importProvidersFrom(AppRoutingModule)],
});

これでルートコンポーネントも standalone component にできる。

まとめ

standalone component の作り方と既存のコンポーネントの standalone 化を試したが、どちらもスムーズに確認できた。 今回は新規アプリケーションに対して試したが、既存のアプリケーションにも部分的に適用できるのでまた色々と試したみたい。

参考

2021 年振り返り & 2022 年の抱負

晦日なので今年も一年を振り返ることにする。

2021 年振り返り

目標を振り返る

まずは目標を振り返ることにする。

今年の目標は これ

インプット / アウトプット

読書をすると意気込んでいたのに去年より少ない 7 冊だった。 が、前のブログにも書いたとおりなんとか立て直したので、この気持ちを維持したい。

kasaharu.hatenablog.com

アウトプットも結局去年より少ない結果になってしまった。 まだまだ気軽にアウトプットするのが苦手みたいだ…

Write Code Everyday

どうにか今年一年はと思って続けた。ただ毎日頭の片隅に 1 commit があるのがストレスになっていたので、来年の目標にはしないことにした。 のんびり本を読みたい日だってある…

英語

何も進展しないし、目標を見失っている…これも一度忘れることにする。

運動

色々あり太ってしまう始末…改善が必要だと感じた。

雑多に振り返る

一番大きなイベントはやはり結婚だった。二人暮らしを始めるために 5 年過ごした墨田区を離れた。 スカイツリーの写真を撮るのが趣味だったのに、今では懐かしい。

Twitter 見返したら出てきた今年イチのスカイツリーを貼っておく。

仕事はリモートワークになって久しく、結局オフィスには 1 回くらいしか行っていない。 家で仕事するのにもすっかり慣れて通勤電車に乗れない体になってしまった。

業務面では社のエンジニアメンターという制度や評価制度などの人に関する部分に少し携わる機会をもらえた。 1on1 やメンティーの目標設定の壁打ちをしたが、自分の中では型が定まらず無力感も大きかった。

まだ道半ばだと思っているので知識をインプットしたい。

フロントエンドに関するところは変わらず Angular 中心だが情報のキャッチアップで精一杯だった気がする。

ng-japan OnAir に参加する機会を多く貰えたのはかなりよかったが、それ以外で OSS のコードを見たりコントリビュートしたりと言うのは去年までと比べてかなり少なかった気がする。

引っ越して生活スタイルが変わったり、リモートワークで通勤時間がなかったりして、なんだか一日のリズムが作れないまま終わってしまった一年に感じた。 このあたりを改善した 2022 年にしたい。

2022 年の抱負

インプット / アウトプット

読書習慣は継続したい。読む本の冊数を決めるというよりは朝活習慣を途絶えさせない方を意識したい。 アウトプットは無理せずブログ月 1 回でやっていく。

運動

ダイエット目的で三が日終わったら頑張る。

ロギング

ツイートも多い方ではないからいざ振り返ると言っても何をしていたか思い出せないことが多かった気がする。 1 年も一瞬で通り過ぎていく年齢になって記憶力も低下しているので、もう少し記録を残したいと思った。

プログラミング

普段は JS / TS を書くことが多いが、必要最低限という感じで自由に使えている感じが薄い。JS / TS じゃなくてもいいが、自由に使える言語を身につけたい。

こんな感じで来年もやっていきたい。2022 年もよろしくお願いします。

積ん読捗ってますか?

はじめに

毎年気になる本が出てはそれを買い、積ん読を増やし続けていた… なんとか時間を作っては「まえがき」読むが、「まえがき」だけを読んだ本が本棚に並んでいく。

そんな状態を打破しようと、去年の年末に読書目標を立てた。

年初は気合を入れて読んでいたが本を読んでも内容があまり頭に残っていない、という問題もあり段々とモチベーションが低下していた…

そんなとき lacolaco さんに「未来のきみを変える読書術」という書籍を教えてもらった。

www.amazon.co.jp

読書革命

詳細が気になる方はぜひこの本を手にとって欲しいが、個人的に一番影響を受けたのはレジュメ「読書ノート」を作るという点だった。

本にはこう書いてあった。

ノートに残すことで、本のエッセンスを記憶に定着させる

1 冊まるまるレジュメを作る

レジュメは本を読み終えてから作る

ただ本を読むだけでも時間を使うのに 1 冊分のレジュメを残そうと書いてある。 さらには「本を読み終えてから作る」というのは実質 2 周しなければ書けない…

「なんてめんどくさいんだ…」と、正直思った。

一方で短時間で読んでも何も覚えていないよりは、多くの時間を使っても要点がまとまったレジュメを作れるほうがいくらかましではないか?とも思った。

読書習慣

まずは読書の習慣化を目指す。習慣化するために続いていることが意識できるように記録する必要があると思った。

読書時間の予定と実績を残すために Studyplus を使うことにした。 コンテンツの登録も本のバーコードを読み取るだけでできるのでとても便利である。

レジュメは Notion に残している。 使うサービスに特に強いこだわりはないが、結構本の引用をするのでパブリックにアウトプットするのは避けた。

文字にすると少ないが意識しているのはこれくらいかもしれない。

まとめ

レジュメを残すようになったので、本の内容をいつでも思い出せる安心感を得た。 また、そのおかげで読書へのモチベーションも取り戻せた。

11 月に「未来のきみを変える読書術」を読み終わってから 2 ヶ月弱で 3 冊本を読むことができた。 読書家よりは全然少ないと思うけど、習慣化している実感もあるので来年も続けていきたい。

半年後「レジュメを残すのが大変でモチベーションが下がった」と言っていないことを祈る…

2021 年の Angular 振り返り

これは Angular Advent Calendar 2021 の 2 日目の記事です。

昨日は @puku0x さんの記事でした。 Angular v13 の開発環境構築 - Qiita

今日は 2021 年の Angular の変更を振り返りたいと思います。

なお、内容の元ネタは ng-japan OnAir - Youtube になります。 毎月配信されているのでぜひこちらも見てみるとよいと思います。

www.youtube.com

機能追加が入る major / minor version は 11.1.0 (2021-01-20) から 13.0.0 (2021-11-03) まで上がったのでそちらを見ていきます。

変更点ピックアップ

Browser Support

一番大きな変更点は v13 で IE サポート廃止になったことではないでしょうか。 引き続き IE をサポートする必要のあるアプリケーションはしばらく v12.x で動かす必要があります。

一方で IE のサポートをやめることで differential loading の機能もカットできたためビルドなどが改善されています。

また Chrome などのブラウザに関してもサポートバージョンが更新されているので詳細はドキュメントを見るとよいです。

Angular 日本語ドキュメンテーション

Ivy Everywhere

v9 で登場したレンダリングエンジン Ivy がアプリケーションで opt-out できなくなり、すべてのアプリケーションが Ivy で動くようになりました。 ライブラリも default Ivy になっており、脱 View Engine が進んでいます。

ビルド時の ngcc が長くて悩んでいるので、すべてのライブラリが Ivy 対応するのが待ち遠しいです。

Production by Default

v12 で新規で作ったアプリケーションはデフォルトで production build になります。 過去バージョンから update をした人は migration する必要があります。 これに伴い build コマンドの --prod オプションも非推奨になります。

builder options のデフォルト値も変更になっているので、過去バージョンから update した人は angular.json を見直すいい機会かもしれません。

これから v12 にあげる方は下記も参考にしてみてください。 kasaharu.hatenablog.com

style & script

CSS や JS が esbuild や terser を使った最適化によりビルド改善がされています。

また v11.1 で Tailwind CSS に対応するようになりました。これはコミュニティーの声を受けての改善のようです。

Specify custom PostCSS plugins · Issue #8427 · angular/angular-cli · GitHub

他にもインラインスタイルでも SCSS などが記述できるようになった一方で Stylus のサポートが非推奨になったりしています。

ビルドキャッシュ

v12 でオプションで入ったビルドキャッシュが v13 でデフォルトになりました。

Angular 日本語ドキュメンテーション

設定が有効だった場合、一度目のビルド時にキャッシュができるので以降のビルドが早くなります。 Tour of Heroes くらいのアプリケーションでも効果は目に見えてわかるので、ぜひお手元でも確認してみてください。

Protractor と TSLint の非推奨

長年 Angular CLI に組み込まれていた E2E テストライブラリの Protractor の builder が非推奨になり TSLint の builder が削除されました。

angular-cli/README.md at 13.0.0 · angular/angular-cli · GitHub

これからは E2E テストや Linter などは自分で整備していく必要があります。

Angular v13 で新しく環境を作っていく方は昨日の puku0x さんの記事 Angular v13 の開発環境構築 - Qiita が参考になるかもしれません。

テスト

これまで、各テストケース実行時の後処理ができていなかった(生成した DOM を破棄できてきていなかった)ために様々な問題がありました。 特に Karma を使ったテストに影響があったようです。

v12.1 で teardown オプションが追加され、これらの問題が解決できるようになりました。

これについては Improving Angular tests by enabling Angular testing module teardown - DEV Community も参考になります。

その他

エラーメッセージのフォーマットに下記のようなルールができました。

Angular Debugging Guides. The best part of coding is when… | by Emma Twersky | Angular Blog

さらに各エラーの説明やデバッグ方法などが載ったドキュメントも作成されています。

Angular 日本語ドキュメンテーション

また、Angular 専用の公式 DevTools も登場しました。

Angular 日本語ドキュメンテーション

どんどん開発者フレンドリーになっているのを感じます。

まとめ

11.1.0 から 13.0.0 までの個人的に記憶に残った変更点をまとめてみました。

他にもテンプレート構文の強化や Forms / Router の改善などたくさんありましたが、ここでは割愛します。 気になる方は ng-japan OnAir - Youtube を見てみると新発見があるかもしれません。

それでは。