Topic: Unable to query a mdb 5 pro element from the DOM in angular 13 unit tests
Felix Wu priority asked 2 years ago
I have a unit test to check if a dialog opens after a button click, but I have been unable to query an MDB element (the dialog content) from the DOM. I am not sure about all configurations at tsconfig.spec.json either.
this is my tsconfig.spec.json:
{ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./out-tsc/spec", "types": ["jasmine"] }, "files": ["src/test.ts", "src/polyfills.ts"], "include": [ "src//.spec.ts", "src//.d.ts", "../node_modules/angular-bootstrap-md/index.ts", "../node_modules/ng-mdb-pro/*_/_.ts" ]}
And this is my test:
*_Expected behavior_*fit(should open a dialog when the button is clicked
, () => {
const button: HTMLElement = fixture.nativeElement.querySelector('.ms-auto');
button.click();
fixture.detectChanges();
const dialog: HTMLElement = document.body.querySelector('.modal-content')!;
expect(dialog).toBeTruthy();
});
Actual behavior
the const dialog is null :(
Resources (screenshots, code snippets etc.)
Thanks a lot for any help provided.
Michał Duszak staff answered 2 years ago
Hello, I was unable to reproduce this issue. I tried the same tsconfig.spec.json
as yours. Here is my spec.ts
working code:
import {
ComponentFixture,
fakeAsync,
TestBed,
tick,
} from '@angular/core/testing';
import { Component, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { MdbModalModule, MdbModalService } from 'mdb-angular-ui-kit/modal';
@Component({
template: `
<button class="ms-auto" type="filled" (click)="openStoreDialog()">
Add a Store
</button>
`,
providers: [MdbModalService],
})
class BasicComponent {
constructor(public dialog: MdbModalService) {}
modalRef;
openStoreDialog = () => {
this.modalRef = this.dialog.open(DialogCreateStoreComponent, {
modalClass: 'modal-dialog-centered',
ignoreBackdropClick: true,
});
};
}
@Component({
template: `
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button
type="button"
class="btn-close"
aria-label="Close"
(click)="modalRef.close()"
></button>
</div>
<div class="modal-body">...</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="modalRef.close()">
Close
</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
`,
providers: [MdbModalService],
})
class DialogCreateStoreComponent {
constructor() {}
}
@NgModule({
declarations: [BasicComponent, DialogCreateStoreComponent],
imports: [BrowserModule],
})
class TestModalModule {}
describe('MDB Modal', () => {
let fixture: ComponentFixture<BasicComponent>;
beforeEach(fakeAsync(() => {
const module = TestBed.configureTestingModule({
imports: [MdbModalModule, TestModalModule],
teardown: { destroyAfterEach: false },
});
TestBed.compileComponents();
fixture = module.createComponent(BasicComponent);
}));
it('should open a dialog when the button is clicked', fakeAsync(() => {
const button: HTMLElement = fixture.nativeElement.querySelector('.ms-auto');
button.click();
fixture.detectChanges();
tick(350);
const dialog: HTMLElement = document.body.querySelector('.modal-content')!;
expect(dialog).toBeTruthy();
}));
});
Felix Wu priority commented 2 years ago
Thanks, Michal, but it did not work on my side :(
Michał Duszak staff commented 2 years ago
Could you reproduce this issue in a new project, so that I could directly face this error?
Felix Wu priority answered 2 years ago
<div class="container-fluid d-flex flex-column px-5 py-5">
<div class="d-flex flex-row align-items-center">
<h1>Stores</h1>
<app-button-primary
class="ms-auto"
type="filled"
(click)="openStoreDialog()"
>
Add a Store
</app-button-primary>
<input
mdbInput
type="search"
class="form-control rounded border-0"
placeholder="Ex. Giant Food."
aria-label="Ex. Giant Food."
aria-describedby="search-addon"
id="search-input"
(keyup)="search($event)"
(search)="this.clearInputSearchbar($event)"
/>
</div>
</mdb-form-control>
{{ header | titlecase }}
<tbody
class="datatable-body"
*ngIf="table.data?.length! >= 1; else noMatches"
id="storeTableBody"
>
<tr
*ngFor="let data of table.data"
scope="row"
(click)="this.onClickItem(data.fkey)"
class="clickable"
>
<td>
{{ data.name }}
</td>
<td>
{{ data.address }}
</td>
<td>
{{ data.region }}
</td>
<td>
{{ data.lastVisit | date: "dd/MM/YYYY HH:mm a" }}
</td>
<td>
{{ data.products }}
{{ data.products > 1 ? "products" : "product" }}
</td>
<td><i class="fa-solid fa-ellipsis-vertical"></i></td>
</tr>
</tbody>
</table>
No matching results found
Felix Wu priority answered 2 years ago
After importing MdbModalService...
openStoreDialog = () => {
this.modalRef = this.dialog.open(DialogCreateStoreComponent, {
modalClass: 'modal-dialog-centered',
ignoreBackdropClick: true,
});
};
Michał Duszak staff commented 2 years ago
Is DialogCreateStoreComponent a valid component? Does it contain a template with valid Modal element? Could you check if modal from DialogCreateStoreComponent injects to the DOM using console.log(document.body.innerHTML) like in the code below? Any errors are thrown during the tests?
it('should open a dialog when the button is clicked', () => { const button:
HTMLElement = fixture.nativeElement.querySelector('.ms-auto');
button.click();
fixture.detectChanges();
console.log(document.body.innerHTML)
const dialog: HTMLElement = document.body.querySelector('.modal-content')!;
expect(dialog).toBeTruthy();
});
Felix Wu priority commented 2 years ago
Hello Michal,
yes, it is a valid component and there is no issue with the functionality. When I open it, it is there in the DOM and no errors are thrown. The problem with the unit test is when I query the nativeElement, the constant dialog is null and the test fails. I am not sure about the tsconfigspec.json either. What do I need to have there regarding mdb?
Thanks again.
Michał Duszak staff commented 2 years ago
Can you try running this test in fakeAsync so that we can wait until the animation ends?
it('should open a dialog when the button is clicked', fakeAsync(() => {
const button: HTMLElement = fixture.nativeElement.querySelector('.ms-auto');
button.click();
fixture.detectChanges();
tick(350);
const dialog: HTMLElement = document.body.querySelector('.modal-content')!;
expect(dialog).toBeTruthy();
}));
Felix Wu priority commented 2 years ago
I had already tried with fakeAsync, done, and waitForAsync...this is the test with fakeAsync:
last expect still fails:
`
it(should open a dialog when the button 'Add a Store' is clicked\
, fakeAsync(() => { const button: HTMLElement = fixture.nativeElement.querySelector('.ms-auto');
button.click();
fixture.detectChanges();
flush();
const dialog: HTMLElement =
fixture.nativeElement.querySelector('.modal-content')!;
expect(fakeDialogService.open).toHaveBeenCalledTimes(1);
expect(dialog).toBeTruthy();
}));`
FREE CONSULTATION
Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.
Answered
- ForumUser: Priority
- Premium support: Yes
- Technology: MDB Angular
- MDB Version: MDB5 1.3.0
- Device: mac os
- Browser: chrome
- OS: ios
- Provided sample code: Yes
- Provided link: No
Michał Duszak staff commented 2 years ago
Hi, could you please share your template and component code related to this test?
Felix Wu priority commented 2 years ago
Hi Michal, Thanks for reaching out to me. The code samples are below.