Skip to content

Commit

Permalink
finish basic feature
Browse files Browse the repository at this point in the history
  • Loading branch information
gwleuverink committed Aug 16, 2024
1 parent 122835d commit 8546347
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 20 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,18 @@ use Leuverink\InjectAssets\Contracts\AssetInjector;
class InjectAssets implements AssetInjector
{
// Used to determine if assets were already injected in the response
public function identifier() {
public function identifier(): string
{
return 'MY_PACKAGE';
}

// You can opt in to asset injection by implementing your own checks.
// For example if a package user can control this via config file.
public function enabled(): bool
{
return true;
}

// Will inject return value in head tag or befor html close if no head is present
public function inject(): string
{
Expand Down
2 changes: 2 additions & 0 deletions src/Contracts/AssetInjector.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ interface AssetInjector
{
public function identifier(): string;

public function enabled(): bool;

public function inject(): string;
}
28 changes: 15 additions & 13 deletions src/InjectAssets.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@

namespace Leuverink\InjectAssets;

use Leuverink\InjectAssets\Contracts\AssetInjector;
use Illuminate\Foundation\Http\Events\RequestHandled;

class InjectAssets
{
/** Injects a inline style tag containing MagicTodo's CSS inside every full-page response */
/** Injects assets inside every full-page response */
public function __invoke(RequestHandled $handled)
{
// No need to inject anything when MagicTodo is disabled
if (! config('magic-todo.enabled')) {
$injector = $this->resolveInjector();

if (! $injector->enabled()) {
return;
}

Expand All @@ -26,30 +28,30 @@ public function __invoke(RequestHandled $handled)
}

// Skip if core was included before
if (str_contains($html, '<!--[MAGIC_TODO-ASSETS]-->')) {
if (str_contains($html, '<!--[{$injector->identifier()} ASSETS]-->')) {
return;
}

// Keep a copy of the original response
$originalContent = $handled->response->original;

// Inject the assets in the response
$js = file_get_contents(__DIR__ . '/../build/magic-todo.js');
$css = file_get_contents(__DIR__ . '/../build/magic-todo.css');

$handled->response->setContent(
$this->injectAssets($html, <<< HTML
<!--[MAGIC_TODO-ASSETS]-->
<script type="module">{$js}</script>
<style>{$css}</style>
<!--[ENDMAGIC_TODO]-->
<!--[{$injector->identifier()} ASSETS]-->
{$injector->inject()}
<!--[END{$injector->identifier()}]-->
HTML)
);

$handled->response->original = $originalContent;
}

/** Injects MagicTodo assets into given html string (taken from Livewire's injection mechanism) */
protected function resolveInjector(): AssetInjector
{
return resolve(AssetInjector::class);
}

/** Injects assets into given html string (taken from Livewire's injection mechanism) */
protected function injectAssets(string $html, string $core): string
{
$html = str($html);
Expand Down
26 changes: 20 additions & 6 deletions tests/Feature/InjectsAssetsTest.php
Original file line number Diff line number Diff line change
@@ -1,25 +1,39 @@
<?php

use Leuverink\InjectAssets\Contracts\AssetInjector;

it('injects assets into head tag', function () {
Route::get('test-inject-in-response', fn () => '<html><head></head></html>');

$this->get('test-inject-in-response')
->assertOk()
->assertSee('<!--[MAGIC_TODO-ASSETS]-->', false);
})->todo();
->assertSee('<!--[TEST_PACKAGE ASSETS]-->', false);
});

it('injects assets into html body when no head tag is present', function () {
Route::get('test-inject-in-response', fn () => '<html></html>');

$this->get('test-inject-in-response')
->assertOk()
->assertSee('<!--[MAGIC_TODO-ASSETS]-->', false);
})->todo();
->assertSee('<!--[TEST_PACKAGE ASSETS]-->', false);
});

it('doesnt inject assets into responses without a closing html tag', function () {
Route::get('test-inject-in-response', fn () => 'OK');

$this->get('test-inject-in-response')
->assertOk()
->assertDontSee('<!--[MAGIC_TODO-ASSETS]-->', false);
})->todo();
->assertDontSee('<!--[TEST_PACKAGE ASSETS]-->', false);
});

it('doesnt inject assets when implementation returns false from enabled method', function () {
$this->partialMock(AssetInjector::class)
->shouldReceive('enabled')->once()
->andReturn(false);

Route::get('test-inject-in-response', fn () => '<html><head></head></html>');

$this->get('test-inject-in-response')
->assertOk()
->assertDontSee('<!--[TEST_PACKAGE ASSETS]-->', false);
});
23 changes: 23 additions & 0 deletions tests/Implement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Tests;

use Leuverink\InjectAssets\Contracts\AssetInjector;

class Implement implements AssetInjector
{
public function identifier(): string
{
return 'TEST_PACKAGE';
}

public function enabled(): bool
{
return true;
}

public function inject(): string
{
return 'TEST_PACKAGE_ASSETS_INJECTED';
}
}
11 changes: 11 additions & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,19 @@

use Orchestra\Testbench\Concerns\WithWorkbench;
use Orchestra\Testbench\TestCase as BaseTestCase;
use Leuverink\InjectAssets\Contracts\AssetInjector;

abstract class TestCase extends BaseTestCase
{
use WithWorkbench;

protected function setUp(): void
{
parent::setUp();

$this->app->bind(
AssetInjector::class,
fn () => new Implement
);
}
}

0 comments on commit 8546347

Please sign in to comment.