In Selenium 4, which of the eight By factories map onto a WebDriver wire locator strategy of their own?
answer
- The client offers more than the wire takes
- Count the factories, then count the keywords
- Three of them carry a spare selector
- Two base classes, one with a format string
- Three keywords W3C dropped from the table
basics
~10 sFive of them: By.cssSelector, By.linkText, By.partialLinkText, By.tagName and By.xpath. By.id, By.name and By.className have no W3C strategy, so the client turns each into an equivalent CSS selector instead.
solid answer
~40 sThe W3C WebDriver specification defines exactly five locator strategies: `css selector`, `link text`, `partial link text`, `tag name` and `xpath`. Selenium 4's Java `By` class still exposes eight factories, so three of them have nothing to map onto. `By.id`, `By.name` and `By.className` extend an internal `PreW3CLocator` base class that eagerly builds a CSS fallback from a format string: `#%s` for id, `.%s` for class name and `*[name='...']` for name. The other five extend `BaseW3CLocator` and reach the remote end with their own `using` keyword untouched. Sending an unrecognised keyword is not merely unsupported: the specification requires the remote end to answer `invalid argument`, which is exactly why the fallback exists.
code
java · 13 linesimport org.openqa.selenium.By;
public class RecallLocatorStrategies {
public static void main(String[] args) {
By dueList = By.id("recall-due");
By reminderLink = By.linkText("Send recall reminder");
By recallRows = By.tagName("tr");
System.out.println(((By.Remotable) dueList).getRemoteParameters());
System.out.println(((By.Remotable) reminderLink).getRemoteParameters());
System.out.println(((By.Remotable) recallRows).getRemoteParameters());
}
}go deeper
Learn the eight factory names and be able to say which one you would reach for. Knowing that By.cssSelector and By.xpath are the general-purpose two, and the rest are shorthands, is enough at this stage.
Be ready to explain that the wire defines five strategies and name them, then say which three factories have no keyword and what selector shape each becomes. The format strings are worth remembering verbatim.
An interviewer expects you to locate the rewrite in the client rather than the browser, and to reason about what that means when you read a driver trace or debug a locator that behaves unlike its hand-written CSS twin.
Own the consequence for tooling: any layer that inspects, logs or rewrites locators must decide whether it reads the declared keyword or the serialised fallback, because the two disagree for three of the eight factories.
## Two lists that are not the same length Selenium 4's Java `By` class exposes **eight** static factories: `By.id`, `By.name`, `By.className`, `By.tagName`, `By.linkText`, `By.partialLinkText`, `By.cssSelector` and `By.xpath`. The **W3C WebDriver** specification, which is the protocol a Selenium 4 session speaks, defines a *table of location strategies* holding exactly **five** keywords. A find command carries a JSON body of `{"using": <keyword>, "value": <selector>}`, and the remote end looks `using` up in that table. A keyword that is not in it produces an `invalid argument` error before any DOM search begins. Three of the eight factories therefore have nothing legal to send. Selenium closes the gap entirely on the client side, by giving each of those three a ready-made CSS selector to use instead. ## The five keywords the wire accepts | `using` keyword | What the remote end is specified to do | |---|---| | `css selector` | Calls `querySelectorAll` on the start node with the value | | `link text` | Collects `a` elements, keeps those whose trimmed rendered text equals the value | | `partial link text` | Collects `a` elements, keeps those whose rendered text contains the value | | `tag name` | Calls `getElementsByTagName` on the start node with the value | | `xpath` | Evaluates the value as an XPath snapshot rooted at the start node | ## Where each factory lands | `By` factory | Keyword it declares | What reaches the remote end | |---|---|---| | `By.cssSelector(v)` | `css selector` | unchanged | | `By.linkText(v)` | `link text` | unchanged | | `By.partialLinkText(v)` | `partial link text` | unchanged | | `By.tagName(v)` | `tag name` | unchanged | | `By.xpath(v)` | `xpath` | unchanged | | `By.id(v)` | `id` | `css selector` with `#v` | | `By.name(v)` | `name` | `css selector` with `*[name='v']` | | `By.className(v)` | `class name` | `css selector` with `.v` | ## How the split is wired in the client Every `By` subclass in Selenium 4 implements the `By.Remotable` interface, whose `getRemoteParameters()` returns a `using`/`value` pair. Underneath sit two internal base classes: - **`BaseW3CLocator`** backs the five specification-aligned factories. It stores one `Parameters` object and hands it straight to the driver; there is no second form of the locator. - **`PreW3CLocator`** backs `By.id`, `By.name` and `By.className`. Its constructor takes a third argument — a **format string** — and eagerly builds a private `ByCssSelector` **fallback** from it: `#%s` for id, `.%s` for class name, and `*[name='...']` for name. The class name is itself the documentation: these three keywords are what the pre-W3C protocol accepted and W3C dropped. - The value is run through a **CSS escape pass** before it is formatted, so metacharacters in a recall-list id survive as literal characters rather than turning into selector syntax. For a dental-practice recall list, the practical effect is that these two lines address the same row and cost the same on the wire: ```java WebElement dueList = driver.findElement(By.id("recall-due")); WebElement same = driver.findElement(By.cssSelector("#recall\\-due")); ``` ## Two different answers to "what is this locator?" A `PreW3CLocator` reports itself two ways, and mixing them up is the usual source of confusion: 1. `getRemoteParameters()` returns the **legacy** pair — `By.id("recall-due")` answers `[id: recall-due]`. This is what the client offers the remote end first, and what an element records about how it was found. 2. `toJson()` returns the **fallback's** serialisation — `{"using":"css selector","value":"#recall\\-due"}`. Anything that serialises a locator as data rather than issuing a find gets this form. 3. `findElement(SearchContext)` on a `PreW3CLocator` does not search at all; it calls `context.findElement(fallback)`, so the search that actually runs is the CSS one. ## What this means when you are writing locators - **`By.tagName` is not rewritten.** `tag name` is a real keyword, so `By.tagName("tr")` on the recall table travels as itself and is answered with `getElementsByTagName`, not `querySelectorAll`. - **`By.linkText` and `By.partialLinkText` are not rewritten either.** They are genuine strategies with their own algorithms, not sugar over a CSS attribute match on `href`. - **`By.className` accepts one class token only.** Because its fallback is `.%s`, a value containing whitespace is rejected outright at construction with `InvalidSelectorException`. - **The rewrite is per-client, not per-browser.** The Java client builds a fallback object; the Python client's `LocatorConverter` performs the same three substitutions with slightly different output. No browser resolves `id` for you. - **A custom locator can opt out.** A `By` subclass that does not implement `By.Remotable` never produces a `using`/`value` pair; the client falls back to calling the locator's own `findElement`. `RelativeLocator`, Selenium 4's proximity filter, is a separate mechanism rather than a ninth factory, and is out of scope here.
- What does a W3C remote end do if a client sends using: "id"?It refuses the command. The Find Element algorithm looks the `using` value up in the table of location strategies, and a keyword that is not in that table yields an `invalid argument` error before any element search happens. Selenium 4's Java client catches the resulting `InvalidArgumentException` and retries the lookup through the CSS fallback the `By` carries.
- Does By.tagName get rewritten into a CSS type selector as well?No. `tag name` is one of the five keywords the specification defines, so `By.tagName` extends `BaseW3CLocator` and its `using`/`value` pair travels unchanged. The remote end answers it with `getElementsByTagName` rather than `querySelectorAll`. Only `By.id`, `By.name` and `By.className` carry a CSS fallback.
- Where does the CSS rewrite surface other than on the find call?In JSON serialisation. `toJson` on `By.id`, `By.name` and `By.className` emits the CSS fallback rather than the legacy pair, so anything that serialises a locator as data ships the CSS form. `getRemoteParameters()` still reports the original keyword, which is why the two views of the same locator disagree.
The By factories are the practice's own shorthand on a recall form; the wire protocol is the form the insurer will actually accept, so three shorthand codes get transcribed into accepted ones before the envelope is sealed.
saying these in an interview costs you the question
- Claims the WebDriver wire protocol defines eight locator strategies
- Says By.id travels as using id and the browser resolves it
- Thinks By.cssSelector is itself rewritten or specially cased
- Believes By.tagName is translated into a CSS type selector
- Assumes the browser, not the client, handles unsupported keywords