Skip to content

Commit

Permalink
laravel#152 Implement facades faking
Browse files Browse the repository at this point in the history
  • Loading branch information
NoelDeMartin committed Feb 18, 2018
1 parent df63e33 commit ef4900e
Show file tree
Hide file tree
Showing 11 changed files with 459 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/Browser.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class Browser
Concerns\InteractsWithMouse,
Concerns\MakesAssertions,
Concerns\WaitsForElements,
Concerns\FakesFacades,
Macroable {
__call as macroCall;
}
Expand Down
21 changes: 21 additions & 0 deletions src/Concerns/FakesFacades.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Laravel\Dusk\Concerns;

use Laravel\Dusk\Faking\FacadeFakeProxy;

trait FakesFacades
{
/**
* Fake a facade and return the fake proxy.
*
* @param string $facade
* @return \Laravel\Dusk\Faking\FacadeFakeProxy
*/
public function fake(string $facade)
{
$this->visit('/_dusk/fake/'.urlencode($facade));

return new FacadeFakeProxy($this, $facade);
}
}
71 changes: 57 additions & 14 deletions src/DuskServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@

use Exception;
use Illuminate\Support\Facades\Route;
use Laravel\Dusk\Faking\FakingManager;
use Illuminate\Support\ServiceProvider;
use Laravel\Dusk\Http\Middleware\SaveFaking;
use Laravel\Dusk\Http\Middleware\StartFaking;
use Laravel\Dusk\Http\Controllers\FakingController;
use Illuminate\Contracts\Http\Kernel as HttpKernel;

class DuskServiceProvider extends ServiceProvider
{
Expand All @@ -15,20 +20,8 @@ class DuskServiceProvider extends ServiceProvider
*/
public function boot()
{
Route::get('/_dusk/login/{userId}/{guard?}', [
'middleware' => 'web',
'uses' => 'Laravel\Dusk\Http\Controllers\UserController@login',
]);

Route::get('/_dusk/logout/{guard?}', [
'middleware' => 'web',
'uses' => 'Laravel\Dusk\Http\Controllers\UserController@logout',
]);

Route::get('/_dusk/user/{guard?}', [
'middleware' => 'web',
'uses' => 'Laravel\Dusk\Http\Controllers\UserController@user',
]);
$this->bootAuthRoutes();
$this->bootFakingRoutes();
}

/**
Expand All @@ -43,6 +36,10 @@ public function register()
throw new Exception('It is unsafe to run Dusk in production.');
}

$this->app->singleton('faking', function ($app) {
return new FakingManager($app);
});

if ($this->app->runningInConsole()) {
$this->commands([
Console\InstallCommand::class,
Expand All @@ -51,6 +48,52 @@ public function register()
Console\PageCommand::class,
Console\ComponentCommand::class,
]);
} else {
$kernel = $this->app->make(HttpKernel::class);
$kernel->pushMiddleware(StartFaking::class);
$kernel->pushMiddleware(SaveFaking::class);
}

}

/**
* Boot auth routes.
*
* @return void
*/
protected function bootAuthRoutes()
{
Route::get('/_dusk/login/{userId}/{guard?}', [
'middleware' => 'web',
'uses' => 'Laravel\Dusk\Http\Controllers\UserController@login',
]);

Route::get('/_dusk/logout/{guard?}', [
'middleware' => 'web',
'uses' => 'Laravel\Dusk\Http\Controllers\UserController@logout',
]);

Route::get('/_dusk/user/{guard?}', [
'middleware' => 'web',
'uses' => 'Laravel\Dusk\Http\Controllers\UserController@user',
]);
}

/**
* Boot faking routes.
*
* @return void
*/
protected function bootFakingRoutes()
{
Route::get('/_dusk/fake/{facade}', [
'middleware' => 'web',
'uses' => 'Laravel\Dusk\Http\Controllers\FakingController@fake',
]);

Route::get('/_dusk/get-fake/{facade}', [
'middleware' => 'web',
'uses' => 'Laravel\Dusk\Http\Controllers\FakingController@getFake',
]);
}
}
22 changes: 22 additions & 0 deletions src/Facades/Faking.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Laravel\Dusk\Facades;

use Illuminate\Support\Facades\Facade;

/**
* @see \Laravel\Dusk\Faking\FakingManager
* @see \Laravel\Dusk\Faking\Driver
*/
class Faking extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'faking';
}
}
116 changes: 116 additions & 0 deletions src/Faking/Driver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php

namespace Laravel\Dusk\Faking;

use Symfony\Component\HttpFoundation\Response;

abstract class Driver
{
/**
* The array of active facade fakes.
*
* @var array
*/
protected $fakes = [];

/**
* Start faking facades.
*
* @return void
*/
public function start()
{
$this->loadFakes();

foreach ($this->fakes as $facade => $fake) {
$facade::swap($fake);
}
}

/**
* Save facades state.
*
* @param \Symfony\Component\HttpFoundation\Response $response
* @return void
*/
public function save(Response $response)
{
$this->storeFakes($response);
}

/**
* Replace facade instance with a fake.
*
* @param string $facade
* @return void
*/
public function fake(string $facade)
{
if (!$this->has($facade)) {
$fake = $this->createFake($facade);
$facade::swap($fake);
$this->fakes[$facade] = $fake;
}
}

/**
* Determine if a facade is being faked.
*
* @param string $facade
* @return boolean
*/
public function has(string $facade)
{
return isset($this->fakes[$facade]);
}

/**
* Serialize a facade fake.
*
* @param string $facade
* @return string
*/
public function serialize(string $facade)
{
return serialize($this->fakes[$facade]);
}

/**
* Deserialize a facade fake.
*
* @param string $serializedFake
* @return mixed
*/
public function unserialize(string $serializedFake)
{
return unserialize($serializedFake);
}

/**
* Create a facade fake.
*
* @param $facade string
* @return mixed
*/
protected function createFake(string $facade)
{
$facade::fake();

return $facade::getFacadeRoot();
}

/**
* Load fakes from storage.
*
* @return void
*/
protected abstract function loadFakes();

/**
* Store fakes.
*
* @param \Symfony\Component\HttpFoundation\Response $response
* @return void
*/
protected abstract function storeFakes(Response $response);
}
54 changes: 54 additions & 0 deletions src/Faking/Drivers/CookiesDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Laravel\Dusk\Faking\Drivers;

use Cookie;
use Laravel\Dusk\Faking\Driver;
use Symfony\Component\HttpFoundation\Response;

class CookiesDriver extends Driver
{
/**
* Name of the cookie used to serialize fakes.
*
* @var string
*/
const COOKIE_NAME = 'Dusk-Facade-Fakes';

/**
* Load fakes from storage.
*
* @return void
*/
protected function loadFakes()
{
$serializedFakes = Cookie::get(self::COOKIE_NAME, '{}');
$serializedFakes = json_decode($serializedFakes, true);

foreach ($serializedFakes as $facade => $serializedFake) {
$this->fakes[$facade] = $this->unserialize($serializedFake);
}
}

/**
* Store fakes.
*
* @param \Symfony\Component\HttpFoundation\Response $response
* @return void
*/
protected function storeFakes(Response $response)
{
$serializedFakes = [];
foreach (array_keys($this->fakes) as $facade) {
$serializedFakes[$facade] = $this->serialize($facade);
}

$response->headers->setCookie(
Cookie::forever(
static::COOKIE_NAME,
json_encode($serializedFakes),
'/'
)
);
}
}
Loading

0 comments on commit ef4900e

Please sign in to comment.