Angular: Testando Deferrable Views
Nesse post vamos entender como testar um dos mais recentes recursos introduzidos no Angular, as Deferrable Views.
Angular: Testando Deferrable Views
Nesse post vamos entender como testar um dos mais recentes recursos introduzidos no Angular, as Deferrable Views.

Contextualizando
Desde a versão 17 o Angular vem passando por um processo de modernização e renascimento, caracterizado pela introdução de uma série de recursos que buscam melhorar a experiência de desenvolvimento, diminuir a curva de aprendizado e tornar o framework mais performático e completo.
Um desses novos recursos foram as Deferrable Views, que nos permite fazer o lazy loading dos elementos da nossa aplicação a nível de template, por exemplo:
@defer {
<app-list [posts]="posts()"/>
} @loading {
<p>Carregando posts...</p>
} @error {
<p>Erro ao tentar carregar posts...</p>
}
Usamos a declaração @defer no nosso template para indicar que tudo que está no bloco entre a sua chave de abertura e fechamento deve ser carregado de forma tardia, nesse exemplo estamos adiando o carregamento de um componente que renderiza uma lista até que os dados estejam disponíveis para ser renderizado.
Podemos ainda declarar um bloco @loading para renderizar um estado de carregamento e um bloco @error para dar um feedback ao usuário caso houver problema ao carregar o componente de lista.
Testando Deferrable Views
Bem, toda essa inclusão de recursos levanta a discussão sobre testes, e com as Deferrable Views não é diferente, e é disso que vamos aprofundar agora.
O Angular gerencia a renderização dos blocos no contexto das Deferrable Views, ele decide quando cada bloco será renderizado para o usuário, no entanto, num contexto de teste onde queremos reproduzir e validar os comportamentos da nossa View o ideal é que tenhamos mais controle sobre isso.
Felizmente o Angular disponibiliza uma API que nos permite disparar os diferentes estados respectivos a cada um desses blocos, por exemplo:
// Renderiza o estado final
await deferBlockFixture.render(DeferBlockState.Complete);
// Renderiza o estado de loading respectivo ao bloco @loading
await deferBlockFixture.render(DeferBlockState.Loading);
// Renderiza o estado de erro respectivo ao bloco @error
await deferBlockFixture.render(DeferBlockState.Error);
// Não incluímos no nosso exemplo, mas
// caso tivesse poderiamos renderizar o estado respectivo
// ao bloco @placeholder
await deferBlockFixture.render(DeferBlockState.Placeholder);
Basicamente, podemos controlar a renderização manualmente e consequentemente controlar o comportamento da nossa View, vamos ver um exemplo completo agora…
Preparando o ambiente
Vamos implementar alguns testes no nosso componente anterior, que serão o seguinte:
- Testar o cenário feliz, onde a lista de posts foi renderizada;
- Testar o cenário infeliz, em que houve um erro ao renderizar a lista;
- Testar o cenário de carregamento, onde o componente de lista ainda está sendo preparado para renderizar;
- E um plus, testando cenário onde a lista carrega com sucesso, porém está vazia.
Porém, antes de começar, precisamos configurar o ambiente, vamos usar o seguinte biblioteca Angular Testing Library e o Jest, para configurar no seu ambiente use os links abaixo:
- Jest: https://timdeschryver.dev/blog/integrate-jest-into-an-angular-application-and-library#
- Angular Testing Library: https://timdeschryver.dev/blog/good-testing-practices-with-angular-testing-library#
Escrevendo os testes
Bora pro primeiro teste, nosso componente responsável por renderizar a lista usa um serviço que requisita dados de uma API, vamos criar um mock para o nosso serviço:
Criando nosso mock
const mockedPosts: Post[] = [
{
"id": 1,
"title": "First Post",
"body": "This is the first post",
"tags": [],
"reactions": {
"likes": 192,
"dislikes": 25
},
"views": 305,
"userId": 121
},
{
"id": 2,
"title": "Second Post",
"body": "This is the second post",
"tags": [],
"reactions": {
"likes": 192,
"dislikes": 25
},
"views": 305,
"userId": 121
},
]
Configurando o teste
describe('AppComponent', () => {
const defaultConfig = {
// Perceba que precisamos mudar o comportamento dos blocos defer
// para manual
deferBlockBehavior: DeferBlockBehavior.Manual,
providers: [
{
provide: PostService,
useValue: {
getPosts() {
return of({
limit: 10,
posts: mockedPosts,
skip: 0,
total: mockedPosts.length
} as GetPostsResponse)
}
}
}
],
}
// ...
Testando o cenário feliz — lista renderizada
it('should display post list', async () => {
const { fixture } = await render(AppComponent, {
...defaultConfig
});
// Obtemos referência ao nosso bloco @defer no template
const deferBlockFixture = (await fixture.getDeferBlocks())[0];
// Renderizamos o estado final
await deferBlockFixture.render(DeferBlockState.Complete);
// Verificamos se os dois itens da lista estão renderizados
expect(screen.getByText(mockedPosts[0].title)).toBeInTheDocument();
expect(screen.getByText(mockedPosts[1].title)).toBeInTheDocument();
});
Testando cenário de carregamento
it('show display loading message while posts are still being fetched', async () => {
const { fixture } = await render(AppComponent, {
...defaultConfig
});
const deferBlockFixture = (await fixture.getDeferBlocks())[0];
await deferBlockFixture.render(DeferBlockState.Loading);
expect(screen.getByText(/Carregando posts.../i)).toBeInTheDocument();
});
Testando o cenário infeliz — erro ao carregar posts
it('show display error message when fetching posts returns an error', async () => {
// Sobrescrevemos o provider para simular
// um erro vindo do PostService usando a função throwError do RxJS
const { fixture } = await render(AppComponent, {
...defaultConfig,
providers: [
{
provide: PostService,
useValue: {
getPosts(){
return throwError(() => new Error('Error on loading posts'))
}
}
}
]
});
const deferBlockFixture = (await fixture.getDeferBlocks())[0];
await deferBlockFixture.render(DeferBlockState.Error);
const errorMsgRegex = /Erro ao tentar carregar posts.../i;
expect(screen.getByText(errorMsgRegex)).toBeInTheDocument();
});
Testando cenário de lista vazia
O nosso componente de lista utiliza o novo Control Flow do Angular, que foi um dos recursos introduzidos nas novas versões.
Aqui usamos a declaração @for para iterar sobre a lista de posts e renderizar cada um dos itens, o interessante é que podemos definir um bloco @empty, que renderiza um conteúdo quando a lista estiver vazia.
<ul>
@for (item of posts(); track item) {
<li data-test="post">
<h2>{{item.title}}</h2>
<p>{{item.body}}</p>
<div>
<span>Views: {{item.views}}</span>
<span>Likes {{item.reactions.likes}}</span>
</div>
</li>
} @empty {
<p>Nenhum post para ser exibido</p>
}
</ul>
E para testar, só precisamos renderizar o estado final do bloco @defer:
it('show display empty state message when fetching posts returns an empty list', async () => {
const { fixture } = await render(AppComponent, {
...defaultConfig,
// Sobrescrevemos o PostService para retornar uma lista vazia
providers: [
{
provide: PostService,
useValue: {
getPosts(){
return of([])
}
}
}
]
});
const deferBlockFixture = (await fixture.getDeferBlocks())[0];
// Renderizando o estado completo do bloco
await deferBlockFixture.render(DeferBlockState.Complete);
const emptyStateMsg = /Nenhum post para ser exibido/i;
expect(screen.getByText(emptyStateMsg)).toBeInTheDocument();
});
Resultado dos nossos testes:

Conclusão
As Deferrable Views são um dos melhores recursos incluídos no Angular nos últimos tempos, com ela podemos adiar o carregamento de componentes, diretivas, pipes e qualquer CSS associado a eles.
E adiar o carregamento também significa que o Angular cria um bundle separado para esses elementos. A API é muito poderosa e recomendo dar uma olhada com mais profundidade, podemos ir muito além, só para mencionar, podemos adiar o carregamento de uma View até a iteração do usuário com a UI, por exemplo.
Os testes nesse recurso também traz desafios, mas com uma API simples a experiência de desenvolvimento dos testes se torna mais suave!
E ai, o que achou ?
Se quiser apoiar o meu trabalho reaja a esse post se te ajudei de alguma forma, compartilhe e me siga por aqui ou nas outras redes pra ficar por dentro dos próximos conteúdos.
Até logo, dev! 😉
메타데이터
- post_id
- 1b45461c5e30
- slug
- angular-testando-deferrable-views-1b45461c5e30
- url
- https://medium.com/@danlima-dev/angular-testando-deferrable-views-1b45461c5e30
- canonical_url
- https://medium.com/@danlima-dev/angular-testando-deferrable-views-1b45461c5e30
- author_url
- https://medium.com/@danlima-dev
- status
- ok
- fetched_at
- 2026-06-24 04:09:36