Real Time Company Interview Questions & Answers
Playwright + Manual Testing + API Testing + AI Testing
Playwright uses a Node.js client API to communicate with browser processes through Playwright's browser automation protocol. It supports Chromium, Firefox and WebKit, creates isolated BrowserContexts, and provides auto-waiting, network control, tracing and parallel execution.
`var` is function-scoped and can be redeclared; `let` and `const` are block-scoped. `let` can be reassigned, while `const` cannot be reassigned. In automation code, I prefer `const` by default and `let` only when a value must change.
I use the `page` or `context` events to capture a newly opened page. For example, I wait for `context.waitForEvent('page')`, perform the action that opens the tab, and then use the returned Page object.
POM is a design pattern where each application page or component is represented by a class containing its locators and reusable actions. Tests then call business-level methods instead of repeating selectors, which improves maintainability.
I validate AI responses using predefined criteria such as correctness, relevance, completeness, safety, consistency and format. For open-ended answers, I use a rubric or reference facts rather than exact string matching, and I include negative and adversarial prompts.
Common Playwright locators include `getByRole`, `getByLabel`, `getByText`, `getByPlaceholder`, `getByAltText`, `getByTitle`, `getByTestId`, CSS and XPath. I prefer user-facing and accessibility-based locators first because they are generally more robust.
I integrate Playwright into CI/CD by installing dependencies, running tests headlessly, publishing reports/artifacts, and failing the pipeline when the test command fails. I also configure retries, workers, environment variables and traces/screenshots for diagnosis.
A simple approach is to initialize the maximum value with the first array element and compare each remaining value. Complexity is O(n). In TypeScript, `Math.max(...array)` is convenient for normal-sized arrays, while a loop avoids spread limitations.
`storageState` stores browser authentication state such as cookies and local storage. I can create it after login and reuse it in tests so every test does not need to perform UI login.
A typical framework contains tests/specs, page objects, fixtures, test data, utilities, API clients, configuration and reporting. I keep business logic in reusable layers and keep test files focused on scenarios and assertions.
Fixtures provide reusable setup and teardown and can inject objects such as `page`, custom page objects or test data into tests. Custom fixtures help centralize common initialization and keep tests clean.
Authentication verifies who the user is; authorization verifies what that authenticated user is allowed to access. For example, logging in is authentication, while checking whether a user can access an admin page is authorization.
I use `page.setInputFiles()` on the file input. For a real file I provide its path; for generated content I can provide an object containing name, MIME type and buffer.
The String Pool is a JVM-managed area where identical string literals can be reused. For example, two identical literals can reference the same pooled object, which saves memory.
Playwright parallelizes tests using worker processes. I configure the worker count in the config or command line and ensure tests are isolated so parallel execution does not create data or session conflicts.
A dynamic XPath is an XPath expression designed around stable attributes or relationships instead of a fragile absolute path. For example, `//button[contains(@id,'login')]` can tolerate changing portions of an attribute.
`await` pauses the async function until the Playwright operation's Promise settles. It is essential for sequencing browser actions and assertions correctly; forgetting it can cause race conditions or operations to run out of order.
I first identify whether the flakiness comes from synchronization, unstable locators, shared data, environment issues, network timing or application defects. I replace hard waits with condition-based waits, isolate data, improve locators, collect traces and fix the root cause rather than simply increasing retries.
Playwright provides web-first assertions such as `toBeVisible`, `toBeEnabled`, `toHaveText`, `toHaveValue`, `toHaveURL`, `toHaveTitle` and `toHaveAttribute`. They automatically retry until the expected condition is met or the assertion timeout expires.
I can create an `APIRequestContext` and call `post()` with a URL, headers, parameters and JSON body. I then validate the response status, headers and parsed body using Playwright assertions.
TypeScript is a statically typed superset of JavaScript that compiles to JavaScript. It improves automation maintainability with types, interfaces, IntelliSense and compile-time checks, while JavaScript is dynamically typed.
I use `page.frameLocator()` for stable iframe interactions, or `page.frames()` when I need to inspect frame objects. The key is to locate the correct frame and then interact with elements inside that frame.
Generative AI creates new content such as text, code, images or structured data from prompts. In testing, it can assist with test-case generation, code suggestions, test-data creation, defect analysis and exploratory testing, but outputs still require human validation.
I install Node.js dependencies, run the Playwright project initializer, choose TypeScript or JavaScript and configure browsers. Then I create tests, configure `playwright.config.ts`, and run them with the Playwright test runner.
The major OOP concepts are encapsulation, abstraction, inheritance and polymorphism. In automation, these help us hide implementation details, reuse common behavior and create maintainable page and utility classes.
For pop-ups, I handle browser dialogs with `page.on('dialog')`. Cookies can be inspected or modified through `context.cookies()` and `context.addCookies()`. For application pop-ups, I locate and interact with the relevant DOM elements.
`==` is Java equality comparison for primitive values and reference comparison for objects; `.equals()` is a method commonly overridden to compare object content. For strings, `.equals()` compares content while `==` compares references.
I group tests with `test.describe()` blocks and can use projects, annotations or naming conventions for larger suites. Grouping improves organization and makes it easier to execute related scenarios.
Playwright mainly relies on automatic waiting and web-first assertions. It also supports configurable action, navigation, assertion and test timeouts; explicit waits such as `waitForSelector` or `waitForTimeout` should be used only when genuinely necessary.
A chatbot application allows users to interact conversationally with a system to obtain information, perform tasks or receive assistance. Testing should cover functional correctness, conversation flow, context, safety, performance and response quality.
I run a selected project using `--project=<project-name>`. Browser projects are defined in `playwright.config.ts`, so this lets me execute only the desired browser configuration.
`APIRequestContext` is Playwright's API client used to send HTTP requests independently of browser UI. It is useful for API testing, creating test data, authentication setup and backend validation.
I use a frequency map such as `Map<string, number>` to count characters, then identify entries whose count is greater than one. I also define whether spaces and case should be considered.
Test isolation means one test should not depend on another test's state. Playwright achieves strong isolation through separate BrowserContexts and encourages independent test data and setup.
I identify what the test is waiting for, then synchronize on a meaningful condition such as element visibility, enabled state, URL, response or a specific application state. I avoid arbitrary sleeps because they make tests slow and still unreliable.
PUT generally replaces the complete representation of a resource, while PATCH applies a partial update. The exact semantics depend on the API contract, so I validate the documented behavior.
I separate test data from test logic using JSON, CSV, fixtures, factories, environment variables or API-generated data. For scalable suites, I prefer unique, disposable data and cleanup mechanisms.
Common authentication mechanisms include Basic, Bearer/token-based authentication, API keys, OAuth 2.0, session/cookie-based authentication and client certificates. The choice depends on the application's security architecture.
Codegen records browser interactions and generates starter Playwright code. I use it to accelerate locator discovery and initial scripting, then refactor the generated code into maintainable POM-based tests.
In Java, I can reverse a string using `StringBuilder(str).reverse().toString()`, or by iterating from the last character to the first. In interviews, I explain both the library-based and logic-based approaches.
For a dynamic calendar, I inspect the month/year controls and date elements, navigate until the required month appears, and then select the requested day. I validate the selected value afterward.
An interface defines a contract that implementing classes must follow, while encapsulation bundles data and behavior and controls access to internal state. Encapsulation is an OOP principle; an interface is a language construct.
Trace Viewer provides a detailed execution trace containing actions, snapshots, network information, console output and other diagnostics. I use it especially when a CI failure cannot be reproduced locally.
I use `locator.hover()` for hover and `locator.dblclick()` for double-click. I then assert the resulting UI state rather than relying only on the action completing.
Basic Authentication sends a Base64-encoded username/password credential in the `Authorization` header. It should be used over HTTPS and only where the API contract supports it.
I first identify a stable distinguishing attribute or accessible name. If several elements are genuinely identical, I scope the locator to a parent container or use a precise `filter()`/`nth()` only when the order is part of the requirement.
I use AI to draft SQL, identify possible validation queries and suggest edge cases, but I verify joins, filters, permissions and expected results against the schema before execution.
A BrowserContext is an isolated browser session inside a browser instance. It has its own cookies, local storage and session state, making it ideal for test isolation and multiple-user scenarios.
I can run a specific test by using the test file path, test title with `-g`, or an appropriate project. For example, `npx playwright test login.spec.ts` runs the selected file.
SQL aggregate functions calculate values over multiple rows. Common examples are `COUNT`, `SUM`, `AVG`, `MIN` and `MAX`, often used with `GROUP BY`.
For a login module I cover valid login, invalid credentials, blank fields, boundaries, error messages, password masking, lockout, session behavior, remember-me, authorization, security and usability. I prioritize critical authentication paths first.
`StringBuffer` is a mutable character sequence in Java with synchronized methods. It is thread-safe but usually slower than `StringBuilder`, which is preferred when synchronization is unnecessary.
I register a `dialog` event handler before triggering the dialog. Depending on the requirement, I call `dialog.accept()` or `dialog.dismiss()` and can validate its message.
`package.json` defines project metadata, dependencies and scripts. `package-lock.json` records the resolved dependency tree and versions so installations are reproducible.
I treat 0%, 50%, 75% and 100% as boundary and representative values. I also test below/above those points, rounding, invalid values, display formatting, calculations and accessibility rather than only checking the four labels.
Java Stream API provides a declarative way to process collections using operations such as `filter`, `map`, `sorted`, `distinct` and `collect`. It can make data transformation concise and readable.
I define browser projects such as Chromium, Firefox and WebKit in the configuration and run the suite across them. This gives cross-browser confidence while allowing project-specific settings.
Workers are independent processes used by Playwright Test to execute tests in parallel. More workers can improve speed, but the practical limit depends on CPU, memory, application capacity and test isolation.
`expect()` provides web-first assertions with retry behavior and useful failure messages. Manual `if` statements do not provide the same synchronization and assertion reporting, so `expect` is preferred for test verification.
I retrieve database records, normalize the fields that should match, collect UI table values, and compare the two sets. I report missing, extra and mismatched records with useful identifiers.
A Java interface defines a contract of methods and can also contain constants, default methods and static methods. A class implements the interface and provides the required behavior.
I reproduce expiry using a controlled timeout or invalidated session, perform a protected action, and verify that the application redirects or returns an appropriate authentication response. I also confirm that a new login restores access.
Playwright supports built-in reporters such as list, line, dot, HTML, JSON and JUnit, and can be configured with custom or multiple reporters. In CI, HTML/JSON/JUnit are commonly useful depending on reporting integration.
I put repeated logic into functions with clear parameters and return types. I also use modules, utility classes and shared fixtures so functionality has one maintainable implementation.
A functional interface in Java has exactly one abstract method, such as `Runnable`. It can be used with lambda expressions and method references.
I parse the user-selected date, compare it with the calendar's displayed month/year, navigate as needed, select the correct day and verify the resulting input value.
I use `context.cookies()` to inspect cookies, `addCookies()` to create them and `clearCookies()` to remove them. I avoid hard-coding sensitive values and use secure test configuration.
Serialization converts an object or data structure into a storable/transmittable representation such as JSON. Deserialization reconstructs the usable object/data structure from that representation.
I use parallel workers, test sharding in CI, API-based data setup, efficient fixtures and selective regression suites. I also avoid unnecessary browser launches and capture artifacts mainly for failures.
A Promise represents the eventual result of an asynchronous operation. In TypeScript, `async/await` provides readable syntax for consuming Promises while `Promise.all()` can run independent operations concurrently.
For usernames I test valid formats and boundaries plus blank, whitespace, invalid characters, too short/long, case sensitivity, duplicate and unauthorized values. I verify both validation behavior and backend handling.
`HashMap` stores key/value pairs without sorted-key ordering and generally provides fast average lookup. `TreeMap` keeps keys sorted and is useful when ordered traversal or range operations are required.
I start with requirements and coding standards, then create Playwright + TypeScript configuration, POM, fixtures, utilities, test data, API helpers, reporting and CI/CD. I add reusable components, environment handling and quality gates before scaling the suite.
I query all required users from the database, extract unique identifiers from the UI table, compare sets, and fail with the missing user IDs. I also investigate pagination or filtering so I do not compare only the first visible page.
Yes. Static methods can be overloaded by declaring multiple methods with the same name but different parameter lists. They cannot be overridden in the normal polymorphic sense because static methods belong to the class.
An explicit wait asks the test to wait for a specified condition, while automatic synchronization is built into Playwright actions and web-first assertions. I prefer Playwright's automatic waiting and use explicit waits only for special cases.
I pull or rebase the latest branch, inspect the conflicting files, resolve conflicts carefully, run tests, review the diff, and then commit the resolution. I avoid blindly accepting one side of a conflict.
A flaky test passes and fails without a relevant application change. Typical causes are timing, unstable selectors, shared data, order dependence, network/environment instability or test code defects.
I wait for the download event before triggering the download, then save or inspect the returned `Download` object. I verify filename, suggested path or file contents according to the requirement.
TestNG DataProvider supplies multiple sets of test data to a test method. It enables data-driven execution so the same test logic runs with different inputs.
I verify validation messages, focus behavior, button state, accessibility and that no request is incorrectly submitted. I test blank, whitespace-only and boundary-length inputs separately.
Cucumber Background contains common steps executed before each scenario in the feature. I keep it short and use it only for setup shared by all scenarios in that feature.
Retries can be configured in Playwright configuration or per test. I use retries mainly to provide diagnostic resilience in CI, not to hide flaky tests; persistent retries should trigger investigation.
An abstract class cannot normally be instantiated and can contain abstract and concrete methods. It is useful when related classes share implementation as well as a common contract.
Yes. An abstract class can extend another class, including another abstract class. The child class inherits available behavior and must implement required abstract methods unless it remains abstract.
I validate the HTTP status, important headers and response body/schema. I also verify negative responses, content types, response time and business rules rather than checking only a 200 status.
Common causes include race conditions, weak locators, fixed sleeps, shared state, random test data, environment instability and application timing. I use traces, logs and repeat runs to isolate the root cause.
I use `click({button:'right'})` for right-click and `dragTo()` for drag-and-drop when supported. For complex cases I may use mouse actions, followed by assertions on the resulting state.
A Scenario Outline is a parameterized Cucumber scenario executed once for each row in an Examples table. It is useful for covering multiple data combinations without duplicating scenario steps.
I maintain a frequency map, increment the count for each character, and then iterate over the map to obtain frequencies. I clarify whether spaces and case differences should be included.
`playwright.config.ts` centralizes test configuration such as projects, browsers, base URL, timeouts, retries, workers, reporter, trace, video and screenshot behavior.
I perform login once in a setup/authentication step, save the resulting storage state, and configure tests to use that state. This reduces repeated UI login while keeping each test's browser context isolated.
I verify the failed-attempt threshold, behavior before the threshold, lockout at the threshold, messages, duration, reset behavior and security against bypass through alternate login paths.
Playwright has timeout settings for tests, assertions, actions and navigation. I set sensible defaults and use targeted overrides for genuinely slower operations instead of globally making all tests very slow.
Interfaces can define contracts for page services, API clients, data providers or common components. This lets multiple implementations share a consistent API and makes dependency substitution easier.
API automation is automated validation of HTTP services without relying on the UI. It checks status codes, headers, payloads, authentication, business rules, error handling and performance-related expectations.
In CI/CD I can run tests in parallel using workers and split large suites across jobs or shards. I publish artifacts and reports and use environment-specific configuration and secrets.
I use a `LEFT JOIN` from employees to departments and filter rows where the department key is null. This identifies employees without a matching department assignment.
I use `locator.press()` or `page.keyboard` for keyboard interactions such as Enter, Escape, Control+A and arrow keys. I assert the resulting UI behavior.
MCP, or Model Context Protocol, is a standardized way for AI models to interact with external tools and data sources through defined interfaces. In testing/automation, it can help an AI agent use controlled tools and project context rather than relying only on prompt text.
I create a session with a controlled inactivity period, wait or simulate expiry, then access a protected feature. I verify timeout messaging, redirect behavior, invalidation of old credentials and successful re-authentication.
Inheritance allows a child class to reuse or extend properties and methods from a parent class. In automation, a carefully designed base page can provide common functionality, while page classes add page-specific behavior.
I create an API request context and call `get()` with the endpoint and any required headers or parameters. I validate the response status and body against the API contract.
A test suite is a logical collection of tests executed for a common purpose, feature, component or release. Good grouping improves organization, execution control and reporting.
I first determine whether the failure is reproducible and whether it is an application, environment or automation issue. I inspect logs/traces, classify failures, communicate blockers and rerun only after the underlying cause is understood.
HTTP 403 means Forbidden: the server understood the request but refuses to authorize it. It is different from 401, which generally indicates missing or invalid authentication credentials.
I enter the search text, wait for the suggestion list to update, locate the required option using stable text/role or attributes, select it, and verify the chosen value. I also test no-result and rapidly changing suggestions.
Polymorphism allows the same interface or method contract to work with different implementations. Common forms include compile-time overloading and runtime overriding.
I configure screenshot, video and trace settings in `playwright.config.ts`, often retaining them on failure or for retries. These artifacts are especially valuable for diagnosing CI failures.
I validate date cells against the expected format, timezone/business rules and actual values. For dynamic dates I calculate expected values in the test rather than hard-coding today's date.
Automation provides fast repeatable feedback on critical regression areas, but it does not replace risk-based exploratory testing. During release, I use automation results as one input to the quality decision.
Abstraction hides implementation details and exposes only the necessary behavior. For example, a `LoginPage.login()` method hides the individual locator and interaction steps from the test.
I run the test file path, for example `npx playwright test tests/login.spec.ts`. I can add a project, grep expression or other CLI options when needed.
POM improves locator reuse, reduces duplication, isolates UI changes and makes tests read closer to business actions. It is especially valuable when many tests use the same page.
I use environment variables or configuration objects for base URLs, credentials and feature-specific settings. I keep secrets outside source control and select the environment through CI/CD configuration.
With REST Assured, I build the request using `given()`, add headers/body, call the HTTP method and validate with `then()` assertions. I separate request specifications and reusable API methods in a framework.
AI can cluster similar defects, summarize logs, identify likely root causes and suggest missing test coverage. I still verify the evidence and do not treat an AI-generated diagnosis as proof.
An interface defines a contract and supports multiple implementations; an abstract class can provide both a contract and shared implementation/state. I choose an interface for capability/contract and an abstract class when shared base behavior is important.
I first scope locators to the relevant parent/container and then use stable attributes, role/name or text. I use `filter()` or `nth()` only when the business requirement genuinely identifies an item by position.
HTTP 402 is historically 'Payment Required'. It is not commonly used as a standard application response, so I follow the API's documented semantics if an application uses it.
I generate the required report in CI, store it as a build artifact or publish it to the team's reporting system, and expose it through the pipeline. I also publish screenshots, videos and traces for failures.
Functional testing types include unit, integration, system/end-to-end, smoke, sanity, regression, retesting and acceptance testing. The exact classification can vary by organization, so I explain the purpose of each.
I test valid and invalid passwords across length boundaries, complexity rules, whitespace, special characters, case sensitivity, reused/common passwords and lockout/security behavior. I verify that errors do not expose sensitive information.
I use API calls to create users, accounts or other prerequisite data quickly and deterministically, then open the UI and verify the resulting behavior. This reduces dependence on slow UI setup.
Encapsulation means keeping an object's data and implementation details protected behind controlled methods or properties. In a framework, page classes encapsulate locators and actions.
I count character frequencies first, then find the character with the greatest count. If multiple characters tie, I follow the stated requirement—for example, return all tied characters or the first occurrence.
Auto-retry assertions repeatedly evaluate conditions until they pass or the assertion timeout is reached. Examples include `toBeVisible`, `toHaveText`, `toHaveValue` and `toHaveURL`.
I create reusable page components, utilities, API clients, fixtures and helper functions with clear responsibilities. Shared code should be generic enough to reuse but not so abstract that it becomes difficult to understand.
Generative AI produces new content from learned patterns. In automation it can generate test ideas, scripts, test data, documentation and defect summaries, but I review generated output for correctness, security and maintainability.
API testing validates service behavior directly through HTTP requests, while UI testing validates the user-facing interface and end-to-end integration. API tests are generally faster and target backend contracts; UI tests provide broader user-flow confidence.
I compare a normalized set of database user IDs with UI user IDs and report the set difference. I check pagination, filters and permissions before concluding that a record is missing.
`getByRole()` locates elements using their accessible role and accessible name. It encourages selectors that resemble how users and assistive technologies perceive the page.
For `<button>Sign in</button>`, I would use `page.getByRole('button', { name: 'Sign in' })` and then perform the required action or assertion.
`getByText('Sign in')` locates an element containing the specified visible text. For a button, I prefer `getByRole('button', {name:'Sign in'})` because it expresses the element's semantic role.
A dynamic locator identifies an element whose attributes or content can change between runs. I build it from stable portions, relationships, roles, labels or test IDs rather than volatile generated values.
I prefer role, label, placeholder and test ID locators; scope to a stable container; avoid generated IDs; and verify uniqueness. If the UI is under my control, I request stable automation attributes where appropriate.
CSS selectors use CSS syntax and are usually concise; XPath supports richer tree relationships and text/attribute expressions. In Playwright I prefer semantic locators over either when possible.
I avoid `waitForTimeout()` for application synchronization. Instead I use auto-waiting, web-first assertions, locator states, URL waits or response waits tied to the event I actually need.
Automatic waiting means Playwright waits for actionability conditions such as visibility, stability and enabled state before performing many actions, and web-first assertions retry until their conditions are met.
I can use `await expect(page.getByRole('button', {name:'Login'})).toBeVisible({timeout: 10000});` to wait up to ten seconds for the button to become visible.
TypeScript asynchronous operations return Promises. `async/await` makes asynchronous flows easier to read while the event loop allows other work to continue instead of blocking the entire process.
TypeScript gives automation teams static typing, safer refactoring, better editor support, interfaces and clearer contracts. These benefits become more valuable as a framework grows.
I create one class per page or meaningful component, keep locators private/organized, expose business actions as methods, and avoid putting assertions everywhere unless they are page-specific validations.
I put cross-page behavior into a base page, component class or utility module depending on responsibility. For example, common navigation helpers belong in a shared abstraction rather than being copied into every page class.
I separate data generation, storage and consumption. For large suites I prefer factories/API setup, unique identifiers, environment-specific configuration and cleanup rather than maintaining huge static datasets.
An enterprise framework should include POM/components, fixtures, API clients, data factories, configuration management, logging, reporting, CI/CD, tagging, parallelism, security controls and coding standards. I design for maintainability and observability, not only execution speed.
I extend Playwright fixtures using `test.extend()` to provide custom objects or setup. For example, I can create a fixture that constructs a page object and automatically handles its lifecycle.
I configure `workers` in `playwright.config.ts` or override it from the command line. I choose the value based on CI capacity, test isolation and application/environment limits.
With a maximum of four workers, Playwright can execute up to four tests in parallel when enough independent work exists. As workers finish, remaining tests are scheduled onto available workers; it does not mean four tests must always remain active.
I use `test.describe('Login', ...)` and `test.describe('Dashboard', ...)`, or tags/projects when the grouping must also control execution. This keeps reporting and selective runs clear.
I use Playwright annotations/tags and `--grep`/`--grep-invert`, or project configuration for larger categories. The important point is to make grouping intentional and consistent.
I define named projects in the config and run one with `npx playwright test --project=<name>`. This is useful for validating one browser or environment configuration.
Each project can define its browser, device, base URL, permissions, storage state and other settings. This allows one suite to run against multiple target configurations.
I configure the `reporter` option with one or multiple reporters, such as HTML plus JUnit. I select reporters based on local debugging, CI integration and stakeholder needs.
I minimize dependencies between tests because Playwright is designed for independent execution. When a workflow truly requires sequencing, I model setup through fixtures or API preparation rather than relying on execution order.
I authenticate once in a setup project or global authentication step, save `storageState`, and reuse it. This preserves speed while allowing each test to start with an authenticated context.
I test whether credentials persist across sessions, browser restarts and appropriate expiration periods. I also verify logout, cookie behavior, security restrictions and that the feature does not bypass account policies.
I test brute-force protection, password masking, secure transport, session fixation/expiry, authorization, sensitive error messages, CSRF-related behavior where applicable, cookie security and access to protected pages after logout.
I verify that the checkbox/link is present, acceptance is mandatory when required, the correct version is referenced, and the user's consent is recorded appropriately. I test both accepted and not-accepted paths.
I verify exact or approved message content, placement, accessibility, consistency, non-disclosure of sensitive information and behavior after correction. I also test server-side validation rather than trusting only client-side messages.
I cover wrong username, wrong password, both wrong, disabled/locked account, expired credentials, whitespace/case variations, repeated failures and unauthorized access attempts. Expected behavior should not reveal which credential was incorrect if security requires generic errors.
I test both fields blank, each field blank individually, whitespace-only input and invalid combinations. I verify validation timing, messages, focus and whether submission is prevented.
I verify the password is obscured by default, that reveal/hide works correctly if provided, that copied values follow the product's security requirements, and that accessibility labels are correct.
I verify enabled/disabled state, keyboard activation, validation on click, duplicate-click behavior, loading state and prevention of multiple submissions. I also verify the correct request is sent once.
I use separate browser contexts/users and independent test data to simulate concurrent sessions. I validate expected behavior for simultaneous logins, updates and conflicting operations according to the application's rules.
After login, I test back/forward navigation, protected pages, cached content and redirects. A logged-out or unauthorized user should not regain protected access merely by using browser history.
I click Logout, verify the session is invalidated, redirect occurs as expected, protected pages are inaccessible, and cached UI does not expose sensitive data.
I verify redirect to the login/public page, session/cookies invalidation, inability to access protected URLs, correct message/state, and that a fresh login is required.
I attempt direct navigation to a protected URL after logout and refresh/reopen it. The application should deny access or redirect to authentication, and sensitive content should not be available from cache.
I pass the required `Authorization` header or other documented authentication headers through the API request options. Secrets come from secure environment/CI configuration rather than source code.
I validate required headers such as content type, cache/security headers and correlation IDs according to the contract. I also verify values and formats, not just that a header exists.
I parse the response JSON and assert required fields, types, values, nested structures, business rules and error payloads. For flexible fields, I use schema or partial assertions instead of brittle full-string comparisons.
I measure response duration and compare it with the agreed SLA or threshold. I avoid using an unrealistically tight threshold that makes the test environment itself the failure source.
I capture data from one response and use it in the next request—for example, create a user, extract its ID/token, then retrieve or update that user. I keep the chain explicit and validate each dependency.
I delete or reset data created by the test through API/database cleanup or disposable test environments. Cleanup should run even when the test fails, where practical.
I perform the UI action, retrieve the authoritative database value, normalize formats such as dates/currency, and compare business-relevant fields. I document how eventual consistency is handled.
Database validation in automation checks that backend records, relationships or state match the expected result after application operations. It is especially useful for verifying persistence and business transactions.
I use a database driver/client with secure connection details from environment configuration, open a connection or pool, execute parameterized queries, validate results and close/release resources.
I normalize UI and database representations, map records by a stable key, then compare required fields. I produce a clear diff showing missing, extra and mismatched values.
I retrieve the database dataset and UI table dataset, handle pagination/filtering, normalize values, compare counts and keys, then compare required columns. Failures should identify the exact record and field.
I first confirm the query, UI filters, pagination and eventual consistency. If the record truly should be visible, I raise a defect with the database key, expected behavior, UI evidence and test details.
I verify whether the UI record is legitimately created by another process or stale data. If it violates the requirement, I report the discrepancy and investigate data integrity or filtering logic.
I compare records by a stable unique key and generate a field-level diff for records present in both sources. This is more reliable than comparing row positions.
I normalize timezone, date format and precision according to the business rule, then compare the equivalent instants/dates. I avoid comparing raw strings when the display format differs from the database format.
A typical solution joins the employee table to itself using the supervisor/manager relationship, then joins the supervisor to the department table and filters for Accounting. I would adapt table and column names to the actual schema.
I use a `LEFT JOIN` from employees to departments and filter `WHERE department_id IS NULL` (or the equivalent missing-assignment condition). The exact query depends on the schema and whether an employee can have a null department key.
I use AI to draft joins, filters and alternative SQL approaches from a schema description. Then I verify the query against the schema, expected cardinality and sample results before execution.
I review table/column names, joins, filters, aggregation, null handling, permissions and SQL injection risk. I run it first against safe/sample data and compare results with an independently reasoned expected outcome.
A chatbot needs functional, conversation-flow, context, accuracy, safety, security, performance, accessibility and usability testing. For AI systems I also test hallucination, refusal behavior, prompt injection and consistency.
I validate chatbot responses against intent, factuality, relevance, completeness, tone, safety and required formatting. For non-deterministic responses I use a rubric and acceptable-answer criteria rather than exact string matching.
I compare the response with trusted reference information or business rules and check citations/evidence when applicable. For subjective questions, I evaluate against a predefined rubric and have human review for high-impact cases.
For descriptive answers, I evaluate meaning rather than exact wording. I check required concepts, factual correctness, clarity, completeness and prohibited content using a scoring rubric.
I define measurable criteria for relevance and accuracy, provide representative and edge-case prompts, compare outputs with trusted references, and record scores. I test across repeated runs because AI output can vary.
I repeat the same or semantically equivalent prompts and compare important claims, decisions and safety behavior. Small wording differences are acceptable when the underlying meaning remains correct.
I create a checklist of required facts, steps, fields or constraints and score the response against it. This prevents a fluent answer from being accepted simply because it sounds convincing.
AI-assisted defect analysis uses models to summarize failures, cluster similar issues, extract patterns from logs and suggest likely causes. A tester still verifies the evidence before assigning root cause.
AI can prioritize tests from change impact, generate additional edge cases, identify redundant coverage and summarize failure patterns. I use it as decision support and retain human ownership of risk decisions.
A strong interview answer should name the tools the candidate actually uses—for example, an AI coding assistant, an LLM for test design, or an AI-based defect/log analysis tool—and explain the real task each supports. I would not claim experience with a tool I have not used.
I explain each AI tool in terms of a measurable outcome: faster test-case generation, code assistance, debugging, documentation, data generation or analysis. I also mention review and security controls.
If I have worked with MCP, I explain the actual tools and workflow I connected. Otherwise I would say I understand MCP as a protocol for exposing tools/context to AI systems and avoid overstating hands-on experience.
MCP can provide a consistent interface for AI systems to access approved tools and contextual data. Benefits can include reuse, controlled access, clearer tool contracts and easier integration of AI agents with engineering workflows.
An AI agent can use conversation state, tool outputs, stored artifacts, test plans or structured task state to retain context. In a robust design, important steps are represented explicitly rather than relying only on model memory.
I answer this honestly based on actual experience. If my experience is prompt-based, I explain how I designed structured prompts, reviewed outputs and integrated them into testing; if I built agents, I explain tools, orchestration, memory/state and guardrails.
I reduce token usage by sending only relevant context, reusing structured summaries, avoiding repeated files/instructions, using focused prompts and asking for concise outputs. I also separate planning from large repetitive generation where practical.
Not necessarily. AI-generated code can contain wrong selectors, outdated APIs, missing awaits, poor synchronization, security issues or incorrect assumptions. I run, review, refactor and test it before accepting it.
I review generated code for correctness, locator quality, waits, assertions, error handling, security, maintainability, duplication and framework conventions. I then execute it and inspect failures rather than trusting the generation.
Typical challenges include dynamic locators, flaky synchronization, test-data dependencies, parallel execution, environment differences and CI failures. I explain the specific root cause and the engineering change I made to solve it.
I reproduce the failure, collect trace/log/screenshot evidence, classify it as application/environment/automation, isolate the smallest failing step and fix the root cause. Then I rerun the affected test and relevant regression coverage.
I check traces, timing, selectors, shared state, test order, network calls and data. I reproduce repeatedly, remove race conditions, improve synchronization and isolate data, then monitor whether the failure rate drops.
I inspect the locator in Trace Viewer/DOM, check uniqueness and accessible name, and determine whether the UI changed. I replace brittle selectors with stable semantic or test-specific locators and add assertions around the intended state.
I determine whether the timeout is caused by a slow application, wrong locator, missing state transition, network issue or incorrect expectation. I inspect the trace and logs before increasing the timeout.
I replace fixed sleeps with condition-based synchronization such as locator assertions, URL waits, response waits or application-state checks. I also ensure asynchronous operations are properly awaited.
I start with the failed step and trace, identify the first meaningful error, classify the failure, compare with recent changes and reproduce if possible. I then document root cause and corrective action rather than focusing only on the final stack trace.
I stop and classify the 40 failures rather than blindly rerunning everything. I look for a common root cause such as environment outage, authentication failure, locator change or shared data problem, then fix the systemic issue and rerun the impacted subset.
I compare the automation behavior with the application manually/API-wise, inspect request/response and logs, and check whether the selector or test expectation is wrong. A reproducible product behavior against a valid requirement points toward an application defect.
I first assess impact and help reproduce/contain the production defect. Then I perform root-cause analysis, identify the test/process gap, add appropriate coverage or monitoring, and communicate corrective/preventive actions without focusing on blame.
I collect timeline, requirements, code/configuration, test evidence, logs and deployment changes; identify the failure point; determine why existing controls missed it; and implement preventive actions such as better tests, monitoring, review or process changes.
I select tests based on business criticality, changed components, dependencies, historical defects, risk and regulatory/security impact. High-risk changed areas and critical end-to-end paths receive priority.
I assess severity and business impact, reproduce and isolate the issue, communicate the release risk, support containment/workaround, and coordinate a verified fix. I also add regression coverage to prevent recurrence.
I describe the application, business purpose, architecture, team, my responsibilities, test approach, framework, CI/CD, major challenges and measurable outcomes. I keep the explanation structured and aligned with my actual experience.
I state my role precisely—for example, Senior QA/Automation Engineer—and distinguish what I personally designed, implemented, reviewed and supported from what the wider team owned.
I explain responsibilities such as requirement analysis, test strategy, framework design, automation, API/UI validation, defect management, CI/CD integration, code reviews, mentoring and release support, but only those I actually performed.
I would say Playwright was selected because it provides reliable browser automation, strong auto-waiting, cross-browser coverage, parallel execution, tracing, network control and a modern test runner. I connect the choice to project needs rather than saying it is simply 'faster'.
I chose TypeScript because strong typing, interfaces, IntelliSense and compile-time checks improve maintainability for a growing automation framework. It also integrates naturally with Playwright's TypeScript tooling.
I describe one or two real challenges, explain how I diagnosed them, the technical change I made, and the measurable result. A strong answer demonstrates ownership rather than simply listing problems.
I continuously review flaky-test trends, framework duplication, execution time, failure diagnostics and new product risks. I refactor reusable components, improve data setup, update dependencies deliberately and use team feedback to prioritize improvements.
I start with requirements and risk analysis, identify automation candidates, design the framework and test data strategy, implement POM/fixtures/API helpers, create tests and assertions, integrate CI/CD, add reporting and diagnostics, execute regression, analyze failures and continuously improve coverage and reliability.
Verification checks whether we are building the product correctly against specifications; validation checks whether we are building the right product for user/business needs. Reviews are common verification activities, while executing functional scenarios is a validation activity.
Severity describes the technical/business impact of a defect; priority describes how urgently it should be fixed. A defect can be high severity but lower priority in a rarely used feature, or low severity but high priority in a highly visible release issue.
Smoke testing is a broad, shallow check that the build is stable enough for deeper testing. Sanity testing is a focused check of a specific changed area after a fix/change.
Retesting verifies that a specific defect has been fixed. Regression testing checks that the change did not break existing functionality elsewhere.
I derive test scenarios from requirements, identify positive/negative/edge cases, apply techniques such as equivalence partitioning and BVA, define clear preconditions/data/steps/expected results, and review coverage against the requirement.
Boundary Value Analysis tests values at and around the limits of an input range because defects often occur at boundaries. For a 1–100 field, typical values are 0, 1, 2, 99, 100 and 101.
Equivalence Partitioning divides input data into classes expected to behave similarly, then selects representative values from each class. It reduces the number of tests while retaining meaningful coverage.
I clarify the requirement with the product owner/BA, document assumptions and examples, identify risks, and avoid silently guessing expected behavior. I update the test cases once the acceptance criteria are confirmed.
A defect lifecycle commonly includes New/Open, Assigned, In Progress, Fixed/Resolved, Retest, Reopened and Closed, with variants such as Deferred, Rejected or Duplicate. Exact statuses depend on the team's workflow.
I use risk-based testing: prioritize critical business flows, recent changes, integrations, high-defect areas, security and regulatory requirements. I communicate what is covered, what is not, and the residual risk.
Query parameters are typically used to filter or modify a request, while path parameters identify a resource in the URL. I pass them using the API client's supported options and validate encoding and resulting behavior.
I validate required fields, data types, formats, nested structures and additional-property rules against the JSON schema. I include both valid and invalid payloads and ensure the API returns the expected validation error.
I test missing/extra fields, invalid types, malformed values, boundary values, unauthorized users, forbidden roles, invalid tokens and unsupported methods. I verify both status code and error contract.
For Bearer tokens I send `Authorization: Bearer <token>`; OAuth flows may require obtaining a token from an authorization server first. Tokens should be handled securely and never committed to source control.
I obtain the API response and the corresponding database record, normalize formats, compare stable keys and business fields, and account for eventual consistency. Failures should show the exact mismatch.
I use Playwright's routing APIs to intercept requests and fulfill, continue or abort them. Mocking lets tests simulate backend responses, error conditions and rare states without depending on an external service.
I never send passwords, production secrets, customer PII or confidential source code to an AI tool unless the organization's approved controls explicitly allow it. I anonymize data, use approved enterprise tools and review generated output for leakage.
I test known-fact questions, ambiguous prompts, adversarial prompts, unsafe requests and requests outside the model's knowledge. I compare claims against trusted sources, verify refusal/safety behavior and measure hallucination rates using a defined rubric.
I define an evaluation rubric with dimensions such as factual accuracy, required concepts, relevance, safety and completeness, then score responses against it. For high-risk use cases, human review remains part of the evaluation process.
An effective prompt states the role, application context, objective, constraints, required output format and relevant examples. I ask for assumptions to be stated and then review the generated test cases for gaps.
I test equivalent prompts across demographic or contextual variations and compare accuracy, treatment and refusal behavior. I use representative datasets and predefined fairness criteria, then investigate statistically or qualitatively meaningful differences.
I simulate model unavailability, timeout, rate limit and invalid upstream responses, then verify the application's fallback message, retry policy, cached/alternative response and recovery path. The fallback should fail safely and not expose internal details.
I map requirements to test scenarios/cases, link defects to failed tests, and identify automated coverage for stable regression scenarios. In CI/reporting, I maintain traceability through IDs, tags or test-management integrations so coverage and gaps are visible.