use-case· 16 min read· by Pramod Dutta

Test an Ecwid Storefront With Plain-English Tests

Learn to test an Ecwid store with plain-English AI tests: verify embedded widgets, add-to-cart, and checkout by intent, honestly across iframe-embedded storefronts.

If you sell through Ecwid, you already know the store is not really "yours" in the way a hand-built React app is. It lives inside a widget that Ecwid injects into whatever page you drop it on: a WordPress post, a Wix block, a plain HTML landing page, or an Instant Site hosted by Ecwid itself. That embedding model is exactly why so many teams struggle to test an Ecwid store reliably. The product grid, the cart, and the checkout are all rendered by Ecwid's own JavaScript at runtime, often inside an iframe, with class names and DOM structure that change when Ecwid ships an update. Traditional selector-based tests break the week Ecwid decides to rename a div.

This is the situation where plain-English, intent-driven testing earns its keep. Instead of pinning a test to #product-42 .form-control__button, you describe what a shopper does: open the store, add a product to the cart, open the cart, and confirm the total. An AI agent reads that objective, looks at the live page, and drives a real browser step by step. When Ecwid reshuffles its markup, the intent still holds. In this guide I will walk through how to test an Ecwid storefront with BrowserBash, where the approach shines, and where I will be honest with you about its limits, especially the iframe question that trips up almost every store owner.

Why Ecwid stores resist traditional test automation

Ecwid is a hosted, embed-first commerce platform. You paste a script tag or a shortcode, and Ecwid renders the store client-side. Three properties make this hostile to classic Selenium or Playwright selector tests.

First, the markup is not stable. Ecwid controls the widget's HTML and CSS, and they change it on their release schedule, not yours. A selector that worked in a demo can be dead by the next sprint. You did not touch your code, but your test suite is red anyway.

Second, a lot of the store lives inside an iframe or a shadow-ish injected container. Depending on how the widget is configured and which Ecwid features you use (the newer store rendering, the classic single-product widget, the buy-now button), parts of the experience may be same-origin DOM you can reach and parts may be framed content you cannot easily pierce with a naive page.click. That inconsistency is the single biggest source of flaky Ecwid tests, and I will come back to it in detail because pretending it does not exist would be dishonest.

Third, the interesting behavior is asynchronous. The catalog loads after the widget boots, adding to cart fires an XHR and then re-renders, and the cart drawer animates in. A brittle test that clicks and immediately asserts will race the widget and fail intermittently. You end up sprinkling waitForTimeout everywhere, which is the automation equivalent of duct tape.

An intent-driven agent handles all three differently. It reads the rendered page (accessibility tree plus visible text), decides the next action from the goal, and naturally waits for the thing it is looking for before acting. You are describing a shopper's journey, not a DOM traversal.

What "plain-English testing" actually means here

BrowserBash is a free, open-source (Apache-2.0) command-line tool. You write an objective in plain English, and an AI agent drives a real Chrome or Chromium browser through it, then returns a deterministic verdict plus structured results. There are no selectors, no page objects, and no CSS classes to maintain.

Here is the simplest possible smoke test for an embedded Ecwid storefront. Install the CLI first, then run one objective:

npm install -g browserbash-cli

browserbash run "Open https://your-store.example.com/shop, wait for the Ecwid product grid to load, click the first product, add it to the cart, open the cart, and confirm the cart shows 1 item" --agent --headless --timeout 120

The --agent flag emits NDJSON, one JSON event per line, so CI systems and other AI agents can read the result without parsing prose. The exit code tells the rest of the story: 0 passed, 1 failed, 2 error or infrastructure problem, 3 timeout. That contract is frozen, so you can build a pipeline gate on it and trust it not to shift under you.

Notice what the objective does not contain: no selector for the product card, no ID for the add-to-cart button, no hardcoded wait. The agent reads the live page and figures out which element is "the first product" and which control is "add to cart." When Ecwid renames things, this sentence still describes what a customer does.

By default BrowserBash is Ollama-first. It prefers a free local model so that nothing leaves your machine and you need no API keys. It auto-resolves in order: a local Ollama model, then ANTHROPIC_API_KEY, then OPENAI_API_KEY, then OpenRouter. For a short storefront smoke test a mid-size local model is fine. For longer multi-step checkout flows I will give you a straight recommendation later, because very small models struggle with long journeys and I would rather tell you that up front.

The honest truth about iframes and embedded Ecwid widgets

Let me address the elephant in the store before we go further, because most guides quietly skip it. Ecwid embeds can render in two broad ways depending on the widget type and configuration, and this materially affects testing.

When the store renders as same-origin DOM injected into your page, an agent that reads the accessibility tree and clicks by intent works smoothly. It sees the products, the buttons, and the cart as first-class page content. This is the common case for the main store widget on many setups, and it is where plain-English testing is at its best.

When part of the experience is inside a cross-origin iframe (some buy-button or single-product embeds, or third-party payment steps at checkout), the browser's security model means content inside that frame is not freely reachable from the parent page. This is not a BrowserBash limitation specifically; it is how the web platform isolates frames. Any automation tool, Selenium, Playwright, or an AI agent, has to explicitly enter the frame or the frame must be same-origin. If your Ecwid widget puts the add-to-cart flow inside a cross-origin iframe, a top-level agent may not be able to reach inside it, and you should verify this against your own store rather than assume.

So the honest, testable rule is: run a probe first. Point BrowserBash at your specific store page and ask it to add one product to the cart. If it succeeds, your embed exposes the flow as reachable DOM and you can build a full suite on intent. If it stalls at the widget boundary, your embed is framing that step, and you have two good options. Option one: test the parts that are reachable (catalog, product details, navigation, and the storefront hosted on Ecwid's own Instant Site domain where everything is same-origin) and treat the framed payment step as out of scope for UI automation. Option two: point your tests at your Ecwid Instant Site URL instead of the embedded copy on your marketing site, since the hosted storefront tends to render the full flow as same-origin content.

I am spelling this out because a test suite that silently cannot reach the cart is worse than no suite. Probe, confirm, then commit. If you want to go deeper on how the agent reads pages, the learn hub covers the engine model.

Writing a repeatable Ecwid test with a committable test file

One-off run commands are great for probing. For a suite you commit and run in CI, use a Markdown test file. BrowserBash reads committable *_test.md files with @import composition and {{variables}} templating, and it writes a human-readable Result.md after each run.

Create ecwid_smoke_test.md:

# Ecwid storefront smoke test

- Open {{STORE_URL}}
- Wait for the product catalog to finish loading
- Click the first product in the grid
- On the product page, click Add to Bag
- Open the shopping cart
- Verify text "Subtotal" is visible
- Verify the cart shows at least 1 item

Run it:

browserbash testmd run ./ecwid_smoke_test.md

Those Verify lines are doing real work. In BrowserBash, Verify steps that match the assertion grammar compile to actual Playwright checks with no LLM judgment involved: URL contains, title is or contains, text visible, a named button, link, or heading visible, element counts, and stored-value equality. A pass means the condition genuinely held. A fail comes with expected-versus-actual evidence in the run_end.assertions block and in the Result.md assertion table. So "Verify text Subtotal is visible" is not the agent's opinion that the cart looks right; it is a deterministic check that the string is on the page.

Verify lines that fall outside the grammar still run, but agent-judged, and they are flagged judged: true in the output so you can always tell a hard assertion from a soft one. That distinction matters when you are debugging a red build at 2am: you want to know whether the check was deterministic or interpretive.

Seeding state and mixing API with UI in testmd v2

Real store tests often need setup. Maybe you want to hit an endpoint to confirm your catalog API is up before you spend time driving the UI, or you want to seed a promo code. BrowserBash's testmd v2 lets you interleave deterministic API steps with plain-English UI steps in a single browser session.

Add version: 2 to the frontmatter and steps execute one at a time against one session. API steps never touch a model: they run GET/POST/PUT/DELETE/PATCH with an optional body, then Expect status N and can store a value from the JSON response for later steps. Consecutive plain-English steps run as grouped agent blocks on the same page.

---
version: 2
---
# Ecwid catalog and cart check

- GET https://app.ecwid.com/api/v3/{{STORE_ID}}/products with body {}
- Expect status 200, store $.items[0].name as 'firstProduct'
- Open {{STORE_URL}}
- Wait for the product grid to load
- Click the product named "{{firstProduct}}"
- Add it to the cart
- Open the cart
- Verify text "{{firstProduct}}" is visible in the cart

This pattern is powerful for Ecwid because it ties the storefront UI to the source of truth. You pull the real first product name from the Store API, then assert that clicking it through the UI lands the same product in the cart. If the catalog and the rendered grid ever disagree, the test catches it.

One honest caveat: testmd v2 currently drives the builtin engine, which needs an ANTHROPIC_API_KEY or a compatible ANTHROPIC_BASE_URL gateway. It does not yet run directly on Ollama or OpenRouter. If you are committed to a fully local, no-key setup, stick with v1 test files (plain steps, no frontmatter) for now, which behave exactly as they always have. The tutorials walk through both.

Handling logged-in shoppers and saved carts

Some Ecwid stores gate pricing or wholesale catalogs behind a customer login, or you want to test the "returning customer" experience where a saved cart persists. Logging in on every test run is slow and, for AI-driven runs, wasteful.

BrowserBash has saved logins for exactly this. Run browserbash auth save once, log in by hand in the browser it opens, press Enter, and it saves the session as Playwright storageState. Then reuse it with --auth <name> on any run, testmd, run-all, or monitor invocation.

browserbash auth save ecwid-customer --url https://your-store.example.com/account

browserbash testmd run ./ecwid_smoke_test.md --auth ecwid-customer

If the saved profile's origins do not cover the start URL of your test, BrowserBash prints a warning instead of silently pretending it worked, which saves you from the classic "why is it not logged in" mystery. This is the difference between a suite that quietly tests the wrong state and one that tells you when your assumptions are stale.

Keeping an Ecwid store green with monitoring

A storefront that passes in CI can still break in production: a CDN hiccup, an Ecwid outage, a payment provider flap, or a theme change on your marketing page that hides the widget. Monitor mode turns any test or objective into a synthetic check.

browserbash monitor ./ecwid_smoke_test.md --every 10m --notify https://hooks.slack.com/services/XXXX

It runs on the interval you set and alerts only on state changes, both directions. You get pinged when the store goes from passing to failing, and again when it recovers. You do not get a green message every ten minutes drowning your channel. Slack incoming-webhook URLs get Slack formatting automatically; any other URL gets the raw JSON payload so you can wire it into PagerDuty or your own service.

The replay cache is what makes an always-on monitor affordable. A green run records its actions, and the next identical run replays them with zero model calls. The agent only steps back in when the page actually changed. So a monitor that passes hour after hour costs almost nothing in tokens, and the moment your Ecwid store's DOM shifts, the agent re-engages and re-plans. That is the right economics for round-the-clock checks.

Running the full suite in CI with sharding and a budget

Once you have a handful of Ecwid tests (catalog, product detail, add to cart, cart math, checkout up to the payment boundary, mobile viewport), you run them together. The run-all orchestrator scans a folder and runs tests in parallel with concurrency derived from your real CPU and RAM, ordering previously-failed and slowest tests first, and flagging flaky ones.

For CI across multiple machines, sharding splits the work deterministically:

browserbash run-all ./ecwid-tests --shard 2/4 --budget-usd 2.00 --junit out/junit.xml

The shard slice is computed on sorted discovery order, so four parallel CI runners agree on who runs what without any coordination service. The --budget-usd guard stops launching new tests once the suite crosses the cap: remaining tests report skipped, the suite exits 2, and the spend lands in RunAll-Result.md and the JUnit <properties>. That is a real seatbelt when an agent-driven suite could otherwise run up a bill on a bad day.

You can also test responsiveness across devices with --matrix-viewport 1280x720,390x844, which runs every test once per viewport, labeled in events, JUnit, and results. Ecwid storefronts often behave differently on mobile (the cart becomes a drawer, the grid reflows), so a viewport matrix catches layout-dependent breakage that a single desktop run would miss.

If you already have Playwright specs for your store, browserbash import converts them to plain-English test files heuristically and deterministically, with no model involved. Anything it cannot translate lands in an IMPORT-REPORT.md rather than being silently dropped or invented, so you know exactly what needs a human pass.

Plugging BrowserBash into your AI coding agent

If you are building or shipping the store with an AI coding assistant (Claude Code, Cursor, Windsurf, Codex, Zed), you can hand it BrowserBash as a validation tool over the Model Context Protocol. One line wires it in:

claude mcp add browserbash -- browserbash mcp

That exposes three tools to the agent: run_objective for a single plain-English objective, run_test_file for a *_test.md file, and run_suite for a whole folder in parallel. Each returns the structured verdict JSON: status, summary, final state, assertions, cost, and duration. The key mental model is that a failed test is still a successful tool call. The MCP call succeeds and hands the agent a verdict to reason about, so your coding assistant can change the store, ask BrowserBash to verify the cart still works, read the assertion evidence, and iterate. BrowserBash is listed on the official MCP Registry as io.github.PramodDutta/browserbash.

When plain-English testing is the right call for Ecwid, and when it is not

Let me be balanced, because credibility beats hype.

Choose intent-driven testing when your Ecwid storefront's markup is not under your control (it is not, Ecwid owns it), when Ecwid's updates keep breaking your selector tests, when you want tests that read like the customer journey so non-engineers can review them, and when the flow renders as reachable DOM (confirm with a probe). This is the sweet spot: durable tests that survive Ecwid's redesigns.

Be more cautious in three cases. If the critical step lives inside a cross-origin iframe your top-level agent cannot enter, no intent test at the parent level will reach it, and you should scope those steps out or point tests at the same-origin Instant Site storefront. If you need microsecond-precise visual pixel diffing of the widget, a dedicated visual-regression tool is a better fit than an agent verdict. And if you are running fully local with no API key, remember that very small local models (roughly 8B and under) get flaky on long multi-step checkouts. The sweet spot for hard flows is a mid-size local model in the Qwen3 or Llama 3.3 70B class, or a capable hosted model. For a three-step catalog smoke test, a small local model is fine; for a ten-step guest checkout, size up.

Here is a quick comparison to set expectations honestly.

Concern Selector-based (Selenium/Playwright) Plain-English agent (BrowserBash)
Ecwid markup changes Breaks, needs selector fixes Survives, intent still holds
Same-origin embedded store Works, high maintenance Works, low maintenance
Cross-origin iframe step Needs explicit frame handling Needs same-origin target or is out of scope
Non-engineer readability Low High (reads like a user story)
Deterministic assertions Yes (you write them) Yes (Verify compiles to Playwright checks)
Pixel-perfect visual diff Add a visual tool Not the primary strength
Fully local, no API key N/A Yes for v1; v2 needs the builtin engine

Neither approach is universally right. If your store is a same-origin embed and Ecwid keeps churning the DOM, plain-English tests will save you weeks of selector maintenance a year. If your one critical step is framed and payment-provider-hosted, be realistic and test around it. You can read through real teardown examples on the case study page and browse more walkthroughs on the blog.

A practical rollout plan

Start narrow. Write one objective that opens your live store and adds a product to the cart, and run it with --agent. If it passes, the flow is reachable and you can build. If it stalls, you have learned your embed frames the cart, which is valuable to know on day one.

Next, convert that objective into a committed ecwid_smoke_test.md with hard Verify assertions on the subtotal and item count. Add a login profile with auth save if your store gates anything, wire the file into CI behind the exit-code contract, and add a viewport matrix so mobile is covered. Once the suite is green and stable, point a monitor at it with a Slack webhook so production regressions page you within ten minutes instead of via an angry customer email. Everything that runs on your machine (the CLI, both engines, the local dashboard, the replay cache, MCP, NDJSON output) is free and open source forever.

FAQ

Can BrowserBash test an Ecwid store embedded on WordPress or Wix?

Yes, as long as the store renders as reachable page content rather than sealed inside a cross-origin iframe. Point BrowserBash at the WordPress or Wix page where the Ecwid widget lives and run a probe objective that adds a product to the cart. If it succeeds, build your full suite on that URL. If the cart step is inside a cross-origin frame, test against your Ecwid Instant Site storefront instead, where the full flow is typically same-origin.

Do I need coding skills to write these Ecwid tests?

No coding is required for the core flow. You describe the shopper's journey in plain English, one step per line, in a Markdown file, and the AI agent drives the browser. You do add deterministic Verify lines like "Verify text Subtotal is visible," but those read like plain sentences, not code. Engineers get more power from the API steps and CI flags, but a non-engineer can write and review the storefront journeys.

Does testing my Ecwid store with an AI agent cost money?

Not by default. BrowserBash is Ollama-first and prefers a free local model, so a basic storefront smoke test can run with no API key and nothing leaving your machine. Costs only appear if you opt into a hosted model like Anthropic or OpenAI for harder multi-step flows, and even then the replay cache means repeat runs of a green test make zero model calls. Every run also reports a cost estimate in its results so there are no surprises.

How does BrowserBash handle Ecwid updates that change the page?

That is the main reason to use intent-driven testing here. Because your tests describe what a customer does rather than which CSS class to click, an Ecwid markup change usually does not break them: the agent re-reads the live page and finds the current add-to-cart control on its own. When the page genuinely changes, the replay cache steps aside and the agent re-plans that run, so your tests adapt instead of going red over a renamed div.

Get started

Testing an Ecwid storefront does not have to mean chasing selectors every time Ecwid ships an update. Describe the shopper's journey once, probe whether your embed exposes the cart, and let an AI agent drive a real browser to a deterministic verdict. Install with npm install -g browserbash-cli and run your first storefront smoke test in a couple of minutes. An account is optional, but if you want hosted history and team features you can sign up here.

Try it on your own appnpm install -g browserbash-cli
Start learning