Technical Exploratory Testing – Using Dev Tools to look under the hood

One of the best things that I’ve learnt to improve my exploration, and make it more technical, has been to use the dev tools to “look under the hood” and see the traffic going between a web page and the servers behind it. Being able to use the dev tools to chase data was a really easy thing to level up my testing and it’s allowed me to help debug issues better, be seen as more technical and work better with developers.

One thing before we start, because I know “technical” is a word that puts a lot of people off… you don’t write a single line of code to do any of this. We’re just looking at things in the browser, something you’re already doing anyway.

When would I use this?

In the middle of exploratory testing, at the point where the UI has stopped telling me enough. I can see that the screen is showing me six fields, but I can’t see whether anything got dropped on the way, or what the servers actually sent back, or how long they took to answer. The dev tools show me all of that; they turn “hmm, that looks a bit odd” into something I can actually use to have an informed quality opinion.

The second is if you’re a manual tester who is interested in getting more technical and hasn’t got a clue where to start. This is where I’d start you (and it’s a much gentler entry than the one I was worrying about back when I asked whether we all need to become SDITs). There’s nothing to install, nothing to set up and nobody to ask permission from. It’s already sat there in the browser you’re testing in. It’s how I got started!

What’s an API?

Quick description on two terms first, because I’m about to use them a lot. The front end is the bit we can see and click, so the web page in the browser. The back end is everything behind it that we can’t see, the servers and databases doing the actual work. When we use a website we’re using the front end which is asking the back end to do things for it (like fetch data or do calculations).

An API is a way that software components talk to each other. One component will send a request (calling for information, sending information or sending instructions) via the API and get a response from the other.

Diagram illustrating the interaction between the front end, API, and back end, showing request and response flow.

On a web page the front end will make calls via an API to back end services or servers to get information or will send information that’s submitted. Let’s say you log in to a website, the details you enter will be sent to the back end via an API when you click submit.

Chasing the data

As a tester I want to know that what the UI shows me is correct (or what I’ve sent from the UI is saved correctly). This usually means looking at the UI, sending things to be saved and checking the database. But what about the sending of data in between? Checking just the bits we can see and calling it done is how we end up 100% tested and nowhere near 100% covered.

We can check the API traffic, the requests and responses, to see what the UI is sending to the back end and what the back end is responding with. This is great to check the accuracy of requests, see any data that’s not saved to a database and see what’s sent and returned when we cannot directly access the back end.

I can also check the speed of requests, whether they were successful and see any errors that are happening; all useful things when trying to explore how good something is.

Let’s open the dev tools together

Let’s just do it, it’s much easier than reading about it.

  1. Open ministryoftesting.com in Chrome.
  2. Right click anywhere on the page and select “inspect”. (F12 does the same thing if you’d rather use the keyboard, or Cmd + Option + I on a Mac.)
  3. The developer tools open in their own panel, either down the right hand side or along the bottom depending on the browser and version. We can move that around later if we want to (they’ll even pop out into a window of their own).
  4. Click the Network tab.
  5. Search the site for your own name.
Context menu displayed in a web browser over the Google homepage, showing options such as 'Open Image in New Tab', 'Save Image As', 'Copy Image', 'Copy Image Address', 'Search Google for Image', 'Inspect', and 'Speech'.
Fig 1. The Inspect option when right clicking on a web page opens the dev tools.

You’ll see something appear in that list, a call from the front end talking to the back end and we’re about to pull it apart.

While we’re here, the other tabs along the top are worth knowing about even if we don’t need them today:

  • Elements: shows the page code as the browser has actually built it, which isn’t always the same as the code the servers sent.
  • Console: shows logged messages and errors as the software is used.
  • Network: shows every request the page makes, including the calls made via the APIs. This is the one we opened in the steps above.
  • Lighthouse: (Chrome only) in built audits that score a page on things like performance and accessibility. Worth a look another day.

With the network tab open, let’s have a deeper dive.

The network tab

The network tab gives us a number of filters, a visual representation of traffic performance and then a list of the calls that have been made in order.

Screenshot of a browser developer tools Network tab, featuring filter controls, a visual representation of traffic performance over time, and a list of traffic calls with status codes and timing details.
Fig 2. The network tab as seen on the Chrome browser developer tools.

Each time we make a call via the front end to the back end (like moving page or submitting a form) a call will be made and can be seen in this list of calls. We can click on these to open them and see the details in them.

Screenshot of a web developer's tool showing HTTP request and response headers for a specific URL.
Fig 3. Opening a traffic call to see its data.

Cutting out the noise

The first time you open the network tab it’s overwhelming, because it shows you everything: images, fonts, styling, adverts, the lot. Two things make it usable straight away.

Click the Fetch/XHR filter along the top. That hides everything except the calls the page is making to its own back end, which is what we care about. On a busy page it can take a list of three hundred rows down to about five. (There’s a filter for every type of thing a page loads and a full reference for what each one does, but Fetch/XHR is the one we’ll live in.)

Tick Preserve log if we’re testing something that navigates or redirects. Without it the list clears every time the page changes and we lose the call we were trying to read, which is maddening when we’re chasing a login.

LET’S LOOK AT A TRAFFIC CALL

Opening a traffic call creates another column in which we can see more tabs:

  • Headers: shows where the call is being made to, status of the call and type of call.
  • Payload: shows the details of what was sent in the request from the front end.
  • Response: shows exactly what the back end sent back, as it sent it.
  • Preview: shows the same thing tidied up into something a human can read.
  • Timing: shows how long each part of the call took.

Here is a traffic call from a Ministry of Testing search of the word “Callum”.

Headers

Screenshot of HTTP response headers from a web page showing request details, status code 200 OK, and various header information.
Fig 4. Traffic call headers.

Request URL: where the query is being sent to is https://www.ministryoftesting.com/search?q=Callum&button= which matches the main URL of the web page.

Request method: is a GET, which makes sense as we’re getting information from a search. If we’d saved data to the back end this could be a POST, or it could be a DELETE if we were removing data.

Status code: this is 200 which means it’s worked fine. MDN has a full list of HTTP status codes and it’s worth a skim. Basically it’s a series of codes that tells us if there’s been a problem or if things have done well (you don’t want to see any 500s as this is a server error).

Payload

Screenshot of a web developer console showing the Payload tab, with query string parameters including 'q: Callum' and a button parameter.
Fig 5. Traffic call payload.

In the payload (the request we’re making to the back end) we can see the q: was Callum, which matches what we’d input.

Worth knowing that for a GET like this one, what we’re looking at is just the bit of the web address after the question mark. When we submit a form or send a chunk of data instead, that data shows up here as its own thing, which is where this tab really earns its place.

When we’re testing we can check for the accuracy of what’s being sent to the back end. Was everything included? Was anything changed unexpectedly? Does anything get added that we didn’t expect?

Response

Screenshot of HTML source code displaying metadata for a website titled 'Callum Search Results | MoT'.
Fig 6. Traffic call response.

For this query the response is the page html which we can look at to see what’s come back. For other calls we make we might get a JSON response instead (which is just data in a tidy text format rather than a whole web page) and we can look at that data directly.

Being able to see the html or the data that’s been returned by the back end allows us to do all sorts of exploration and testing. Has everything been saved? Is everything returned shown on the UI? Is anything missing?

That last question is the one I get the most out of. If the back end is returning ten fields and the UI is only showing six, somebody has made a decision about the other four and it’s worth finding out whether it was on purpose.

Preview

Screenshot of a webpage preview displaying navigation links such as 'Learn', 'Events', 'Discussions', 'Contribute', 'JOIN NOW', 'Help', and 'Sign In'.
Fig 7. Traffic call preview.

For this query the preview renders the html that’s been sent (missing any page styling that hasn’t been inherited). This is another way of reviewing the response to see what’s been sent back from the back end, we can then compare this to what the browser shows us.

When the response from the API is a JSON response, the preview will format this into a nice human readable view. We can use this to easily check the response data and see if it’s what we expected and then look at how the UI uses this.

Timing

Earlier I said I check the speed of requests, so here’s where we do it. The Timing tab breaks a single call down into how long it spent waiting, how long it spent downloading and how long it was stuck queueing behind something else.

This matters because “the page is slow” isn’t a bug report anybody can act on. “This one call waits 4 seconds for a response before anything appears on screen” is. Same finding; only one of them gets fixed.

While we’re in here, the throttling dropdown at the top of the network tab lets us pretend to be on a rubbish mobile connection. That’s a whole area of exploration on its own and I’ve written about it in an introduction to chaos engineering for testers as well as in exploring non functional requirements by finding low hanging fruit.

Using AI to interrogate the API traffic

This next bit is for once everything above feels comfortable, so do skip it on a first read. None of it is needed to get value out of the network tab and you’ll get plenty without it.

Reading a call tells us what happened. The harder bit is working out what else to try and that’s where I’ve found an AI assistant genuinely useful, in the same way I described in yes you can run exploratory testing with AI.

What it’s good at

Turning a call into test ideas. Paste a request and its response in and ask what could go wrong with this call. We’ll get edge values to try for each field, missing field cases, odd characters worth sending and error responses worth forcing. Some of it will be nonsense and some of it we’d never have thought of, which is exactly the trade we want when we’re generating ideas rather than answers.

Spotting the mismatch. Give it the request and the response together and ask what’s in one and not the other. It’s quick at noticing that we sent seven fields and got five back.

Explaining the unfamiliar. Odd header we’ve never seen… what the heck is a 418 response? Just ask the AI, it’s faster than searching and we can ask a follow up.

Making the call replayable. Right click a call in the network tab and we can copy it as cURL, which is a text version of the whole request that runs from a command line. Hand that to an AI, ask it to vary one thing at a time and we’ve got a rough set of API checks without ever opening Postman.

What to watch for

Strip the auth before pasting anything. Request headers carry the things that prove it’s you: tokens, cookies and session IDs. A copy-as-cURL contains all of them, so pasting that into a public chat tool hands over live credentials to your own system. Same goes for real customer data in a response; that’s somebody’s personal information and it isn’t yours to share. This is the bit I’d want a junior to learn before any of the clever stuff.

It will invent things. It’ll confidently describe calls, fields and behaviours that don’t exist in your system, because it’s pattern matching on every API it’s ever seen rather than reading yours. Everything it tells you is a hypothesis to check against the actual traffic, which is the same rule as any other test idea.

The skill is still yours. It can give you thirty things to try. Deciding which five matter for this product, this release and this set of risks is the job and no amount of generated ideas does that part for you. If you want the prompts I actually use, they’re in my QE-Skills repo.

So go and look under the hood

Increase what you’re looking at in your exploration. Look under the hood by using the developer tools to chase data and look at the network traffic. Honestly, five minutes on a site you already test will teach you more than the rest of this post did.

Thanks for reading. If this resonated (or if you think that I’ve got it wrong) there’s more to read on the blog… or get in touch via LinkedIn. I’ll talk quality to anyone who wants to listen!

Discover more from Callum Akehurst-Ryan's Testing Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading