diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 49e8c56..7da841a 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -2,3 +2,4 @@ filter: excluded_paths: - "public/" - "tests/" + - "resources/assets/js/mixpanel.js" diff --git a/.travis.yml b/.travis.yml index 505a405..2ff3f83 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,4 +23,3 @@ notifications: on_success: change # options: [always|never|change] default: always on_failure: always # options: [always|never|change] default: always on_start: never # options: [always|never|change] default: always - diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bd8f7e..58a897f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,13 @@ This project adheres to [Semantic Versioning](http://semver.org/). (This is already detected in subscription update.) - Filter any incoming web-hook events that are in test mode. +## [WIP] - 5 Nov 2017 +### Added +- unit and feature tests. + +### Changed +- class structure as part of refactoring. + ## [0.7.2] - 5 Nov 2017 ### Fixed - inclusion of auto-track JS scripts. NPM library is broken and seems to not be maintained anymore, switched to script provided by mixpanel setup instructions. diff --git a/composer.json b/composer.json index 4fb76f7..470b014 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,7 @@ "require-dev": { "fzaninotto/faker": "~1.4", "laravel/laravel": "5.5.*", + "laravel/browser-kit-testing": "^2.0", "mockery/mockery": "0.9.*", "phpmd/phpmd": "^2.6", "phpunit/phpunit": "5.7.*", diff --git a/phpunit.xml b/phpunit.xml index 730c6c8..d7b48a9 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -32,5 +32,6 @@ + diff --git a/src/LaravelMixpanel.php b/src/LaravelMixpanel.php index e65c6b5..eba335d 100644 --- a/src/LaravelMixpanel.php +++ b/src/LaravelMixpanel.php @@ -12,12 +12,6 @@ class LaravelMixpanel extends Mixpanel private $defaults; private $request; - /** - * @param Request $request - * @param array $options - * - * @internal param Result $browser - */ public function __construct(Request $request, array $options = []) { $this->defaults = [ @@ -33,12 +27,6 @@ public function __construct(Request $request, array $options = []) ); } - /** - * @param string $event - * @param array $properties - * - * @internal param array $data - */ public function track($event, $properties = []) { $browserInfo = new Browser(); diff --git a/src/Listeners/LaravelMixpanelEventHandler.php b/src/Listeners/LaravelMixpanelEventHandler.php deleted file mode 100644 index c38252c..0000000 --- a/src/Listeners/LaravelMixpanelEventHandler.php +++ /dev/null @@ -1,47 +0,0 @@ -credentials['email'] ?? $event['email'] ?? ''; - - $authModel = config('auth.providers.users.model', config('auth.model')); - $user = app($authModel) - ->where('email', $email) - ->first(); - $eventName = 'Login Attempted'; - - event(new MixpanelEvent($user, $eventName)); - } - - public function onUserLogin($login) - { - $user = $login->user ?? $login; - event(new MixpanelEvent($user, 'User Logged In')); - } - - public function onUserLogout($logout) - { - $user = $logout->user ?? $logout; - event(new MixpanelEvent($user, 'User Logged Out')); - } - - public function subscribe(Dispatcher $events) - { - $events->listen('auth.attempt', self::class . '@onUserLoginAttempt'); - $events->listen('auth.login', self::class . '@onUserLogin'); - $events->listen('auth.logout', self::class . '@onUserLogout'); - - $events->listen(Attempting::class, self::class . '@onUserLoginAttempt'); - $events->listen(Login::class, self::class . '@onUserLogin'); - $events->listen(Logout::class, self::class . '@onUserLogout'); - } -} diff --git a/src/Listeners/LaravelMixpanelUserObserver.php b/src/Listeners/LaravelMixpanelUserObserver.php index 002a889..b707758 100644 --- a/src/Listeners/LaravelMixpanelUserObserver.php +++ b/src/Listeners/LaravelMixpanelUserObserver.php @@ -1,26 +1,26 @@ user, 'User Logged In')); + } +} diff --git a/src/Listeners/LoginAttempt.php b/src/Listeners/LoginAttempt.php new file mode 100644 index 0000000..8d56059 --- /dev/null +++ b/src/Listeners/LoginAttempt.php @@ -0,0 +1,20 @@ +credentials['email'] ?? $event['email'] ?? ''; + + $authModel = config('auth.providers.users.model', config('auth.model')); + $user = app($authModel) + ->where('email', $email) + ->first(); + $eventName = 'Login Attempted'; + + event(new Mixpanel($user, $eventName)); + } +} diff --git a/src/Listeners/Logout.php b/src/Listeners/Logout.php new file mode 100644 index 0000000..ed769c8 --- /dev/null +++ b/src/Listeners/Logout.php @@ -0,0 +1,12 @@ +user, 'User Logged Out')); + } +} diff --git a/src/Providers/Service.php b/src/Providers/Service.php index 62e9f86..37d5a2a 100644 --- a/src/Providers/Service.php +++ b/src/Providers/Service.php @@ -1,12 +1,17 @@ [ - MixpanelEventListener::class, - ], + MixpanelEvent::class => [MixpanelEventListener::class], + Attempting::class => [LoginAttempt::class], + Login::class => [LoginListener::class], + Logout::class => [LogoutListener::class], ]; public function boot() { parent::boot(); - $this->initialize(); - } - - protected function initialize() - { include __DIR__ . '/../../routes/api.php'; $this->loadViewsFrom(__DIR__ . '/../../resources/views', 'genealabs-laravel-mixpanel'); @@ -39,7 +40,6 @@ protected function initialize() if (config('services.mixpanel.enable-default-tracking')) { $authModel = config('auth.providers.users.model') ?? config('auth.model'); $this->app->make($authModel)->observe(new LaravelMixpanelUserObserver()); - app('events')->subscribe(new LaravelMixpanelEventHandler()); } } @@ -50,10 +50,7 @@ public function register() $this->app->singleton('mixpanel', LaravelMixpanel::class); } - /** - * @return array - */ - public function provides() + public function provides() : array { return ['genealabs-laravel-mixpanel']; } diff --git a/tests/CreatesApplication.php b/tests/CreatesApplication.php new file mode 100644 index 0000000..30c9253 --- /dev/null +++ b/tests/CreatesApplication.php @@ -0,0 +1,40 @@ +copyFixtures([ + __DIR__ . '/Fixtures/app/Http/Controllers/HomeController.php' => __DIR__ . '/../vendor/laravel/laravel/app/Http/Controllers/HomeController.php', + __DIR__ . '/Fixtures/resources/views/home.blade.php' => __DIR__ . '/../vendor/laravel/laravel/resources/views/home.blade.php', + __DIR__ . '/Fixtures/resources/views/auth/login.blade.php' => __DIR__ . '/../vendor/laravel/laravel/resources/views/auth/login.blade.php', + __DIR__ . '/Fixtures/resources/views/auth/register.blade.php' => __DIR__ . '/../vendor/laravel/laravel/resources/views/auth/register.blade.php', + __DIR__ . '/Fixtures/resources/views/auth/passwords/email.blade.php' => __DIR__ . '/../vendor/laravel/laravel/resources/views/auth/passwords/email.blade.php', + __DIR__ . '/Fixtures/resources/views/auth/passwords/reset.blade.php' => __DIR__ . '/../vendor/laravel/laravel/resources/views/auth/passwords/email.blade.php', + __DIR__ . '/Fixtures/resources/views/layouts/app.blade.php' => __DIR__ . '/../vendor/laravel/laravel/resources/views/layouts/app.blade.php', + __DIR__ . '/Fixtures/routes/web.php' => __DIR__ . '/../vendor/laravel/laravel/routes/web.php', + ]); + $app = require __DIR__ . '/../vendor/laravel/laravel/bootstrap/app.php'; + $app->make(Kernel::class)->bootstrap(); + $app->register(Service::class); + + return $app; + } + + protected function copyFixtures(array $fixtures) + { + $fixtures = collect($fixtures)->each(function ($destination, $source) { + $pathInfo = pathinfo($destination); + + if (! file_exists($pathInfo['dirname'])) { + mkdir($pathInfo['dirname'], 0777, true); + } + + copy($source, $destination); + }); + } +} diff --git a/tests/Feature/AuthenticationTest.php b/tests/Feature/AuthenticationTest.php new file mode 100644 index 0000000..c35eec4 --- /dev/null +++ b/tests/Feature/AuthenticationTest.php @@ -0,0 +1,69 @@ +create(); + + $result = $this->visit('/login') + ->type($user->email, 'email') + ->type('hoogabaloo', 'password') + ->press('Login'); + + $this->assertResponseStatus(200); + $result->seePageIs('/login'); + Event::assertDispatched(MixpanelEvent::class, function ($event) use ($user) { + return ($event->user->email === $user->email && $event->eventName === 'Login Attempted'); + }); + } + + public function testLoginSuccess() + { + Event::fake([MixpanelEvent::class]); + $password = 'hoogabaloo'; + $user = factory(User::class)->create([ + 'password' => bcrypt($password), + ]); + + $result = $this->visit('/login') + ->type($user->email, 'email') + ->type($password, 'password') + ->press('Login'); + + $this->assertResponseStatus(200); + $result->seePageIs('/home'); + Event::assertDispatched(MixpanelEvent::class, function ($event) use ($user) { + return ($event->user->email === $user->email && $event->eventName === 'User Logged In'); + }); + } + + public function testLogoutSuccess() + { + Event::fake([MixpanelEvent::class]); + $user = factory(User::class)->create(); + + $result = $this->actingAs($user) + ->post('/logout'); + + $this->assertRedirectedTo('/'); + Event::assertDispatched(MixpanelEvent::class, function ($event) use ($user) { + return ($event->user->email === $user->email && $event->eventName === 'User Logged Out'); + }); + } +} diff --git a/tests/FeatureTestCase.php b/tests/FeatureTestCase.php new file mode 100644 index 0000000..cb9b9cf --- /dev/null +++ b/tests/FeatureTestCase.php @@ -0,0 +1,13 @@ +middleware('auth'); + } + + /** + * Show the application dashboard. + * + * @return \Illuminate\Http\Response + */ + public function index() + { + return view('home'); + } +} diff --git a/tests/Fixtures/resources/views/auth/login.blade.php b/tests/Fixtures/resources/views/auth/login.blade.php new file mode 100644 index 0000000..ad371e3 --- /dev/null +++ b/tests/Fixtures/resources/views/auth/login.blade.php @@ -0,0 +1,67 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
Login
+ +
+
+ {{ csrf_field() }} + +
+ + +
+ + + @if ($errors->has('email')) + + {{ $errors->first('email') }} + + @endif +
+
+ +
+ + +
+ + + @if ($errors->has('password')) + + {{ $errors->first('password') }} + + @endif +
+
+ +
+
+
+ +
+
+
+ + +
+
+
+
+
+
+@endsection diff --git a/tests/Fixtures/resources/views/auth/passwords/email.blade.php b/tests/Fixtures/resources/views/auth/passwords/email.blade.php new file mode 100644 index 0000000..ad38245 --- /dev/null +++ b/tests/Fixtures/resources/views/auth/passwords/email.blade.php @@ -0,0 +1,47 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
Reset Password
+ +
+ @if (session('status')) +
+ {{ session('status') }} +
+ @endif + +
+ {{ csrf_field() }} + +
+ + +
+ + + @if ($errors->has('email')) + + {{ $errors->first('email') }} + + @endif +
+
+ +
+
+ +
+
+
+
+
+
+
+
+@endsection diff --git a/tests/Fixtures/resources/views/auth/passwords/reset.blade.php b/tests/Fixtures/resources/views/auth/passwords/reset.blade.php new file mode 100644 index 0000000..84ec010 --- /dev/null +++ b/tests/Fixtures/resources/views/auth/passwords/reset.blade.php @@ -0,0 +1,70 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
Reset Password
+ +
+
+ {{ csrf_field() }} + + + +
+ + +
+ + + @if ($errors->has('email')) + + {{ $errors->first('email') }} + + @endif +
+
+ +
+ + +
+ + + @if ($errors->has('password')) + + {{ $errors->first('password') }} + + @endif +
+
+ +
+ +
+ + + @if ($errors->has('password_confirmation')) + + {{ $errors->first('password_confirmation') }} + + @endif +
+
+ +
+
+ +
+
+
+
+
+
+
+
+@endsection diff --git a/tests/Fixtures/resources/views/auth/register.blade.php b/tests/Fixtures/resources/views/auth/register.blade.php new file mode 100644 index 0000000..38eef83 --- /dev/null +++ b/tests/Fixtures/resources/views/auth/register.blade.php @@ -0,0 +1,77 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
Register
+ +
+
+ {{ csrf_field() }} + +
+ + +
+ + + @if ($errors->has('name')) + + {{ $errors->first('name') }} + + @endif +
+
+ +
+ + +
+ + + @if ($errors->has('email')) + + {{ $errors->first('email') }} + + @endif +
+
+ +
+ + +
+ + + @if ($errors->has('password')) + + {{ $errors->first('password') }} + + @endif +
+
+ +
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+@endsection diff --git a/tests/Fixtures/resources/views/home.blade.php b/tests/Fixtures/resources/views/home.blade.php new file mode 100644 index 0000000..d8437bf --- /dev/null +++ b/tests/Fixtures/resources/views/home.blade.php @@ -0,0 +1,23 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
Dashboard
+ +
+ @if (session('status')) +
+ {{ session('status') }} +
+ @endif + + You are logged in! +
+
+
+
+
+@endsection diff --git a/tests/Fixtures/resources/views/layouts/app.blade.php b/tests/Fixtures/resources/views/layouts/app.blade.php new file mode 100644 index 0000000..6d3bf22 --- /dev/null +++ b/tests/Fixtures/resources/views/layouts/app.blade.php @@ -0,0 +1,80 @@ + + + + + + + + + + + {{ config('app.name', 'Laravel') }} + + + + + +
+ + + @yield('content') +
+ + + + + diff --git a/tests/Fixtures/routes/web.php b/tests/Fixtures/routes/web.php new file mode 100644 index 0000000..12fc04c --- /dev/null +++ b/tests/Fixtures/routes/web.php @@ -0,0 +1,20 @@ +name('home'); diff --git a/tests/Unit/ExampleTest.php b/tests/Unit/ExampleTest.php new file mode 100644 index 0000000..70dc327 --- /dev/null +++ b/tests/Unit/ExampleTest.php @@ -0,0 +1,12 @@ +assertTrue(true); + } +} diff --git a/tests/UnitTestCase.php b/tests/UnitTestCase.php new file mode 100644 index 0000000..9e88a60 --- /dev/null +++ b/tests/UnitTestCase.php @@ -0,0 +1,8 @@ +