How can I pass DOCUMENT in Angular?

In my directive, I use dependency injection to access the DOCUMENT and set up an event listener:

constructor(@Inject(DOCUMENT) private document: Document) {}

ngOnInit() {
  this.document.addEventListener('click', this.clicked, true);
}

@Bound // custom decorator, you can ignore it
private clicked() {
  // do stuff
}

Now, I need to write a test that verifies whether the injected document has had the addEventListener method called on it:

it('should add a click event listener to document on ngOnInit', async(() => {

  // Override the template and get the fixture
  overrideAndCompileComponent(LibTestComponent, `
    <div libClickOutsideDocumentListener></div>
  `).then((fixture) => {

    const spy = spyOn<any>(fixture.componentRef.injector.get(Document), 'addEventListener');

    expect(spy).toHaveBeenCalled();
  });
}));

However, when running the test, I encounter the following error:

StaticInjectorError(Platform: core)[Document]

The problem seems to be related to how I'm providing the DOCUMENT. When I include it in the providers array of the TestBed configuration like this:

TestBed.configureTestingModule({
  ... excluded code ...
  providers: [
   { provide: DOCUMENT, useValue: Document }
  ]
});

I receive an internal Angular error:

el.querySelectorAll is not a function

It appears that the value provided for document is incorrect. Despite researching Angular documentation, I haven't found a solution yet.

What am I missing here?

Answer №1

It seems like a bit much to me...

Simplify your workflow by using the host listener decorator:

@HostListener('document:click', ['$event'])
onDocumentClick(event: MouseEvent) { ... }

This eliminates the need to override providers and allows you to focus on testing the function itself, rather than checking if the event listener has been added. By delegating the event listener logic to Angular, you only need to test your own code instead of angular's implementation.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Object.assign versus the assignment operator (i.e. =) when working with React components

Just a quick question: I've come across some answers like this one discussing the variances between Object.assign and the assignment operator (i.e. =) and grasp all the points made such as object copying versus address assignment. I'm trying to ...

The issue of binding subjects in an Angular share service

I established a shared service with the following Subject: totalCostSource$ = new Subject<number>(); shareCost(cost: number ) { this.totalCostSource$.next(cost); } Within my component, I have the following code: private incomeTax: num ...

Local hosting of Angular 8 application with Universal and i18n integration encountered issues

I have integrated Angular Universal into my existing project that already has i18n. I am able to build the project, but facing issues while trying to serve it. Currently, I am encountering the following error: Cannot find module '/home/my-user/my-ap ...

Is there a method to uncover the code that controls the display of a <div> element?

As a fresh face at the company, I've been given the responsibility of developing a chart that is similar to one already present on their website. While I have the knowledge and skills to create it, I am struggling to locate the specific code where the ...

Firebase Functions Project encountering a "Cannot find module" error in VS Code

While working on a firebase functions project in Visual Studio Code, I encountered an issue inside the index.ts file. The imported modules were not being recognized even though autocomplete showed that the modules exist. When attempting to import them, I k ...

Are there any alternatives to ui-ace specifically designed for Angular 2?

I am currently working on an Angular2 project and I'm looking to display my JSON data in an editor. Previously, while working with AngularJS, I was able to achieve this using ui-ace. Here is an example of how I did it: <textarea ui-ace="{ us ...

Using regular expressions, you can locate and replace the second-to-last instance of a dot character in an email address

I'm looking to replace the second last occurrence of a character in a given string. The length of the strings may vary but the delimiter is always the same. Here are some examples along with my attempted solutions: Input 1: james.sam.uri.stackoverflo ...

How can I ensure I am receiving real-time updates from a Resolver Service by subscribing and staying in sync with the

How can I effectively implement this code without encountering an error? "Property 'resolve' in type 'DocumentaryResolverService' is not assignable to the same property in base type 'Resolve'." import { Documentary } from ...

An issue has occurred with ng-material-multilevel-menu: NullInjectorError - MultilevelMenuService provider is missing. This problem is specific to

I have been working with Angular 12 and I am looking to integrate the ng-material-multilevel-menu plugin. Following this link, I tried implementing the multilevel menu. Although it compiled successfully, I encountered an error in the browser. After some ...

"Customizing the template of the Angular Material 2 datepicker: A step-by-step

Looking to make changes to the templates of the angular 2 material date-picker? These templates are located within various internal components in @angular/material/esm5/datepicker.es5.js. One option is to directly modify the template in the node package, ...

Issue with Angular 7: In a ReactiveForm, mat-select does not allow setting a default option without using ngModel

I have a Angular 7 app where I am implementing some reactive forms. The initialization of my reactive form looks like this: private initFormConfig() { return this.formBuilder.group({ modeTransfert: [''], modeChiffrement: [' ...

Leveraging cloud functions on Firebase for maximum efficiency

Question: Do you require a backend language when using Firebase Cloud Functions, or can TypeScript alone suffice for coding tasks like creating a matchmaking system? Response: There seems to be some uncertainty on the matter even from ChatGPT himself. Is ...

Adaptable Style Properties Adjusted by Component Size

Check out this awesome React Native component: const CustomView = (props) => { return ( <View style={{ maxHeight: "100%", width: "100%", aspectRatio: 2, borderWidth: 10, borderCo ...

Exploring the potential of Socket.io and Angular with the seamless integration of

I have encountered an issue regarding the use of async pipe with Observables. Initially, I assumed that returning an Observable from my service on a socket.on event would suffice. However, it appears that my approach is incorrect. Can you guide me on the c ...

Angular error: The property 'component' cannot be read because it is null

I encountered an unusual problem with my route configuration. Here is a snippet of the basic routes: const appRoutes: Routes = [ {path: '', redirectTo: '/search', pathMatch: 'full'}, {path: 'login', component: L ...

Using the -t or --testNamePattern in Jest will execute all tests

Currently, I have set up my testing framework using jest and ts-jest based on the guidelines provided by the ts-jest documentation. When I execute the command yarn test --listTests, I can identify the specific test file I intend to run: processNewUser.ts ...

Error thrown when using React Router DOM: FC{} | ReactNode is not compatible with type ReactNode

Recently, I started using TypeScript and delving into a project that involves the react-router-dom. However, as I attempt to create elements in my App.tsx file, an error keeps popping up. Let's take a look at the code snippet: <Route path="la ...

What is the reason behind having to press the Tab button twice for it to work?

Currently, I am implementing a Tabbed Form with jQuery Functionality in Angular 4. The Tabbed Form itself is functioning, but I've noticed that I have to click the Tab Button twice for it to respond. See the code snippet below: TS declare var jquery ...

The use of credentials is not allowed when the ‘Access-Control-Allow-Origin’ CORS header is set to ‘*’

My Java web application makes CORS requests where the browser performs an OPTIONS preflight before the actual request. The format of each request is as follows: Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:63.0) Gecko/2 ...

I encountered TS2345 error: The argument type X cannot be assigned to the parameter type Y

Currently, I am delving into the world of Angular 8 as a beginner with this framework. In my attempt to design a new user interface with additional elements, I encountered an unexpected linting error after smoothly adding the first two fields. The error m ...