How can I make jest spied function internally store arguments that the function was called with by deep copy and not by reference

I’m trying to test a class that is combining fetching, caching, geocoding and returning a list of places. The code that is being tested looks something like this (this is not a full working executable code, but enough to illustrate the problem):

interface Place {
  name: string;
  address: string;
  longitude: number | null;
  latitude: number | null;
}

class Places {
  findAll(country: string): Place[] {
    let places = this.placesCache.get(country)
    if (places === null)
      places = this.placesExternalApiClient.fetchAll(country);
      // BREAKPOINT no.1 (before store() call)
      this.placesCache.store(country, places);
      // BREAKPOINT no.2 (after store() call)
    }
    
    for (const place of places) {
      // BREAKPOINT no.3 (before geocode() call)
      const geocodedAddress = this.geocoder.geocode(place.address);
      place.longitude = geocodedAddress.longitude;
      place.latitude = geocodedAddress.latitude; 
    }  

    return places;
  }
}

class PlacesExternalApiClient {
  fetchAll(country: string): Place[] {
    // makes a request to some external API server, parses results and returns them
  }
}

class PlacesCache {
  store(country: string, places: Place[]) {
    // stores country and places in database with a relation
  }

  get(country: string): Place[] | null {
    // if country is in database, returns all related places (possibly []),
    // if country is not in db, returns null
  }
}

interface GeocodedAddress {
  address: string;
  longitude: number;
  latitude: number;
}

class Geocoder {
  geocode(address: string): GeocodedAddress {
    // makes a request to some geocoding service like Google Geocoder,
    // and returns the best result.
  }
}

And this is the test (kinda, illustrates the problem):

mockedPlaces = [
  { name: "place no. 1", address: "Atlantis", longitude: null, latitude: null },
  { name: "place no. 2", address: "Mars base no. 3", longitude: null, latitude: null },
]

mockedPlacesExternalApiClient = {
  fetchAll: jest.fn().mockImplementation(() => structuredClone(mockedPlaces))
}

mockedGeocodedAddress = {
  address: "doesn't matter here",
  longitude: 1337,
  latitude: 7331,
}

mockedGeocoder = {
  geocode: jest.fn().mockImplementation(() => structuredClone(mockedGeocodedAddress))
}

describe('Places#findAll()', () => {
  it('should call cache#store() once when called two times', () => {
    const storeMethod = jest.spyOn(placesCache, 'store');
    
    places.findAll('abc');
    places.findAll('abc');

    expect(storeMethod).toHaveBeenCalledTimes(1);
    expect(storeMethod).toHaveBeenNthCalledWith(
      1,
      'abc',
      mockedPlaces, // ERROR: expected places have lng and lat null, null
                    //    but received places have lng and lat 1337, 7331
    );
  })
})

I found during debugging that, during first iteration over places.findAll() (when there is cache miss):

  • on BREAKPOINT no.1: places (var) has null as coordinates
  • on BREAKPOINT no.2:
    • places (var) still has null as coordinates
    • placesCache.store (which is a Spied jest object) has .mock.calls[0][1] which is an array where there a two places, both with null for lng and lat as expected
  • on first hit of BREAKPOINT no.3: nothing changed in .mock.calls and nothing changed in places (var)
  • on second hit of BREAKPOINT no.3: first place in both arrays: places (var) and array .mock.calls[0][1] had changed their coordinates to 1337, 7331!

because of that, later when I ask jest what argument storeMethod was called with, it incorrectly thinks it was called with latitude and longitude 1337, 7331 and not null, null.

It does not work as I expected it to work because spyOn simply assigns/pushes arguments that it got to .mock.calls[], it does not perform a deep copy, and therefore when the argument is an object that is later mutated, that change is also affecting what the spied object recorded as its call argument.

How can I make spyOn deep clone the arguments it gets?
or, How can I make this test work some other way, without changing the implementation of business logic (first snippet)?

I want to test that store() was called with longitude and latitude set to null. Now my test gives me a false negative.