temporary = sys_get_temp_dir().'/livewire-material-mail-'.Str::random(8);
File::ensureDirectoryExists($this->temporary);
File::put($this->temporary.'/mail-theme-probe.blade.php', <<<'BLADE'
# Your export is ready
The report has **finished**.
Download
Files expire after seven days.
| File | Size |
|:-----|-----:|
| orders.csv | 1.2 MB |
BLADE);
File::put($this->temporary.'/mail-footer-probe.blade.php', <<<'BLADE'
Hello.
Sent by the probe · [Unsubscribe](https://example.com/unsubscribe)
BLADE);
View::addLocation($this->temporary);
config(['mail.markdown.theme' => 'livewire-material::mail.theme']);
});
afterEach(function () {
File::deleteDirectory($this->temporary);
});
/**
* The inline style of the first element carrying the class.
*/
function inlineStyle(string $html, string $class): string
{
preg_match('/<[^>]+class="[^"]*\b'.preg_quote($class, '/').'\b[^"]*"[^>]*style="([^"]*)"/', $html, $match);
return $match[1] ?? '';
}
/**
* Put the package's mail components on `mail.markdown.paths`, as the provider does when
* `livewire-material.mail.components` is on at boot, and make the renderer again.
*/
function withPackageMailComponents(): void
{
config(['livewire-material.mail.components' => true]);
$provider = app()->getProvider(LivewireMaterialServiceProvider::class);
(fn () => $this->registerMailComponents())->call($provider);
app()->forgetInstance(Markdown::class);
}
it('inlines the application\'s scheme onto the mail', function () {
File::put($this->temporary.'/material-scheme.json', json_encode([
'light' => ['primary' => '#123456', 'on-primary' => '#fefefe', 'surface-container' => '#eeeeee', 'surface-container-lowest' => '#fdfdfd'],
'dark' => ['primary' => '#abcdef'],
]));
config(['livewire-material.scheme' => $this->temporary.'/material-scheme.json']);
$html = (new ThemedProbeMail)->render();
expect(inlineStyle($html, 'button-primary'))
->toContain('background-color: #123456')
->toContain('border-top: 16px solid #123456')
->toContain('color: #fefefe')
->toContain('border-radius: 9999px')
->and(inlineStyle($html, 'inner-body'))->toContain('background-color: #fdfdfd')
->and(inlineStyle($html, 'wrapper'))->toContain('background-color: #eeeeee')
->and(inlineStyle($html, 'panel-content'))->toContain('background-color: #eeeeee')
->and($html)
->toMatch('/
toMatch('/
toMatch('/
]*style="[^"]*font-weight: 500/')
->toMatch('/ | not->toContain('#abcdef')
->not->toContain('var(--')
->not->toContain('color-mix');
});
it('takes the theme from a mailable too', function () {
config(['mail.markdown.theme' => 'default']);
$mail = new ThemedProbeMail;
$mail->theme = 'livewire-material::mail.theme';
expect(inlineStyle($mail->render(), 'button-primary'))->toContain('border-radius: 9999px');
});
it('falls back to the package\'s default scheme', function (?string $contents) {
$path = $this->temporary.'/material-scheme.json';
if ($contents !== null) {
File::put($path, $contents);
}
config(['livewire-material.scheme' => $path]);
$default = json_decode(File::get(__DIR__.'/../../resources/css/tokens/scheme.json'), true);
expect(inlineStyle((new ThemedProbeMail)->render(), 'button-primary'))
->toContain("background-color: {$default['light']['primary']}");
})->with([
'no scheme file' => [null],
'not JSON' => ['{ nope'],
'not a colour' => [json_encode(['light' => ['primary' => 'red; background: url(x)']])],
]);
it('styles every button colour Laravel and M3 name', function () {
$css = view('livewire-material::mail.theme')->render();
foreach (['primary', 'secondary', 'tertiary', 'error', 'success', 'warning', 'info', 'blue', 'green', 'red'] as $color) {
expect($css)->toContain(".button-{$color} {");
}
expect($css)->not->toContain('@media');
});
it('leaves the application\'s mail components alone unless asked', function () {
expect(config('mail.markdown.paths'))->not->toContain(LivewireMaterialServiceProvider::mailComponentPath());
withPackageMailComponents();
withPackageMailComponents();
expect(config('mail.markdown.paths'))->toBe([
resource_path('views/vendor/mail'),
LivewireMaterialServiceProvider::mailComponentPath(),
]);
});
it('renders the package header: the app name, never Laravel\'s logo', function () {
config(['app.name' => 'Laravel']);
$framework = (new ThemedProbeMail)->render();
withPackageMailComponents();
$html = (new ThemedProbeMail)->render();
expect($framework)->toContain('notification-logo')
->and($html)->not->toContain('notification-logo')
->toMatch('/ |