Back to skills
SKILL.md
Condition Based Waiting
ASecurityReplace arbitrary timeouts with condition polling for reliable async tests
- 74 stars
- 0 votes
- 0 copies
- 2 views
- Added September 6, 2026
Security analysis
100/100Pro scans all 2 files and shows the line behind each finding
npx -y skills add bobmatnyc/claude-mpm-skills --skill condition-based-waiting --agent claude-codeAre you the author of Condition Based Waiting?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/bobmatnyc-condition-based-waiting)---
name: condition-based-waiting
description: Replace arbitrary timeouts with condition polling for reliable async tests
user-invocable: false
disable-model-invocation: true
when_to_use: when tests have race conditions, timing dependencies, or inconsistent pass/fail behavior
version: 1.1.0
languages: all
progressive_disclosure:
entry_point:
summary: "Replace arbitrary timeouts with condition polling for reliable async tests"
when_to_use: "Tests with setTimeout/sleep, flaky tests, or timing-dependent async operations"
quick_start: |
1. Identify arbitrary delays in tests (setTimeout, sleep, time.sleep())
2. Replace with condition-based waiting (waitFor pattern)
3. Use domain-specific helpers for common scenarios
See @example.ts for complete working implementation
core_pattern: |
// ❌ Guessing at timing
await new Promise(r => setTimeout(r, 50));
// ✅ Waiting for condition
await waitFor(() => getResult() !== undefined);
references:
- path: references/patterns-and-implementation.md
purpose: Detailed waiting patterns, implementation guide, and common mistakes
when_to_read: When implementing waitFor or debugging timing issues
---
# Condition-Based Waiting
## Overview
Flaky tests often guess at timing with arbitrary delays. This creates race conditions where tests pass on fast machines but fail under load or in CI.
**Core principle:** Wait for the actual condition you care about, not a guess about how long it takes.
## When to Use
```dot
digraph when_to_use {
"Test uses setTimeout/sleep?" [shape=diamond];
"Testing timing behavior?" [shape=diamond];
"Document WHY timeout needed" [shape=box];
"Use condition-based waiting" [shape=box];
"Test uses setTimeout/sleep?" -> "Testing timing behavior?" [label="yes"];
"Testing timing behavior?" -> "Document WHY timeout needed" [label="yes"];
"Testing timing behavior?" -> "Use condition-based waiting" [label="no"];
}
```
**Use when:**
- Tests have arbitrary delays (`setTimeout`, `sleep`, `time.sleep()`)
- Tests are flaky (pass sometimes, fail under load)
- Tests timeout when run in parallel
- Waiting for async operations to complete
**Don't use when:**
- Testing actual timing behavior (debounce, throttle intervals)
- Always document WHY if using arbitrary timeout
## Core Pattern
```typescript
// ❌ 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))` |
| Complex condition | `waitFor(() => obj.ready && obj.value > 10)` |
## Implementation
Generic polling function:
```typescript
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 @example.ts for complete implementation with domain-specific helpers (`waitForEvent`, `waitForEventCount`, `waitForEventMatch`).
For detailed patterns, implementation guide, and common mistakes, see @references/patterns-and-implementation.md
## Real-World Impact
From debugging session (2025-10-03):
- Fixed 15 flaky tests across 3 files
- Pass rate: 60% → 100%
- Execution time: 40% faster
- No more race conditions
Files in this skill
- SKILL.md
- references/patterns-and-implementation.md
Attribution
Comments
Loading comments…