QA Interview Hub · Knowledge base · Quizzes

Manual QA

Web and client-server

HTTP, the browser, DevTools

What is client-server architecture?

A client (a browser, a mobile app) sends requests, and the server processes them and returns responses. The server works with a database and other services.

For QA this means: a bug may be on the client (display, validation), on the server (logic, data) or at the junction (a wrong request, an unexpected response). DevTools helps quickly localise where exactly.

Browser ──HTTP request──► Server (API) ──► Database
        ◄─HTTP response─              ◄──
In an interview: The client sends a request, the server processes it, works with the database and returns a response. When I find a bug, the first thing I do is determine where it is: if the request is right and the response is wrong, it is the backend; if the response is right but shown wrongly, it is the front end.

What are the main HTTP methods and status codes?

Methods: GET to retrieve, POST to create, PUT to replace completely, PATCH to change partially, DELETE to remove.

GroupExamples
2xx success200 OK, 201 Created, 204 No Content
3xx redirection301, 302, 304 Not Modified
4xx client error400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 422, 429 Too Many Requests
5xx server error500, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout

A frequent question: 401 is not authenticated (who are you?), 403 is authenticated but has no rights.

In an interview: GET retrieves, POST creates, PUT replaces, PATCH changes partially, DELETE removes. Codes: the two hundreds are success, the three hundreds redirection, the four hundreds a client error, the five hundreds a server one. An important difference: four hundred and one means the system doesn't know who you are, and four hundred and three means it knows but doesn't give you rights.

How do cookies, localStorage and sessionStorage differ?

CookieslocalStoragesessionStorage
Sent to the serverYes, with every requestNoNo
LifetimeUntil expires or the end of the sessionUntil deletedWhile the tab is open
Size~4 KB~5–10 MB~5 MB
Visible between tabsYesYesNo

For security a cookie with a token must be HttpOnly (inaccessible from JS), Secure (HTTPS only) and with SameSite.

In an interview: Cookies are sent to the server with every request and are limited to a few kilobytes. LocalStorage lives in the browser until it is cleared, and sessionStorage only while the tab is open. For security I check that the session cookie has the HttpOnly, Secure and SameSite flags.

How do you use DevTools in testing?

  • Network: requests and responses, statuses, duration, payload; a HAR file for a bug report.
  • Console: JS errors and warnings.
  • Elements: the DOM, styles, checking that a field is really disabled and not just grey.
  • Application: cookies, localStorage, sessionStorage.
  • Device toolbar: responsiveness and mobile sizes.
  • Network throttling: a slow network and offline.
In an interview: In DevTools I look at the Network tab: requests, statuses and response bodies, and I save a HAR for a bug report. Console for JS errors, Application for cookies and storages, the device toolbar for responsiveness, and throttling to check behaviour on a slow network.

How do you approach cross-browser and responsive testing?

First determine the matrix from analytics: which browsers, OSes and devices clients really use. Then prioritise: the most popular get full testing, the rest a smoke of critical scenarios.

Check: layout at breakpoints, behaviour of form elements, date and number formats, the virtual keyboard on mobile, screen orientation. Tools: emulation in DevTools, real devices, cloud farms such as BrowserStack.

In an interview: I build a matrix of browsers and devices based on analytics, not everything at once. The most popular configurations I test fully, and the rest with smoke. I check the layout at breakpoints, forms, date and number formats, and I always check part of it on real devices, because emulation doesn't show everything.

What happens when you enter a URL

First the browser parses the URL and looks for the domain's IP address through DNS: the browser cache, the OS cache, the ISP's resolver, and then the root, TLD and authoritative servers. Then a TCP connection is established through a three-way handshake: SYN, SYN-ACK, ACK. For HTTPS a TLS handshake follows: the server sends a certificate, the browser verifies it, and the parties agree on encryption keys.

Then the browser sends an HTTP request with a method, headers and cookies. The request may pass through a CDN, a load balancer and a reverse proxy before it reaches the application server. The server processes the request, goes to the DB or other services and returns a response with a status code, headers and HTML.

The browser parses the HTML and builds the DOM, loads CSS, JS and images in parallel and builds the CSSOM. Then come layout, paint and composite, and the page is displayed. JavaScript runs and may make additional API requests and change the DOM.

A front-end or back-end bug through DevTools

The main tool is the Network tab: I find the request related to the action and look at the request and response. If the front end sent wrong data (wrong fields, format, a missing parameter), it is a front-end bug. If the request is right and the backend returned an error or wrong data, it is a backend bug.

If the backend returned correct data and the UI shows something else, the bug is on the front end: in display, handling or state. If the request wasn't sent at all, I look at the Console tab for JS errors. I also check status codes: 5xx usually points to the backend, and a 4xx needs analysis of which of them is wrong, per the API contract.

Additionally: the Application tab for cookies, localStorage and tokens, Elements for the DOM and styles, Performance for speed. You can repeat a request through Copy as cURL in Postman to isolate the backend from the UI. In a bug report I attach the request, the response and a HAR file.

Cookies vs localStorage vs sessionStorage

Cookies are small data up to 4 KB that the browser automatically sends with every request to the matching domain. They can be set both by the server through the Set-Cookie header and by JS. They have an expiry and security attributes: HttpOnly (inaccessible to JS, protection from XSS), Secure (HTTPS only), SameSite (protection from CSRF).

localStorage holds about 5–10 MB of data, doesn't send it to the server automatically and stores it with no expiry until it is deleted. sessionStorage has a similar size, but lives only within one tab and is cleared when it closes. Both are accessible only through JavaScript and are tied to the origin.

For testing: I check that sensitive data, such as session tokens, is stored in HttpOnly cookies and not in localStorage. I also check behaviour after logout, closing the tab, in incognito mode and in a new tab. In DevTools this is visible on the Application tab.

The DOM, layout and responsiveness

The DOM (Document Object Model) is a tree-shaped representation of the HTML document in the browser's memory, which JavaScript can manipulate. Each tag becomes a node, and changing the DOM changes what the user sees. Locators in automated tests work with the DOM.

I check the layout against the Figma mockup: spacing, fonts, colours, sizes, alignment. Typical problems: text spilling out of its block, overlapping elements, long words that break the layout, missing hover, focus and disabled states. For analysis I use the Elements tab in DevTools and extensions like PerfectPixel.

I test responsiveness through Device Mode in DevTools at different breakpoints, for example 320, 768, 1024 and 1440 pixels, and on real devices. I also check screen orientation, zooming, cross-browser behaviour and working from the keyboard. For visual regression you can use screenshot tests: Percy or Applitools.

JavaScript basics

== compares with type coercion, so '5' == 5 gives true, and null == undefined is also true. === compares without coercion, taking the type into account, so '5' === 5 gives false. In practice I always use === to avoid non-obvious bugs.

var has function scope and hoisting with the value undefined, so it is hardly used now. let and const have block scope; let can be reassigned, const can't. But const for an object or array doesn't make it immutable: the contents can be changed, only the reference can't be reassigned.

JS is single-threaded, and asynchrony is implemented through the event loop: synchronous code runs on the call stack, and callbacks wait in queues. Microtasks (promises) run before macrotasks (setTimeout). A promise has the states pending, fulfilled and rejected; async/await is syntactic sugar over promises, and errors are caught with try/catch.