ScreenshotNeo

BlogHow-to

How to Work With Strings in JavaScript Selenium Tests

Learn to enter, retrieve, and assert strings in JavaScript Selenium tests, including special keys, Unicode, and common input pitfalls.

By the ScreenshotNeo team4 October 20264 min read

In JavaScript Selenium tests, strings are ordinary JavaScript values. Locate a keyboard-interactable element, clear it if needed, await sendKeys(), then read an input’s value with getAttribute('value'). For visible rendered text, use getText(). Assert the representation your application actually exposes.

Set up a runnable Selenium test

The examples below use Selenium’s JavaScript WebDriver binding and Node.js. Install the binding and a browser driver supported by your environment:

npm install selenium-webdriver

Save this as strings.test.js. It opens a small data URL, types into an input, checks the input value, submits the form, then checks visible text. The finally block closes the browser even if an assertion fails.

const { Builder, By } = require('selenium-webdriver');
const assert = require('node:assert/strict');

(async function testStrings() {
  const driver = await new Builder().forBrowser('chrome').build();
  try {
    const html = `<!doctype html>
      <form onsubmit="event.preventDefault(); document.querySelector('#result').textContent = document.querySelector('#message').value">
        <input id="message">
        <button type="submit">Send</button>
      </form>
      <output id="result"></output>`;
    await driver.get(`data:text/html;charset=utf-8,${encodeURIComponent(html)}`);

    const expected = 'Hello, Selenium!';
    const field = await driver.findElement(By.id('message'));
    await field.clear();
    await field.sendKeys(expected);

    const value = await field.getAttribute('value');
    assert.equal(value, expected);

    await driver.findElement(By.css('button')).click();
    const rendered = await driver.findElement(By.id('result')).getText();
    assert.equal(rendered, expected);
  } finally {
    await driver.quit();
  }
})().catch(error => {
  console.error(error);
  process.exitCode = 1;
});

The Selenium API calls are asynchronous. Await each one before using its result or making the next dependent interaction. See the WebElement API and element interactions guide.

Enter strings into form controls

sendKeys() simulates keyboard input. It is for keyboard-interactable elements such as text inputs, textareas, and editable content; it is not a universal setter for arbitrary elements. If the page has prefilled content and the test means to replace it, clear first. If the scenario is appending, do not clear.

const field = await driver.findElement(By.name('message'));
await field.clear();
await field.sendKeys('A string entered by the test');
assert.equal(await field.getAttribute('value'), 'A string entered by the test');

Use a locator that identifies the intended control reliably, such as a stable id, name, or test-specific attribute. For contenteditable elements, locate the editable node and use keyboard input; read back the rendered content in a way that matches the application’s markup and behavior.

Typing multiple values

You can pass multiple strings to sendKeys(); Selenium types them in sequence. This can be useful when combining ordinary text and key constants. Keep assertions focused on the resulting value, not on the number of calls used to produce it.

const field = await driver.findElement(By.id('search'));
await field.clear();
await field.sendKeys('selenium', ' webdriver');
assert.equal(await field.getAttribute('value'), 'selenium webdriver');

Read the right string from the page

Page content Read with What to expect
Input or textarea contents getAttribute('value') The control’s current value
Visible text in an element getText() Visible inner text, including descendant text, with leading and trailing whitespace removed
DOM property or computed page-side result executeScript() The value returned by the script running in the selected frame or window

A common false alarm is comparing input text with getText(). Form controls expose their entered contents as a value, not as visible inner text. Selenium’s interaction examples read the input value after typing. See the Selenium interaction guide.

const field = await driver.findElement(By.name('message'));
const inputValue = await field.getAttribute('value');
assert.equal(inputValue, 'expected input');

const label = await driver.findElement(By.id('status'));
const visibleText = await label.getText();
assert.equal(visibleText, 'Saved');

Use executeScript() when the test specifically needs a browser-side computation or property. For ordinary user-like typing and reading, the element interaction methods make the tested behavior clearer. With executeAsyncScript(), the injected script must call its callback to signal completion.

Assert exact strings and Unicode correctly

Node’s strict equality assertion is case-sensitive and checks the exact string value:

const assert = require('node:assert/strict');
assert.equal(actual, expected);

Do not trim, lowercase, or normalize values unless the product requirement calls for it. Such transformations can hide behavior the test is supposed to catch. If the requirement is locale-aware, case-insensitive comparison, use Intl.Collator with the intended locale and sensitivity:

const collator = new Intl.Collator('en', { sensitivity: 'accent' });
assert.equal(collator.compare(actual, expected), 0);

JavaScript string length and indexes count UTF-16 code units, not necessarily user-perceived characters. A supplementary-plane emoji commonly occupies two code units. Iteration with spread syntax yields code points, but a displayed grapheme can contain several code points, as with joined or modified emoji. Therefore, decide whether a character limit means code units, code points, or grapheme clusters before asserting length. See MDN’s String reference.

const sample = '😀';
console.log(sample.length);       // 2 UTF-16 code units
console.log([...sample].length);  // 1 code point

For URI or UTF-8 boundaries, malformed strings containing lone surrogates may cause encoding failures. Where arbitrary input is in scope, check isWellFormed() or use toWellFormed() where supported by the runtime, and test the behavior your application intends.

Test special keys and shortcuts

Use Selenium’s Key constants for non-text keys. Modifiers are stateful while held, so pair key-down with key-up, use a chord where appropriate, or reset with Key.NULL. Selenium’s keyboard guide demonstrates explicit modifier actions.

const { Builder, By, Key } = require('selenium-webdriver');

const field = await driver.findElement(By.id('message'));
await field.clear();
await field.sendKeys(Key.SHIFT, 'hello');
// Prefer Actions when the test needs explicit key-down/key-up state.

For platform-sensitive shortcuts, select Command on macOS and Control on other platforms, as in Selenium’s example. Keep the operating system in the test configuration explicit so a shortcut assertion has a clear expectation.

const { Key } = require('selenium-webdriver');
const modifier = process.platform === 'darwin' ? Key.COMMAND : Key.CONTROL;
await field.sendKeys('hello');
await field.sendKeys(modifier, 'a'); // select all on common desktop platforms

Keyboard behavior can vary with focus, element state, browser, and platform. Make focus part of the scenario and assert the resulting value or effect.

Wait for application updates before asserting

Typing completes when Selenium’s command completes, but an application may update a result asynchronously afterward. Wait for the condition that represents completion rather than inserting an arbitrary delay.

const { By, until } = require('selenium-webdriver');
await field.sendKeys('query');
const result = await driver.wait(until.elementLocated(By.id('result')), 5000);
await driver.wait(async () => (await result.getText()) === 'query received', 5000);
assert.equal(await result.getText(), 'query received');

Choose a condition tied to the page’s behavior: element presence, visibility, enabled state, or expected text/value. Ensure the timeout reflects the test environment and report which condition timed out.

Troubleshooting

Symptom Likely cause Fix
getText() returns an empty string for an input The control value is not visible inner text Read getAttribute('value')
The assertion sees old text plus the new text The field was not cleared and typing appended Call clear() when replacement is intended
sendKeys() fails with an element interaction error The target is not keyboard-interactable, is disabled, or is otherwise in an invalid state Locate the actual editable control, wait for it to be ready, and check its state
The value is unexpectedly empty The locator matched the wrong element, typing happened before readiness, or the app subsequently reset the field Verify the locator and wait for readiness; inspect the value after the app update
Shortcut affects the wrong thing Focus or modifier state is wrong, or the platform uses a different modifier Focus the intended element, release modifiers explicitly, and choose Command or Control by platform
Unicode length assertion disagrees with what users see length counts UTF-16 code units Define the required character model and count code points or grapheme clusters as appropriate
URI encoding throws for unusual input The string may contain a lone surrogate Validate well-formedness or apply the product’s intended sanitization before encoding

Reliability, performance, and test cost

  • Reliability: Use stable locators, await each WebDriver operation, wait on observable page conditions, and clean up with driver.quit(). Avoid depending on incidental whitespace or implicit browser timing.
  • Performance: Each WebDriver command crosses the browser automation boundary. Keep the scenario focused, avoid repeated reads that do not add coverage, and use condition-based waits instead of long fixed sleeps.
  • Cost: Selenium itself is an open-source browser automation project; execution cost depends on where browsers and CI run. Account for machine time, parallel workers, and any hosted browser service you choose.

Or skip the browser setup

If the job is to capture a page for a visual check or report, ScreenshotNeo returns a screenshot or PDF from one API request. It also provides an MCP server for AI agents. See the API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
  • Cookie banners are accepted or removed before the shot; known consent platforms, newsletter popups, and chat widgets can be removed.
  • Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers report the page verdict and billing status.
  • An MCP server lets AI agents use screenshot tools.
  • 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000.

Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.

FAQ

Should I use Selenium or set the input with page JavaScript?

Use Selenium keyboard interaction when the test should cover the user’s typing path. Use page-side JavaScript only when the behavior under test specifically requires that computation or property access.

Does JavaScript treat two visually identical strings as equal?

Not always. Equality compares code units exactly; visually equivalent text can differ by Unicode representation. Normalize only when that matches the application requirement.

Can I type into any element with sendKeys()?

No. The target must accept keyboard input in its current state, such as a text field or editable element.

Sources