Angular Testing Library - Casos de Uso
Published: 2023-01-23 21:07:40

### Verificar que redireccione a una URL

```javascript
it('...', async () => {
  const spyRouter = jest.spyOn(Router.prototype, 'navigate')
  await setupComponent()
  ...
  expect(spyRouter).toHaveBeenCalledWith(['/stores'])
})
```
---

### Emular datos adquiridos por la URL

Para poder simular un id como dato ingresado por url (`Ej. www.my-web.com/users/edit/1`).

Debemos utilizar la clase stub `ActivatedRouteStub` que fué creado para simular datos de entrada por URL. Esta clase se le puede pasar lo siguiente:

```javascript
new ActivatedRouteStub({
  initialParams: {
    id: '1', // Ej de URL: /user/edit/:id
  },
  initialQueryParams: {
    page: '1' // Ej de URL: /user/list?page=1
  }
})
```

Esta clase se puede poner al inicio del renderizado del componente `setupComponent()` o en la zona de test

```javascript
// Opción 1: En el renderizado del componente
async function setupComponent() {
  return await render(UsersUpsertComponent, {
    declarations: [...],
    imports: [...],
    providers: [
      ...
      {
        provide: ActivatedRoute,
        useValue: new ActivatedRouteStub({
          initialParams: {
            id: '1',
          },
        }),
      },
    ],
  })
}
```

```javascript
// Opción 2: En la zona de test
async function setupComponent(params: { id?: string; zoneId?: string } = {}) {
  const initialParams = {
    id: '3157',
    ...params,
  }
  return await render(DeliveryZoneUpsertComponent, {
    declarations: [...],
    imports: [...],
    providers: [
      ...
      {
        provide: ActivatedRoute,
        useValue: new ActivatedRouteStub({ initialParams }),
      },
    ],
  })
}

it('...', () => {
  const initialParams = {
    id: '3157',
    zoneId: '445',
  }
  const { fixture } = await setupComponent(initialParams)
  
  ... actions ...
  ... assertions ...
})
```
---

### Captura de un elemento y ejecutar un evento

#### Mat-Toogle

Capturar el `input` dentro del `mat-toggle`

```javascript
const toggle = screen.getByTestId('productList_productDisplay0Enabled0_toggle-input')
```

Ejecutar el evento change con `fireEvent()`

```javascript
// Debemos capturar el input que está dentro del 'mat-toggle'
const toggle = screen.getByTestId('productList_productDisplay0Enabled0_toggle-input')
fireEvent.change(toggle, {
  target: { checked: false },
})
```

Ejecutar el evento click con `userEvent()`

```javascript
const user = userEvent.setup()
// Debemos capturar el 'mat-toggle' como tal.
const toggleEnabled = screen.getByTestId('[ELEMENT_ID]')

await user.click(toggleEnabled)
expect(toggleEnabled).toHaveAttribute('ng-reflect-checked', 'false')
```

#### Mat-Select

Capturar el elemento

```javascript
// Por su ID
const select = screen.getByTestId('[ELEMENT_ID]')

// Por su Rol
const select = screen.getByRole('combobox', { name: /List/i })
```

Ejecutar el evento `select` con `userEvent()`

```javascript
const user = userEvent.setup()
const { fixture } = await setupComponent()
const select = screen.getByRole('combobox', { name: /List/i })

await user.click(select)
await user.click(screen.getByText(/Minimarket/i))

... assertions ...
```
> Para este caso no se puede usar `fireEvent()` directamente ya que el `mat-select` no contiene un select nativo HTML 

#### Mat-Input

Capturar el elemento

```javascript
//Por su ID
const input = screen.getByTestId('[ELEMENT_ID]')

//Por su label
const input = screen.getByLabelText(/Minimum order amount/i)
```

Ejecutar el evento `input` usando `fireEvent()`

```javascript
const input = screen.getByTestId('products_searchValue_input')
fireEvent.input(input, { target: { value: 'foo' } })

... assertions ...
```

Ejecutar el evento `type` usando `userEvent()`

```javascript
const user = userEvent.setup()
const legalName = screen.getByTestId('[ELEMENT_ID]')
user.type(legalName, 'Kirby')

... assertions ...
```

#### Mat-Button

Capturar el elemento

```javascript
//Por su ID
const button = screen.getByTestId('app_save_button')

//Por su label del button
const button = screen.getByText(/Save/i)
```
---

### Emular retorno de datos en un Modal

Para este caso debemos usar el stub `test/__stubs__/MatDialogStub` que es un clase que emula el retorno de datos de un modal y se implementa llamando a la clase `MatDialogStub` en el archivo `.spec` donde se monta el componente a testear.

```javascript
//component.spec.ts

async function setupComponent() {
  return await render(ApiIntegrationComponent, {
    declarations: [],
    imports: [],
    providers: [
      // Se implementa el Stub
      { provide: MatDialog, useValue: new MatDialogStub() },
      ...
    ],
    schemas: [CUSTOM_ELEMENTS_SCHEMA],
  })
}

describe('...', () => {
  it('Should create component correctly', async () => {
    const { fixture } = await setupComponent()
    ...
  })
})
```

Por defecto la clase `MatDialogStub()` retorna `true`. Si queremos retornar otro valor, entonces sería de esta manera.

```javascript
providers: [
  { provide: MatDialog, useValue: new MatDialogStub({
      name: 'Foo',
      age: 23
    })
  },
  ...
],
```