angulartypescriptgoogle-maps-api-3karma-runnerangular-google-maps

Angular Google Maps Karma Testing


I updated an Angular project (8 -> 11) and the dependencies. Previously the project used the the @agm/core (https://github.com/SebastianM/angular-google-maps) package, which is not compatible with Angular 11. So I replaced it and followed the suggestions to use the @angular/google-maps directly. Not a big deal, everything working as expected except the tests.

The map is part of an component and the Google API ist loaded there (with prevention of loading it multiple times):

import { Component, OnInit, ViewChild } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { environment } from 'src/environments/environment';
import { GoogleMap } from '@angular/google-maps';

@Component({
  selector: 'app-map',
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.scss']
})
export class MapComponent implements OnInit {

  @ViewChild(GoogleMap, { static: false }) map: GoogleMap;

  apiLoaded: Observable<boolean>;

  constructor(httpClient: HttpClient) {
    if (window.google === undefined) {
      this.apiLoaded = httpClient.jsonp(`https://maps.googleapis.com/maps/api/js?key=${environment.googleAPIKey}`, 'callback')
          .pipe(
            // Doing preparation stuff
          );
    }
    else {
      this.apiLoaded = of(true);
    }
  }

}

Running ng serve everything is working as expected. But as there are already a lot of tests I ran into problems running ng test:

Unhandled promise rejection: InvalidValueError: ng_jsonp_callback_0 is not a function
error properties: null({ constructor: Function })
Error: 
    at new ge (https://maps.googleapis.com/maps/api/js?key=<api-key>&callback=ng_jsonp_callback_0:70:72)
    at Object._.he (https://maps.googleapis.com/maps/api/js?key=<api-key>&callback=ng_jsonp_callback_0:70:182)
    at Nj (https://maps.googleapis.com/maps/api/js?key=<api-key>&callback=ng_jsonp_callback_0:146:233)
    at https://maps.googleapis.com/maps/api/js?key=<api-key>&callback=ng_jsonp_callback_0:146:118
    at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:364:1)
    at Zone.run (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:123:1)
    at http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:857:1
    at ZoneDelegate.invokeTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:399:1)
    at Zone.runTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:167:1)
    at drainMicroTaskQueue (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:569:1)

So I guess the Google API is not present during the test. I tried the following things already without any success:

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
    files: [
      'https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY'
    ],
  beforeEach(waitForAsync(() => {
    httpClient.jsonp(`https://maps.googleapis.com/maps/api/js?key=${environment.googleAPIKey}`, 'callback');

I still want to try to move the API loading into a service, but I think this does not change anything. Also downloading the API pre test to load it in the Karma config does not seem to be a good solution either.

How can I ensure to have the current Google Maps API present for testing in an elegant manner?


Solution

  • I fixed it for now with a pretest script:

    package.json:

    //...
      "scripts": {
        //...
        "pretest": "./pretest.sh",
        "test": "ng test",
    //...
    

    The script loads the API code before testing (pretest.sh):

    echo "Running 'pretest.sh' script do download Google Maps API for testing..."
    rm google-maps-api.js
    date +"// Download time: %Y-%m-%d %H:%M" >> google-maps-api.js
    curl 'https://maps.googleapis.com/maps/api/js?key=<API_KEY>' >> google-maps-api.js
    echo "'pretest.sh' finished"
    

    And Karma loads the file for testing in the karma.config.js files section:

    module.exports = function (config) {
      config.set({
        basePath: '',
        plugins: [
          //...
        ],
        files: [
          'google-maps-api.js'
        ],