With vitest we cannot put logic inside describe for GIVEN/WHEN/THEN setup as with-describe
However, we can use beforeAll to power GIVEN/WHEN/THEN:
GT-Sandbox-Snapshot
Code
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
/**
* NOTE: There is a quirk in Vitest where console.log() statements inside beforeAll()
* hooks get buffered separately and appear under "unknown test" in the output, making
* them appear out of order even though execution happens correctly. This executionLog
* array tracks the actual execution order and prints it at the end via afterAll() to
* prove the GIVEN/WHEN/THEN flow executes as expected.
*/
const executionLog: string[] = [];
describe('GIVEN a user account', () => {
let account: any;
beforeAll(() => {
executionLog.push("1) GIVEN - Setting up account context");
account = {balance: 0, transactions: []};
});
describe('WHEN depositing money', () => {
beforeAll(() => {
executionLog.push("2) WHEN - Depositing $100");
account.balance += 100;
account.transactions.push({type: 'deposit', amount: 100});
});
it('THEN balance should increase', () => {
executionLog.push("3) THEN - Checking balance");
expect(account.balance).toBe(100);
});
it('THEN transaction should be recorded', () => {
executionLog.push("4) THEN - Checking transaction");
expect(account.transactions).toHaveLength(1);
expect(account.transactions[0].type).toBe('deposit');
});
describe('WHEN withdrawing money', () => {
beforeAll(() => {
executionLog.push("5) WHEN - Withdrawing $30");
account.balance -= 30;
account.transactions.push({type: 'withdrawal', amount: 30});
});
it('THEN balance should reflect withdrawal', () => {
executionLog.push("6) THEN - Checking new balance");
expect(account.balance).toBe(70);
});
it('THEN both transactions should be recorded', () => {
executionLog.push("7) THEN - Checking all transactions");
expect(account.transactions).toHaveLength(2);
});
});
});
describe('WHEN checking balance without deposits', () => {
let cleanAccount: any;
beforeAll(() => {
executionLog.push("8) WHEN - Creating clean account");
cleanAccount = {balance: 0, transactions: []};
});
it('THEN balance should be zero', () => {
executionLog.push("9) THEN - Checking zero balance");
expect(cleanAccount.balance).toBe(0);
});
});
afterAll(() => {
console.log("\n=== EXECUTION ORDER ===");
executionLog.forEach(log => console.log(log));
console.log("======================\n");
});
});Command to reproduce:
gt.sandbox.checkout.commit 2f99590ccd576a626a1c \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./run.sh"Recorded output of command:
up to date, audited 182 packages in 614ms
33 packages are looking for funding
run `npm fund` for details
2 moderate severity vulnerabilities
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
> glassthought-sandbox@1.0.0 test
> vitest run
RUN v0.34.6 /home/nickolaykondratyev/git_repos/glassthought-sandbox
✓ src/main.test.ts (5 tests) 3ms
stdout | unknown test
=== EXECUTION ORDER ===
1) GIVEN - Setting up account context
2) WHEN - Depositing $100
3) THEN - Checking balance
4) THEN - Checking transaction
5) WHEN - Withdrawing $30
6) THEN - Checking new balance
7) THEN - Checking all transactions
8) WHEN - Creating clean account
9) THEN - Checking zero balance
======================
Test Files 1 passed (1)
Tests 5 passed (5)
Start at 11:39:40
Duration 463ms (transform 33ms, setup 0ms, collect 16ms, tests 3ms, environment 0ms, prepare 79ms)Notes
itblocks that are in the outer level THENdescribe.beforeAllwill have priority in order of execution.describe.beforeAllwill execute once for that describe block.- Any code that you would like to put directly into
describeblock likely belongs indescribe.beforeAllto act as you would expect (See with-describe)