FabricFabricExperiments
Testing on Databricks

BDD quickstart

Run your first Databricks-style Gherkin scenario locally, inspect its reports, and move the same feature to a real workspace.

This tutorial starts with no Databricks account, credentials, Python, or Fabric Experiments server. In about ten minutes you will run a real Gherkin scenario against local DuckDB and produce the same evidence formats used in CI. The last section moves that scenario to an isolated Databricks schema.

If you already maintain a Cucumber project, skip to Add Fabric to an existing suite. If you are evaluating Fabric against Behave, read the Behave migration guide after this tutorial.

What you will build

fx-bdd-evaluation/
├── cucumber.mjs
├── features/
│   ├── experiment-results.feature
│   └── support/
│       └── steps.ts
├── package.json
└── reports/                  # created by the test run

The feature seeds a table, queries it, and checks its contents. Fabric creates and closes a scenario-isolated execution context automatically.

1. Check the prerequisites

Install Node.js 22 or newer and enable pnpm:

node --version
corepack enable
pnpm --version

You do not need a JVM, Python, Docker, or a Databricks workspace for the local profile.

2. Create a project and install the published packages

The quickest supported path is the published fx scaffold:

npx @fabricorg/experiments@0.7.0 init databricks-tests fx-bdd-evaluation
cd fx-bdd-evaluation
pnpm install
pnpm test

That creates the package manifest, Cucumber configuration, support import, feature, fixture, and example environment file described below. To understand or add the pieces manually, continue with these commands:

mkdir fx-bdd-evaluation
cd fx-bdd-evaluation
pnpm init
pnpm add -D \
  @cucumber/cucumber@13.0.0 \
  @duckdb/node-api@1.5.4-r.1 \
  @fabricorg/databricks-bdd@0.4.0 \
  @fabricorg/databricks-testkit@0.2.4 \
  tsx@4
mkdir -p features/support reports

Add "type": "module" and these scripts to package.json:

{
  "type": "module",
  "scripts": {
    "test:bdd": "cucumber-js",
    "test:bdd:pretty": "cucumber-js --format pretty",
    "test:bdd:wip": "cucumber-js --tags @wip --fail-fast --format summary"
  }
}

Pinning the versions makes an evaluation reproducible. After the first green run, adopt your normal dependency-update policy.

3. Configure Cucumber and reports

Create cucumber.mjs:

const common = {
  paths: ['features/**/*.feature'],
  import: ['features/support/steps.ts'],
  parallel: process.env.DBX_TEST_PROFILE === 'live' ? 0 : 2,
}

export default {
  ...common,
  format: [
    'progress',
    ['junit', 'reports/bdd-junit.xml'],
    ['html', 'reports/bdd.html'],
    ['rerun', 'reports/rerun.txt'],
    ['@fabricorg/databricks-bdd/evidence-formatter', 'reports/evidence.json'],
  ],
}

Local scenarios can run in parallel because each scenario owns its DuckDB context. Live scenarios stay serial by default because they can share governed workspace resources.

Create features/support/steps.ts:

import '@fabricorg/databricks-bdd/steps'

That one import registers the Fabric World, lifecycle hooks, typed parameters, Databricks workload steps, cleanup, output capture, and failure evidence.

4. Write the first feature

Create features/experiment-results.feature:

Feature: Validate an experiment result table

  Scenario: Treatment has the expected conversions
    Given a table "experiment_results" with:
      | variant_key | exposures | conversions |
      | control     | 100       | 12          |
      | treatment   | 100       | 18          |
    When I query table "experiment_results"
    Then the result has 2 rows
    And the result contains rows matching:
      | variant_key | conversions |
      | treatment   | 18          |

The wording is standard Gherkin. Analysts can change examples and expected values without writing TypeScript. Platform engineers add TypeScript only when the team needs a new reusable action or assertion.

5. Run it locally

pnpm test:bdd

A successful run ends with one passed scenario and all listed Gherkin steps passing. It also creates:

FileUse
reports/bdd.htmlHuman-readable scenario and step report.
reports/bdd-junit.xmlCI test annotation and test-history input.
reports/evidence.jsonStructured, schema-versioned audit evidence.
reports/rerun.txtFailed-scenario manifest for targeted reruns.

Open reports/bdd.html in a browser. Then deliberately change 18 to 19 and rerun the feature. The failure report demonstrates the secret-redacted SQL, statement identifier when live, and up to 32 KiB of captured step output. Put the value back to 18 before continuing.

Add Fabric to an existing suite

Install the two Fabric packages and DuckDB peer, import @fabricorg/databricks-bdd/steps from your existing support file, and add the evidence formatter to your Cucumber configuration. Existing standard Gherkin, Scenario Outlines, Examples, Rules, tags, hooks, and domain step files can stay in place.

Use the Behave migration guide when the existing suite is Python Behave. Feature text normally moves unchanged; Python step and hook implementations are rewritten as TypeScript support modules.

6. Run the same scenario on Databricks

Use a dedicated scratch catalog and schema. The test identity needs workspace access, CAN USE on the SQL warehouse, USE CATALOG, and ownership or USE SCHEMA, CREATE TABLE, MODIFY, and SELECT on the scratch schema. Do not point fixture-writing scenarios at a production schema.

Set one supported authentication method:

export DATABRICKS_HOST=https://<your-workspace-host>

# Recommended for secretless CI: Databricks workload identity federation
export DATABRICKS_AUTH_TYPE=env-oidc
export DATABRICKS_CLIENT_ID=<service-principal-application-id>
export DATABRICKS_OIDC_TOKEN_ENV=GITHUB_ID_TOKEN
export GITHUB_ID_TOKEN=<short-lived-idp-jwt>

# Also supported: OAuth machine-to-machine
export DATABRICKS_CLIENT_ID=<service-principal-application-id>
export DATABRICKS_CLIENT_SECRET=<service-principal-secret>

# Or, for a short local evaluation only:
# export DATABRICKS_TOKEN=<personal-access-token>

Then configure the warehouse and isolated scope:

export DATABRICKS_HTTP_PATH=/sql/1.0/warehouses/<warehouse-id>
export DBX_TEST_CATALOG=fx_test
export DBX_TEST_SCHEMA=quickstart_<your_name>
export DBX_TEST_PROFILE=live
export DBX_TEST_LIVE=1

pnpm test:bdd

DBX_TEST_LIVE=1 is a deliberate safety gate: a live suite is a no-op without it. Fixture tables are dropped during scenario cleanup unless DBX_TEST_KEEP_FIXTURES=1 is set temporarily for debugging.

7. Publish the run to Studio

Create a write-scoped API key from Studio Settings, then send the generated evidence to the organization Quality Center:

fx login --api-key fx_key_...
fx doctor
npx @fabricorg/experiments@0.7.0 test publish reports/evidence.json \
  --suite "Databricks evaluation"

Open Quality in Studio to inspect scenarios, captured failures, CI metadata, and Databricks query-history links. JUnit-only suites can publish their XML the same way. On Databricks Apps, also configure the gateway service principal described in Quality Center.

Troubleshooting

SymptomCheck
Cannot use import statementConfirm package.json contains "type": "module" and tsx is installed.
DuckDB module cannot be resolvedInstall @duckdb/node-api; it is an optional peer because live-only consumers do not need it.
Live run exits without testsSet both DBX_TEST_PROFILE=live and DBX_TEST_LIVE=1.
Warehouse cannot be resolvedSet DATABRICKS_HTTP_PATH or DATABRICKS_WAREHOUSE_ID, and grant the identity CAN USE.
PERMISSION_DENIED creating fixturesUse a scratch schema owned by the test identity or grant the schema permissions listed above.
A live-only scenario is skipped locallyExpected: @live, @jobs, @dlt, @pipeline, @autoloader, @lakebase, and @slow require the live profile.
Failure output contains less than expectedCapture is limited to 32 KiB per step; use DBX_TEST_CAPTURE_OUTPUT=passthrough to display while capturing.

Choose the next path

On this page