When you export a Selenium IDE recording to JUnit code and then edit it, what have you given up?
answer
- The generator only runs one direction
- There is no matching import
- Two artefacts, one of them silently stale
- Decide which file people maintain
- Re-recording overwrites hand edits entirely
basics
~10 sThe recording, in practice. Export is one-way with no import back into the .side project, so the first hand edit makes the two artefacts diverge and re-recording silently overwrites your work.
solid answer
~40 sSelenium IDE exports a test, a suite or a project to C# NUnit, C# xUnit, Java JUnit, JavaScript Mocha, Python pytest or Ruby RSpec - one statement per recorded row, plus a driver field, a `vars` map and a `js` executor field. Nothing reads that code back: there is no import. So the first time you extract a helper, add a wait or replace a recorded positional XPath, the code and the `.side` file describe different flows, and re-recording after a UI change overwrites the edits with no merge. What you give up is the ability to re-record at all. The decision belongs up front: either keep the `.side` file authoritative and run it with `selenium-side-runner`, accepting the IDE command-set ceiling, or treat the export as a one-time seed and retire the recording.
code
java · 42 linespackage com.example.solar;
import java.util.HashMap;
import java.util.Map;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.Select;
public class AugustYieldTotalTest {
private WebDriver driver;
private Map<String, Object> vars;
private JavascriptExecutor js;
@Before
public void setUp() {
driver = new ChromeDriver();
js = (JavascriptExecutor) driver;
vars = new HashMap<String, Object>();
}
@After
public void tearDown() {
driver.quit();
}
@Test
public void augustYieldTotal() {
driver.get("https://reports.example.com/reports/yield");
driver.manage().window().setSize(new Dimension(1280, 900));
new Select(driver.findElement(By.id("site-picker"))).selectByVisibleText("North Array");
driver.findElement(By.id("month")).sendKeys("2026-08");
driver.findElement(By.id("run-report")).click();
assertEquals(driver.findElement(By.cssSelector(".total-kwh")).getText(), "1842 kWh");
}
}go deeper
Be ready to name what Selenium IDE can export to - Java JUnit, Python pytest, C# NUnit, JavaScript Mocha, Ruby RSpec - and to say that the generated file is a snapshot rather than a live link.
Explain the shape of the generated code: one statement per recorded row, the setup and teardown that creates and quits the driver, and the vars and js fields the template always emits.
Show that you would settle the source-of-truth question before exporting, and can say what each choice costs: the command-set ceiling on one side, the loss of re-recording on the other.
Own where a record-and-playback tool belongs across teams: who drafts with it, when a flow graduates to maintained code, and how you stop half-migrated recordings from accumulating unowned in a repository.
## What code export emits Selenium IDE can turn a recorded test, a suite or a whole project into source code. Right-click the test in the project pane and choose Export, and the dialog offers a fixed set of language-and-framework targets: **C# NUnit**, **C# xUnit**, **Java JUnit**, **JavaScript Mocha**, **Python pytest** and **Ruby RSpec**. It writes a file per test class. Options on that dialog let you include origin-tracing comments - each generated statement annotated with the recorded command it came from - and to generate code aimed at a Selenium Grid rather than a local browser. What comes out is a straightforward translation. Each `.side` row becomes one statement, in order, in the target binding's Selenium 4 API: | `.side` row | Generated Java statement | |---|---| | `open` / `/reports/yield` | `driver.get("https://reports.example.com/reports/yield")` | | `setWindowSize` / `1280x900` | `driver.manage().window().setSize(new Dimension(1280, 900))` | | `select` / `id=site-picker` / `label=North Array` | `new Select(driver.findElement(By.id("site-picker"))).selectByVisibleText("North Array")` | | `click` / `id=run-report` | `driver.findElement(By.id("run-report")).click()` | | `assertText` / `css=.total-kwh` / `1842 kWh` | `assertEquals(driver.findElement(By.cssSelector(".total-kwh")).getText(), "1842 kWh")` | The class the exporter emits also carries its standard scaffolding: a `WebDriver` field created in setup and quit in teardown, a `Map<String, Object> vars` for the IDE's `${variable}` mechanism, and a `JavascriptExecutor js` field - the last two present whether or not your recording used them. ## The property that decides everything: export is one-way **There is no import.** Nothing reads a Java, Python or Ruby file back into a `.side` project. The exporter is a generator, and the generated file is a snapshot of the recording at the moment you pressed Export. That is fine right up until you edit the output - and you will, because the output is a literal transcription. The moment you extract a helper, add a wait the recording never had, parameterise the month, or replace a positional XPath, the code and the recording have diverged, and: - Re-recording the flow after a UI change and re-exporting **overwrites** your edits; there is no merge. - Editing the `.side` rows instead leaves the code stale, and nothing warns you that the two disagree. - Keeping both up to date by hand is doing the same work twice, forever, and it decays the first busy week. So the cost of an edited export is not the edit. It is that you have silently made the recording obsolete while keeping it in the repository as if it were still authoritative. ## Pick the source of truth before you export There are exactly two coherent positions, and the decision belongs at the front of the work, not after the first edit: 1. **The `.side` file is authoritative.** Never export for execution; run the project with `selenium-side-runner` in the pipeline. Cheap, editable by people who do not write code, and hard-limited to the IDE command set - `if`, `while`, `times`, `forEach`, `run`, `executeScript` and the recorded commands. 2. **The code is authoritative.** Export once as a seed, then retire the `.side` file - archive it, or delete it - so nobody re-records against a flow that has moved on. From that point the recording was a drafting tool that has done its job. | | `.side` + `selenium-side-runner` | Exported code | |---|---|---| | Editing | the IDE's table, no code needed | any editor, full language | | Ceiling | the IDE command set | the whole Selenium API and the host language | | Re-recording | supported and cheap | destroys hand edits | | Review | JSON diffs, awkward but readable | ordinary code review | The failure mode to avoid is the third position, where a team exports, edits, keeps the `.side` file "in case we need to re-record", and then discovers a year later that neither artefact describes the current flow. ## What export does not fix - **Locators travel verbatim.** `xpath=//div[3]/table/tbody/tr[2]/td[4]` becomes `By.xpath("//div[3]/table/tbody/tr[2]/td[4]")`. Generation is not improvement. - **Missing assertions stay missing.** A recording of the yield report that never checked the total exports to code that never checks the total, and it will pass just as emptily in a compiled suite. - **Waits are translated, not invented.** A recorded `pause` becomes a sleep; it does not become a condition. - **Structure is not created.** You get a flat sequence of statements in one method, per recorded test. Export changes the *language* the flow is written in and the *ceiling* on what it can express. It changes nothing about whether the flow was a good test, which is why exporting a weak recording produces weak code faster.
- If the exported code is now authoritative, what should happen to the .side file?Retire it - archive it outside the suite, or delete it. Leaving it in the repository invites someone to re-record against a flow that has moved on and then export over the maintained code. Keeping both current by hand is doing the work twice and decays the first busy week.
- What does exporting a weak recording actually change about it?Only the language and the ceiling. Recorded locators travel verbatim, so a positional XPath becomes a By.xpath with the same path; a recording with no assertions exports to code with no assertions; a pause becomes a sleep rather than a condition. Export gives you the whole Selenium API to fix those things, but it fixes none of them for you.
- When is keeping the .side file as the source of truth the better call?When the flows fit inside the IDE command set, and when the people who own them are more comfortable editing a step table than code. Running the project with selenium-side-runner keeps one artefact, keeps it editable without a build, and avoids the divergence entirely. The ceiling is real, so it holds only while the flows stay simple.
saying these in an interview costs you the question
- Thinks edited code can be imported back into the .side project
- Expects export to rewrite recorded locators into stabler ones
- Keeps re-recording after the exported code was edited by hand
- Treats exported code as a finished automation framework
- Maintains both the recording and the exported code in parallel