Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularFireModule has not been provided using v7.0.1 and new method of initializing the firebase app

Tags:

I'm attempting to connect to the firebase emulator within an integration test, using the new AngularFire API (>v7)

import {
  TestBed
} from '@angular/core/testing';
import {
  initializeApp,
  provideFirebaseApp
} from '@angular/fire/app';
import {
  doc,
  enableIndexedDbPersistence,
  Firestore,
  getFirestore,
  provideFirestore,
  setDoc
} from '@angular/fire/firestore';
import {
  connectFirestoreEmulator
} from "firebase/firestore";

describe('FirestoreEmulatorSmoketest', () => {
  let projectId: string;
  let firestore: Firestore;

  beforeAll(() => {

    const testConfig = {
      projectId,
      auth: ...
    };
    TestBed.configureTestingModule({
      imports: [
        provideFirebaseApp(() => initializeApp(testConfig)),
        provideFirestore(() => {
          const firestore = getFirestore();
          connectFirestoreEmulator(firestore, 'localhost', 8080);
          enableIndexedDbPersistence(firestore);
          return firestore;
        }),
      ],
    })

  });

  beforeEach(() => {})
  afterAll(() => {})

  it('should connect', () => {
    const fooDoc = doc(firestore, "foo/12345");
    return setDoc(fooDoc, {
      updated: new Date()
    })
  })
});

This code produces the following error "AngularFireModule has not been provided"

I can only assume I'm not initialising angular fire somehow?

like image 758
stevecowling Avatar asked Sep 16 '21 06:09

stevecowling


1 Answers

First of all, my native language is not English, so if I write like a fool you know why.

Try this.

environment.ts

export const environment = {
    production: false,
    useEmulators: true,
    firebaseConfig: {
        apiKey: 'YOUR-API-KEY',
        authDomain: 'YOUR-AUTH-DOMAIN',
        projectId: 'YOUR-PROJECT-ID',
        storageBucket: 'YPUR-STORAGE-BUCKET',
        messagingSenderId: 'YOUR-MESSAGING-SENDER-ID',
        appId: 'YOUR-APP-ID',
        measurementId: 'YOUR-MEASUREMENT-ID',
    },
};

Important: As you can see I have the variable useEmulators, which in the following lines I will explain what it is going to be used for.

app.module.ts

import { provideFirebaseApp, initializeApp } from '@angular/fire/app';
import { getAuth, provideAuth, connectAuthEmulator } from '@angular/fire/auth';
import { getFirestore, provideFirestore, connectFirestoreEmulator, enableIndexedDbPersistence } from '@angular/fire/firestore';
import { getStorage, provideStorage, connectStorageEmulator } from '@angular/fire/storage';
import { getAnalytics, provideAnalytics } from '@angular/fire/analytics';
import { getFunctions, provideFunctions, connectFunctionsEmulator} from '@angular/fire/functions';
import { environment } from 'environments/environment'; // <--- Environment variables.  

imports: [
    // Firebase
    provideFirebaseApp(() => initializeApp(environment.firebaseConfig)),
    provideFirestore(() => {
        if (environment.useEmulators) {
            const firestore = getFirestore();
            connectFirestoreEmulator(firestore, 'localhost', 8080);
            enableIndexedDbPersistence(firestore);
            return firestore;
        } else {
            getFirestore();
        }
    }),
    provideAuth(() => {
        if (environment.useEmulators) {
            const fireauth = getAuth();
            connectAuthEmulator(fireauth, 'http://localhost:9099'); // <---FireAuth Port
            return fireauth;
        } else {
            getAuth();
        }
    }),
    provideStorage(() => {
        if (environment.useEmulators) {
            const firestorage = getStorage();
            connectStorageEmulator(firestorage, 'localhost', 9199); // <---- Firestorage Port
            return firestorage;
        } else {
            getStorage();
        }
    }),
    provideFunctions(() => {
        if (environment.useEmulators) {
            const firefunctions = getFunctions();
            connectFunctionsEmulator(firefunctions, 'localhost', 5001); // <--- FireFunctions Port
            return firefunctions;
        } else {
            getFunctions();
        }
    }),
    provideAnalytics(() => getAnalytics()),
],

Important (Environment Path): Change the environment path of the variables in case you don't have them in the default location.

Important (Local Ports): In case you use different local ports than the default ones, change them.

As you can see I have added code to the initializations to be able to switch between the emulated project and the online project, in a simple way:

useEmulators: true // We load the emulator environment
useEmulators: false // We load the production environment

_fireAuth.service.ts

import { Auth } from '@angular/fire/auth';

constructor(private _fireAuth: Auth) {} 

_fireStorage.service.ts

import { Storage } from '@angular/fire/storage';

constructor(private _fireStorage: Storage) {} 

_fireStore.service.ts

import { Firestore } from '@angular/fire/firestore';

constructor(private _fireStore: Firestore) {} 

It only remains to import the functions you are going to use, e.g. { doc, Collection, etc... }.

Use the documentation provided by Google to see how they changed the functions: https://firebase.google.com/docs/build and use the code found in the "Web version 9 (modular)" tab.

like image 76
raulabad Avatar answered Sep 23 '22 13:09

raulabad