Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Eloquent Scope Assertion Laravel Package

tkaratug/eloquent-scope-assertion

A lightweight Laravel testing helper for asserting that Eloquent model scopes apply the expected query constraints. Write expressive, readable tests for your local scopes without brittle SQL comparisons, and keep your query logic verified and maintainable.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a dev-only testing helper: it lets you assert that an Eloquent local scope was applied to a query without necessarily executing the query against a database. That makes it useful for testing scope logic in isolation, especially scopes that are conditional, composable, or buried inside repository/query-builder methods.

Minimal setup:

composer require --dev tkaratug/eloquent-scope-assertion

The package supports Laravel package auto-discovery, so no manual service provider registration is normally required. Confirm the exact assertion method names and supported Laravel/PHP versions in the repository README and composer.json before adopting it — the last tagged release is from February 2023, so verify compatibility with your Laravel version (10/11/12) and PHP version.

Where to look first:

  1. The README usage section — the assertion API is small; read it end to end.
  2. The package's own tests/ directory — the best source of truth for how scopes are detected (e.g., whether it inspects $query->getQuery()->scopes or the generated SQL).
  3. Your model's scope* methods — identify which ones you want to pin down with assertions.

First use case: you have a User::scopeActive() or Post::scopePublished() and want a fast unit test that a query built by some service/repository actually applied it:

public function test_active_users_query_applies_scope(): void
{
    $query = User::query()->active();

    // Use the package's assertion helper here; check README for exact signature,
    // e.g. $this->assertScope(...) / assertScopeApplied(...).
    $this->assertScope('active', $query);

    // Sanity check while learning the package:
    $this->assertStringContainsString('active = 1', $query->toSql());
}

Start by pairing the package assertion with a raw toSql()/getBindings() check until you trust what the assertion actually verifies.

Implementation Patterns

Pin scope application in repository/service tests. The highest-value pattern is asserting that a query builder returned by your application code has the expected scopes attached, without needing seeded data:

public function test_repository_applies_visible_scope(): void
{
    $query = (new PostRepository())->visible();

    $this->assertScope('visible', $query);
}

Test conditional scopes with data providers. Scopes that branch on input are ideal targets. Assert the scope is present when the condition is true and absent when false:

/**
 * @dataProvider roleProvider
 */
public function test_scope_is_conditional(string $role, bool $expected): void
{
    $query = User::query()->forRole($role);

    $expected
        ? $this->assertScope('forRole', $query)
        : $this->assertScopeNotApplied('forRole', $query); // verify exact name in README
}

Pair “scope applied” with behavioral tests. Use the scope assertion as a cheap contract test, then keep one database-backed feature test that proves the scope returns the right rows. The assertion package proves wiring; the feature test proves behavior.

Use it in Pest. The assertion should work anywhere Laravel's TestCase assertions are available:

it('applies the published scope', function () {
    $query = Post::query()->published();

    $this->assertScope('published', $query);
});

Guard scope composition. If a scope delegates to another scope (scopePublished() calling $query->whereNotNull('published_at') plus ->active()), assertions let you verify the outer scope is present and, separately, that composition chains produce the expected builder state.

CI integration. Because the package avoids database round-trips for the scope check itself, these tests run fast in a pure unit suite. Keep them in a separate tests/Unit/Scopes directory so they don't require RefreshDatabase.

Integration tip: wrap the assertion in your own base test helper (e.g., assertQueryHasScope($query, 'active')) so a future API change or package replacement touches one file instead of hundreds.

Gotchas and Tips

  • Maintenance risk. With ~18 stars and a last release in early 2023, treat this as a small utility rather than infrastructure. Pin the version, and be prepared to replace it if Laravel's query builder internals change. The underlying mechanics (inspecting applied scopes) are trivial to reimplement as a custom assertion if needed.
  • Local scopes only. This package targets Eloquent local scopes (scopeFoo). Global scopes, $query->withGlobalScope(), and relationship constraints are a different mechanism — don't expect assertions to cover them.
  • Know what “applied” means. The assertion likely inspects the query builder's registered scopes/constraints rather than executing SQL. A scope that is registered but whose body adds no where clauses may still count as “applied.” Confirm this behavior in the package tests before relying on it for negative assertions.
  • Arguments and bindings aren't validated. If scopeOfType($query, $type) is “applied,” the assertion generally won't prove the value of $type was bound correctly. Add an explicit getBindings() or toSql() assertion for scopes with parameters.
  • Debugging failures. When an assertion fails, dump $query->toSql() and $query->getBindings(), and inspect $query->getQuery()->scopes (or removedScopes) to see what the builder actually holds. Most failures are “scope never called” rather than “assertion helper broken.”
  • Beware of lazy scopes. Scopes invoked implicitly by a ->get() call are not the same as explicitly chaining ->active(). If your code applies scopes deep inside a method, extract and return the builder so the test can inspect it.
  • Config quirks. There is generally little to configure, but check composer.json for extra.laravel.providers/aliases and the README for any publishable config. If auto-discovery is disabled in your app, register the provider manually in the test environment.
  • Extension point. If the package exposes a macro or trait on TestCase, you can compose your own assertions around it. If it doesn't, a 10-line custom assertion using getQuery()->scopes gives you the same value with zero dependency risk:
protected function assertQueryHasScope(string $scope, Builder $query): void
{
    $this->assertContains($scope, $query->getQuery()->scopes);
}
  • Don't over-assert. Scope assertions document intent; they don't replace at least one integration test showing the scope filters correctly against a real (SQLite in-memory is fine) database.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log