Seed the backend before Selenium opens the React page. In Spring integration tests, use repeatable SQL fixtures (usually with @Sql) or a setup API/database step. Then let Selenium perform only the user workflow and assertions. This separation is faster, easier to isolate, and less brittle than clicking through the UI to create every prerequisite record.
Choose the fixture mechanism for the test lifecycle
Spring Boot has two related but different data-loading mechanisms:
- Application startup initialization runs while the application starts. Its ordering depends on how the schema is created and which Boot version you use.
- Spring TestContext SQL runs for selected test classes or methods.
@Sqlcan execute scripts before or after a test and can be customized with@SqlConfig.
Use startup initialization when every application launch needs the same baseline. Use test-managed fixtures when a particular test needs a known record set. Check the reference documentation for your exact Spring Boot and Spring Framework versions; annotation merging and transaction behavior are version-sensitive.
Option 1: Seed an integration test with @Sql
Create test-only schema and data files
Put scripts under src/test/resources. Keep the fixture small and name records so the test intent is obvious.
Recommended Free Tools
-- src/test/resources/sql/customer-test-data.sql
INSERT INTO customers (id, email, display_name, status)
VALUES ('selenium-customer-001', 'selenium@example.test', 'Selenium Customer', 'ACTIVE');
-- src/test/resources/sql/customer-cleanup.sql
DELETE FROM customers WHERE id = 'selenium-customer-001';
Adapt table names, columns, keys, and quoting to your schema. If migrations create the schema, let migrations run first and load only rows that satisfy current constraints.
Attach the fixture to a Spring test
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD;
@SpringBootTest
@Sql(scripts = "/sql/customer-test-data.sql")
@Sql(
scripts = "/sql/customer-cleanup.sql",
executionPhase = AFTER_TEST_METHOD
)
class CustomerApiTest {
@Test
void returnsTheSeededCustomer() {
// Call the application API and assert the response.
}
}
A method-level declaration can target one scenario instead of the whole class. If class and method declarations must combine or replace one another, configure the merge mode explicitly and verify the behavior against the Spring Framework version in your build.
Handle transactions deliberately
By default, a Spring test may run inside a test-managed transaction. That is useful for rollback isolation, but it can surprise a browser or a separately running API client: uncommitted rows are not visible outside the transaction. If the seeded record must be visible to Selenium, either commit the setup in a separate transaction or run the setup outside the transaction used by the assertion. Configure this with your test transaction strategy and, where needed, @SqlConfig; do not assume a script is committed merely because it completed.
Option 2: Prepare data through an API or database step
For an end-to-end React workflow, create the account, order, or other record before launching the browser. A supported test-only API is often preferable because it exercises the same validation and authorization boundaries without making Selenium navigate setup screens. A direct database fixture is appropriate when no setup API exists or when the test specifically concerns persistence.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →- Generate a unique identifier (for example, a UUID) for this test run.
- Create the record through a test API or a fixture transaction, and retain its identifier.
- Start a fresh WebDriver session and authenticate the way the application requires.
- Open the React route that displays the record.
- Perform only the user action under test and assert the visible result.
- Delete or expire the record, then quit the driver even when the assertion fails.
// Pseudocode; replace endpoints and selectors with your application values
const id = crypto.randomUUID();
await api.post('/test-support/customers', {
id, email: `${id}@example.test`, status: 'ACTIVE'
});
const driver = await new Builder().forBrowser('chrome').build();
try {
await driver.get(`${baseUrl}/customers/${id}`);
await driver.findElement(By.css('[data-testid="customer-menu"]')).click();
await driver.findElement(By.css('[data-testid="customer-status"]'))
.getText();
} finally {
await api.delete(`/test-support/customers/${id}`);
await driver.quit();
}
The exact association between a seeded backend row and a React screen depends on your routes, authentication, API contract, and client state management. The title does not establish one universal React fixture API, so keep that integration explicit in your project.
Option 3: Use Testcontainers when database fidelity matters
A disposable real database is useful when production-specific SQL, constraints, indexes, or transaction behavior must be represented. Testcontainers can start a temporary database for the test suite; a Spring Boot example uses a PostgreSQL container together with @SpringBootTest and @Sql. This requires a working container runtime and adds startup time. Choose it when that fidelity is worth the operational cost; otherwise a simpler test database can make feedback faster.
@SpringBootTest
@Testcontainers
class CustomerBrowserDataTest {
@Container
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:16");
// Supply the container JDBC URL, username, and password to Spring
// using the integration mechanism supported by your Boot version.
@Test
@Sql("/sql/customer-test-data.sql")
void browserScenarioUsesPostgres() {
// Start the app against the disposable container, then test it.
}
}
The container image, service-connection support, and configuration differ across Spring Boot generations. Treat a PostgreSQL example as a pattern, not a universal dependency recipe.
Drive the React UI with Selenium after setup
Wait for application state, not arbitrary sleeps
React renders asynchronously. Prefer an explicit wait for a route, element, or meaningful state rather than a fixed delay.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15));
driver.get(baseUrl + "/customers/" + customerId);
WebElement status = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.cssSelector("[data-testid='customer-status']")));
assertEquals("Active", status.getText());
Stable data-testid attributes are generally less fragile than CSS classes generated by a component library. Wait for the UI state that proves the API response has been applied.
Keep browser assertions narrow
Use Selenium for navigation, clicks, keyboard input, and what a user can observe. Test validation rules, repository behavior, and most error branches at lower layers. Selenium describes functional browser tests as comparatively expensive; moving non-visual coverage into unit or integration tests shortens the suite and reduces maintenance.
Isolation rules for repeatable runs
- Unique data: include a run or test identifier in emails, external keys, and order numbers.
- No shared mutable records: two tests should not update the same customer or depend on another test’s ordering.
- Fresh sessions: use a distinct WebDriver instance per test when your runner and resources permit; clear cookies and local storage when reuse is unavoidable.
- Cleanup: remove rows in an after-test script or API call, and also arrange periodic cleanup for abandoned runs.
- Parallel safety: make selectors, accounts, ports, and database schemas independent so parallel workers cannot observe each other’s state.
Selenium’s guidance on avoiding shared state is especially relevant when tests are retried or run concurrently. A clean database alone does not isolate browser cookies, local storage, or server-side sessions.
Which approach should you use?
| Approach | Best fit | Strength | Trade-off |
|---|---|---|---|
@Sql fixture |
Spring integration tests with known rows | Versioned, repeatable, close to the test | Must manage schema compatibility and transaction visibility |
| Setup API | End-to-end tests needing realistic application creation | Uses application validation without browser setup | Requires a safe test-support endpoint and authentication |
| Direct database setup | No suitable API or large fixture needed | Fast and deterministic | Can bypass application rules and couple tests to schema |
| Testcontainers | Database-specific behavior and constraints | Production-like engine in a disposable environment | Container runtime and slower startup required |
| Browser-created data | Only when the creation journey itself is under test | Tests the complete user journey | Slowest and most brittle setup |
Common failures and fixes
“Table does not exist” or an insert fails on startup
Your script ran before migrations or used a different schema. Run migrations first, place the script in the test lifecycle, and confirm the datasource initialization ordering for your Boot version.
Free tools Windows power users keep installed
One-click scans. No signup required.
Selenium cannot see the seeded row
The setup transaction may still be uncommitted, the browser may use another database, or the React app may request a different tenant. Commit setup data, log the effective JDBC URL, and verify the request identity and route identifier.
Duplicate-key errors on retries
A previous run left data behind or parallel workers reused a fixed key. Generate unique IDs and make cleanup idempotent, for example by deleting by a run-specific prefix.
The page is blank or assertions race the API
Wait for a meaningful element or loading state, inspect browser and server logs, and verify that the seeded record satisfies every field the React API expects. Replace sleeps with explicit waits.
Rank #4
Tests pass alone but fail in the suite
Look for shared rows, reused cookies, static ports, and test-order assumptions. Give each test its own records and driver, and reset external state between cases.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchTestcontainers cannot start
Check that the container runtime is running, the image is available, and the test process can reach the mapped port. If database fidelity is not required, use a non-container test database to reduce environmental dependencies.
Performance and reliability checklist
- Seed only the rows needed for the scenario.
- Prefer one setup API call or one SQL script over dozens of UI interactions.
- Reuse a container for a suite only when your reset strategy guarantees isolation; otherwise start a disposable instance per scope.
- Capture server logs, browser console output, screenshots, and the test data identifier on failure.
- Set bounded page and explicit-wait timeouts; an unbounded wait hides infrastructure failures.
- Run a small browser smoke set on every change and keep broad data/validation coverage below the browser layer.
Or skip the browser setup
If your goal is to capture a page image for a test artifact or review rather than drive the React workflow, ScreenshotNeo returns a screenshot or PDF from one request. Its cleaner capture accepts cookie/consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing result. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for all options, including full-page lazy-image loading, CSS-selector element capture, custom JavaScript, waits, headers, cookies, device and viewport settings, PDF output, caching, webhooks, and bulk jobs. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.
FAQ
Should fixture SQL live beside production migrations?
Keep test-only rows and scripts under test resources so they cannot be deployed accidentally. Share migration definitions only when the test genuinely validates them.
Can Selenium create the records through the React form?
Yes, when creation is the behavior being tested. For unrelated prerequisites, an API or database setup is more reliable and keeps the browser scenario focused.
Best Value
Is an in-memory database equivalent to production?
Not necessarily. SQL dialects, constraints, indexing, and transaction behavior can differ. Use a disposable production-engine container when those differences could change the result.
Frequently Asked Questions
Should fixture SQL live beside production migrations?
Keep test-only rows and scripts under test resources so they cannot be deployed accidentally. Share migration definitions only when the test genuinely validates them.
Can Selenium create the records through the React form?
Yes, when creation is the behavior being tested. For unrelated prerequisites, an API or database setup is more reliable and keeps the browser scenario focused.
Is an in-memory database equivalent to production?
Not necessarily. SQL dialects, constraints, indexing, and transaction behavior can differ. Use a disposable production-engine container when those differences could change the result.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

