After the Playwright practice section now we take a closer look at another popular candidate, Selenium.
Selenium is the original, vendor-neutral UI automation stack for web browsers. As a dependable, stable and widely used tool, getting familiar with it is essential.
In this section we will provide two tests that cover the essentials:
- Smoke: open a page and assert the title.
- Form + negative path: type invalid creds, click Login, wait for an error, and assert both message and URL.
Prerequisites:
Since we already set up Node.js and VS Code (if you started with the Selenium section, for the proper prerequisites see the Playwright/cucumber section), and the Selenium manager handles the drivers for browsers to test, we are basically ready to set up and create our tesp project.
Creating a fresh project
- Create new folder for selenium practice named selenium_test
- Open the folder in VS Code
- install dependencies (selenium webdriver, mocha, chai)
selenium-webdriver
→ Selenium for JSmocha
→ simple test runnerchai
→expect(...)
assertions- in the terminal:
npm i -D selenium-webdriver mocha chai
Edit package.json, so it’ll be a complete json object
- Insert in the editor then save it:
{
"name": "selenium_test",
"version": "1.0.0",
"private": true,
"type": "commonjs",
"scripts": {
"test": "mocha tests/**/*.spec.js"
},
"devDependencies": {
"selenium-webdriver": "^4.23.0",
"mocha": "^10.4.0",
"chai": "^4.4.1"
}
}
Let’s creating a test
Select the folder —> new folder: tests —>new file in the tests folder example.spec.js
Then let’s edit it:
const { Builder } = require('selenium-webdriver');
const { expect } = require('chai');
describe('Example Domain (Selenium smoke)', function () {
this.timeout(15000); // give us 15s so nothing rushes
let driver;
before(async () => {
driver = await new Builder().forBrowser('chrome').build(); // opens Chrome
});
after(async () => {
if (driver) await driver.quit(); // always close the browser
});
it('opens the page and checks title', async () => {
await driver.get('https://example.org/');
const title = await driver.getTitle();
expect(title).to.contain('Example Domain');
});
});
Why this works: Selenium 4’s Selenium Manager auto-fetches the right chromedriver, so no manual driver install required. In the terminal run the test:
npm test
Now, as we set up everything, let’s see our actual practice tests:
Wikipedia search smoke test
In this example we automate a simple search flow on Wikipedia to learn the Selenium basics.
What the test does
- Starts Chrome via Selenium (
before
hook). - Opens
https://www.wikipedia.org/
. - Finds the search input by id (
By.id('searchInput')
), types “Playwright”, and presses Enter. - Uses an explicit wait (
until.titleContains('Playwright')
) so we don’t rely on sleeps. - Reads the page title and asserts it contains “Playwright” with Chai.
- Closes the browser (
after
hook).
Why this example
- Shows the driver lifecycle (open/quit).
- Demonstrates locators (
By.id
) and keyboard input (Key.RETURN
). - Teaches Selenium’s explicit waiting pattern (more reliable than fixed delays).
Expected outcome
When you run npm test
, Chrome briefly opens, navigates, and the test passes.
Mocha output: a green check for “searches for Playwright and opens the article” (and “1 passing” if it’s the only test, or “2 passing” if you run it with the example test).
So let’s do this!
In the tests folder create a new file: search.spec.js
Paste the following in the editor:
const { Builder, By, Key, until } = require('selenium-webdriver');
const { expect } = require('chai');
describe('Wikipedia search (Selenium)', function () {
this.timeout(20000); // give ourselves time
let driver;
before(async () => {
driver = await new Builder().forBrowser('chrome').build();
});
after(async () => {
if (driver) await driver.quit();
});
it('searches for Playwright and opens the article', async () => {
await driver.get('https://www.wikipedia.org/');
// type into the search box and press Enter
await driver.findElement(By.id('searchInput')).sendKeys('Playwright', Key.RETURN);
// wait for the page title to mention Playwright
await driver.wait(until.titleContains('Playwright'), 10000);
const title = await driver.getTitle();
expect(title).to.match(/Playwright/i);
});
});
run the test:
npm test
And now, let’s see our second Selenium test:
Negative login on “The Internet” site
What we’ll do
- Open a login page.
- Type wrong credentials.
- Click Login.
- Wait for the error banner.
- Assert the banner text says the username is invalid and we’re still on
/login
.
Why this example
- Teaches form fill + click (most UI tests do this).
- Shows explicit waits for feedback (
until.elementLocated
+until.elementIsVisible
). - Uses a stable demo site: https://the-internet.herokuapp.com
So let’s begin:
In the tests folder create a new file: login_negative.spec.js
.
Paste the below in the editor and save:
const { Builder, By, until } = require('selenium-webdriver');
const { expect } = require('chai');
describe('The Internet – negative login', function () {
this.timeout(20000);
let driver;
before(async () => {
driver = await new Builder().forBrowser('chrome').build();
});
after(async () => {
if (driver) await driver.quit();
});
it('shows an error for invalid credentials', async () => {
await driver.get('https://the-internet.herokuapp.com/login');
// fill the form with wrong creds
await driver.findElement(By.id('username')).sendKeys('wronguser');
await driver.findElement(By.id('password')).sendKeys('wrongpass');
await driver.findElement(By.css('button[type="submit"]')).click();
// wait for the flash error to appear and be visible
const flashLocator = By.id('flash');
const flashEl = await driver.wait(until.elementLocated(flashLocator), 10000);
await driver.wait(until.elementIsVisible(flashEl), 5000);
// assert message and that we stayed on /login
const msg = (await flashEl.getText()).trim();
expect(msg).to.include('Your username is invalid!');
const url = await driver.getCurrentUrl();
expect(url).to.match(/\/login$/);
});
});
run it
npm test
# or just this file:
npx mocha tests/login_negative.spec.js
Congratulations! You successfully ran two tests with Selenuim. For more practical examples make sure to check out the Playwright/Cucumber and Appium section just as well!