I haven't found much help on the internet on how to do tests on directives with cypress. I have done tests before on a lot of components. but I am quite 'stupidly' stuck here. I have done only few lines. I don't know if I am supposed to test the methods as I do with components or just test the html. Here is the directive I am supposed to test : @Directive({ selector: '[style-paginator]' }) export class StylePaginatorDirective implements OnInit, OnChanges { private _pageGapTxt = '...'; private _rangeStart: number; private _rangeEnd: number; private _isPaginatorReady = false; private _buttons = []; private _curPageObj: PageObject = { length: 0, pageIndex: 0, pageSize: 0, previousPageIndex: 0, }; private _showTotalPages = 2; @Input() get showTotalPages(): number { return this._showTotalPages; } @Input() dataLength: number; set showTotalPages(value: number) { this._showTotalPages = value % 2 == 0 ? value + 1 : value; } get inc(): number { return this._showTotalPages % 2 == 0 ? this.showTotalPages / 2 : (this.showTotalPages - 1) / 2; } get numOfPages(): number { return this.matPag.getNumberOfPages(); } get lastPageIndex(): number { return this.matPag.getNumberOfPages() - 1; } constructor( @Host() @Self() @Optional() private readonly matPag: MatPaginator, private vr: ViewContainerRef, private ren: Renderer2, private translate: TranslateService ) { //to rerender buttons on items per page change and first, last, next and prior buttons this.matPag.page.subscribe((e: PageObject) => { if ( this._curPageObj.pageSize != e.pageSize && this._curPageObj.pageIndex != 0 ) { e.pageIndex = 0; this._rangeStart = 0; this._rangeEnd = this._showTotalPages - 1; } this._curPageObj = e; this.initPageRange(); }); // On fait un setTimeOut pour que le component finisse le rendering des éléments avant d'ajouter les boutons du paginateur /* setTimeout(() => { this._rangeStart = 0; this._rangeEnd = this._showTotalPages - 1; this.initPageRange(); }, 500); */ } ngOnChanges(changes: SimpleChanges): void { this._rangeStart = 0; this._rangeEnd = this._showTotalPages - 1; this.initPageRange(); } private buildPageNumbers() { // On ajoute la classe table-paginator au mat-paginator this.ren.addClass(this.vr.element.nativeElement, 'table-paginator'); const actionContainer = this.vr.element.nativeElement.querySelector( 'div.mat-mdc-paginator-range-actions' ); const nextPageNode = this.vr.element.nativeElement.querySelector( 'button.mat-mdc-paginator-navigation-next' ); const prevButtonCount = this._buttons.length; // Ajout de la classe paginator-range-label sur le label qui affiche le compteur des éléments actuellement affichés if (this.vr.element.nativeElement.querySelector('div.mat-mdc-paginator-range-label')){ setTimeout(() => { this.ren.addClass(this.vr.element.nativeElement.querySelector('div.mat-mdc-paginator-range-label'), 'paginator-range-label'); this.ren.addClass(this.vr.element.nativeElement.querySelector('div.mat-mdc-select-value'), 'paginator-page-size-value'); this.ren.addClass(this.vr.element.nativeElement.querySelector('div[matformfieldnotchedoutline]'), 'paginator-page-size-default-outline'); this.ren.addClass(this.vr.element.nativeElement.querySelector('div.mat-mdc-form-field-flex'), 'paginator-page-size-form-field-flex'); this.ren.addClass(this.vr.element.nativeElement.querySelector('mat-form-field'), 'paginator-page-size-form-field'); this.ren.addClass(this.vr.element.nativeElement.querySelector('.mat-mdc-paginator-page-size-label'), 'paginator-page-size-label'); this.ren.addClass(this.vr.element.nativeElement.querySelector('.mat-mdc-select-arrow-wrapper'), 'paginator-page-size-arrow-wrapper'); this.ren.addClass(this.vr.element.nativeElement.querySelector('.mat-mdc-select-arrow'), 'paginator-page-size-arrow'); this.ren.addClass(this.vr.element.nativeElement.querySelector('div.mat-mdc-paginator-container'), 'paginator-container'); this.vr.element.nativeElement.querySelector('.paginator-page-size-label').innerHTML = this.translate.instant('ITEMS_PER_PAGE'); const pageSizeArrow = this.vr.element.nativeElement.querySelector('.mat-mdc-select-arrow'); const arrowSvg = pageSizeArrow.childNodes[0]; const arrowImg = this.ren.createElement('img'); this.ren.addClass(arrowImg, 'icon-paginator-select-page'); this.ren.insertBefore(pageSizeArrow, arrowImg, arrowSvg); this.ren.removeChild(pageSizeArrow, arrowSvg); // remove buttons before creating new ones if (this._buttons.length > 0) { this._buttons.forEach((button) => { this.ren.removeChild(actionContainer, button); }); //Empty state array this._buttons.length = 0; } //initialize next page and last page buttons if (this._buttons.length == 0) { let nodeArray = this.vr.element.nativeElement.childNodes[0].childNodes[0].childNodes[2] .childNodes; setTimeout(() => { for (let i = 0; i < nodeArray.length; i++) { if (nodeArray.nodeName === 'BUTTON') { if (nodeArray.innerHTML.length > 100 && nodeArray.disabled) { this.ren.addClass(nodeArray, 'paginator-navigation-next-previous'); } else if ( nodeArray.innerHTML.length > 100 && !nodeArray.disabled ) { this.ren.addClass(nodeArray, 'paginator-navigation-next-previous'); } } } }); } // On affiche toujours la première page si elle n'est pas déjà visible if (this._rangeStart >= 1) this.ren.insertBefore( actionContainer, this.createFirstPageButton(), nextPageNode ); // On affiche toujours '...' au début si la deuxième page n'est pas visible if (this._rangeStart > 1) this.ren.insertBefore( actionContainer, this.createFirstThreeDots(), nextPageNode ) // On affiche tous les boutons sauf la dernière for (let i = 0; i < this.numOfPages; i++) { this._isPaginatorReady = true; if (i >= this._rangeStart && i <= this._rangeEnd) { this.ren.insertBefore( actionContainer, this.createButton(i, this.matPag.pageIndex), nextPageNode ); } // Enfin on ajoute '...' (si l'avant dernière page n'est pas visible) if (i == this._rangeEnd) { this.ren.insertBefore( actionContainer, this.createButton(this._pageGapTxt, this._rangeEnd), nextPageNode ); } } // On ajoute toujours la dernière page sauf si elle déja visible if (this._rangeEnd < this.lastPageIndex) this.ren.insertBefore( actionContainer, this.createLastPageButton(), nextPageNode ) },2); } } private createFirstPageButton() { const linkBtn: MatButton = this.ren.createElement('button'); this.ren.addClass(linkBtn, 'paginator-navigation-page'); const text = this.ren.createText(1 + ''); this.ren.listen(linkBtn, 'click', () => { this.switchPage(0); }); this.ren.appendChild(linkBtn, text); //Add button to private array for state this._buttons.push(linkBtn); return linkBtn; } private createFirstThreeDots() { const linkBtn: MatButton = this.ren.createElement('button'); this.ren.addClass(linkBtn, 'paginator-navigation-page'); const text = this.ren.createText(this._pageGapTxt); let newIndex = this._rangeStart-1; if (newIndex < 0) newIndex = 0; this.ren.listen(linkBtn, 'click', () => { this.switchPage(newIndex); }); this.ren.appendChild(linkBtn, text); //Add button to private array for state this._buttons.push(linkBtn); return linkBtn } private createLastPageButton() { const linkBtn: MatButton = this.ren.createElement('button'); this.ren.addClass(linkBtn, 'paginator-navigation-page'); const text = this.ren.createText(this.lastPageIndex + 1 + ''); this.ren.listen(linkBtn, 'click', () => { this.switchPage(this.lastPageIndex); }); this.ren.appendChild(linkBtn, text); //Add button to private array for state this._buttons.push(linkBtn); return linkBtn; } private createButton(i: any, pageIndex: number): any { const linkBtn: MatButton = this.ren.createElement('button'); //this.ren.addClass(linkBtn, "mat-mini-fab"); this.ren.addClass(linkBtn, 'paginator-navigation-page'); const pagingTxt = isNaN(i) ? this._pageGapTxt : +(i + 1); const text = this.ren.createText(pagingTxt + ''); switch (i) { case pageIndex: this.ren.setAttribute(linkBtn, 'disabled', 'disabled'); this.ren.addClass(linkBtn, 'page-active'); break; case this._pageGapTxt: let newIndex = this._rangeEnd + 1; if (newIndex >= this.numOfPages) newIndex = this.lastPageIndex; if (pageIndex != this.lastPageIndex) { this.ren.setStyle(linkBtn, 'display', 'inline-block'); this.ren.listen(linkBtn, 'click', () => { this.switchPage(newIndex); }); } if (pageIndex == this.lastPageIndex || pageIndex == this.lastPageIndex-1) { this.ren.setAttribute(linkBtn, 'disabled', 'disabled'); this.ren.setStyle(linkBtn, 'display', 'none'); } break; default: this.ren.listen(linkBtn, 'click', () => { this.switchPage(i); }); break; } this.ren.appendChild(linkBtn, text); //Add button to private array for state this._buttons.push(linkBtn); return linkBtn; } //calculates the button range based on class input parameters and based on current page index value. Used to render new buttons after event. private initPageRange(): void { const middleIndex = (this._rangeStart + this._rangeEnd) / 2; this._rangeStart = this.calcRangeStart(middleIndex); this._rangeEnd = this.calcRangeEnd(middleIndex); this.buildPageNumbers(); } //Helper function To calculate start of button range private calcRangeStart(middleIndex: number): number { switch (true) { case this._curPageObj.pageIndex == 0 && this._rangeStart != 0: return 0; case this._curPageObj.pageIndex > this._rangeEnd: return this._curPageObj.pageIndex + this.inc > this.lastPageIndex ? this.lastPageIndex - this.inc * 2 : this._curPageObj.pageIndex - this.inc; case this._curPageObj.pageIndex > this._curPageObj.previousPageIndex && this._curPageObj.pageIndex > middleIndex && this._rangeEnd < this.lastPageIndex: return this._rangeStart + 1; case this._curPageObj.pageIndex < this._curPageObj.previousPageIndex && this._curPageObj.pageIndex < middleIndex && this._rangeStart > 0: return this._rangeStart - 1; default: return this._rangeStart; } } //Helpter function to calculate end of button range private calcRangeEnd(middleIndex: number): number { switch (true) { case this._curPageObj.pageIndex == 0 && this._rangeEnd != this._showTotalPages: return this._showTotalPages - 1; case this._curPageObj.pageIndex > this._rangeEnd: return this._curPageObj.pageIndex + this.inc > this.lastPageIndex ? this.lastPageIndex : this._curPageObj.pageIndex + 1; case this._curPageObj.pageIndex > this._curPageObj.previousPageIndex && this._curPageObj.pageIndex > middleIndex && this._rangeEnd < this.lastPageIndex: return this._rangeEnd + 1; case this._curPageObj.pageIndex < this._curPageObj.previousPageIndex && this._curPageObj.pageIndex < middleIndex && this._rangeStart >= 0 && this._rangeEnd > this._showTotalPages - 1: return this._rangeEnd - 1; default: return this._rangeEnd; } } //Helper function to switch page on non first, last, next and previous buttons only. private switchPage(i: number): void { const previousPageIndex = this.matPag.pageIndex; this.matPag.pageIndex = i; this.matPag['_emitPageEvent'](previousPageIndex); this.initPageRange(); } //Initialize default state after view init public ngOnInit() { const interval = setInterval(() => { if (!this._isPaginatorReady) { this._rangeStart = 0; this._rangeEnd = this._showTotalPages - 1; this.initPageRange(); } else clearInterval(interval); }, 300); } } Here is what i have done so far, which is basically nothing. @Component({ template: ` <mat-paginator [length]="100" [pageSize]="10" [pageIndex]="0" data-cy="paginator"></mat-paginator> <div data-cy="buttons"> <ng-container *ngFor="let button of buttons"> <div class="paginator-navigation-page" data-cy="page-button">{{ button }}</div> </ng-container> </div> `, }) class TestPaginatorComponent { buttons: string[] = []; } const mockTranslateService = { get: (key: string) => key, instant: (key: string) => key, use: () => {}, }; describe('StylePaginatorDirective', () => { it('should display the paginator and navigate between pages', fakeAsync(() => { cy.mount(TestPaginatorComponent, { declarations: [StylePaginatorDirective], imports: [ MatPaginatorModule, NoopAnimationsModule, TranslateModule.forRoot(), ], providers: [ { provide: TranslateService, useValue: mockTranslateService }, ] }); cy.get('[data-cy=paginator]').should('be.visible'); cy.get('.mat-mdc-paginator-range-label').should('contain', '1 – 10 of 100'); cy.get('button.mat-mdc-paginator-navigation-next') .should('be.visible') .click(); cy.get('.mat-mdc-paginator-range-label').should('contain', '11 – 20 of 100'); cy.get('button.mat-mdc-paginator-navigation-previous').click(); cy.get('.mat-mdc-paginator-range-label').should('contain', '1 – 10 of 100'); })); }); Continue reading...