Ok, I have something that's working and ready for you to take a look at, essentially the approach is to separate presentation testing from business logic, I tested the contracts between components/providers to ensure the correct methods are being called internally.
This is repeated across all relevant components, this is testing solely the logic behind the buttons.
In e2e, I've tested to ensure the modal displays, and the buttons are present, admittedly you'd also want to ensure the modal disappears and the buttons also disappear and are no longer enabled, but I'm sure you're not looking for a complete example here.
This is a separation of concerns, keeping logic away from your UI. As I mentioned in my above comment, I'd personally opt to use unit testing for only my logic, and e2e testing on the UI components (ensuring that if you hit a button, it'll retrieve from a service or whatever your intention may be).
Anyway, enough talk, more code. I'll post a few examples for anyone who finds themselves in a similar position to OP. Github link at the bottom.
Unit testing would look similar to:
it('.reject() should call activeModal with false', async () => {
spyOn(activeModal, 'close').and.returnValue(null);
expect(component.decline()).toBeUndefined();
expect(activeModal.close).toHaveBeenCalledTimes(1);
expect(activeModal.close).toHaveBeenCalledWith(false);
});
And:
it('should return the correct result of a Modal (object is correct, calls internal modal)', async () => {
const mock = {
componentInstance: {
title: 'Are you sure?',
message: 'Are you actually sure though?',
btnOkText: 'OK',
btnCancelText: 'Cancel',
},
result: true,
};
spyOn(modal, 'open').and.returnValue(mock as any);
const result = await service.confirm(
mock.componentInstance.title,
mock.componentInstance.message
);
expect(result).toBe(mock.result);
expect(modal.open).toHaveBeenCalledTimes(1);
expect(modal.open).toHaveBeenCalledWith(ModalComponent, { size: 'sm' });
});
Whereas, my e2e testing would look more like:
it('should have an Open button on the home page, the button should open a modal with an OK option (returning TRUE)', async () => {
page.navigateTo();
const button = await page.getButton();
expect(button.getText()).toBe('Open');
await button.click();
const modal = await page.getConfirmationModal();
expect(await modal.isEnabled()).toBeTruthy();
const acceptBtn = await page.getAcceptButton();
expect(await acceptBtn.isDisplayed()).toBeTruthy();
expect(await acceptBtn.isEnabled()).toBeTruthy();
expect(await acceptBtn.getText()).toBe('OK');
await acceptBtn.click();
});
It's not the most elegant testing (if I took more time it'd test more areas, but I'm sure you can get that bit).
I'll also say, this way isn't strictly right, technology in general isn't really about right and wrong, however, I'm not entirely sure how analysing DOM events would work in unit testing.
Although testing the logic is entirely possible (sort of the purpose (IMO)).
https://github.com/Isolated-/angular-dialog-example-stack-overflow
I hope this in someway helped to resolve your frustration, if I've got the wrong idea let me know and I'll correct it!