Challenges Faced & How I Coped โ Java, Playwright, API Testing, UI Testing (STAR)¶
These are the "tell me about a challenge you faced" questions. Interviewers aren't testing trivia here โ they're testing how you think under pressure. Answer with a real story, not a definition.
Format: each answer uses STAR โ Situation โ Task โ Action (the bulk, say "I" not "we") โ Result (quantified + what you learned). Aim for 60โ90 seconds spoken.
How to use: read the ๐ค say-this one-liner first (that's your compressed answer), then the full STAR if they probe. Every story is grounded in your real projects โ Morrie (Playwright/TS), RestAssured_API (Java/REST Assured), B2BProjectTest (Selenium 4/TestNG). The bold words are what the interviewer listens for.
Golden rule for ALL of these: name a specific problem โ the specific thing you did โ a result. "It was hard so I worked harder" fails. "Endpoints rate-limited my parallel runs, so I built a throttle with Retry-After handling, and the suite went green" wins.
Contents - Part A โ Java challenges (5) - Part A2 โ Python challenges (5) - Part B โ Playwright challenges (5) - Part C โ API testing challenges (5) - Part D โ UI testing challenges (5) - Part E โ Cross-cutting / behavioural ("biggest challenge", "learned the hard way") - Part F โ The 30-second template for ANY challenge question
PART A โ JAVA CHALLENGES¶
A1. What was a challenging problem you faced in Java, and how did you solve it?¶
๐ค Say-this: "Running my Selenium suite in parallel caused tests to hijack each other's browser sessions. The root cause was a shared WebDriver. I moved it to a ThreadLocal<WebDriver> so each thread got its own instance โ the cross-talk disappeared and the suite ran ~3ร faster."
- Situation: On B2BProjectTest I switched TestNG to
parallel="classes"to cut a slow suite's runtime. - Task: Tests suddenly failed randomly โ clicks landed in the wrong browser, sessions collided.
- Action: I traced it to a single shared
WebDriverfield being used by all threads. I wrapped the driver in aThreadLocal<RemoteWebDriver>so every thread gets its own isolated browser, and made sure I calleddriver.quit()+remove()in teardown so threads didn't leak sessions. - Result: The flakiness from concurrency vanished, runtime dropped roughly 3ร, and I learned that shared mutable state is the enemy of parallel test execution โ the fix is thread-confinement, not more waits.
Follow-up they'll ask: "Why ThreadLocal and not just a new driver per method?" โ "ThreadLocal keeps one driver per thread reused across the methods that thread runs, so I'm not paying browser-startup cost on every test โ I get isolation and speed."
A2. Have you dealt with flaky tests in Java? How?¶
๐ค Say-this: "I added a TestNG RetryAnalyzer wired in automatically via IAnnotationTransformer, so every test retries once on failure โ but only once, so a genuine bug that fails twice still fails the build."
- Situation: A handful of UI tests failed intermittently on CI but passed locally โ classic flakiness from timing.
- Task: Stop the noise without hiding real defects.
- Action: I wrote a custom
RetryAnalyzer(retryLimit = 1) and applied it to all tests through anIAnnotationTransformerlistener (so I didn't have to annotate each test by hand). I paired that with explicit waits to fix the actual root cause, not just paper over it. - Result: CI noise dropped sharply, but because retry is capped at one, a real bug (fails twice) still breaks the build โ so I got stability without masking regressions. Lesson: retry is a safety net, not a cure โ always fix the underlying wait too.
A3. Did working on an older Java version ever constrain you?¶
๐ค Say-this: "My API framework was on Java 7, so no lambdas or Streams. I leaned on clean helper/service classes and loops instead โ and it taught me the fundamentals aren't the syntax sugar; they're the design."
- Situation: RestAssured_API ran on Java 1.7; B2BProjectTest on Java 1.8.
- Task: Keep the code readable and DRY without Java 8 features on the older repo.
- Action: On the Java 7 repo I structured logic into a helper/service layer and request wrappers (
GET/POST/PATCH) instead of reaching for Streams; on the Java 8 repo I could use lambdas/AssertJ SoftAssertions, so I did. I was deliberate about not mixing idioms across repos. - Result: Both stayed maintainable. Honestly, if I re-did the Java 7 one I'd upgrade the JDK and replace loops with Streams โ and I say that in interviews because it signals a maintenance/upgrade mindset.
A4. A tricky Java bug โ NullPointerException / object comparison?¶
๐ค Say-this: "A test compared two Strings with == and passed locally but failed on CI. The values were equal but not the same object โ I switched to .equals() and it was fixed. Classic reference-vs-content trap."
- Situation: An assertion comparing an API field to an expected value behaved inconsistently.
- Task: Figure out why equal-looking strings weren't "equal."
- Action: I realised the code used
==, which compares references, not content โ one string came from the String pool, the other was built at runtime, so they were different objects. I changed it to.equals()(and added a null-safeObjects.equals()where either side could be null). - Result: Deterministic pass. Lesson I now apply everywhere:
==for primitives / reference identity,.equals()for content โ and guard nulls withObjects.equals().
A5. How did you handle test data in Java?¶
๐ค Say-this: "Hardcoded data made tests brittle and un-reusable, so I made them data-driven โ reading inputs from JSON/CSV/Excel (Jackson, OpenCSV, Apache POI) via TestNG @DataProvider โ so non-engineers could extend cases without touching code."
- Situation: Early tests had inputs baked into the code; adding a case meant editing Java.
- Task: Make the suite data-driven and easy to extend.
- Action: I externalised inputs into JSON/CSV/Excel and fed them through a custom
ReadTestDatareader + TestNG@DataProvider, so one test method ran across many rows. - Result: Coverage grew without new code, and a BA could add a scenario by editing a spreadsheet. Lesson: separate the data from the logic โ it scales and it invites collaboration.
PART A2 โ PYTHON CHALLENGES¶
(Grounded in your Python work: the LLM-evaluation framework โ pytest + asyncio, Pydantic, LLM-as-judge, Langfuse โ the bce practice-repo, and the cicd-cloud-lab Flask app.)
A2-1. What was a challenging problem you solved in Python?¶
๐ค Say-this: "The chatbot streams answers over SSE/WebSocket, so a normal blocking test couldn't read the response. I moved the suite to pytest-asyncio and wrote async/await tests that consume the stream chunk-by-chunk โ so I could assert on streaming output without blocking."
- Situation: On the LLM-eval framework the chatbot replied over Server-Sent Events / WebSocket, not a single synchronous response.
- Task: Test a streaming, asynchronous channel reliably.
- Action: I adopted
pytest+pytest-asyncio(async mode), wrote coroutine tests withasync/await, and used async HTTP/WebSocket clients (httpx,websocket-client) to read the stream as it arrived, then asserted on the assembled result. - Result: I could validate streaming responses end-to-end. Lesson: match the test's concurrency model to the app's โ a streaming app needs async tests, not blocking ones.
A2-2. How did you test something non-deterministic like an LLM judge in Python?¶
๐ค Say-this: "An LLM scoring an LLM drifts run-to-run. I pinned the judge to temperature 0 with strict JSON-schema output, and I calibrated it against human labels using Cohen's kappa โ I only trusted the judge once kappa cleared ~0.6 (substantial agreement)."
- Situation: Using LLM-as-judge to grade chatbot answers, scores weren't repeatable.
- Task: Make an inherently non-deterministic evaluator trustworthy and repeatable.
- Action: I set the judge to temperature 0, forced structured JSON output (OpenAI JSON-schema / Anthropic forced tool-use) so scores were always parseable, and measured agreement with human labels via Cohen's kappa before relying on it. I also anchored grading to a ground-truth oracle (re-running the business logic in a read-only DB) so the judge graded against fact, not vibes.
- Result: Reproducible, defensible scores instead of a black box. Lesson: for non-deterministic evaluators, constrain (temp 0 + schema) and calibrate (kappa) โ don't just trust the model.
A2-3. LLMs return messy text โ how did you get reliable structured data in Python?¶
๐ค Say-this: "Models sometimes returned prose around the JSON, breaking json.loads. I enforced strict JSON-schema / tool-use output and wrapped parsing in a validate-and-retry loop with Pydantic, so a malformed response was re-requested, not crashed on."
- Situation: The judge/eval pipeline needed clean JSON, but LLMs occasionally wrapped it in explanation.
- Task: Guarantee parseable, typed output.
- Action: I used the provider's structured-output mode, validated every response against a Pydantic model, and on a validation failure retried the call โ so bad output self-corrected instead of failing the run. Pydantic also validated my config from env vars, so a bad setting failed fast.
- Result: The pipeline stopped crashing on stray model text. Lesson: never trust raw LLM text โ schema-validate it, and retry on failure.
A2-4. Eval runs were slow and expensive โ how did you cope?¶
๐ค Say-this: "Judge calls cost money and time, so re-runs were painful. I added a SQLite cache with a 7-day TTL on judge results, so repeated evals hit the cache instead of the paid API โ re-runs went from expensive to nearly free."
- Situation: Every eval re-called paid LLM judges, making iteration slow and costly.
- Task: Cut cost/latency without losing correctness.
- Action: I cached judge/agent results in SQLite with a 7-day TTL keyed on the input, so identical evaluations reused prior results, and only genuinely new inputs hit the API. I kept the fast subset in CI and excluded slow/UI tests to keep the gate quick.
- Result: Dramatically cheaper re-runs and a fast CI signal. Lesson: cache expensive deterministic-enough calls, and tier your suite (fast gate vs full run).
A2-5. A Python design/quality challenge?¶
๐ค Say-this: "Three eval repos duplicated ~80% of their code, which made fixes error-prone. My lesson โ and what I'd do next โ is extract a shared core package so the telecom/FMCG/retail variants import one library instead of copy-pasting it. I also added a detect-secrets pre-commit hook after finding committed keys."
- Situation: The LLM-eval framework was reused across three domains by copying the repo.
- Task: Recognise and address the maintainability cost.
- Action: I standardised tooling (black, flake8, mypy, isort, pre-commit) across them, and added
detect-secretsto stop credentials leaking into git. The honest next step is consolidating the shared 80% into one installable package. - Result: Consistent quality gates today; a clear refactor path tomorrow. Lesson: duplication is a debt โ say so openly; it signals a maintenance mindset. (Honest: the consolidation is planned, not done โ I don't claim otherwise.)
PART B โ PLAYWRIGHT CHALLENGES¶
B1. What was the toughest problem in your Playwright project?¶
๐ค Say-this: "The AI platform's APIs rate-limited me, so parallel setup kept hitting 429s. I built an Axios BaseApi with a 700 ms throttle + Retry-After handling, so setup stayed under the limit even running fully parallel. That's the part of the framework I'm proudest of."
- Situation: On Morrie (Playwright + TypeScript) I seeded state through the product's REST API before UI tests, running
fullyParallel. - Task: Parallel requests tripped the platform's rate limits (HTTP 429), making setup flaky.
- Action: I wrote a shared
BaseApion Axios that enforces a ~700 ms minimum gap between requests and, on a 429, readsRetry-Afterand backs off before retrying. Auth/User/Chats/Agents API classes all extend it, so throttling is centralised, not copy-pasted. - Result: Setup stopped failing on limits, and I could keep the suite fully parallel for speed. Lesson: when you can't change the server, make the client well-behaved โ throttle + honour the server's own backoff signal.
Follow-up: "Any weakness in that approach?" โ "The throttle is a single global lock; under high concurrency I'd move to a per-host token bucket so independent hosts aren't serialised."
B2. Playwright tests were flaky โ how did you stabilise them?¶
๐ค Say-this: "I leaned on Playwright's auto-waiting instead of manual sleeps, and turned on trace on-first-retry so when something did fail I could open the Trace Viewer and see exactly what happened โ no guessing."
- Situation: Some UI steps intermittently failed on slower CI runners.
- Task: Cut flakiness and make failures diagnosable.
- Action: I removed hard waits and relied on Playwright's built-in actionability auto-wait (it waits for elements to be visible/enabled before acting). I configured screenshot + video only-on-failure and trace on-first-retry, so a first failure retries and captures a full trace I can replay.
- Result: Far fewer false failures, and the ones that remained were debuggable in minutes via Trace Viewer. Lesson: auto-wait beats sleep, and capture evidence on retry so flakiness becomes a solvable data point, not a mystery.
B3. Logging in for every test was slow โ how did you fix it?¶
๐ค Say-this: "I logged in once in global-setup and saved the session with storageState (API token + UI cookie), then every test reused it โ so I skipped the login flow entirely and the suite got noticeably faster."
- Situation: Every test re-doing the login flow was slow and added a flaky UI dependency to unrelated tests.
- Task: Authenticate once, reuse everywhere.
- Action: In
global-setup.tsI logged in a single time, captured both the API token and UI cookie viastorageState, and pointed thechromiumproject at that saved state so tests start already logged in. - Result: Big speed win and login flakiness stopped contaminating other tests. Lesson: authenticate once, reuse state โ don't pay the login cost per test.
B4. How did you test non-deterministic AI responses in Playwright?¶
๐ค Say-this: "The product is an AI agent, so responses vary run-to-run. I stopped asserting exact text and instead asserted on structure and invariants โ that a response arrived, had the right shape, and contained expected entities โ plus API-level checks where I could."
- Situation: Morrie automates an AI-agent platform where the same input yields different wording each time.
- Task: Write assertions that are meaningful but not brittle against non-determinism.
- Action: I shifted from exact-match to property-based checks โ response is non-empty, matches an expected schema/shape, contains required keywords/entities, and completes within a timeout. Where a deterministic contract existed, I verified it at the API layer and used the UI test only for the user-visible flow.
- Result: Stable tests that still catch real breakage. Lesson: for AI/LLM outputs, test invariants, not exact strings โ the same mindset as evaluating a chatbot.
B5. Why Playwright over Selenium โ and what did you have to learn?¶
๐ค Say-this: "It was a greenfield project, so I chose Playwright for auto-waiting, parallel-by-default, and the Trace Viewer. The learning curve was fixtures and the async/await model โ once I built reusable fixtures for a logged-in page and an API client, tests read like English."
- Situation: New project, free choice of tooling.
- Task: Pick and ramp up on a framework that reduces flakiness and setup boilerplate.
- Action: I chose Playwright + TypeScript and invested in custom fixtures (8 of them) so setup like "a logged-in page" or "an API client" is injected cleanly instead of repeated in
beforeEach. I had to get comfortable with strict async/await and TypeScript typing. - Result: Less flaky than my Selenium suites, parallel out of the box, and readable. Lesson: the framework choice matters, but the reusable-fixture design is what actually made it maintainable.
PART C โ API TESTING CHALLENGES¶
C1. What's the hardest API-testing problem you've solved?¶
๐ค Say-this: "Backend changes were silently breaking things โ a renamed or retyped field would slip through. I added JSON-schema validation on every response with matchesJsonSchema(), so any contract drift fails the test immediately. That's the standout of my REST Assured framework."
- Situation: On RestAssured_API, backend responses occasionally changed shape (a field renamed, a type flipped from string to number).
- Task: Catch contract drift early instead of discovering it downstream.
- Action: I committed 21+ JSON schema files and validated each response with REST Assured's
matchesJsonSchema(). So a response that no longer matches the agreed contract fails right there, pointing at the exact field. - Result: Breaking changes were caught at the API layer, immediately, not silently later in the UI. Lesson: schema validation = contract protection โ it's the cheapest early-warning system for API tests.
C2. How did you automate authentication โ tokens and OTP?¶
๐ค Say-this: "The APIs used token- and OTP-based auth. I centralised the token flow in a helper so every test got a fresh valid token, and for OTP I pulled the code from a test endpoint / DB hook rather than a real phone โ you can't automate a real SMS, so you design a testable path."
- Situation: Endpoints required a bearer token, and some flows needed an OTP.
- Task: Make auth automatic and repeatable without manual steps.
- Action: I built an
AccessToken/Login service layer that fetches and caches a token, injected via a base request spec. For OTP, I retrieved the code from a test-environment hook (a QA endpoint / DB read) instead of a real SMS, because real OTP is deliberately un-automatable. - Result: Auth became a one-line setup for any test. Lesson: when something is designed to block bots (OTP/CAPTCHA), the answer is a test-env bypass, not brute force.
C3. How do you handle chained / dependent API calls?¶
๐ค Say-this: "Many flows depend on prior data โ you can't PATCH a profile you haven't created. I extracted IDs/tokens from one response and fed them into the next using REST Assured's extract().path(), and kept that wiring in the service layer so tests stayed clean."
- Situation: Real API journeys are sequential โ create โ read โ update โ delete.
- Task: Pass data (IDs, tokens) from one call to the next reliably.
- Action: I used REST Assured's
.extract().path()to pull values out of a response and pass them into the next request, and I kept this orchestration in helper/service methods so individual tests just calledchallengesHelper.create(...)without seeing the plumbing. - Result: End-to-end API journeys ran deterministically and read like a story. Lesson: state flows through the service layer, not through copy-pasted response parsing in every test.
C4. How did you keep API tests DRY and maintainable?¶
๐ค Say-this: "Auth, base URI, and common calls were being repeated everywhere. I pulled them into a helper/service layer with GET/POST/PATCH wrappers, so a base-URL or header change happens in one place."
- Situation: Early API tests duplicated base URI, headers, and auth in every method.
- Task: Remove duplication so changes don't ripple across dozens of tests.
- Action: I created request wrappers (
GET/POST/PATCH) and a service layer per domain (Login/Profile/Challenges/StudyPlan), centralising base spec and auth. - Result: A header or endpoint change is a one-line edit, and tests dropped to readable, intention-revealing calls. (Honest improvement I'd make: some helpers had assertions inside them, which breaks reuse for negative tests โ I'd return the
Responseand assert in the test instead.)
C5. How did you make API tests data-driven for non-engineers?¶
๐ค Say-this: "I fed test inputs from CSV/Excel/JSON (OpenCSV, Apache POI) so business folks could add cases without touching Java โ one method, many data rows."
- Situation: New test cases required a developer every time.
- Task: Let non-engineers extend coverage.
- Action: I read inputs from CSV/Excel/JSON and drove tests via
@DataProvider, so adding a case = adding a row. - Result: Faster coverage growth and shared ownership of test data. Lesson: externalise data to scale contributions beyond the automation engineer.
PART D โ UI TESTING CHALLENGES¶
D1. What was the hardest UI-automation challenge you faced?¶
๐ค Say-this: "The app was built on Webix, which generates dynamic IDs like webix_tm_id โ no stable ids to grab. I wrote robust relative XPath using stable custom attributes and parent/child navigation, so locators survived re-renders."
- Situation: B2BProjectTest automated a Webix-based UI where element IDs were generated and changed between renders.
- Task: Build locators that don't shatter every time the DOM re-renders.
- Action: Instead of brittle absolute paths or volatile IDs, I anchored on stable custom attributes (
view_id,webix_tm_id) and used relative XPath with parent/child axes to reach elements by their reliable context. I kept every locator in the Page class (POM), so a UI change touched one file. - Result: Locators became resilient to re-renders, and maintenance stayed contained. Lesson: prefer stable attributes and relative XPath; never trust auto-generated IDs.
D2. How did you handle dynamic waits / synchronization in UI tests?¶
๐ค Say-this: "Hard-coded Thread.sleep was both slow and flaky. I replaced it with explicit waits (WebDriverWait + ExpectedConditions) that wait for the actual condition โ and for an Angular app I used ngwebdriver to wait for Angular to settle."
- Situation: Tests failed randomly on elements that loaded asynchronously (AJAX/Angular).
- Task: Sync the test to the app without wasteful sleeps.
- Action: I removed
Thread.sleep, added explicitWebDriverWaitonelementToBeClickable/visibilityOf, and โ because part of the app was Angular โ usedngwebdriverto wait for pending Angular tasks to finish before interacting. - Result: Faster and more stable โ waits ended the moment the app was ready, not after a fixed guess. Lesson: wait for a condition, never a duration; and never mix implicit + explicit waits (it causes unpredictable timeouts).
D3. How did you debug UI failures on CI where you can't watch?¶
๐ค Say-this: "I made failures capture their own evidence โ a TakesScreenshot on failure via a custom listener, plus ExtentReports embedding the screenshot โ so a red test comes with a picture of the exact moment it broke."
- Situation: UI tests failed on CI with no visible browser to inspect.
- Task: Make failures self-explanatory without re-running locally.
- Action: I hooked screenshot-on-failure (via
TakesScreenshotin aCustomException/listener) and embedded it into ExtentReports, so every failure in the report shows the screen at the point of failure. - Result: Triage went from "re-run and hope" to "look at the picture." Lesson: failures should carry their own evidence โ screenshots/traces are non-negotiable for headless CI.
D4. How did you handle cross-browser / parallel UI execution?¶
๐ค Say-this: "I parameterised the browser and ran suites in parallel with a ThreadLocal driver so each thread had its own isolated browser โ no cross-talk, and coverage across Chrome/Firefox without duplicating tests."
- Situation: Needed the same tests across browsers, and faster.
- Task: Run in parallel and across browsers without flakiness.
- Action: I drove the browser choice from config, gave each thread its own
ThreadLocal<WebDriver>, and set TestNGparallel="classes"with a thread count. WebDriverManager (and in Selenium 4.6+, Selenium Manager) handled the driver binaries. - Result: Cross-browser coverage with no shared-state bugs, at a fraction of the runtime. Lesson: thread-confined drivers are the foundation of safe parallel UI testing.
D5. A hard-to-automate UI interaction (dropdown / alert / frame / upload)?¶
๐ค Say-this: "The classic traps โ I use the right tool per case: Select for real <select> dropdowns, switchTo().alert() for JS alerts, switchTo().frame() for iframes, and sendKeys(path) to a file input for uploads instead of fighting the OS dialog."
- Situation: Different pages needed dropdowns, JS alerts, iframes, and file uploads โ each a common failure point.
- Task: Handle each reliably instead of hacking around them.
- Action: I matched the tool to the element:
Selectclass (only for<select>tags), Alert API for pop-ups, frame switching before interacting inside iframes, andsendKeys()to the<input type=file>for uploads (no AutoIt/native dialog needed). - Result: These "gotcha" interactions became boringly reliable. Lesson: most "hard" UI cases have a correct native API โ reach for that before JavaScript hacks.
PART E โ CROSS-CUTTING / BEHAVIOURAL¶
E1. "What is the biggest challenge you've faced in automation overall?"¶
๐ค Say-this: "Flakiness โ tests that fail for reasons unrelated to real bugs. It erodes trust in the whole suite. I attack it on three fronts: proper waits (condition, not sleep), thread-confined state for parallel runs, and evidence capture (screenshots/traces) so the rare real failure is instantly diagnosable."
- Keep this one principle-level โ it shows you've seen the pattern across projects (Selenium and Playwright), not just one incident. Name the three fixes; they map to A1/B2/D3 above.
E2. "Tell me about a time you had to learn something fast."¶
๐ค Say-this: "Moving from Selenium/Java to Playwright/TypeScript on a greenfield project. I had to pick up the async/await model and fixtures quickly โ I did it by building the reusable pieces first (a logged-in fixture, an API client), which forced me to understand the framework deeply while producing something useful."
E3. "A challenge where you were wrong / learned the hard way."¶
๐ค Say-this: "On an older repo I put assertions inside helper methods. It felt DRY until I needed a negative test and couldn't reuse the helper because it always asserted success. I learned to return the response and assert in the test โ helpers should do, tests should judge."
- This one is gold: it's honest, shows growth, and pre-empts a code-quality follow-up. (Also true of your real repos โ safe to say.)
E4. "How do you handle disagreement about a defect / priority?" (see also Manual Q23)¶
๐ค Say-this: "Evidence over opinion. I make it reproducible, attach steps + screenshot + logs, and tie it to the requirement so it's fact, not preference. If we still disagree, I escalate to the person who owns the requirement โ not to win, but to decide."
PART F โ The 30-second template for ANY "challenge" question¶
When they name a technology you weren't ready for, fill in this skeleton live:
"One real challenge on [project] was [specific problem โ e.g. rate limits / flaky parallel runs / contract drift / dynamic locators]. The impact was [why it mattered โ flaky CI / silent breakage / slow suite]. So I [the specific action โ throttle+Retry-After / ThreadLocal / JSON-schema validation / relative XPath]. As a result [outcome โ suite went green / caught breakage early / 3ร faster], and it taught me [one-line lesson]."
Pick from your real inventory (so you never blank):
| If they ask aboutโฆ | Your go-to story | The one-liner |
|---|---|---|
| Java | Parallel cross-talk โ ThreadLocal | "Shared driver broke parallel runs; thread-confined it." |
| Java flakiness | RetryAnalyzer + IAnnotationTransformer | "Retry once, auto-applied โ net without hiding bugs." |
| Python | Streaming chatbot โ pytest-asyncio | "Matched the test's concurrency to the app's." |
| Python / LLM | Non-deterministic judge โ temp 0 + Cohen's kappa | "Constrain and calibrate โ don't just trust the model." |
| Python cost | SQLite judge cache, 7-day TTL | "Cache expensive calls; re-runs go near-free." |
| Playwright | Rate limits โ Axios throttle + Retry-After | "Made the client well-behaved when I couldn't change the server." |
| Playwright flakiness | Auto-wait + trace on-first-retry | "Stopped sleeping; captured evidence on retry." |
| API testing | JSON-schema validation (21+ schemas) | "Contract drift fails the test immediately." |
| API auth | Token + OTP via test hook | "Can't automate real OTP โ design a testable path." |
| UI testing | Webix dynamic IDs โ relative XPath | "Never trust auto-generated IDs." |
| UI sync | Explicit waits + ngwebdriver | "Wait for a condition, never a duration." |
| Debugging on CI | Screenshot/trace on failure | "Failures must carry their own evidence." |
Remember: a challenge answer is a story with a result, not a list of technologies. Situation โ what you did โ the outcome โ the lesson. Keep it under 90 seconds and stop on the result.