Resource library

QA Interview

JavaScript Coding Interview Questions for Testers (2026)

Master JavaScript coding interview questions testers face in 2026 with runnable examples, async testing patterns, Playwright tasks, and model answers.

23 min read | 2,909 words

TL;DR

JavaScript tester interviews emphasize data transformation, language semantics, asynchronous control flow, and reliable browser or API automation. Practice small runnable functions, then explain edge cases, mutation, complexity, failure behavior, and how the code would behave in a parallel test suite.

Key Takeaways

  • Explain coercion, mutation, ordering, and missing-value behavior before coding.
  • Practice arrays, maps, sets, objects, strings, promises, and event-loop reasoning.
  • Use `async` and `await` with explicit timeout, error, and cleanup strategies.
  • Write Playwright locators and assertions with supported auto-waiting APIs.
  • Keep test helpers deterministic and avoid shared state across workers.
  • Prove solutions with edge cases and state both time and space complexity.

JavaScript coding interview questions testers receive in 2026 extend well beyond reversing strings. A modern QA or SDET candidate may need to transform API data, explain the event loop, limit asynchronous work, diagnose a flaky promise chain, or write a concise Playwright test using supported locators and auto-retrying assertions.

The best answers combine JavaScript fluency with a testing mindset. You should make input assumptions explicit, avoid accidental mutation, handle rejected promises, and prove behavior with representative cases. This guide gives you runnable examples and an interview method that works for both coding screens and automation-design discussions.

TL;DR

Area Interview signal Common failure
Arrays and objects Clear transformation and data modeling Mutating shared fixtures
Map and Set Correct identity and counting choices Losing duplicates with a set
Language semantics Understanding equality, scope, and values Confusing null, undefined, and falsy
Promises Correct sequencing and rejection handling Missing await or unhandled work
Playwright User-facing locators and web-first assertions Manual sleeps and stale assumptions
Test design Boundaries, properties, and observability Checking only one example

Use this answer pattern: define the contract -> choose the representation -> implement -> run cases -> discuss production risks.

1. What JavaScript Coding Interview Questions Testers Evaluate

The surface task may be simple, but interviewers observe how you manage JavaScript's flexible semantics. Do you distinguish an absent property from a property holding undefined? Do you know whether a function mutates its argument? Can you explain why await inside forEach does not make the outer function wait? Can you design an error message that helps someone diagnose a failed CI run?

Start every problem with three categories of questions. First, clarify data: type, shape, size, ordering, duplicates, and invalid values. Second, clarify output: exact shape, stable order, and error policy. Third, clarify execution: synchronous or asynchronous, allowed concurrency, timeout, cancellation, and retry rules. These questions are especially valuable for API and UI tasks because external systems rarely return perfectly shaped data.

State your intended complexity and mutation policy. Saying "I will return a new array and leave the fixture unchanged" is a meaningful design decision. If you sort, remember that Array.prototype.sort() mutates the array, so copy first with [...values] or toSorted() when the interview runtime supports the modern copying method. Avoid guessing runtime support. A portable answer can use the spread copy.

Your goal is not maximum cleverness. It is an implementation another engineer can verify and maintain. The JavaScript automation interview guide offers additional language drills after you master the patterns here.

2. Master Values, Equality, Scope, and Mutation

JavaScript interview mistakes often come from semantics rather than algorithms. Know that === avoids coercive equality, Object.is differs for NaN and signed zero, and object equality compares identity. Two distinct objects with equal-looking fields are not strictly equal. For structural comparison in tests, use the assertion library's deep-equality feature or compare a defined canonical representation.

Understand missing values. null is an explicitly assigned value, while undefined often represents absence or an uninitialized result. Optional chaining, such as response.user?.profile?.name, prevents an access error but can also hide a malformed contract if used everywhere. Validation at the system boundary is usually clearer than allowing undefined to travel through many helpers.

Scope also matters. let and const are block-scoped. const prevents rebinding, not mutation of an object. A const array can still receive push. Prefer creating new values for shared test fixtures, especially when the runner can execute tests concurrently.

Concept Accurate explanation Testing consequence
=== Strict equality without coercion Prevents surprising matches such as number versus string
Object.is Same-value comparison Treats NaN as equal to itself
const Binding cannot be reassigned Object contents can still change
Spread syntax Shallow copy Nested objects remain shared
Optional chaining Stops on null or undefined May mask a broken required-field contract
sort() Sorts in place Can contaminate reused fixtures

Be ready to demonstrate each with a two-line example. Precise explanations build confidence before a larger coding task begins.

3. Solve Array Deduplication Without Losing the Contract

Deduplicating primitives is easy with Set, but real test data often contains objects. The interviewer must define what makes two records equivalent. The following complete Node.js program retains the first record for each normalized email and returns duplicate details without changing the input.

'use strict';

function uniqueUsersByEmail(users) {
  if (!Array.isArray(users)) {
    throw new TypeError('users must be an array');
  }

  const unique = [];
  const duplicates = [];
  const firstIndexByEmail = new Map();

  users.forEach((user, index) => {
    if (typeof user?.email !== 'string' || user.email.trim() === '') {
      throw new TypeError(`users[${index}].email must be a non-empty string`);
    }

    const key = user.email.trim().toLowerCase();
    if (firstIndexByEmail.has(key)) {
      duplicates.push({ index, firstIndex: firstIndexByEmail.get(key), user });
    } else {
      firstIndexByEmail.set(key, index);
      unique.push(user);
    }
  });

  return { unique, duplicates };
}

const users = [
  { id: 10, email: 'qa@example.com' },
  { id: 11, email: 'SDET@example.com' },
  { id: 12, email: ' qa@example.com ' }
];

console.log(uniqueUsersByEmail(users));

Run it with node filename.js. The expected time is O(n), with O(k) additional space for distinct normalized emails. The result preserves first-seen order and provides diagnostic indexes.

Do not normalize automatically without discussing the domain. Email addresses, usernames, product codes, and IDs may have different case or whitespace rules. Also ask which duplicate wins. The first entry, last entry, newest timestamp, or highest-priority source are different requirements. A quality engineer makes that rule visible rather than letting object assignment decide accidentally.

4. Group API Results and Detect Data-Quality Problems

A common JavaScript array coding question testing candidates is to summarize records by status while identifying malformed entries. A weak solution assumes every record is valid and uses a long chain that throws an unhelpful error. A strong solution separates accepted data from validation findings.

'use strict';

const allowedStatuses = new Set(['passed', 'failed', 'skipped']);

function summarizeResults(results) {
  if (!Array.isArray(results)) {
    throw new TypeError('results must be an array');
  }

  const counts = { passed: 0, failed: 0, skipped: 0 };
  const invalid = [];

  results.forEach((result, index) => {
    const status = result?.status;
    if (typeof status !== 'string' || !allowedStatuses.has(status)) {
      invalid.push({ index, status });
      return;
    }
    counts[status] += 1;
  });

  return { counts, invalid, total: results.length };
}

const summary = summarizeResults([
  { name: 'login', status: 'passed' },
  { name: 'checkout', status: 'failed' },
  { name: 'search', status: 'unknown' }
]);

console.log(summary);

This is deliberately an explicit loop. A reduce solution could also work, but nested accumulator mutation often becomes difficult to read during an interview. Explain the policy: invalid values are collected instead of counted, and the total includes them. A different contract might throw on the first invalid record or return only valid totals.

Useful test properties include: valid counts never become negative, the sum of valid counts plus invalid length equals total, input order does not affect counts, and the input array is unchanged. Property statements help you find cases that a few examples miss. They also show how coding work becomes an oracle for API contract testing.

5. Explain Promises, the Event Loop, and async Functions

An async function always returns a promise. await pauses that async function until the awaited promise settles, but it does not block the JavaScript runtime. Promise callbacks run as microtasks after the current call stack completes and before the next task is selected. In browser and Node.js interviews, avoid overgeneralizing every queue under one label. Explain the ordering relevant to the given snippet.

The classic trap is this code:

items.forEach(async (item) => {
  await save(item);
});
console.log('done');

forEach ignores the promises returned by its callback, so done can print before saves finish, and rejections may escape the intended handling. Choose the pattern based on execution requirements:

// Sequential, preserves one-at-a-time execution.
for (const item of items) {
  await save(item);
}

// Concurrent, waits for every save and rejects if one rejects.
await Promise.all(items.map((item) => save(item)));

Sequential execution may be necessary for rate limits, ordered state changes, or shared data. Promise.all starts mapped operations without a concurrency cap and fails fast from the caller's perspective, although already-started operations continue. For a large input or constrained service, implement bounded concurrency or use a reviewed library already approved by the project.

Always discuss rejection. Use try and catch only when you can add context, recover, or map an expected failure. A finally block is appropriate for cleanup that must occur after success or failure. Do not swallow a rejected promise to keep the test green.

6. Implement Bounded Asynchronous Work

Async JavaScript questions for testers often ask you to call several endpoints without overwhelming the service. The following program runs promise-returning tasks with a fixed number of workers, preserves result order, and rejects when a task rejects. It uses only standard JavaScript.

'use strict';

async function mapWithConcurrency(items, limit, worker) {
  if (!Number.isInteger(limit) || limit < 1) {
    throw new RangeError('limit must be a positive integer');
  }
  if (typeof worker !== 'function') {
    throw new TypeError('worker must be a function');
  }

  const results = new Array(items.length);
  let nextIndex = 0;

  async function runWorker() {
    while (true) {
      const index = nextIndex;
      nextIndex += 1;
      if (index >= items.length) return;
      results[index] = await worker(items[index], index);
    }
  }

  const workerCount = Math.min(limit, items.length);
  await Promise.all(Array.from({ length: workerCount }, () => runWorker()));
  return results;
}

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const output = await mapWithConcurrency([3, 1, 2], 2, async (value) => {
  await delay(value * 20);
  return value * value;
});
console.log(output); // [9, 1, 4]

Save this as an .mjs file or run it in a project configured for ECMAScript modules because it uses top-level await. The shared index is safe in this single-threaded execution model because assignment occurs synchronously before each await. If worker code used actual shared memory across worker threads, different synchronization would be required.

Discuss cancellation as a production improvement. A rejected worker causes the aggregate promise to reject, but other started tasks do not automatically stop. For network calls, pass an AbortSignal through the worker and define whether one failure should cancel the remaining work or produce a complete per-item report. Testing both policies is more valuable than assuming one is universally correct.

7. Test HTTP Behavior with Native fetch

Modern Node.js provides a standards-based global fetch. A coding exercise may ask you to retrieve JSON, enforce a timeout, and fail clearly for non-success status codes. The function below accepts a URL and timeout, uses AbortSignal.timeout, checks response.ok, verifies the content type, and returns parsed JSON.

'use strict';

export async function getJson(url, timeoutMs = 5000) {
  if (!Number.isInteger(timeoutMs) || timeoutMs < 1) {
    throw new RangeError('timeoutMs must be a positive integer');
  }

  const response = await fetch(url, {
    headers: { accept: 'application/json' },
    signal: AbortSignal.timeout(timeoutMs)
  });

  if (!response.ok) {
    throw new Error(`GET ${url} failed with HTTP ${response.status}`);
  }

  const contentType = response.headers.get('content-type') ?? '';
  if (!contentType.toLowerCase().includes('application/json')) {
    throw new Error(`Expected JSON but received ${contentType || 'no content type'}`);
  }

  return response.json();
}

A production API test should not depend on an uncontrolled public endpoint. Test this helper against a local stub server or by injecting a fetch-compatible function. Cover a valid JSON response, each relevant non-2xx family, malformed JSON, wrong content type, timeout, connection failure, and sensitive-data rules for error messages.

Remember that fetch resolves normally for HTTP 404 or 500. Network failure rejects, but application-level HTTP failure requires an explicit status check. Also avoid retrying every GET mechanically. Some failures are deterministic, and even a nominally safe method can interact with rate limits or expensive backend work. The API automation testing guide expands these contract and reliability decisions.

8. Write Current Playwright Code in an Interview

Playwright questions test whether you understand locators, auto-waiting, web-first assertions, isolation, and observability. Use role, label, text, or a stable test ID based on the product's testing contract. Avoid long CSS or XPath chains that mirror implementation structure. Locators resolve elements when used, which supports re-rendering better than storing raw element handles.

This is a valid Playwright Test example using current public APIs:

import { test, expect } from '@playwright/test';

test('signed-in user can add an item to the cart', async ({ page }) => {
  await page.goto('/products');

  const product = page
    .getByRole('listitem')
    .filter({ hasText: 'Noise-cancelling headphones' });

  await product.getByRole('button', { name: 'Add to cart' }).click();
  await expect(page.getByTestId('cart-count')).toHaveText('1');
  await expect(page.getByRole('status')).toContainText('Added to cart');
});

toHaveText and toContainText are asynchronous web assertions, so they must be awaited. Do not add a sleep before them. Playwright retries these supported locator assertions until they pass or the assertion timeout is reached.

In an interview, state what remains outside the snippet: authentication setup, deterministic seed data, cleanup, environment configuration, and ownership of the test ID. Also explain why two assertions exist. The cart count validates state, while the status message validates user feedback. Depending on risk, you may verify the backend contract through the UI's network behavior or an independent API check, but avoid testing the same implementation twice and calling it independent evidence.

9. Test JavaScript Utilities with Node's Built-In Runner

The Node.js test runner is available from the node:test module, and strict assertions come from node:assert. This makes a useful interview example because it has no third-party dependency. The code below tests a small normalization function.

// normalize-status.js
export function normalizeStatus(value) {
  if (typeof value !== 'string') {
    throw new TypeError('status must be a string');
  }
  const normalized = value.trim().toLowerCase();
  if (!['passed', 'failed', 'skipped'].includes(normalized)) {
    throw new RangeError(`unsupported status: ${value}`);
  }
  return normalized;
}
// normalize-status.test.js
import test from 'node:test';
import assert from 'node:assert/strict';
import { normalizeStatus } from './normalize-status.js';

test('normalizes supported status values', () => {
  assert.equal(normalizeStatus(' FAILED '), 'failed');
});

test('rejects unsupported status values', () => {
  assert.throws(
    () => normalizeStatus('blocked'),
    { name: 'RangeError', message: 'unsupported status: blocked' }
  );
});

test('rejects non-string input', () => {
  assert.throws(() => normalizeStatus(null), TypeError);
});

With a package configured for modules, run node --test normalize-status.test.js. Explain that the cases cover normalization, invalid domain input, and invalid type input. Add an empty-string case if the specification distinguishes it.

Avoid overspecifying implementation. Tests should assert the public result and error contract, not whether the function called trim exactly once. For a more complex function, separate deterministic transformation tests from network or filesystem integration tests. That boundary keeps feedback fast and failures diagnosable.

10. JavaScript Coding Interview Questions Testers: 14-Day Practice Plan

Days 1 and 2: practice values, strict equality, strings, arrays, objects, destructuring, and optional chaining. Predict short snippets before running them. Days 3 and 4: solve frequency, deduplication, grouping, sorting, and list-difference tasks with Map and Set. State whether each solution mutates input.

Days 5 and 6: work with functions, closures, scope, modules, errors, and validation. Day 7 is a timed mock with a data-transformation problem. Days 8 and 9: focus on promises, the event loop, sequential versus concurrent loops, timeout, and cancellation. Implement bounded concurrency once from memory and test rejection behavior.

Days 10 and 11: write one HTTP helper and three Playwright scenarios using role or label locators and awaited web-first assertions. Day 12: review test isolation, fixtures, parallel workers, retries, traces, and data cleanup. Day 13: complete a 45-minute simulation containing one JavaScript problem and one automation design prompt. Day 14: repair the weakest category and rehearse concise model answers.

Keep a mistake log with four labels: syntax, contract, async, and test design. Repeated async mistakes require event-loop practice, not more array puzzles. Repeated contract mistakes require writing examples before implementation. Candidates targeting typed automation roles should also review TypeScript interview questions for QA engineers and be ready to explain how types reduce, but do not eliminate, runtime validation.

Interview Questions and Answers

Q: What is the difference between var, let, and const?

let and const are block-scoped, while var is function-scoped and has different hoisting behavior. const prevents rebinding but does not make an object deeply immutable. I default to const, use let for intentional rebinding, and avoid var in modern automation code.

Q: Why does await inside forEach cause problems?

forEach does not consume or await the promises returned by its callback. The surrounding function can continue before asynchronous callbacks finish. I use for...of for sequential work or Promise.all(items.map(...)) for concurrent work, with a concurrency limit when required.

Q: What is the difference between null and undefined?

null is commonly an explicit empty value, while undefined commonly indicates absence or no assigned value. Both are nullish, but they are not strictly equal. At system boundaries I validate required fields instead of letting either state propagate ambiguously.

Q: Does fetch reject for HTTP 500?

No. fetch resolves with a Response when an HTTP response is received, including 4xx and 5xx status codes. I check response.ok or the precise expected status and throw an error with safe context when it does not match. Network failures and aborts reject the promise.

Q: How do you compare two objects in JavaScript tests?

Strict equality compares object identity, not structure. For a test, I use the runner's deep-equality assertion when full structural equality is the contract. If only selected fields matter, I assert those fields explicitly so irrelevant additions do not make the test brittle.

Q: When would you use a Map instead of an object?

I use Map when keys are not limited to strings and symbols, when insertion order and size are meaningful, or when frequent keyed additions and iteration make the intent clearer. Plain objects are appropriate for fixed record-like shapes. I avoid accepting untrusted keys into a normal object without considering prototype-related risks.

Q: What causes flaky Playwright tests?

Common causes include unstable data, brittle locators, shared state, external dependencies, arbitrary sleeps, and assertions made before observable state settles. I use isolated contexts, deterministic setup, supported locators, web-first assertions, and traces to diagnose the actual source. Retry is a signal and containment tool, not the primary fix.

Q: How does shallow copying affect test fixtures?

Spread syntax copies the outer array or object, but nested references remain shared. Mutating a nested object in one test can therefore alter another fixture. I use immutable builders, targeted deep creation, or structuredClone when its supported data semantics match the need.

Q: What does Promise.all do after one promise rejects?

The returned aggregate promise rejects when an input rejects, but operations that already started are not automatically canceled. If continuing work is undesirable, the operations must support cancellation, commonly through an AbortSignal, and the orchestration policy must trigger it.

Q: How would you test a promise timeout?

I control the dependency so it settles at known times and pass a configurable timeout or signal. I assert both completion before the boundary and rejection at or after it, plus cleanup. Where practical I use a fake clock or injected scheduler rather than real long delays.

Q: Why prefer Playwright role locators?

They locate elements using accessibility semantics close to how users interact with the page. This often creates resilient tests and catches missing accessible names. A test ID is appropriate when the interface lacks a stable user-facing locator or the team defines an explicit testing contract.

Q: What is a closure and where might tests use one?

A closure is a function that retains access to its lexical environment after the outer function returns. Test factories and configurable helpers use closures to keep settings private. I watch for unintended retained state that leaks between tests or grows memory usage.

Common Mistakes

  • Using coercive == without a deliberate reason.
  • Mutating shared fixtures with sort, push, or nested object changes.
  • Treating object identity as deep equality.
  • Writing await inside forEach and assuming completion is awaited.
  • Starting unlimited network requests with Promise.all against a constrained service.
  • Ignoring non-2xx HTTP responses because fetch did not reject.
  • Swallowing rejected promises or catching errors only to log them.
  • Adding fixed delays to Playwright instead of waiting for observable behavior.
  • Copying generated locators without evaluating their stability and intent.
  • Using optional chaining to hide a required field that should fail validation.
  • Claiming JavaScript is single-threaded without acknowledging worker threads or shared memory contexts.
  • Testing only the sample input and skipping mutation, missing data, and rejection cases.

Conclusion

Strong answers to JavaScript coding interview questions testers face are explicit about language behavior and production risk. They distinguish identity from structure, preserve fixture isolation, coordinate promises intentionally, validate HTTP responses, and use supported Playwright locators and asynchronous assertions. The solution should be simple enough to explain and complete enough to fail safely.

Practice five data-transformation tasks, three asynchronous tasks, and two browser scenarios without copying code. For each, state the contract, mutation policy, time and space complexity, rejection behavior, and verification cases. That routine turns JavaScript knowledge into the engineering judgment interviewers expect from a QA or SDET candidate.

Interview Questions and Answers

How do you remove duplicate objects from an array by a property?

I clarify the identity rule, normalize only if the domain permits it, and track seen keys in a `Set` or `Map`. A `Map` is useful when I also need the first index or duplicate details. I state which occurrence wins and preserve order if required.

Why is `Array.prototype.sort()` risky in test code?

It sorts the array in place, so a reused fixture can change for later assertions or tests. I copy first with spread syntax or use a supported copying alternative. I also provide a comparator for numeric or domain-specific sorting.

What happens when an async function throws?

The function returns a rejected promise with the thrown value as its reason. Callers must await it, return it to their runner, or otherwise handle the rejection. A missing await can create false passes or unhandled rejections.

How do you run asynchronous operations sequentially?

I use a `for...of` loop and await each operation inside it. This is appropriate when order matters, the system enforces a strict rate, or operations share dependent state. I avoid `forEach` because it does not await callback promises.

How do you limit promise concurrency?

I use a bounded worker pool or a reviewed concurrency utility, then await all workers. I preserve item-to-result mapping, define failure and cancellation policy, and validate the limit. This prevents a large input from starting every network request at once.

What is the difference between a microtask and a task?

Promise reactions are queued as microtasks, while timers and many external events schedule tasks. After the current stack finishes, the runtime drains the relevant microtask queue before selecting the next task. Exact host details vary, so I explain only the ordering required by the given snippet.

How do you validate data from an API in JavaScript?

I treat external data as untrusted at runtime, check required shapes and domain values, and report the precise failing path. TypeScript types alone do not validate JSON. For large contracts I use a team-approved schema validator and test both accepted and rejected examples.

How do you avoid false passes in async tests?

I return or await every promise, make assertions inside the awaited flow, and let rejections reach the test runner. I verify that callbacks actually execute when using event-based APIs and close resources in cleanup hooks.

How would you choose between a role locator and a test ID?

I prefer a role and accessible name when they express the user interaction and remain stable. I use a test ID for a deliberate automation contract when no suitable user-facing locator exists. I avoid selectors tied to transient styling or DOM depth.

Why must Playwright locator assertions be awaited?

Web-first assertions return promises and retry against changing page state. Awaiting them ensures the test runner observes success or failure before the test continues or ends. Omitting `await` can cause an assertion to finish after the test.

What is the testing risk of a shallow copy?

Nested arrays and objects still reference the original values, so later mutation can cross test boundaries. I create fresh nested fixtures or use an appropriate clone mechanism. I do not use JSON serialization blindly because it changes or rejects several JavaScript value types.

How should errors be handled in a JavaScript test helper?

I validate inputs at the boundary, catch only when I can recover or add meaningful context, and preserve the original cause where supported. I let the test fail rather than returning an ambiguous value. Error output must omit tokens, passwords, and sensitive payload data.

What tests would you write for a grouping function?

I cover empty input, one record, repeated groups, all groups, invalid records, missing properties, and input order changes. I assert an invariant that grouped counts plus rejected records equals input length. I also verify the input was not changed if immutability is part of the contract.

How do you answer an API question if you cannot remember a method name?

I state the operation I need and use a simpler standard construct I know is valid. I do not invent a library method. If documentation is permitted, I verify the exact signature, then explain the behavior and error path.

Frequently Asked Questions

What JavaScript topics are most important for QA interviews?

Prioritize arrays, objects, `Map`, `Set`, strings, functions, scope, equality, mutation, promises, `async` and `await`, errors, modules, and JSON handling. For automation roles, also prepare Playwright locators, assertions, fixtures, and parallel-isolation concepts.

Do QA engineers need event-loop knowledge?

Yes, especially when tests use browser automation, API calls, timers, or concurrent setup. You should explain the current call stack, promise microtasks, and why awaiting a promise pauses an async function without blocking the runtime.

Should I solve JavaScript coding questions with loops or array methods?

Use the form that communicates the algorithm most clearly. Array methods are excellent for simple transformations, while loops can be clearer for early exits, complex diagnostics, or stateful validation.

Is TypeScript required for a Playwright interview?

Many Playwright projects use TypeScript, so basic typing, interfaces, unions, generics, and narrowing are valuable. Runtime behavior is still JavaScript, and external data still requires runtime validation.

How should testers practice asynchronous JavaScript?

Write small programs for sequential work, `Promise.all`, bounded concurrency, timeout, rejection, and cleanup. Predict the order of logs before running each example, then test both success and failure paths.

What makes a JavaScript interview solution production-ready?

A production-minded solution has a defined input and output contract, no accidental mutation, meaningful errors, deterministic behavior, bounded resource use, and tests for edge and failure cases. It should also avoid leaking secrets in diagnostics.

Can I use Node.js built-in test tools in an interview?

Yes, if the environment supports them and the interviewer allows execution. The `node:test` and `node:assert/strict` modules are useful for dependency-free examples, but you should follow the target team's runner when a specific framework is requested.

Related Guides