Pierre-Henry Soria – CTO Insights, Software Architecture & Product Leadership

How I Automate Web Tasks Without Building Fragile Scripts

I wrote the original version of this article around a Firefox extension based on Selenium IDE. The central idea still holds: when I repeat the same browser task, I ask whether a small automation can remove the repetition.

The old tool list no longer helps. The better question is whether the browser should be involved at all.

I Look for an API First

Clicks are tied to a page. An API is tied to a contract. If a service lets me export a report, create a record, or update data through an API, I normally use it.

I automate the browser when I need to test the path a person actually follows or when no suitable API exists. I also check the service terms before writing the script. Automation does not make fake accounts, unsolicited messages, or limit avoidance acceptable.

This distinction matters because a browser script has more ways to fail. Text changes, a modal appears, authentication expires, or a button moves behind a different state. I accept that cost only when the browser provides evidence or access that I cannot get another way.

Playwright and Selenium Solve Different Starting Problems

For a new JavaScript or TypeScript project, I often begin with Playwright. Its locators can target roles, labels, and visible text. It also checks whether an element is ready before acting on it.

Selenium WebDriver remains a sound choice for an existing Selenium suite, teams working across several programming languages, or infrastructure already built around Selenium Grid. Selenium IDE can still record a first scenario, but I treat the recording as a draft. The final automation belongs in readable, reviewed code.

A Small Playwright Example

This test exports a report from a test environment:

 1import { test, expect } from "@playwright/test";
 2
 3test("exports a report", async ({ page }) => {
 4  await page.goto(process.env.APP_URL!);
 5
 6  await page.getByLabel("Email address").fill(process.env.TEST_EMAIL!);
 7  await page.getByLabel("Password").fill(process.env.TEST_PASSWORD!);
 8  await page.getByRole("button", { name: "Sign in" }).click();
 9
10  await expect(page.getByRole("heading", { name: "Reports" })).toBeVisible();
11
12  const download = page.waitForEvent("download");
13  await page.getByRole("button", { name: "Export" }).click();
14  await download;
15});

I do not target “the third button” or copy a long CSS path from the browser inspector. I target the control as a user understands it. The Playwright locator guide recommends the same preference for user-facing attributes and explicit contracts.

Credentials stay in a secret store. The test account receives only the permissions required for this scenario.

Scheduling Is the Easy Part

A test can run on every pull request. A business task may run on a schedule. In both cases, I want the code to be safe when it runs twice.

GitHub Actions workflows can run on repository events, manually, or on a schedule. For an important job, I keep a manual trigger as a recovery option and record enough context to understand every run:

I also define an owner. A scheduled script without an owner becomes a hidden service that everyone depends on and nobody maintains.

My Release Checklist for an Automation

Before letting a task run unattended, I verify that:

  1. a retry will not create an unwanted duplicate;
  2. a changed page causes a clear failure rather than a wrong action;
  3. permissions and secrets are limited;
  4. logs explain the result without exposing sensitive data;
  5. someone can stop, inspect, and resume the job;
  6. the automation saves more time than it consumes in maintenance.

The first recording rarely creates the real value. The value comes from a small script that another engineer can read, test, and repair without guessing what I intended.


Pierre-Henry Soria

GitHub · PierreHenry.Dev · YouTube

<< Previous Post

|

Next Post >>

#Automation #Playwright #Selenium #Software Testing #Github Actions #Web Development