I have an angular component that uses Authorize.nets Accept.js SDK to complete a payment. I don't want to load the Accept.js script unless the user is on the payment screen so I add the script to the page via a method I call on onInit in the component.
some.component.ts
ngOnInit {
this.addAcceptJsScript();
}
private addAcceptJsScript(): void {
const element = document.createElement('script');
element.src = environment.acceptJsUrl;
element.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(element);
}
some.service.ts
declare var Accept: any;
@Injectable()
export class SomeService {
private sendPaymentToAuthNet(paymentPayload): void {
Accept.dispatchData(paymentPayload, this.handleAuthNetResponse);
}
}
This works fine for the users as the script is loaded in the DOM and available when the component calls the service that uses the Accept API
However my unit test in the service that uses the API doesn't have any reference to what Accept is so when it tries to test the line of code where I call Accept.dispatchData(...) the test errors out saying 'Reference Error: Accept is not defined".
I have tried various ways of mocking Accept but none of them make it available to the test. How do I go about injecting my mock Accept into the service so that it's declared when the code tries to use it?
Problems with testing usually indicate flaws in application design.
documentpreferably should be a provider, because it is supposed to be mocked at some point to avoid adding script elements to real DOM. There isDOCUMENTprovider already that can be injected into the component instead ofdocumentglobal. And be mocked in test bed:Where
createElementandgetElementsByTagNameJasmine spies should be configured to return proper mock objects.Acceptshould be made a provider for testability reasons as well. The value can be assigned towindow['Accept']as shown in this answer and be mocked in test bed.