Skip to Content
VS Code ExtensionWriting Tests

Writing Tests

The extension provides in-editor tools that make writing tests faster: code snippets, CodeLens buttons, and full support for data-driven patterns.

This page is about the extension’s raw test() authoring surface. For durable API behavior that should become specs, docs, reports, and agent context, start with HTTP Contracts and Workflows. Use raw test() when you need the full TypeScript escape hatch.


Snippets

Type a prefix in any .ts or .js file and press Tab to expand.

PrefixWhat it generates
gb-scratch / gbsComplete scratch test (import + HTTP + assertions)
gb-t / gbtSimple test
gb-ti / gbtiSimple test with import
gb-tm / gbtmTest with meta (tags, name)
gb-flow / gbfBuilder-style multi-step test()
gb-each / gbetest.each inline data-driven
gb-each-csv / gbectest.each + fromCsv
gb-each-yaml / gbeytest.each + fromYaml builder
gb-pick / gbptest.pick named examples
gb-pick-json / gbpjtest.pick + JSON file
gb-pick-dir / gbpdtest.pick + fromDir.merge
gb-config / gbcconfigure() shared config
gb-plugin / gbpldefineClientFactory + configure plugins
gb-i / gbiimport { test } from "@glubean/sdk"
gb-id / gbidImport test + data loaders
gb-ic / gbicImport configure
gb-ip / gbipImport configure + defineClientFactory
gb-expect / gbxctx.expect(...).orFail() assertion guard
gb-assert / gbactx.assert() structured assertion

gb-flow is a legacy-friendly snippet name for a builder-style test() chain. It is different from the SDK workflow() API, which composes contract cases as durable business behavior.


CodeLens: test.pick buttons

When you use test.pick(), CodeLens buttons appear above the definition letting you run specific examples.

  • 5 or fewer examples — each key appears as a separate button: Run "normal", Run "edge", etc.
  • More than 5 — a single Pick example... (N) button opens a QuickPick list with multi-select. The list includes “Run All” at the top.
  • Always availableRun (random) runs without specifying a key, letting the SDK pick one.

Keys are resolved from inline object literals, JSON file imports, or fromDir.merge("./data/") calls. If resolution fails, you still get the Run (random) button.


CodeLens: Open data

Data loader calls (fromCsv(), fromYaml(), fromDir(), JSON imports) show an Open data button above the call.

  • Single file — opens the data file in a bottom split, keeping focus on your test code.
  • Directory — shows Open data (N files) with the file count; clicking opens the first file.
  • Invalid path — shows a warning instead.

The button auto-refreshes when files in **/data/** change.


CodeLens: Results (N)

Each test definition shows a Results (N) button with the count of saved history results. Click to open the latest result in the Result Viewer. If no results exist yet, clicking prompts you to run the test first.


Data-driven patterns

These snippets focus on extension behavior. In real project files, create a shared client with configure() and import it into the test file.

test.each — array of cases

Run the same test logic with different inputs. Each row appears as a child node in Test Explorer.

import { configure, test } from "@glubean/sdk"; const { http: api } = configure({ http: { prefixUrl: "{{BASE_URL}}" }, }); export const statusCodes = test.each([ { id: 1, expected: 200 }, { id: 999, expected: 404 }, ])("get-item-$id", async (ctx, { id, expected }) => { const res = await api.get(`items/${id}`); ctx.expect(res).toHaveStatus(expected); });

Data can come from files too: test.each(fromCsv("./data/items.csv")).

test.pick — named examples (key-value)

Why: Separate test logic from test data. Write the verification once, let the team add cases by editing data files — no code changes needed. Each case gets its own CodeLens button so you can run and debug one at a time.

const cases = await fromDir.merge<UserCase>("./data/users/"); export const getUser = test.pick(cases)( { id: "get-user-$_pick", name: "Get user: $_pick" }, async (ctx, { id, expected }) => { const res = await api.get(`users/${id}`); ctx.expect(res).toHaveStatus(expected); }, );

Data files can be JSON or YAML (with comments). Each team member can add a *.local.json file with personal test cases that won’t conflict with the shared baseline.

For the full data-driven guide — including fromDir.merge, fromCsv, fromYaml, structured data patterns, personal *.local.json files, and merge ordering — see Data-Driven and Local Data.


test.extend aliases

If your team creates custom test functions with test.extend(), the extension discovers them automatically:

// config/browser-test.ts export const browserTest = test.extend({ /* plugins */ }); // tests/login.test.ts export const login = browserTest("login", async (ctx) => { ... });

Tests defined with browserTest are discovered and appear in Test Explorer alongside regular tests.


Project structure

explore/ vs tests/

DirectoryPurposeCI behavior
explore/Quick experiments, AI-generated drafts, bug reproductionRequires --profile explore or explicit path
tests/Committed regression suiteDefault glubean run (the local profile)

Test Explorer groups them separately when both directories exist. The default glubean init template creates tests/ and contracts/; add explore/ plus an explore profile when your team wants a committed draft lane.

Contracts and workflows are still the main source-of-truth layer. The extension helps most with local test() discovery, data navigation, and result inspection; use the CLI or MCP for the full project run.

When a test is stable, move it from explore/ to tests/. That is the only change needed for the default local/CI profile to pick it up.

config/ and data/

  • config/ — shared configure.ts for base URL, auth, plugins
  • data/ — JSON, YAML, CSV files for data-driven tests

What’s next?

Last updated on