Stop Duplicating Your Tests: craft-test, a Shared Core Framework for Scalable Test Automation
A single core automation framework, lightweight consumer frameworks, and every fix made exactly once.
Most test automation suites begin the same way.
A team writes an automated login test: a script that opens the website, enters a username and password, and confirms the user is signed in. When another product needs the same coverage, the test is duplicated, and then duplicated again for the next one.
Months later, the login button changes. The same fix now has to be applied in every single copy, often by different people. Over time the copies drift apart, each fix lands slightly differently, and defects slip through the gaps.
craft-test was designed to remove that duplication entirely. Built with Playwright, a tool that drives a web browser automatically, and TypeScript, it centralises everything that can be shared and keeps each product’s test setup deliberately small.
The core idea: one core, many consumers
Individual branches don’t write their own recipes. The head office maintains one master recipe book, and every branch works from it. Each branch contributes only its local details: its address, its menu and its opening hours. When the head chef refines a recipe, every branch serves the improved dish immediately.
craft-test follows the same model and is made up of two kinds of framework:
The core automation framework
The master recipe book. It owns the shared tools, the shared tests and the configuration, and is packaged so any test project can install it as a dependency.The consumer test automation frameworks
The branches. Each product under test has its own lightweight framework that installs and uses the core. It contains no shared logic, only what is unique to its website: a description of the site, its test users, and a single instruction naming the shared tests to run.Dependencies flow in one direction only: consumers rely on the core, never the reverse. As a result, a fix made in the core reaches every consumer with its next update, and bringing a new product under test means adding one lightweight consumer framework rather than cloning an existing project.
What’s inside the core
The core is organised into clearly defined layers, each with a single responsibility:
One feature, one folder
In large test suites, finding the right file can take longer than making the change. craft-test avoids this by keeping everything related to a feature together. Any change to login, whether a locator, a label, an action or a test, happens in one folder:
features/login/ ├── web/ │ ├── pages/ login.selector.ts where the elements are │ │ login.content.ts what the page says │ │ login.page.ts what it can do │ └── specs/ login.spec.ts what must be true (the tests) └── index.ts
One design decision makes this structure especially powerful. The login page does not hard-code its buttons and labels; they are supplied from separate files. This allows each consumer framework to specify where elements sit on its own website without any change to the page itself.
A consumer framework is mostly configuration
Because the core carries the logic, a consumer framework needs remarkably little code. This is its entire test file:
import { loginPositiveTests } from 'craft-test'; import { test } from '../fixtures/fixtures'; loginPositiveTests(test);
The first line imports the shared login tests from the installed core. The last line runs them against the consumer’s own website. Everything else in the consumer is configuration rather than code.
Each consumer maintains a concise site profile describing its brand, language and region, the user roles that exist, and the address of each environment, such as staging and production.
The profile also captures anything unusual about the site. If the login page lives at an unexpected address or its fields are labelled differently, the consumer records that detail and the core adapts accordingly. The consumer never writes login code of its own.
Security by design
Test accounts still use real credentials, so the framework enforces three safeguards:
The principles behind it
Three design principles shape the entire framework:
The core executes, consumers describe. Pages, actions and tests exist only in the core. A consumer framework never rebuilds them; it only describes its website.
Configuration over code. Differences between websites are expressed in a site profile, not in new code, which keeps every consumer small, readable and easy to maintain.
Clear separation of concerns. Test data, machine settings and test logic each live in their own place, so changing one never puts the others at risk.
Built to scale
- New features, one folder. Adding shared coverage such as search, contact forms, navigation or accessibility checks means adding a single folder to the core, complete with its own tests.
- Every consumer benefits. New features and fixes reach a consumer framework as soon as it installs the latest version of the core package.
- Ready for more platforms. The feature-based structure already leaves room for mobile and API testing alongside web.
One core. Many consumers.
All the shared code lives in the core; each consumer just describes its website.
Fixed once, fixed everywhere.
Authored By:
SanchiAutomation QA engineering, Span Technoverse