bupkis-assertion-patterns

Bupkis Assertion Patterns

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "bupkis-assertion-patterns" with this command: npx skills add boneskull/claude-plugins/boneskull-claude-plugins-bupkis-assertion-patterns

Bupkis Assertion Patterns

Write idiomatic, expressive assertions using bupkis' powerful assertion vocabulary to make tests more readable and maintainable.

When to Use

  • Writing tests with the bupkis assertion library

  • Checking properties, types, or structure of objects

  • Verifying arrays or collections

  • Want clearer, more expressive test failures

When NOT to Use

  • When a simple, direct assertion is clearer (don't over-complicate)

  • When the pattern doesn't improve readability

Core Principles

  • Use semantic assertions: Choose assertions that express intent, not implementation

  • Combine related checks: Use to satisfy for multiple properties rather than separate assertions

  • Leverage bupkis vocabulary: Use built-in assertions like to have property , to be empty , etc.

  • Let assertions imply related checks: e.g., to be an object already implies non-null

Patterns

  1. Property Existence

Prefer semantic property checks over truthiness checks.

// ❌ DON'T - unclear intent, indirect check expect('filesCompleted' in state, 'to be truthy');

// ✅ DO - clear, semantic assertion expect(state, 'to have property', 'filesCompleted');

Why: to have property expresses the intent clearly and provides better error messages.

  1. Type Checking Multiple Properties

Combine related type checks using to satisfy instead of separate assertions.

// ❌ DON'T - repetitive, verbose expect(typeof state.filesCompleted, 'to equal', 'number'); expect(typeof state.suitesCompleted, 'to equal', 'number'); expect(typeof state.tasksCompleted, 'to equal', 'number');

// ✅ DO - concise, shows structure at a glance expect(state, 'to satisfy', { filesCompleted: expect.it('to be a number'), suitesCompleted: expect.it('to be a number'), tasksCompleted: expect.it('to be a number'), });

Why: to satisfy lets you verify multiple properties in one assertion, showing the expected structure clearly. Better error messages show exactly which properties failed.

  1. Non-Empty Collections

Use semantic collection assertions instead of length comparisons.

// ❌ DON'T - indirect, requires mental math expect(result.files.length, 'to be greater than', 0);

// ✅ DO - direct, semantic expect(result.files, 'not to be empty');

Why: not to be empty directly expresses the intent. Works for arrays, strings, objects, Maps, Sets, etc.

  1. Object and Null Checks

Don't redundantly check for null when object check already implies it.

// ❌ DON'T - redundant null check expect(config, 'to be an object'); expect(config, 'not to be null');

// ✅ DO - object check implies non-null expect(config, 'to be an object'); // already implies non-null

Why: In bupkis, to be an object already ensures the value is not null. Redundant checks add noise.

  1. Object Structure Verification

Verify object structure with to satisfy instead of multiple property assertions.

// ❌ DON'T - fragmented, hard to see expected structure expect(config, 'to be an object'); expect(config.iterations, 'to equal', 500); expect(config.reporters[0], 'to equal', 'json'); expect(config.reporters.length, 'to equal', 1);

// ✅ DO - clear, declarative structure check expect(config, 'to satisfy', { iterations: 500, reporters: expect.it('to deep equal', ['json']), });

Why: to satisfy lets you declaratively specify the expected structure. Combines type check and property validation in one assertion. Shows the expected shape at a glance.

5b. Multiple Conditions on the Same Result Object

Combine multiple checks on a result object with to satisfy instead of separate assertions.

// ❌ DON'T - multiple separate assertions expect(result.exitCode, 'to equal', 0); expect(result.stdout, 'to match', /No historical data/); expect(result.stderr, 'not to match', /toLocaleDateString is not a function/);

// ✅ DO - single to satisfy assertion expect(result, 'to satisfy', { exitCode: 0, stdout: expect.it('to match', /No historical data/), stderr: expect.it('not to match', /toLocaleDateString is not a function/), });

Why: Groups all related checks on the same object. Shows the expected result state clearly. Easier to maintain - add/remove checks in one place. Better error messages show exactly which property failed.

  1. Defined Value Checks

Use positive assertions instead of negated ones when possible.

// ❌ DON'T - negated assertion expect(result, 'not to be undefined');

// ✅ DO - positive, semantic expect(result, 'to be defined');

Why: to be defined is clearer and more idiomatic than negating undefined. It's a positive assertion that directly expresses intent.

  1. Chaining Assertions with 'and'

Use concatenation when making multiple assertions on the same subject.

// ❌ DON'T - separate assertions expect(config, 'to be an object'); // implies non-null expect(config, 'to have property', 'reporters');

// ✅ DO - chain with 'and' expect(config, 'to be an object', 'and', 'to have property', 'reporters');

Why: Chaining assertions with 'and' keeps related checks together in a single statement. More concise and shows that you're checking multiple aspects of the same value. Better error messages that show which part of the chain failed.

  1. Multiple Property Checks with Array

Use to have properties with an array when checking for multiple properties.

// ❌ DON'T - chain multiple property checks expect( config, 'to be an object', 'and', 'to have property', 'outputDir', 'and', 'to have property', 'reporters', );

// ✅ DO - use 'to have properties' with array expect(config, 'to have properties', ['outputDir', 'reporters']);

Why: to have properties with an array is specifically designed for checking multiple properties at once. More concise than chaining. Shows all required properties clearly in one place. Better error messages that list all missing properties.

  1. Promise Rejection Checks

Use expectAsync with 'to reject' for testing promise rejections.

// ❌ DON'T - wishy-washy try/catch try { await configManager.load('nonexistent.config.json'); expect(true, 'to be truthy'); // Maybe it works? } catch (error) { expect(error, 'to be an', Error); // Or maybe it throws? expect((error as Error).message, 'not to be empty'); }

// ✅ DO - explicit promise rejection check await expectAsync(configManager.load('nonexistent.config.json'), 'to reject');

Why: Makes the contract explicit - either it should reject or it shouldn't. No ambiguity. expectAsync is specifically designed for promise-based assertions. 'to reject' clearly expresses that rejection is the expected behavior.

Related assertions:

  • 'to reject'

  • promise should be rejected

  • 'to reject with error satisfying'

  • promise should reject with specific error

Advanced to satisfy Patterns

Partial Object Matching

// Only check specific properties, ignore others expect(result, 'to satisfy', { status: 'complete', // other properties ignored });

Nested Structure

expect(benchmark, 'to satisfy', { name: expect.it('to be a string'), results: expect.it('to satisfy', { mean: expect.it('to be a number'), median: expect.it('to be a number'), }), });

Array Element Values

// Check specific array values within to satisfy expect(config, 'to satisfy', { iterations: 100, reporters: ['human'], // checks first element matches });

// Or check multiple elements expect(config, 'to satisfy', { tags: ['performance', 'critical'], });

Arrays with Patterns

// All items must satisfy condition expect(results, 'to have items satisfying', { duration: expect.it('to be a number'), status: 'success', });

Quick Reference

Instead of... Use...

'prop' in obj, 'to be truthy'

obj, 'to have property', 'prop'

typeof x.prop, 'to equal', 'number'

x, 'to satisfy', {prop: expect.it('to be a number')}

arr.length, 'to be greater than', 0

arr, 'not to be empty'

result, 'not to be undefined'

result, 'to be defined'

Separate expect() on same subject Chain with 'and' : expect(x, 'a', 'and', 'b')

Multiple 'to have property' assertions to have properties , ['prop1', 'prop2']

try/catch for promise rejection await expectAsync(promise, 'to reject')

Multiple assertions on the same object to satisfy with object structure

Separate object + null checks Just to be an object

Benefits

  • Clearer intent: Semantic assertions express what you're testing, not how

  • Better error messages: bupkis shows exactly what failed in structural checks

  • More maintainable: Related checks grouped together, easier to update

  • Less code: Combine multiple assertions into expressive structure checks

  • Discover structure: to satisfy shows expected object shape at a glance

Tools Used

  • expect() with bupkis assertion vocabulary

  • expect.it() for nested assertions within to satisfy

  • Semantic assertions: to have property , not to be empty , to be an object

  • Structural assertions: to satisfy , to deep equal

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

zod-v4

No summary provided by upstream source.

Repository SourceNeeds Review
General

git-directory-management

No summary provided by upstream source.

Repository SourceNeeds Review
General

git-rebase-interactive

No summary provided by upstream source.

Repository SourceNeeds Review
General

git-commit-messages

No summary provided by upstream source.

Repository SourceNeeds Review