Functional Testing with AI Agents
Turn business requirements into functional tests with Claude Code, Cursor, or Codex, then create and verify ContextQA cases through MCP.
Quick answer
Start with a requirement, turn it into an observable expected outcome, and ask your coding agent to test that behavior at the most useful layer. Functional testing describes what the software must do, not a particular framework: a functional rule can be checked through a function, an API, or a browser. ContextQA MCP can turn requirements into cases, but you still need to review their assertions and inspect real execution results.
This guide follows a report-export permission rule from a decision table to code-level checks and a ContextQA browser workflow. The example is illustrative; it does not describe a particular customer's authorization model.
Functional, integration, and end-to-end are different dimensions
A functional test asks whether an approved user can export a ready report and whether a disallowed request is denied. An integration test asks whether real connected components cooperate correctly. An end-to-end test asks whether the full selected journey works. One test may satisfy more than one description.
Use fast code-level checks for numerous rule combinations, real API tests for authorization enforcement, and selected browser flows for the user's experience. A disabled button is useful UX evidence, but it cannot establish that an API rejects a forbidden request. See unit, integration, and end-to-end testing for those layers.
Prerequisites
You need an agreed requirement, named roles and states, representative disposable data, the existing test command, and an environment where you can verify the outcome. Record unresolved policy questions instead of asking the agent to invent them.
For our example, report export is allowed only when the requester belongs to the report's tenant, the role is admin or analyst, and the report state is ready. A viewer cannot export. Tenant checks happen before role or readiness checks so a cross-tenant request does not disclose a report's state.
The small runnable example uses Node.js 24 or later and its built-in test runner. No ContextQA access is needed for the local exercise. Node test runner.
1. Make a decision table before generating tests
F-01
Same tenant, analyst, ready report
Export permitted
F-02
Same tenant, admin, ready report
Export permitted
F-03
Same tenant, viewer, ready report
Denied; no file produced
F-04
Same tenant, analyst, building report
Denied as not ready
F-05
Different tenant, admin, ready report
Denied without revealing report state
F-06
Same tenant, unknown role, ready report
Denied by default
Discuss ambiguous states such as cancelled, failed, deleted, and expired reports. Determine what should happen if permission is revoked between opening the page and clicking Export. These are product questions; fluent generated steps are not a substitute for an agreed answer.
2. Ask the agent to preserve the business rule
Use this prompt with Claude Code, Cursor, or Codex:
This makes the handoff reviewable for a QA manager or product owner who does not use the agent's editor. Each result answers a requirement rather than merely listing how many scripts were generated.
3. Run a small policy example
Create report-policy.mjs:
Create report-policy.test.mjs beside it:
Run:
This is a functional decision table executed at the unit level. It verifies the illustrated policy function, not a deployed application's authentication or storage. To test your real product, import the policy it actually calls, then use API and browser checks to establish enforcement. Do not accept a separate test-only policy function as evidence about production code.
4. Verify the action, its absence, and the artifact
For an allowed export, assert the file type, expected headers or schema, known row values, tenant identity, and report identifier. Use a small seeded dataset with an exact expected result. “File exists” can pass even if the file contains an error page, an empty body, or another user's records.
For a denied export, verify the documented denial and the absence of the forbidden side effect. Decide how to observe that reliably: no successful export response, no new export record, or a bounded check that no download starts. The strongest check depends on your architecture. If the test cannot inspect the required state, mark that part unverified.
Test stale sessions and permissions changed mid-flow separately. Keep setup assertions clear so a missing seeded report is diagnosed as a precondition problem rather than a product authorization failure.
5. Create corresponding ContextQA cases through MCP
Set up ContextQA MCP, confirm the correct workspace, and inspect available tools. The documented generate_tests_from_requirements tool accepts requirements_text. Supply the decision table, approved staging URL, role fixtures, and exact expected behavior in that requirements text. Generation does not establish execution or coverage quality. Generation reference.
Use get_test_case_steps to review the created cases, then the documented execution/status/result tools to obtain evidence. A terminal completion state is not itself a passing assertion. See case management and execution results.
Review and debugging
When expected and actual behavior disagree, establish which requirement is authoritative before changing code or tests. A screenshot of “Access denied” is a good result for the viewer case and a defect for the allowed analyst case. Keep that interpretation attached to the role and seeded state.
If a locator changes, repair how the test finds the same intended element. Do not remove the authorization assertion or broaden the target to a different action. Retries, generated explanations, and self-healing proposals should retain the original evidence and expected outcome.
Common questions
Does functional testing mean browser testing?
No. It checks required behavior at the layer that exposes the relevant risk. Browser testing is one execution method.
Can AI derive tests from a ticket?
It can propose cases, but incomplete acceptance criteria remain incomplete. Review roles, state, boundaries, and expected results before treating the generated cases as coverage.
How do we keep the tests portable?
Store native tests and requirement IDs in Git. For ContextQA cases, follow export and portability, inspect assertions and fixtures after export, and rerun them before claiming equivalent coverage.
Next step: Connect ContextQA MCP to translate one decision table into reviewable cases. For a demonstration using your roles and report workflow, book a functional-testing demo.
Last updated
Was this helpful?
