condition-based-waiting
This skill should be used when the user mentions "flaky tests", "race condition", "timing issues", "wait for", "test sometimes fails", or when tests have inconsistent pass/fail behavior. Replaces arbitrary timeouts with condition polling.
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
Condition-Based Waiting
Flaky tests often guess at timing with arbitrary delays.
Core principle: Wait for the actual condition that matters, not a guess about how long it takes.
Core Pattern
// ❌ BEFORE: Guessing at timing
await new Promise((r) => setTimeout(r, 50));
const result = getResult();
expect(result).toBeDefined();
// ✅ AFTER: Waiting for condition
await waitFor(() => getResult() !== undefined);
const result = getResult();
expect(result).toBeDefined();
Quick Patterns
| Scenario | Pattern |
|---|---|
| Wait for event | waitFor(() => events.find(e => e.type === 'DONE')) |
| Wait for state | waitFor(() => machine.state === 'ready') |
| Wait for count | waitFor(() => items.length >= 5) |
| Wait for file | waitFor(() => fs.existsSync(path)) |
Implementation
async function waitFor<T>(
condition: () => T | undefined | null | false,
description: string,
timeoutMs = 5000
): Promise<T> {
const startTime = Date.now();
while (true) {
const result = condition();
if (result) return result;
if (Date.now() - startTime > timeoutMs) {
throw new Error(
`Timeout waiting for ${description} after ${timeoutMs}ms`
);
}
await new Promise((r) => setTimeout(r, 10)); // Poll every 10ms
}
}
See examples/example.ts for domain-specific helpers (waitForEvent, waitForEventCount, waitForEventMatch).
Common Mistakes
| Mistake | Fix |
|---|---|
| Polling too fast (1ms) | Poll every 10ms |
| No timeout | Always include timeout with clear error |
| Stale data | Call getter inside loop for fresh data |
When Arbitrary Timeout IS Correct
When testing actual timing behavior:
// Tool ticks every 100ms - need 2 ticks
await waitForEvent(manager, "TOOL_STARTED"); // First: wait for condition
await new Promise((r) => setTimeout(r, 200)); // Then: wait for known timing
// 200ms = 2 ticks at 100ms - documented and justified
Requirements:
- First wait for triggering condition
- Based on known timing (not guessing)
- Comment explaining WHY
Integration
Referenced by systematic-debugging when flaky tests are identified.
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-01-26
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!