Giter Club home page Giter Club logo

laravel-test-assertions's Introduction

Laravel Test Assertions

A set of helpful assertions when testing Laravel applications.

Requirements

Your application must be running the latest LTS version (5.5) or higher and using Laravel's testing harness.

Installation

You may install these assertions with Composer by running:

composer require --dev jasonmccreary/laravel-test-assertions

Afterwards, add the trait to your base TestCase class:

<?php
namespace Tests;

use JMac\Testing\Traits\AdditionalAssertions;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication, AdditionalAssertions;
}

Assertions

This package adds several assertions helpful when writing Http Tests.

assertActionUsesFormRequest(string $controller, string $method, string $form_request)

Verifies the action for a given controller performs validation using the given form request.

assertRouteUsesFormRequest(string $routeName, string $formRequest)

Verifies that the corresponding action/controller, for a given route name performs the validation using the given form request.

assertActionUsesMiddleware(string $controller, string $method, string|array $middleware)

Verifies the action for a given controller uses the given middleware or set of middleware.

assertRouteUsesMiddleware(string $routeName, array $middlewares, bool $exact)

Verifies the route for a given route name uses all the given middlewares or only the given set of middlewares.

assertValidationRules(array $expected, array $actual)

Verifies the expected subset of validation rules for fields are within a set of validation rules. Rules may be passed as a delimited string or array.

assertExactValidationRules(array $expected, array $actual)

Verifies the expected set of validation rules for fields exactly match a set of validation rules. Rules may be passed as a delimited string or array.

assertValidationRuleContains($rule, string $class)

Verifies the rule or rules contains an instance of the given Rule class.

Matchers

LaravelMatchers::isModel(Model $model = null)

Matches an argument is the same as $model. When called without $model, will match any argument of type Illuminate\Database\Eloquent\Model.

LaravelMatchers::isCollection(Collection $collection = null)

Matches an argument equals $collection. When called without $collection, will match any argument of type Illuminate\Support\Collection.

LaravelMatchers::isEloquentCollection(Collection $collection = null)

Matches an argument equals $collection. When called without $collection, will match any argument of type \Illuminate\Database\Eloquent\Collection.

Creation Methods

This package also provides methods for quickly creating common objects used within Laravel application to use when testing.

createFormRequest(string $class, array $data = [])

Creates an instance of the given Form Request class with the given request data.

Support Policy

Starting with version 2, this package will only support the latest stable version of Laravel (currently Laravel 8). If you need to support older versions of Laravel, you may use version 1 or upgrade your application (try using Shift).

This package still follows semantic versioning. However, it does so with respect to its own code. Any breaking changes will increase its major version number. Otherwise, minor version number increases will contain new features. This includes changes for future versions of Laravel.

laravel-test-assertions's People

Contributors

a-lawrence avatar devmsh avatar devoncmather avatar devonmather avatar faustbrian avatar hdvinnie avatar jasonmccreary avatar laravel-shift avatar mikkoaf avatar mmghunaim avatar morpheus7cs avatar nestecha avatar niveshsaharan avatar sharafat avatar svenluijten avatar zpwparsons avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-test-assertions's Issues

Assert Event has Listener

Assert Event has Listener might be an assertion that others may use too.
My strategy for testing event is as follows: In a feature test, I assert that the event is fired. In a unit test, I assert everything related to the listener:

public function test_listener()
{
    $listener = new Listener();
    $listener->handle();

    $this->assert.....
}

What I need is a test in an EventServiceProviderTest class to assert that an event has a listener.

I copied and modified code from event list artican command:

public function assertEventHasListener($event, $listener)
{
        $events = [];

        foreach ($this->app->getProviders(EventServiceProvider::class) as $provider) {
            $providerEvents = array_merge_recursive(
                $provider->shouldDiscoverEvents() ? $provider->discoverEvents() : [], $provider->listens()
            );

            $events = array_merge_recursive($events, $providerEvents);
        }

        $this->assertTrue(in_array($listener, $events[$event]));
}

I can create a PR but I don't have access.

Testing FormRequest

Let me know your thoughts on this concept.
I like the form creation, withUser, and expects gates.

I want to be able to do something like validateOn(...) and pass the data in, and list the items I expect to fail / pass, but I'm not sold yet on my implementation. Thoughts?

Usage

$this->formRequest(StoreRequest::class, route('api.employees.store'), 'POST')
    ->withUser($this->getAuthUser())
    ->expectsGate('create', null, null, [User::class, UserPolicy::EMPLOYEE])
    ->validateOn([], [], [], [], ['username']) // Fail on username
    ->validateOn([], [
        'username' => $employee->username
    ], [], [], ['username']) // Fails on username already existing
    ->execute();

code

<?php

namespace App\Testing;

use Exception;
use Illuminate\Auth\AuthManager;
use Illuminate\Contracts\Auth\Access\Gate;
use Illuminate\Contracts\Container\Container;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Routing\Redirector;
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Validator;
use Mockery;
use PHPUnit\Framework\TestCase as PHPUnitTestCase;

class PendingFormRequest {

    /**
     * Whether the gate callback needs to be applied
     *
     * @var bool
     */
    public static $appliedGateCallback = false;

    /**
     * The test being run
     *
     * @var \Illuminate\Foundation\Testing\TestCase
     */
    public $test;

    /**
     * The application instance
     *
     * @var \Illuminate\Contracts\Container\Container
     */
    protected $app;

    /**
     * The gate instance
     *
     * @var \Illuminate\Contracts\Auth\Access\Gate
     */
    protected $gate;

    /**
     * The underlying form request to be tested
     *
     * @var \Illuminate\Foundation\Http\FormRequest
     */
    protected $formRequest;

    /**
     * The list of gates executed
     *
     * @var array
     */
    protected $gatesExecuted = [];

    /**
     * List of expected gates executed
     *
     * @var array
     */
    protected $expectedGates = [];

    /**
     * List of expected validation lists
     *
     * @var array
     */
    protected $validateOn = [];

    /**
     * Determine if command has executed.
     *
     * @var bool
     */
    protected $hasExecuted = false;

    /**
     * Create a new pending console command run
     *
     * @param \PHPUnit\Framework\TestCase $test
     * @param \Illuminate\Contracts\Container\Container $app
     * @param \Illuminate\Foundation\Http\FormRequest|string $formRequest
     * @param string $route
     * @param string $method
     */
    public function __construct(PHPUnitTestCase $test, Container $app, $formRequest, $route, $method) {
        $this->app = $app;
        $this->test = $test;

        // Set up gate checking
        $this->prepGates($app->get(Gate::class));
        $this->prepFormRequest($formRequest, $route, $method);
    }

    /**
     * Destroy the pending console command
     */
    public function __destruct() {
        $this::$appliedGateCallback = false;
    }

    /**
     * Prepare the pending form request's gate
     *
     * @param \Illuminate\Contracts\Auth\Access\Gate $gate
     * @return self
     */
    private function prepGates(Gate $gate) {
        $this->expectedGates = [];
        $this->gatesExecuted = [];

        $this->gate = $gate;

        if (!$this::$appliedGateCallback) {
            $this->gate->after(function ($user, $ability, $result, $arguments = []) {
                $this->gatesExecuted[] = [
                    'user' => $user,
                    'ability' => $ability,
                    'result' => $result,
                    'arguments' => $arguments,
                ];
            });
            $this::$appliedGateCallback = true;
        }

        return $this;
    }

    /**
     * Prepare the pending form request's form request
     *
     * @param \Illuminate\Foundation\Http\FormRequest|string $formRequest
     * @param string $route
     * @param string $method
     * @return self
     */
    private function prepFormRequest($formRequest, $route, $method) {
        // Build the form request
        $this->formRequest = tap($formRequest::create($route, $method)
            ->setContainer($this->app)
            ->setRedirector(tap(Mockery::mock(Redirector::class), function ($redirector) {
                $fakeUrlGenerator = Mockery::mock();
                $fakeUrlGenerator->shouldReceive('to', 'route', 'action', 'previous')->withAnyArgs()->andReturn(null);

                $redirector->shouldReceive('getUrlGenerator')->andReturn($fakeUrlGenerator);
            }))
            ->setUserResolver(function () {
                return $this->app->get(AuthManager::class)->user();
            })->setRouteResolver(function () {
                $router = $this->app->get(Router::class);
                $routes = Route::getRoutes();
                $route = null;
                try {
                    $route = $routes->match($this->formRequest);

                    // Resolve bindings
                    $router->substituteBindings($route);
                    $router->substituteImplicitBindings($route);
                } catch (Exception $e) {
                } finally {
                    return $route;
                }
            }), function (FormRequest $formRequest) {
            $formRequest->files->replace([]);
            $formRequest->query->replace([]);
            $formRequest->request->replace([]);
        });

        $this->app->bind('request', $this->formRequest);

        return $this;
    }

    /**
     * Set the user for the form request
     *
     * @param \Illuminate\Database\Eloquent\Model $user
     * @return self
     */
    public function withUser($user) {
        $this->formRequest->setUserResolver(function () use ($user) {
            return $user;
        });

        return $this;
    }

    /**
     * Execute the command
     *
     * @return int
     */
    public function execute() {
        return $this->run();
    }

    /**
     * Execute the command
     *
     * @return int
     */
    public function run() {
        $this->hasExecuted = true;

        // Trigger authorize and check if all gates were executed
        if (count($this->expectedGates) > 0) {
            $this->formRequest->authorize();

            $this->verifyExpectedGates();
        }

        foreach ($this->validateOn as $key => $run) {
            // "Reset" all of the form requests data to this run's data
            $this->formRequest->files->replace($run['files'] ?? []);
            $this->formRequest->query->replace($run['get'] ?? []);
            $this->formRequest->request->replace($run['post'] ?? []);

            // Grab merged files and input data
            $data = array_merge_recursive(
                $this->formRequest->all(),
                $this->formRequest->allFiles()
            );
            $rules = $this->formRequest->rules();
            $messages = $this->formRequest->messages();

            $validator = Validator::make($data, $rules, $messages);
            $validator->passes();

            $errors = $validator->errors()->toArray();

            // Validate passed fields
            foreach ($run['passesOn'] as $key) {
                $this->test->assertArrayNotHasKey($key, $errors, "Failed to assert the field {$key} passed validation");
            }

            // Validate failed fields
            foreach ($run['failsOn'] as $key) {
                $this->test->assertArrayHasKey($key, $errors, "Failed to assert the field {$key} failed validation");
            }
        }

        return 0;
    }

    /**
     * Determine if expected gates were called
     *
     * @return void
     */
    protected function verifyExpectedGates() {
        $actualGates = collect($this->gatesExecuted);
        foreach ($this->expectedGates as $expectedGate) {
            $matched = $actualGates->filter(function ($actualGate) use ($expectedGate) {
                $result = true;

                if ($expectedGate['ability']) {
                    $result &= ($expectedGate['ability'] == $actualGate['ability']);
                }

                if ($expectedGate['user']) {
                    $result &= ($expectedGate['user'] == $actualGate['user']);
                }

                if ($expectedGate['result']) {
                    $result &= ($expectedGate['result'] == $actualGate['result']);
                }

                if ($expectedGate['arguments']) {
                    $result &= ($expectedGate['arguments'] == $actualGate['arguments']);
                }

                return $result;
            });

            $this->test->assertGreaterThan(0, $matched->count(), "Failed to assert that the gate {$expectedGate['ability']} resulted in {$expectedGate['result']}");
        }
    }

    /**
     * Add an expected gate to the pending list of gates
     *
     * @param string $ability
     * @param boolean|null $result
     * @param \Illuminate\Database\Eloquent\Model|null $user
     * @param array $arguments
     * @return $this
     */
    public function expectsGate($ability, $result = null, $user = null, $arguments = []) {
        $this->expectedGates[] = [
            'ability' => $ability,
            'user' => $user,
            'result' => $result,
            'arguments' => $arguments,
        ];

        return $this;
    }

    /**
     * Add an expected validation item to the list
     *
     * @param array $GET
     * @param array $POST
     * @param array $files
     * @param array $validFields
     * @param array $invalidFields
     * @return $this
     */
    public function validateOn($GET = [], $POST = [], $files = [], $validFields = [], $invalidFields = []) {
        $this->validateOn[] = [
            'get' => $GET,
            'post' => $POST,
            'files' => $files,
            'passesOn' => $validFields,
            'failsOn' => $invalidFields,
        ];

        return $this;
    }
}

Asserting a route uses a form request doesn't work with first class callables

I came across this when using rector with the LevetSetList::UPTO_PHP_82 rule to upgrade my code from PHP 8.1 to 8.2.

Rector converted my routes from this format:

 Route::post('/', [SensorController::class, 'store'])
            ->name('store');

To use a first-class callable:

Route::post('/', new (SensorController())->store(...))
            ->name('store');

My pest test then failed:

it('validates using the correct form request', function () {
    $this->assertRouteUsesFormRequest('sensors.store', SensorRequest::class);
});

Upon closer inspection, inside assertRouteUsesFormRequest it looks for the controller action at https://github.com/jasonmccreary/laravel-test-assertions/blob/master/src/Traits/AdditionalAssertions.php#L14-L16, which is not set when using a first class callable, so the test then failed.

Feature Request: Form Request Assertions

Problem: Testing form requests in Laravel is difficult and annoying.

Solution: I have a little Trait FormRequestAssertions that results in the following test structure...

$this->makeFormRequest(FormRequest::class, route('...'), 'POST');

// Validate Authorization
$this->assertAuthorized();

// Validate rules
// Name is required
$this->updateFormData($data, $files)
        ->assertIsNotValid('name');

// Name exists
$this->updateFormData([
    'name' => $this->faker->company,
])->assertIsValid('name');

This solution allows for form requests tests that target specific validation rule(s) along with the authorization function.

I want to ask if you would like this functionality within this package as this seems like the best place for it; a nice collection of PHPUnit assertions for Laravel. If so, I'd be happy to submit the trait within a PR for your review.

(Maybe bundle in the https://laracasts.com/series/phpunit-testing-in-laravel/episodes/12) as well for mail assertions? I've got a trait build that can be submitted as well

assertNotSoftDeleted declaration breaks in Laravel 8.62

When Laravel Shift upgraded my repo to Laravel 8.62, this error appears in my build:

PHP Fatal error:  Declaration of JMac\Testing\Traits\AdditionalAssertions::assertNotSoftDeleted(Illuminate\Database\Eloquent\Model $model) must be compatible with Illuminate\Foundation\Testing\TestCase::assertNotSoftDeleted($table, array $data = [], $connection = null, $deletedAtColumn = 'deleted_at')

Naming conflict with Laravel's `assertNotSoftDeleted`

laravel/framework@cb72e7b has added an implementation of assertNotSoftDeleted to Laravel's InteractsWithDatabase itself. This leads to the following error message when using both traits:

Fatal error: Declaration of JMac\Testing\Traits\AdditionalAssertions::assertNotSoftDeleted(Illuminate\Database\Eloquent\Model $model) must be compatible with Illuminate\Foundation\Testing\TestCase::assertNotSoftDeleted($table, array $data = [], $connection = null, $deletedAtColumn = 'deleted_at') in xxx.php on line yyy

To restore compatibility, I'd suggest to rename or remove the assertNotSoftDeleted method present in this package.

Package incompatible with laravel/framework 8.62.0

PhpUnit throws a fatal error when using this package with laravel 8.62.0 and PHP 8.0:

PHP Fatal error:  Declaration of JMac\Testing\Traits\AdditionalAssertions::assertNotSoftDeleted(Illuminate\Database\Eloquent\Model $model) must be compatible with Illuminate\Foundation\Testing\TestCase::assertNotSoftDeleted($table, array $data = [], $connection = null, $deletedAtColumn = 'deleted_at') in /var/www/html/tests/TestCase.php on line 182

This is because assertNotSoftDeleted() has been added to Illuminate\Foundation\Testing\Concerns\InteractsWithDatabase but with a different method signature.

A temporary workaround is to add the following method to the class that imports the AdditionalAssertions trait:

protected function assertNotSoftDeleted($table, array $data = [], $connection = null, $deletedAtColumn = 'deleted_at')
{
    return parent::assertNotSoftDeleted($table, $data, $connection, $deletedAtColumn);
}

Possible to pass in arguments

Would there be a good reason to check the arguments that might get passed to the Unique or Exists or any other custom rules? I feel as if this would help your assertValidationRuleContains assertion method?

Closure Based Rules Doesn't Pass Unit Validation Test

Currently I have a test that doesn't pass because of the Rule class having a closure attached to the rule. I'm seeing this happen with Rule::requiredIf but could also be seeing this using the new Rule::when() but that's just newly introduced to the Laravel framework. Has anyone come across this unexpected situation?

'started_at' => [
    Rule::requiredIf(function () {
        return  ! $this->route('user')->isUnactivated();
    }),
]

Running the following test gives me the following result.

/**
   * @test
    */
   public function rules_returns_validation_requirements()
   {
       $subject = $this->createFormRequest(UpdateRequest::class);

       $rules = $subject->rules();

       $this->assertValidationRules([
           'started_at' => ['nullable', 'string', 'date'],
       ], $rules);

       $this->assertValidationRuleContains($rules['started_at'], RequiredIf::class);
   }
array (
       0 => 'nullable',
  -    1 => 'string',
  -    2 => 'date',
  +    1 => 
  +    Illuminate\Validation\Rules\RequiredIf::__set_state(array(
  +       'condition' => 
  +      Closure::__set_state(array(
  +      )),
  +    )),
  +    2 => 'string',
       3 => 'date',

Laravel 9.x support - illuminate/testing

In preparation for Laravel 9:

Problem 1
    - illuminate/testing[v8.0.0, ..., v8.11.2] require php ^7.3 -> your php version (8.0.15) does not satisfy that requirement.
    - Root composer.json requires jasonmccreary/laravel-test-assertions ^2.0 -> satisfiable by jasonmccreary/laravel-test-assertions[v2.0.0].
    - Conclusion: don't install laravel/framework v9.0.0-beta.2 (conflict analysis result)
    - Conclusion: don't install laravel/framework v9.0.0-beta.3 (conflict analysis result)
    - Conclusion: don't install laravel/framework v9.0.0-beta.4 (conflict analysis result)
    - Conclusion: don't install laravel/framework v9.0.0-beta.1 (conflict analysis result)
    - jasonmccreary/laravel-test-assertions v2.0.0 requires illuminate/testing ^8.0 -> satisfiable by illuminate/testing[v8.0.0, ..., 8.x-dev].
    - Only one of these can be installed: illuminate/testing[v8.0.0, ..., 8.x-dev], laravel/framework[v9.0.0-beta.1, ..., 9.x-dev]. laravel/framework replaces illuminate/testing and thus cannot coexist with it.
    - Root composer.json requires laravel/framework ^9.0 -> satisfiable by laravel/framework[v9.0.0-beta.1, ..., 9.x-dev].

question about resources namr

bellow naming convention, route name should be plurial (https://github.com/alexeymezenin/laravel-best-practices#follow-laravel-naming-conventions)
like /posts/1

when use laravel shift

it create in resource view /resource/view/post/

+-----------+---------------------------------+-------------------------------------------------------------------------+
| Method    | URI                             | Action                                                                  |
+-----------+---------------------------------+-------------------------------------------------------------------------+
| GET|HEAD  | /                               | Closure                                                                 |
| GET|HEAD  | api/user                        | Closure                                                                 |
| GET|HEAD  | confirm-password                | App\Http\Controllers\Auth\ConfirmablePasswordController@show            |
| POST      | confirm-password                | App\Http\Controllers\Auth\ConfirmablePasswordController@store           |
| GET|HEAD  | contact                         | App\Http\Controllers\ContactController@index                            |
| POST      | contact                         | App\Http\Controllers\ContactController@store                            |
| GET|HEAD  | contact/create                  | App\Http\Controllers\ContactController@create                           |
| GET|HEAD  | contact/{contact}               | App\Http\Controllers\ContactController@show                             |
| PUT|PATCH | contact/{contact}               | App\Http\Controllers\ContactController@update                           |
| DELETE    | contact/{contact}               | App\Http\Controllers\ContactController@destroy                          |
| GET|HEAD  | contact/{contact}/edit          | App\Http\Controllers\ContactController@edit                             |
| GET|HEAD  | dashboard                       | Closure                                                                 |
| GET|HEAD  | document                        | App\Http\Controllers\DocumentController@index                           |

TestResponse and FactoryBuilder macros

Hi,

I don't know if TestResponse macros can be part of the package or it's out of your interests? for example, I have a assertJsonPaths and assertPaginated witch I have several use cases for them when I develop APIs.

If you interested let me know to open RP for some of them, and if you prefer to have each one as a separate PR or we can add a bulk of macros together.

Sometimes I also add some macros to the FactoryBuilder like a data macro as a shortcut for factory(Model::class)->make()->toArray() which is also useful for some use cases.

Have a nice day and keep safe 👍

using assertValidationRules in pest

I used assertValidationRules from this package when I want to write a test for my request file:

test('rules', function () {
    $actual = $this->subject->rules();
    $this->assertValidationRules([
        'mobile' => [
            'required',
        ],
    ], $actual);
});

But when I run php test get an error:
Call to undefined method Tests\Unit\Http\Requests\MobileRequestTest::assertValidationRules()

And I don't know what the reason is
Please help me.
Also thanks in advance.

Use with Invoked Controllers

Issue: The assertActionUsesMiddleware does not work with invoke methods

Resolution: Change the following lines [52-53] in assertActionUsesMiddleware
$route = $router->getRoutes()->getByAction($controller . '@' . $method);
to

if($method) {
        $route = $router->getRoutes()->getByAction($controller . '@' . $method);
}
else {
        $route = $router->getRoutes()->getByAction($controller);
}

Then the usage would be $this->assertActionUsesMiddleware ('Controller', 'Method', 'Middleware'); for a method and $this->assertActionUsesMiddleware ('Controller', '', 'Middleware'); for invoked controllers

Asserting inverse of assertSoftDeleted

Problem:

Asserting that a model has not been soft deleted is not a separate available test assertion

https://laravel.com/docs/8.x/database-testing#assert-deleted

Solution:

There exists a ready solution which can be used. Adding this to the package could be helpful

public function assertModelNotSoftDeleted(Model $model)
{
    return $this->assertDatabaseHas($model->getTable(), [
        $model->getKeyName() => $model->getKey(),
        $model::DELETED_AT => null,
    ]);
}

Original snipped posted by
https://github.com/ImLiam
https://stackoverflow.com/questions/50328298/laravel-assert-not-soft-deleted-inverse-laravel-tests

Invokable controllers are not compatible with the assertRouteUsesFormRequest method

I've noticed that the following assertion causes a ErrorException: Undefined offset: 1

$this->assertRouteUsesFormRequest('api.import.csv', ValidateCsvRequest::class);

Looking at the code seems we are only splitting the string on the @ symbol, thus causing the undefined index issue when that @ symbol ins't present when using an __invoke function on a controller as seen here. [$controller, $method] = explode('@', $controllerAction->first());

FR: pass array for method in `assertActionUsesMiddleware`

I currently have this in a test:

    public function controller_uses_middleware()
    {
        $this->assertActionUsesMiddleware(SubscriptionController::class, 'store', 'auth');
        $this->assertActionUsesMiddleware(SubscriptionController::class, 'update', 'auth');
        $this->assertActionUsesMiddleware(SubscriptionController::class, 'destroy', 'auth');
    }

Would be great if I could do:

    public function controller_uses_middleware()
    {
        $this->assertActionUsesMiddleware(SubscriptionController::class, ['store, 'update', 'destroy',] 'auth');
    }

Once I get a bit more comfortable with this, I'll take a crack at a PR.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.