Limitations & Trade-offs
Every tool makes trade-offs. Here are the ones Glubean makes — and why.
Scratch Mode
.test.tsfiles show TypeScript errors — nonode_modulesmeans no type definitions. Use.test.jsfor scratch files. In a full project,.test.tsworks normally with full type safety.- No
.env/.env.secrets— environment variables and secrets aren’t loaded in scratch mode. Hardcode values or useprocess.envdirectly. - No
configure()— shared HTTP clients need a project setup. Each test writes its own URL and headers.
Shared State & Execution Order
Tests in the same file share the module scope and currently run sequentially in export order. Treat this as an escape hatch, not the default way to model a business lifecycle.
Prefer:
workflow()when the lifecycle should project and stay tied to contract casestest()builder.setup(),.step(), and.teardown()when the lifecycle is imperative and should stay raw TypeScript
Module-level shared state can still be useful for tiny local probes:
import { configure, test } from "@glubean/sdk";
const { http: api } = configure({
http: { prefixUrl: "{{BASE_URL}}" },
});
let userId: number; // declare at module level
export const createUser = test("create-user", async (ctx) => {
const res = await api.post("users", {
json: { name: "Test" },
});
ctx.expect(res).toHaveStatus(201);
userId = (await res.json<{ id: number }>()).id; // assign inside test
});
export const verifyUser = test("verify-user", async (ctx) => {
const res = await api.get(`users/${userId}`);
ctx.expect(res).toHaveStatus(200);
});Rules:
- Declare shared variables at module top level
- Assign them only inside test callbacks, never at the top level
- Export order = execution order — put dependencies first
- Running a single test skips earlier tests, so shared variables keep their initial value
Why not parallel within one file yet? Parallel execution would break module-level shared state. Files are the isolation boundary; different files can run in parallel.
CodeLens Static Analysis
The extension uses regex-based static analysis (no runtime imports) to show CodeLens buttons. Some patterns can’t be resolved statically:
- Nested generics lose pick key resolution:
fromDir.merge<Record<string, T>>()may not show individual pick buttons —fromDir.merge<T>()works - Dynamic keys — computed variable names or conditional data loading won’t show pick buttons
require()syntax — only ESimportis detected; CommonJSrequireis not
When static analysis fails, tests still run correctly — only the inline CodeLens buttons are affected. Use glubean run --pick <name> from the CLI as a fallback.
Template Resolution ({{KEY}})
In configure() HTTP options, {{KEY}} templates resolve from both vars and secrets (secrets checked first). There is no strict mode that limits resolution to secrets only.
export const { vars, secrets, http: api } = configure({
vars: { baseUrl: "{{BASE_URL}}" }, // reads from .env
secrets: { apiKey: "{{API_KEY}}" }, // reads from .env.secrets
http: {
prefixUrl: "{{BASE_URL}}",
headers: {
Authorization: "Bearer {{API_KEY}}", // checks .env.secrets first, then .env
},
},
});If you put a secret in
.envinstead of.env.secrets, it will still work — but you shouldn’t. Secrets in.envare commit-prone public config, not explicitly registered secret inputs. They may appear in local artifacts or uploaded evidence unless another redaction rule catches them. Always use.env.secretsfor sensitive values.
Optional Packages Are Separate
The project template installs the SDK, runner, and local CLI dependency it needs to run generated package scripts. Extra capabilities live in separate packages so the local runtime stays small:
npm install @glubean/auth # bearer, apiKey, OAuth, basicAuth
npm install @glubean/browser # Puppeteer-based browser tests
npm install @glubean/graphql # GraphQL query/mutation helpers
npm install @glubean/grpc # gRPC client@glubean/auth is a helper package used directly from configure() or
test().use(...). @glubean/browser, @glubean/graphql, and @glubean/grpc
also ship plugin manifests; install those manifests in glubean.setup.ts when
you use their global matchers or contract protocols. Plain clients registered
through configure({ plugins }) do not need manifest installation.
CLI Defaults to the local Profile
glubean run without arguments runs the local profile from glubean.yaml.
In most projects, that means stable authored assets such as tests/ and
contracts. If your project declares an explore suite/profile, run it with:
glubean run --profile explore # run the explore profile (explore/ suite)
glubean run explore/smoke.test.ts # run a specific explore file (ad-hoc)This is intentional — explore/ is optional and is for drafts, reproductions,
and one-case iteration, not something CI should run automatically.