Earlier work: an undocumented map library and a date picker

March 2023 to November 2025Web, then mobile

Two automation roles, a web team and then a mobile one. In the first I read an undocumented internal map library until I could teach it, and the team changed frameworks to use it. In the second I built a React Native suite from nothing and handed it on. Both employers stay unnamed, and neither left a repository to link.

The web role turned on a library nobody had documented. The mobile role turned on a date picker.

A map the suite was not allowed to touch

Web automation, Mar 2023 to Jun 2024

I joined a team automating a large enterprise application with Cypress. A set of behaviors had been filed as out of scope, the way teams do when a tool cannot reach something and the list of exceptions becomes the plan. Map interaction was on that list: drawing a polygon, moving the view, dragging an object to a new position. The product was a mapping application, so the untested part was the part people used.

Searching the organization's filesystem turned up an internal library built for exactly that application, by another team at a different site of the same organization. It did polygon drawing, map movement, object movement, and a long list of map assertions to go with the actions. It had reached us through a pipeline from a separate intranet network, which meant no documentation arrived with it and there was nobody I could ask. It was also Puppeteer-only. That settled the framework question before I could have an opinion about it: using the library at all meant moving off Cypress.

Writing my own map interactions was not an option. The application sat on the organization's own framework and infrastructure, and the logic behind a map action was hard to follow and harder to recreate, so the library was the only way in.

So I read it. I downloaded the package and went through its source, starting with an inventory: which methods it offered, and which of those the team would actually want. For each one I kept, I worked out what it does, what it expects to receive and how to call it.

Then I wrote throwaway tests against the library itself, one per action, to confirm what each call actually did before any real test depended on it. Each one paired an action with one of the library's own assertions and ran against the real application while I watched the map. Both halves of a test like that come from the code under study, so my eyes were the independent check. Characterizing it that way was slower than guessing and it was the only way to write down behavior I could not look up. The tests were scratch work and I threw them away. The documentation is what survived.

The interactions, hardest first:

  1. Drawing polygons, for two reasons. Where a click lands depends on the viewport, so the same call draws a different shape unless the view is pinned first. And the result lives on a canvas, with nothing in the DOM to assert on.
  2. Getting the map into a known viewport, which has to come first, because no assertion downstream of a drifting view means anything.
  3. The assertions, which cost more than the actions did. Making the map do something was usually tractable; proving afterwards that it had ended up in the expected state was the half that took the time.
  4. Moving an object, the easy one.

What came out of it was documentation and slide decks, first to argue for migrating from Cypress to Puppeteer, then to teach the team the library I had just finished reading. They migrated. The behaviors that had been filed as out of scope became tests.

The same problem, a map on a canvas that a DOM-only suite cannot see into, is what geowright takes on now, without depending on someone else's undocumented package.

A date picker decided the framework

Mobile automation, Jun 2024 to Nov 2025

The next role was sole QA on a React Native product with no automation at all. It also had no test IDs, and the developers were not adding any, so putting them into the product became part of my job rather than a ticket I filed. I opened those pull requests against the app myself.

The suite started as a proposal: decks and documents to the development team about what to build it on. Detox was proposed, approved, and developed for a couple of months. Then it ran into a date picker. The team had picked an arbitrary React Native date-picker library, Detox could not drive what that library rendered, and reverse-engineering the component for some other way in went nowhere. One blocked interaction in one flow, and it decided the framework: Appium could drive the native picker, so the suite moved to Appium.

The rewrite cost less than the two months suggests. The page-object structure, the choice of which flows were worth automating, and the naming all carried over. The driver was the loss. Coverage of the core flows went from nothing to roughly three quarters, my own estimate from the time.

It ended in a handoff. Two junior QA engineers took it over: one was headed for ownership of the automation, the other leaned toward manual testing and later became the team's product manager. I wrote the documentation and trained both, so the suite would survive the person who built it.