0

I am using stand alone components in a lazy loaded route for my angular app. When I ng serve the app, everything works properly. The main app is using modules, but all other comps are stand alone.

The problem is when I try to use Cyprus component testing for one of these lazy stand alone components.

The component that generates an error uses material ui elements (table, inputs, sort, pagination etc). Something in this component giving me the following error during testing:

(uncaught exception)Error: Unexpected synthetic listener @arrowPosition.start found. Please make sure that:

  • Either BrowserAnimationsModule or NoopAnimationsModule are imported in your application.
  • There is corresponding configuration for the animation named @arrowPosition.start defined in the animations field of the @Component decorator

here is my comp code:

import {
  AfterViewInit, ChangeDetectionStrategy, Component, EventEmitter, Input, Output,
  ViewChild,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { MatPaginator } from '@angular/material/paginator';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSort, MatSortModule } from '@angular/material/sort';
import { PersonalRecordListItem } from '@t3/data/domain/shared';
import { PrimaryContentCardComponent } from '@t3/training-tracker-web/ui-shared';
import { MatInputModule } from '@angular/material/input';

@Component({
  selector: 't3-personal-records-list',
  imports: [
    CommonModule,
    MatTableModule,
    MatPaginatorModule,
    MatSortModule,
    MatInputModule,
    PrimaryContentCardComponent,
  ],
  templateUrl: './personal-records-list.component.html',
  styleUrls: ['./personal-records-list.component.scss'],
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class PersonalRecordsListComponent implements AfterViewInit {
  @ViewChild(MatPaginator)
  paginator!: MatPaginator;
  @ViewChild(MatSort) sort!: MatSort;

  @Input() tabelData: PersonalRecordListItem[] = [];
  @Output() selectedRowChanged = new EventEmitter<string>();

  dataSource = new MatTableDataSource<PersonalRecordListItem>();
  displayedColumns: string[] = ['date', 'name', 'displayValue'];

  ngAfterViewInit() {
    this.dataSource = new MatTableDataSource(this.tabelData);
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
  }

  applyFilter(event: Event) {
    const filterValue = (event.target as HTMLInputElement).value;
    this.dataSource.filter = filterValue.trim().toLowerCase();

    if (this.dataSource.paginator) {
      this.dataSource.paginator.firstPage();
    }
  }

  selectRow(rowItem: PersonalRecordListItem) {
    this.selectedRowChanged.emit(rowItem.id);
  }
}

So I tried to add the following to the component declaration:

providers: [provideAnimations()],

but the error remains

If I add BrowserAnimationsModule to the component imports I get the following error:

Providers from the BrowserModule have already been loaded. If you need access to common directives such as NgIf and NgFor, import the CommonModule instead.

BrowserAnimationsModule is imported into the main app.module so that is why the error does not appear when serving the app, only when testing its stand alone components

EDIT 1:

I tired to add provideAnimations() to the cy.ts file:

describe(PersonalRecordsListComponent.name, () => {
  beforeEach(() => {
    TestBed.overrideComponent(PersonalRecordsListComponent, {
      add: {
        imports: [],
        providers: [provideAnimations()],
      },
    });
  });

This does not solve the error.

If I add AnimationsModule to the cypress file like this:

    imports: [BrowserAnimationsModule],
    providers: [],

I get the already provided error I mentioned above.

Can someone help me get Cyprus component testing working here?

J King
  • 4,108
  • 10
  • 53
  • 103
  • Hi, did you find a solution for this? I have the same problem where I need to add providers for ngxs store to be used by a standalone component. – Andre May 22 '23 at 20:22

1 Answers1

1

The way you can solve this is to add the NoopAnimationsModule to your cypress test file. I don't use a Testbed with Cypress component testing, but you could do it that way:

beforeEach(() => {
    TestBed.overrideComponent(PersonalRecordsListComponent, {
      add: {
        imports: [NoopAnimationsModule],
      },
    });
  });

If the above does not work, try the following: In your project you should have a cypress folder. Within that folder there is a file: 'commands.ts'

/cypress
|- /downloads
|- /fixtures
|- /support
|--- commands.ts // this is where you want to go
|--- component.ts

If I'm not mistaken, this is setup automatically, but nonetheless, lets check if it is.

Within that file you can declare custom commands and add typings for them so you can use them.

What we are looking for is the 'mount' command. So the file should look at least something like this:

/// <reference types="cypress" />
import {mount} from 'cypress/angular'

// ***********************************************
// This example commands.ts shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
declare global {
  namespace Cypress {
    interface Chainable<Subject> {
      mount: typeof mount;
    }
  }
}

Cypress.Commands.add('mount', mount)

With the mount function of cypress, you can easily mount the component and add the necessary imports, declarations etc. With this you could change your code to look something like this:

describe(PersonalRecordsListComponent.name, () => {
  beforeEach(() => {
    cy.mount(PersonalRecordsListComponent, {
      imports: [NoopAnimationsModule, YourMaterialModules]
    })    
  });

  // your tests here

}

With the NoopAnimationsModule imported, you should not experience any issues regarding the Material UI Components. And don't forget to replace YourMaterialModules with any material modules your component relies on.

Hope this helps!

Safe
  • 11
  • 3