ScreenshotNeo

BlogGuides

How to Simplify UI Tests With Bi-Directional Contract Testing

Use UI tests to capture the API interactions a client needs, then compare those expectations with the provider’s OpenAPI contract. Learn what this catches, what it cannot prove, and how to adopt the workflow safely.

By the ScreenshotNeo team4 October 20269 min read

Bi-directional contract testing (BDCT) can reduce duplicated UI-to-API compatibility tests by comparing the API interactions a client needs with the capabilities declared in the provider’s API contract. Keep UI tests for user-visible behavior, capture the client’s relevant requests and responses through controlled mocks, verify the provider against its own specification, and run a compatibility check between the consumer and provider contracts in CI.

BDCT does not execute the UI against the real provider, prove that an order was persisted, or establish that every business rule works. Retain focused UI and provider functional tests for those guarantees.

1. What bi-directional contract testing checks

Swagger Contract Testing defines BDCT as “a type of static contract testing where two contracts – one representing consumer expectations, and another representing the provider’s capability – are compared to ensure they are compatible.” In the documented HTTP workflow, the consumer contract is in Pact format and the provider contract is an OpenAPI definition. AsyncAPI can represent event-driven APIs. Swagger Contract Testing’s guide describes the workflow and its scope.

The key distinction is that the compatibility check compares contracts. It does not replay the consumer contract against the provider implementation. The provider still needs checks that its implementation matches its own specification, and functional tests still need to exercise behavior that cannot be inferred from messages.

Question What BDCT can establish What it cannot establish alone
Does the provider contract support the requests and responses the consumer expects? Compatibility between the two maintained contracts. That the running provider behaves exactly as specified.
Does a UI flow render and respond correctly? Nothing about the rendered experience by itself. Visible behavior, accessibility, or browser-specific behavior.
Did a requested operation cause its intended side effect? Nothing about persistence or other effects by itself. That an order was saved, a payment authorized, or a rule applied.

2. The UI-centered workflow

  1. Keep meaningful UI tests. Exercise important user flows and assert visible outcomes such as validation messages, updated lists, navigation, and loading or error states.
  2. Control network calls in the UI test environment. Stub the API responses the UI needs so tests stay deterministic. Choose the calls that express real consumer requirements rather than recording every incidental request.
  3. Capture consumer interactions. Generate a consumer contract from the selected requests and responses. The PactFlow Cypress example uses cy.intercept for stubbing and cy.usePactWait to record chosen calls into a consumer-driven contract. Treat this as an example integration, not a universal Cypress API.
  4. Publish the consumer contract. Publish it to the contract-testing broker used by your team so compatibility can be evaluated against provider changes.
  5. Maintain the provider contract. Keep an OpenAPI definition for HTTP APIs or an AsyncAPI definition for event-driven APIs. Verify the provider implementation against its own contract with an appropriate tool.
  6. Cross-check contracts and gate deployments. Run compatibility validation in CI. The example pipeline runs tests, publishes pacts, calls can-i-deploy, deploys from the main branch, and records the deployment.
  7. Keep tests for guarantees contracts do not cover. Use provider functional tests for persistence, authentication, business rules, and other runtime behavior. Keep UI tests for user-visible outcomes.

The PactFlow Cypress example shows one way to connect Cypress stubs, generated consumer contracts, publishing, and deployment checks. Swagger’s guide presents web-based testing with Cypress or MSW as a possible use case for BDCT, and says it can remove the need for additional Pact tests in that setting. That is a possible reduction in duplicated contract work, not a reason to delete every end-to-end test.

Illustrative CI sequence

# Consumer/UI pipeline
run-ui-tests
publish-consumer-contract

# Provider pipeline
verify-provider-against-openapi
run-provider-functional-tests

# Compatibility and release pipeline
check-contract-compatibility
can-i-deploy
record-deployment

This is a sequence sketch, not a drop-in CI configuration. Use the commands and broker integration supported by your chosen contract tooling.

3. What to keep in the test suite

A useful split assigns each question to the least expensive test that can answer it while preserving the required guarantee:

  • UI tests: Does the user see the correct state and can they complete the flow? Mock external or backend calls when that makes the UI test deterministic, while asserting meaningful user outcomes.
  • Consumer contract generation: Which request and response shapes does this client actually depend on?
  • Provider specification verification: Does the implementation conform to its declared API contract?
  • Cross-contract validation: Are the consumer’s expectations compatible with the provider’s declared capability?
  • Provider functional tests: Does the implementation perform the side effect and enforce the business behavior?
  • End-to-end tests: Does a critical journey work across the real integrated system? Keep a targeted set where the broader runtime guarantee justifies the setup and maintenance cost.

Contract compatibility can miss semantic disagreements where both sides accept the same shapes but interpret them differently. For example, an HTTP success response may have the expected fields while the provider fails to persist the requested operation. Test such behavior against an implementation.

4. BDCT, consumer-driven contracts, and end-to-end tests

Approach What is exercised Guarantee and tradeoff
Bi-directional contract testing Compatibility between consumer and provider contracts; provider implementation is checked separately against its specification. Decouples the cross-check from replaying consumer tests against provider code. Its compatibility guarantee is weaker than executing integrated behavior.
Consumer-driven contract testing Consumer expectations are used to verify provider behavior, according to the selected workflow and tooling. Can provide stronger evidence that provider behavior satisfies consumer expectations, with more coordination and learning overhead in the Swagger guide’s qualitative comparison.
End-to-end testing A running integrated flow, often through the UI and real services. Can offer the strongest integrated guarantee, with greater maintenance and test-data costs in the guide’s qualitative comparison.

These are qualitative tradeoffs from vendor documentation, not measured performance results. Compare approaches in your context by compatibility guarantees, maintenance burden, feedback time, team coupling, test-data complexity, support for unknown consumers, and whether the test executes against the provider implementation. No measured reduction in UI test count, flakiness, cost, or duration is established here. Track your own baseline before claiming savings.

5. When BDCT is a good fit

  • You have a maintained, trusted API specification and want to check it against consumer expectations.
  • An API is relatively stable and has many consumers, so discovering incompatibility before release is valuable.
  • You are retrofitting contract checks onto existing systems or working with contract-first APIs.
  • You have an API gateway, internal APIs with multiple clients, or a third-party API whose specification is available and refreshed often enough to be useful.
  • You want to reduce duplicated contract work or release coupling without pretending static compatibility proves runtime behavior.

A third-party specification is evidence of the provider’s declared capability, not proof that the remote service conforms to it. Refresh it and check the provider when you can. BDCT is less useful if the specification is stale, incomplete, or not maintained with provider changes.

API gateway cases

Pact’s guidance says a gateway doing basic pass-through routing can often be excluded from contract testing while other tests cover authentication. If the gateway orchestrates or combines services, that shortcut can leave important behavior unrepresented. Consider contracts from consumer to gateway and gateway to provider, or BDCT between the client and gateway, and add functional checks for gateway behavior that affects outcomes. See Pact’s provider guidance for gateway considerations.

6. Adoption checklist

  1. List the UI flows and user-visible assertions that must remain.
  2. Identify the API calls those flows genuinely depend on.
  3. Decide which calls should be stubbed and captured as consumer expectations.
  4. Choose and maintain the provider’s OpenAPI or AsyncAPI contract.
  5. Verify provider implementation conformance separately from cross-contract compatibility.
  6. Publish contracts and add compatibility checks to CI before deployment.
  7. Keep functional tests for side effects, security, business rules, and integrated behavior.
  8. Measure your current test count, CI duration, failure causes, and maintenance effort; compare after adoption instead of assuming a savings percentage.
  9. Review the workflow when endpoints, consumers, or gateway responsibilities change.

7. Troubleshooting

Symptom Likely cause Fix
Expected interaction is missing from the consumer contract. The UI test did not trigger the call, or the recording setup did not select it. Check the user flow and stub/intercept matching. Confirm the chosen interaction is captured and published.
Compatibility fails after an API change. The provider contract no longer supports a request or response shape the consumer expects. Decide whether the provider change is breaking. Update the provider compatibly, or coordinate a consumer change and release sequence.
Compatibility passes, but users still see a broken flow. Contracts agree on message shapes, but runtime behavior or UI logic is wrong. Add or repair UI assertions and provider functional tests for the behavior or side effect in question.
Provider verification fails while cross-contract comparison passes. The declared provider contract may be compatible with the consumer but the implementation may violate its own specification. Fix the provider implementation or correct the specification if it does not describe intended behavior, then rerun provider verification.
Contract check gives false confidence for a third-party API. The saved provider specification is stale or not verified against the live provider. Refresh the specification and retain targeted tests against the third-party service where its runtime behavior matters.
Gateway tests miss an orchestration defect. The gateway does more than pass through requests and its behavior is absent from the contract boundary. Model consumer-to-gateway and gateway-to-provider boundaries, and test orchestration behavior functionally.

8. Tooling and scope cautions

The documented workflow uses Pact-format consumer contracts and OpenAPI for HTTP providers, with AsyncAPI for event-driven APIs. Tool support and syntax vary. Swagger Contract Testing documentation says its BDCT feature is not available in Pact OSS; the general pattern of comparing contracts should not be confused with a feature offered by every Pact product. Check the tooling documentation for the broker, contract format, validation command, and deployment check your team uses.

Or skip the browser setup

If your article workflow also needs website screenshots, ScreenshotNeo is a website screenshot API and MCP server for developers. It is separate from contract testing: use it to capture a page, not to validate API compatibility. Its browser setup can accept cookie/consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before the shot; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and responses report page verdict and billing in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

One GET request returns an image or PDF. Example cURL:

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.webp

ScreenshotNeo API documentation covers the request options. The same API also supports full-page and selector captures, device presets and custom viewports, dark mode, retina scale, PDF settings, custom CSS and JavaScript, waits, request blocking, headers, cookies, user agent, timezone, geolocation, caching, signed image links, async jobs, bulk capture, a usage API, and an OpenAPI spec.

There is a free plan with 1,000 screenshots per month and no card. Paid plans start at $5 for 3,000 shots; every feature is on every plan. Yearly billing gives two months free.

Sign up for ScreenshotNeo and get 1,000 screenshots a month free, with no card.

FAQ

Can UI tests generate consumer contracts?

They can in supported setups. The PactFlow Cypress example records selected intercepted interactions from UI tests into a consumer-driven contract. Confirm that your chosen integration captures only interactions that represent real consumer needs.

Does BDCT mean I can delete end-to-end tests?

No. It can reduce duplicated compatibility work, but it does not prove a running, integrated user journey works. Keep a focused set of end-to-end tests for journeys where that guarantee matters.

Does a passing contract check prove an API operation succeeded?

No. It shows compatibility between the contracts being compared. Use provider functional tests to establish runtime behavior and side effects.

Can I use BDCT with a third-party API?

Potentially, when a usable provider specification is available and kept current. The specification alone does not prove that the live provider conforms to it.

Is BDCT available in Pact OSS?

The Swagger Contract Testing guide says its BDCT feature is not available in Pact OSS. Check the current documentation for the specific product and workflow you intend to use.