'race problem with mocha unit testing Firestore onSnapshot, test ends before onSnapshot returns data

I have a function I'm testing. It's called from the constructor on an object.

constructor(authorID: string) {
  this.loadRecipes(authorID)
}

private loadRecipes = (author_id: string) => {
    
    const first = query(collection(db, "cookbook"), where("author_id", "==", author_id));
    this._unsubscribe = onSnapshot(first, (querySnapshot) => {
      this._recipes = [];
      querySnapshot.forEach((doc) => {
        this._recipes.push(new Recipe(doc.id, doc.data().author_id, "", "", -1, "draft", [], [], [], 0, ""));
      });
    });
};

I'm calling it from a mocha test:

it("Creates a recipe list by author ID", () => {
    authorRecipes = new RecipeList(author_id);
    assert(authorRecipes.list.length>0);
  });

The code works fine, but the test fails. The problem is that the test completes running long before the onSnapshot ever fires and populates the list. Is there a way to force the query to populate - sort of like an async/await? Or a way to force mocha to wait? Setting a breakpoint & debugging, the onSnapshot is eventually called so the code works. I just cannot do any follow on tests because the data isn't there yet.



Solution 1:[1]

I ended up adding a "loading" flag to the class:

private loadRecipes = (author_id: string, _max?: number, _start?: number) => {
    this._loading = true;
    const first = query(collection(db, "cookbook"), where("author_id", "==", author_id));
    this._unsubscribe = onSnapshot(first, (querySnapshot) => {
      this._recipes = [];
      querySnapshot.forEach((doc) => {
        this._recipes.push(new Recipe(doc.id, doc.data().author_id, "", "", -1, "draft", [], [], [], 0, ""));
      });
      this._loading = false;
    });
  };

And then watched the flag with a delay in the test:

it("Creates a recipe list by author ID", async () => {
    authorRecipes = new RecipeList(author_id);
    while (authorRecipes.loading) {
      await timeout(1000);
    }
    assert(!authorRecipes.loading);
  });

Not super elegant, but gets the job done.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Wayne Culbreth