Software Engineering Blog

Testing & QA

Meet Dejavu: Deterministic Network Testing for Swift (without the flakiness)

By: Harish Kunchala

Meet Dejavu: Deterministic Network Testing for Swift (without the flakiness)

If your iOS tests touch the network, you’ve probably felt the pain: they get slow, they get flaky, and they sometimes fail for reasons that have nothing to do with your code. We built Dejavu to make those tests boring—in the best possible way.

Dejavu is Esri’s open‑source, Swift‑native library that records real HTTP requests and replays them later, so your test suite runs fast and predictably. It plugs into URLSession via URLProtocol, stores request/response pairs in a SQLite cache, and plays them back on demand—all while fitting neatly into XCTest.

Why we built it

Around 2017, across our ArcGIS Maps SDK for Swift development, we ran thousands of tests that exercised geospatial services and large, nested payloads—think routing, analysis, tiles, search, and cloud APIs. Then as the scale and variety of our tests grew (today we are over 200,000 tests across our Native Maps SDKs), the typical network hazards (latency spikes, rate limits, service downtime) crept into CI and increasingly slowed teams down. When we looked for network mocking tools, no tool did everything we wanted. We decided to build a tool so that we could have tests that were:

  • Deterministic: same inputs, same outputs, every run.
  • Swift‑native: nothing that fights modern concurrency or XCTest.
  • Scalable: able to handle big payloads and lots of concurrent requests.

Dejavu is the tool we wished existed—so we open‑sourced it.
(ArcGIS Maps SDK for Swift samples show the breadth of workflows we exercise: arcgis-maps-sdk-swift-samples).

What Dejavu is (in one paragraph)

Dejavu intercepts URLSession requests during a recording run and writes each request and its server response to a local SQLite database. In playback runs, the same requests are intercepted and matched to the recorded entries; the exact responses are returned instantly, without hitting the network. The result: tests that are fastrepeatable, and resilient (with modes you can toggle per run).

What you get (day one)

  • Speed: No real network calls during playback—tests finish faster.
  • Reliability: Eliminate flakiness caused by external services.
  • Isolation: Run end‑to‑end flows without credentials or live endpoints.
  • Native fit: Built around URLProtocol and XCTest patterns—no awkward harnesses.
    (Architecture and defaults described in the GitHub README: Esri/Dejavu)

How it works (high level, no code)

  1. Intercept: Register Dejavu’s URLProtocol for the URLSession your tests use.
  2. Record: In a recording mode, write the full request/response pair to a SQLite file. We use Record only as needed. For example, we create a fresh recording when tests change, requests change (params, headers, etc.), or when we need to resync with services.
  3. Match: On future runs, match outgoing requests to recorded ones.
  4. Replay: Return the exact recorded response locally—no live I/O.
    (Usage overview and modes documented in the package: GitHubSPI)

Modes

Dejavu ships with multiple modes you can switch via configuration or env vars (for example, playback on PRs): .cleanRecord.supplementalRecord, and .playback.

  • First time (or you want a clean slate): use .cleanRecord
    Think “fresh record.” It wipes the DB and records everything again—perfect when you’re setting up Dejavu the first time or the API payloads changed.
  • Adding new tests/endpoints: use .supplementalRecord
    Keeps what you already recorded and adds any missing calls. Great for growing coverage without nuking your existing cache.
    .supplementalRecord is configurable to be .supplementalRecord(.updateExisting) (default) or .supplementalRecord(.insertNew).
  • Day‑to‑day mock testing (fast + deterministic): use .playback
    Runs your tests against the local recordings with zero live network, so CI and PRs stay quick and stable.
  • Real network debugging: use .disabled
    Turns Dejavu off so requests hit the real services—handy when you’re chasing a live issue.

Mode definitions: Swift Package RegistryREADME

A quick look at performance

To illustrate the idea, we pointed a sample test at JSONPlaceholder—a popular, free fake REST API (jsonplaceholder.typicode.com)—and measured the same test with and without playback:

  • Recording (.cleanRecord): 1 test in 0.068s
  • Playback (.playback): 1 test in 0.005s

It’s a simple example, but it demonstrates the core benefit: once recorded, playback avoids network overhead and variability. Your numbers will vary based on payload size and the number of requests per test, but the pattern is consistent.

Where we use it at Esri

ArcGIS Maps SDK for Swift and its toolkit

We rely on Dejavu to stabilize and speed up tests for the ArcGIS Maps SDK for Swift and its toolkit, both of which exercise complex geospatial workflows and large datasets. By removing network variability from the critical path, our test runs are faster and CI gets more predictable.

ArcGIS Field Maps

The ArcGIS Field Maps development team uses Dejavu extensively for testing its app for iOS devices.

Operational tips for teams (so you can drop it into CI)

  • Cache strategy: Store SQLite recordings per test; cache across CI runs to avoid re‑recording.
  • Usage: Treat recordings as test data—version them alongside code and refresh when APIs evolve.

All of the wiring details, including URLProtocol registration/unregistration and examples, live in the repo’s README and example projects.
(Start here: github.com/Esri/Dejavu)

Security and privacy (important in real projects)

Recordings can contain sensitive data (headers, bodies, query params). We recommend:

  • Redacting credentials and personal data in the recording phase.
  • Scoping access to caches in CI (avoid committing secrets to VCS).
  • Pinning environment variables (locale, time zone) to maximize determinism.

The package surfaces configuration points and guidance to help you do this right.

Redacting credentials and personal data in the recording phase

The following snippet shows how you can replace credentials and personal information with dummy values to ensure sensitive data remains safe.

let configuration = DejavuSessionConfiguration(...)
 configuration.queryParameterReplacements = [
 "apikey": "dummyAPIKey",
 "client_id": "dummyClientID",
 "client_secret": "dummyClientSecret",
 "token": "dummyToken",
 "username": "dummyUsername",
 "password": "dummyPassword"
 ]
 configuration.jsonResponseKeyValueReplacements = [
 "access_token": "dummyToken",
 "token": "dummyToken",
 "expires": Date.distantFuture.timeIntervalSince1970 * 1_000,
 "expires-in": Date.distantFuture.timeIntervalSince1970 * 1_000
 ]
 configuration.authenticationTokenParameterKeys = ["token"]
 configuration.authenticationHeaderParameterKeys = [
 "Authorization"
 ]
 
 try Dejavu.startSession(configuration: configuration)

Limitations (and when not to use Dejavu)

Dejavu is ideal for HTTP request/response flows. It isn’t a drop‑in for real‑time streaming or custom socket protocols where timing semantics matter more than payload determinism. Some chaos scenarios (e.g., partial reads, mid‑stream disconnects) may need purpose‑built harnesses rather than pure playback.

License, community, and where to learn more

We welcome issues and pull requests on GitHub. If you’re curious about how we use Dejavu across Esri apps, browse our sample code and developer site for the ArcGIS Maps SDK for Swift.

Ready to give it a try?

If your network‑dependent tests are slowing you down or failing for all the wrong reasons, record them once and let Dejavu do the rest. Flip your CI into playback mode and enjoy faster, quieter test runs—so you can focus on shipping features.

Related Articles

Next Article

Securing ArcGIS Hub with Hardened Docker Images

Read this article