mirror of
https://github.com/usetrmnl/byos_laravel.git
synced 2026-01-13 15:07:49 +00:00
Compare commits
6 commits
58fad59301
...
f777e850b1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f777e850b1 | ||
|
|
14d0fbfa7e | ||
|
|
9d1f62c6dd | ||
|
|
f38ac778f1 | ||
|
|
2eee024b36 | ||
|
|
a129c71d79 |
8 changed files with 368 additions and 128 deletions
|
|
@ -63,4 +63,30 @@ class Data extends FiltersProvider
|
|||
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a random element from an array
|
||||
*
|
||||
* @param array $array The array to sample from
|
||||
* @return mixed A random element from the array
|
||||
*/
|
||||
public function sample(array $array): mixed
|
||||
{
|
||||
if (empty($array)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $array[array_rand($array)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a JSON string into a PHP value
|
||||
*
|
||||
* @param string $json The JSON string to parse
|
||||
* @return mixed The parsed JSON value
|
||||
*/
|
||||
public function parse_json(string $json): mixed
|
||||
{
|
||||
return json_decode($json, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
25
app/Liquid/Filters/Date.php
Normal file
25
app/Liquid/Filters/Date.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Liquid\Filters;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Keepsuit\Liquid\Filters\FiltersProvider;
|
||||
|
||||
/**
|
||||
* Data filters for Liquid templates
|
||||
*/
|
||||
class Date extends FiltersProvider
|
||||
{
|
||||
/**
|
||||
* Calculate a date that is a specified number of days in the past
|
||||
*
|
||||
* @param int|string $num The number of days to subtract
|
||||
* @return string The date in Y-m-d format
|
||||
*/
|
||||
public function days_ago(int|string $num): string
|
||||
{
|
||||
$days = (int) $num;
|
||||
|
||||
return Carbon::now()->subDays($days)->toDateString();
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ namespace App\Models;
|
|||
|
||||
use App\Liquid\FileSystems\InlineTemplatesFileSystem;
|
||||
use App\Liquid\Filters\Data;
|
||||
use App\Liquid\Filters\Date;
|
||||
use App\Liquid\Filters\Localization;
|
||||
use App\Liquid\Filters\Numbers;
|
||||
use App\Liquid\Filters\StringMarkup;
|
||||
|
|
@ -215,6 +216,7 @@ class Plugin extends Model
|
|||
{
|
||||
$replacements = [
|
||||
'date: "%N"' => 'date: "u"',
|
||||
'date: "%u"' => 'date: "u"',
|
||||
'%-m/%-d/%Y' => 'm/d/Y',
|
||||
];
|
||||
|
||||
|
|
@ -271,11 +273,12 @@ class Plugin extends Model
|
|||
);
|
||||
|
||||
// Register all custom filters
|
||||
$environment->filterRegistry->register(Numbers::class);
|
||||
$environment->filterRegistry->register(Data::class);
|
||||
$environment->filterRegistry->register(Date::class);
|
||||
$environment->filterRegistry->register(Localization::class);
|
||||
$environment->filterRegistry->register(Numbers::class);
|
||||
$environment->filterRegistry->register(StringMarkup::class);
|
||||
$environment->filterRegistry->register(Uniqueness::class);
|
||||
$environment->filterRegistry->register(Localization::class);
|
||||
|
||||
// Register the template tag for inline templates
|
||||
$environment->tagRegistry->register(TemplateTag::class);
|
||||
|
|
|
|||
|
|
@ -574,7 +574,7 @@ HTML;
|
|||
$fieldKey = $field['keyname'] ?? $field['key'] ?? $field['name'];
|
||||
$currentValue = $configuration[$fieldKey] ?? '';
|
||||
@endphp
|
||||
<div class="mb-8">
|
||||
<div class="mb-4">
|
||||
@if($field['field_type'] === 'author_bio')
|
||||
@continue
|
||||
@endif
|
||||
|
|
@ -587,14 +587,35 @@ HTML;
|
|||
<flux:input
|
||||
label="{{ $field['name'] }}"
|
||||
description="{{ $field['description'] ?? '' }}"
|
||||
descriptionTrailing="{{ $field['help_text'] ?? '' }}"
|
||||
wire:model="configuration.{{ $fieldKey }}"
|
||||
value="{{ $currentValue }}"
|
||||
/>
|
||||
@elseif($field['field_type'] === 'text')
|
||||
<flux:textarea
|
||||
label="{{ $field['name'] }}"
|
||||
description="{{ $field['description'] ?? '' }}"
|
||||
descriptionTrailing="{{ $field['help_text'] ?? '' }}"
|
||||
wire:model="configuration.{{ $fieldKey }}"
|
||||
value="{{ $currentValue }}"
|
||||
/>
|
||||
@elseif($field['field_type'] === 'code')
|
||||
<flux:textarea
|
||||
label="{{ $field['name'] }}"
|
||||
description="{{ $field['description'] ?? '' }}"
|
||||
descriptionTrailing="{{ $field['help_text'] ?? '' }}"
|
||||
rows="{{ $field['rows'] ?? 3 }}"
|
||||
placeholder="{{ $field['placeholder'] ?? null }}"
|
||||
wire:model="configuration.{{ $fieldKey }}"
|
||||
value="{{ $currentValue }}"
|
||||
class="font-mono"
|
||||
/>
|
||||
@elseif($field['field_type'] === 'password')
|
||||
<flux:input
|
||||
type="password"
|
||||
label="{{ $field['name'] }}"
|
||||
description="{{ $field['description'] ?? '' }}"
|
||||
descriptionTrailing="{{ $field['help_text'] ?? '' }}"
|
||||
wire:model="configuration.{{ $fieldKey }}"
|
||||
value="{{ $currentValue }}"
|
||||
viewable
|
||||
|
|
@ -603,6 +624,7 @@ HTML;
|
|||
<flux:input
|
||||
label="{{ $field['name'] }}"
|
||||
description="{{ $field['description'] ?? '' }}"
|
||||
descriptionTrailing="{{ $field['help_text'] ?? '' }}"
|
||||
value="{{ $field['value'] }}"
|
||||
copyable
|
||||
/>
|
||||
|
|
@ -611,6 +633,7 @@ HTML;
|
|||
label="{{ $field['name'] }}"
|
||||
wire:model="configuration.{{ $fieldKey }}"
|
||||
description="{{ $field['description'] ?? '' }}"
|
||||
descriptionTrailing="{{ $field['help_text'] ?? '' }}"
|
||||
>
|
||||
<option value="">Select timezone...</option>
|
||||
@foreach(timezone_identifiers_list() as $timezone)
|
||||
|
|
@ -622,6 +645,7 @@ HTML;
|
|||
type="number"
|
||||
label="{{ $field['name'] }}"
|
||||
description="{{ $field['description'] ?? $field['name'] }}"
|
||||
descriptionTrailing="{{ $field['help_text'] ?? '' }}"
|
||||
wire:model="configuration.{{ $fieldKey }}"
|
||||
value="{{ $currentValue }}"
|
||||
/>
|
||||
|
|
@ -629,6 +653,7 @@ HTML;
|
|||
<flux:checkbox
|
||||
label="{{ $field['name'] }}"
|
||||
description="{{ $field['description'] ?? $field['name'] }}"
|
||||
descriptionTrailing="{{ $field['help_text'] ?? '' }}"
|
||||
wire:model="configuration.{{ $fieldKey }}"
|
||||
:checked="$currentValue"
|
||||
/>
|
||||
|
|
@ -637,6 +662,16 @@ HTML;
|
|||
type="date"
|
||||
label="{{ $field['name'] }}"
|
||||
description="{{ $field['description'] ?? $field['name'] }}"
|
||||
descriptionTrailing="{{ $field['help_text'] ?? '' }}"
|
||||
wire:model="configuration.{{ $fieldKey }}"
|
||||
value="{{ $currentValue }}"
|
||||
/>
|
||||
@elseif($field['field_type'] === 'time')
|
||||
<flux:input
|
||||
type="time"
|
||||
label="{{ $field['name'] }}"
|
||||
description="{{ $field['description'] ?? $field['name'] }}"
|
||||
descriptionTrailing="{{ $field['help_text'] ?? '' }}"
|
||||
wire:model="configuration.{{ $fieldKey }}"
|
||||
value="{{ $currentValue }}"
|
||||
/>
|
||||
|
|
@ -646,6 +681,7 @@ HTML;
|
|||
label="{{ $field['name'] }}"
|
||||
wire:model="configuration.{{ $fieldKey }}"
|
||||
description="{{ $field['description'] ?? '' }}"
|
||||
descriptionTrailing="{{ $field['help_text'] ?? '' }}"
|
||||
>
|
||||
@if(isset($field['options']) && is_array($field['options']))
|
||||
@foreach($field['options'] as $option)
|
||||
|
|
@ -664,6 +700,7 @@ HTML;
|
|||
label="{{ $field['name'] }}"
|
||||
wire:model="configuration.{{ $fieldKey }}"
|
||||
description="{{ $field['description'] ?? '' }}"
|
||||
descriptionTrailing="{{ $field['help_text'] ?? '' }}"
|
||||
>
|
||||
<option value="">Select {{ $field['name'] }}...</option>
|
||||
@if(isset($field['options']) && is_array($field['options']))
|
||||
|
|
@ -687,6 +724,7 @@ HTML;
|
|||
label="{{ $field['name'] }}"
|
||||
wire:model="configuration.{{ $fieldKey }}"
|
||||
description="{{ $field['description'] ?? '' }}"
|
||||
descriptionTrailing="{{ $field['help_text'] ?? '' }}"
|
||||
wire:init="loadXhrSelectOptions('{{ $fieldKey }}', '{{ $field['endpoint'] }}')"
|
||||
>
|
||||
<option value="">Select {{ $field['name'] }}...</option>
|
||||
|
|
@ -722,7 +760,7 @@ HTML;
|
|||
wire:click="searchXhrSelect('{{ $fieldKey }}', '{{ $field['endpoint'] }}')"
|
||||
icon="magnifying-glass"/>
|
||||
</flux:input.group>
|
||||
|
||||
<flux:description>{{ $field['help_text'] ?? '' }}</flux:description>
|
||||
@if((isset($xhrSelectOptions[$fieldKey]) && is_array($xhrSelectOptions[$fieldKey]) && count($xhrSelectOptions[$fieldKey]) > 0) || !empty($currentValue))
|
||||
<flux:select
|
||||
wire:model="configuration.{{ $fieldKey }}"
|
||||
|
|
@ -753,7 +791,7 @@ HTML;
|
|||
@endif
|
||||
</div>
|
||||
@else
|
||||
<p>{{ $field['name'] }}: Field type "{{ $field['field_type'] }}" not yet supported</p>
|
||||
<flux:callout variant="warning">Field type "{{ $field['field_type'] }}" not yet supported</flux:callout>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
|
|
|
|||
|
|
@ -1,23 +1,15 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Plugin;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PluginInlineTemplatesTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
public function test_plugin_with_inline_templates(): void
|
||||
{
|
||||
$plugin = Plugin::factory()->create([
|
||||
'name' => 'Test Plugin',
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => <<<'LIQUID'
|
||||
test('renders plugin with inline templates', function () {
|
||||
$plugin = Plugin::factory()->create([
|
||||
'name' => 'Test Plugin',
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => <<<'LIQUID'
|
||||
{% assign min = 1 %}
|
||||
{% assign max = facts | size %}
|
||||
{% assign diff = max | minus: min %}
|
||||
|
|
@ -39,7 +31,6 @@ class PluginInlineTemplatesTest extends TestCase
|
|||
|
||||
{% template title_bar %}
|
||||
<div class="title_bar">
|
||||
<img class="image" src="https://res.jwq.lol/img/lumon.svg">
|
||||
<span class="title">{{ trmnl.plugin_settings.instance_name }}</span>
|
||||
<span class="instance">{{ instance }}</span>
|
||||
</div>
|
||||
|
|
@ -59,32 +50,31 @@ class PluginInlineTemplatesTest extends TestCase
|
|||
%}
|
||||
</div>
|
||||
LIQUID
|
||||
,
|
||||
'data_payload' => [
|
||||
'facts' => ['Fact 1', 'Fact 2', 'Fact 3'],
|
||||
],
|
||||
]);
|
||||
,
|
||||
'data_payload' => [
|
||||
'facts' => ['Fact 1', 'Fact 2', 'Fact 3'],
|
||||
],
|
||||
]);
|
||||
|
||||
$result = $plugin->render('full');
|
||||
$result = $plugin->render('full');
|
||||
|
||||
// Should render both templates
|
||||
// Check for any of the facts (since random number generation is non-deterministic)
|
||||
$this->assertTrue(
|
||||
str_contains($result, 'Fact 1') ||
|
||||
str_contains($result, 'Fact 2') ||
|
||||
str_contains($result, 'Fact 3')
|
||||
);
|
||||
$this->assertStringContainsString('Test Plugin', $result);
|
||||
$this->assertStringContainsString('Please try to enjoy each fact equally', $result);
|
||||
$this->assertStringContainsString('class="view view--full"', $result);
|
||||
}
|
||||
// Should render both templates
|
||||
// Check for any of the facts (since random number generation is non-deterministic)
|
||||
$this->assertTrue(
|
||||
str_contains($result, 'Fact 1') ||
|
||||
str_contains($result, 'Fact 2') ||
|
||||
str_contains($result, 'Fact 3')
|
||||
);
|
||||
$this->assertStringContainsString('Test Plugin', $result);
|
||||
$this->assertStringContainsString('Please try to enjoy each fact equally', $result);
|
||||
$this->assertStringContainsString('class="view view--full"', $result);
|
||||
});
|
||||
|
||||
public function test_plugin_with_inline_templates_using_with_syntax(): void
|
||||
{
|
||||
$plugin = Plugin::factory()->create([
|
||||
'name' => 'Test Plugin',
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => <<<'LIQUID'
|
||||
test('renders plugin with inline templates using with syntax', function () {
|
||||
$plugin = Plugin::factory()->create([
|
||||
'name' => 'Test Plugin',
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => <<<'LIQUID'
|
||||
{% assign min = 1 %}
|
||||
{% assign max = facts | size %}
|
||||
{% assign diff = max | minus: min %}
|
||||
|
|
@ -126,31 +116,30 @@ LIQUID
|
|||
%}
|
||||
</div>
|
||||
LIQUID
|
||||
,
|
||||
'data_payload' => [
|
||||
'facts' => ['Fact 1', 'Fact 2', 'Fact 3'],
|
||||
],
|
||||
]);
|
||||
,
|
||||
'data_payload' => [
|
||||
'facts' => ['Fact 1', 'Fact 2', 'Fact 3'],
|
||||
],
|
||||
]);
|
||||
|
||||
$result = $plugin->render('full');
|
||||
$result = $plugin->render('full');
|
||||
|
||||
// Should render both templates
|
||||
// Check for any of the facts (since random number generation is non-deterministic)
|
||||
$this->assertTrue(
|
||||
str_contains($result, 'Fact 1') ||
|
||||
str_contains($result, 'Fact 2') ||
|
||||
str_contains($result, 'Fact 3')
|
||||
);
|
||||
$this->assertStringContainsString('Test Plugin', $result);
|
||||
$this->assertStringContainsString('Please try to enjoy each fact equally', $result);
|
||||
$this->assertStringContainsString('class="view view--full"', $result);
|
||||
}
|
||||
// Should render both templates
|
||||
// Check for any of the facts (since random number generation is non-deterministic)
|
||||
$this->assertTrue(
|
||||
str_contains($result, 'Fact 1') ||
|
||||
str_contains($result, 'Fact 2') ||
|
||||
str_contains($result, 'Fact 3')
|
||||
);
|
||||
$this->assertStringContainsString('Test Plugin', $result);
|
||||
$this->assertStringContainsString('Please try to enjoy each fact equally', $result);
|
||||
$this->assertStringContainsString('class="view view--full"', $result);
|
||||
});
|
||||
|
||||
public function test_plugin_with_simple_inline_template(): void
|
||||
{
|
||||
$plugin = Plugin::factory()->create([
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => <<<'LIQUID'
|
||||
test('renders plugin with simple inline template', function () {
|
||||
$plugin = Plugin::factory()->create([
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => <<<'LIQUID'
|
||||
{% template simple %}
|
||||
<div class="simple">
|
||||
<h1>{{ title }}</h1>
|
||||
|
|
@ -163,21 +152,20 @@ LIQUID
|
|||
content: "This is a test"
|
||||
%}
|
||||
LIQUID
|
||||
,
|
||||
]);
|
||||
,
|
||||
]);
|
||||
|
||||
$result = $plugin->render('full');
|
||||
$result = $plugin->render('full');
|
||||
|
||||
$this->assertStringContainsString('Hello World', $result);
|
||||
$this->assertStringContainsString('This is a test', $result);
|
||||
$this->assertStringContainsString('class="simple"', $result);
|
||||
}
|
||||
$this->assertStringContainsString('Hello World', $result);
|
||||
$this->assertStringContainsString('This is a test', $result);
|
||||
$this->assertStringContainsString('class="simple"', $result);
|
||||
});
|
||||
|
||||
public function test_plugin_with_find_by_filter(): void
|
||||
{
|
||||
$plugin = Plugin::factory()->create([
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => <<<'LIQUID'
|
||||
test('renders plugin with liquid filter find_by', function () {
|
||||
$plugin = Plugin::factory()->create([
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => <<<'LIQUID'
|
||||
{% template user_info %}
|
||||
<div class="user">
|
||||
<h2>{{ user.name }}</h2>
|
||||
|
|
@ -188,68 +176,65 @@ LIQUID
|
|||
{% assign found_user = collection | find_by: 'name', 'Ryan' %}
|
||||
{% render "user_info", user: found_user %}
|
||||
LIQUID
|
||||
,
|
||||
'data_payload' => [
|
||||
'collection' => [
|
||||
['name' => 'Ryan', 'age' => 35],
|
||||
['name' => 'Sara', 'age' => 29],
|
||||
['name' => 'Jimbob', 'age' => 29],
|
||||
],
|
||||
,
|
||||
'data_payload' => [
|
||||
'collection' => [
|
||||
['name' => 'Ryan', 'age' => 35],
|
||||
['name' => 'Sara', 'age' => 29],
|
||||
['name' => 'Jimbob', 'age' => 29],
|
||||
],
|
||||
]);
|
||||
],
|
||||
]);
|
||||
|
||||
$result = $plugin->render('full');
|
||||
$result = $plugin->render('full');
|
||||
|
||||
// Should render the user info for Ryan
|
||||
$this->assertStringContainsString('Ryan', $result);
|
||||
$this->assertStringContainsString('Age: 35', $result);
|
||||
$this->assertStringContainsString('class="user"', $result);
|
||||
}
|
||||
// Should render the user info for Ryan
|
||||
$this->assertStringContainsString('Ryan', $result);
|
||||
$this->assertStringContainsString('Age: 35', $result);
|
||||
$this->assertStringContainsString('class="user"', $result);
|
||||
});
|
||||
|
||||
public function test_plugin_with_find_by_filter_and_fallback(): void
|
||||
{
|
||||
$plugin = Plugin::factory()->create([
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => <<<'LIQUID'
|
||||
test('renders plugin with liquid filter find_by and fallback', function () {
|
||||
$plugin = Plugin::factory()->create([
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => <<<'LIQUID'
|
||||
{{ collection | find_by: 'name', 'ronak', 'Not Found' }}
|
||||
LIQUID
|
||||
,
|
||||
'data_payload' => [
|
||||
'collection' => [
|
||||
['name' => 'Ryan', 'age' => 35],
|
||||
['name' => 'Sara', 'age' => 29],
|
||||
['name' => 'Jimbob', 'age' => 29],
|
||||
],
|
||||
,
|
||||
'data_payload' => [
|
||||
'collection' => [
|
||||
['name' => 'Ryan', 'age' => 35],
|
||||
['name' => 'Sara', 'age' => 29],
|
||||
['name' => 'Jimbob', 'age' => 29],
|
||||
],
|
||||
]);
|
||||
],
|
||||
]);
|
||||
|
||||
$result = $plugin->render('full');
|
||||
$result = $plugin->render('full');
|
||||
|
||||
// Should return the fallback value
|
||||
$this->assertStringContainsString('Not Found', $result);
|
||||
}
|
||||
// Should return the fallback value
|
||||
$this->assertStringContainsString('Not Found', $result);
|
||||
});
|
||||
|
||||
public function test_plugin_with_group_by_filter(): void
|
||||
{
|
||||
$plugin = Plugin::factory()->create([
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => <<<'LIQUID'
|
||||
test('renders plugin with liquid filter group_by', function () {
|
||||
$plugin = Plugin::factory()->create([
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => <<<'LIQUID'
|
||||
{{ collection | group_by: 'age' | json }}
|
||||
LIQUID
|
||||
,
|
||||
'data_payload' => [
|
||||
'collection' => [
|
||||
['name' => 'Ryan', 'age' => 35],
|
||||
['name' => 'Sara', 'age' => 29],
|
||||
['name' => 'Jimbob', 'age' => 29],
|
||||
],
|
||||
,
|
||||
'data_payload' => [
|
||||
'collection' => [
|
||||
['name' => 'Ryan', 'age' => 35],
|
||||
['name' => 'Sara', 'age' => 29],
|
||||
['name' => 'Jimbob', 'age' => 29],
|
||||
],
|
||||
]);
|
||||
],
|
||||
]);
|
||||
|
||||
$result = $plugin->render('full');
|
||||
$result = $plugin->render('full');
|
||||
|
||||
// Should output JSON representation of grouped data
|
||||
$this->assertStringContainsString('"35":[{"name":"Ryan","age":35}]', $result);
|
||||
$this->assertStringContainsString('"29":[{"name":"Sara","age":29},{"name":"Jimbob","age":29}]', $result);
|
||||
}
|
||||
}
|
||||
// Should output JSON representation of grouped data
|
||||
$this->assertStringContainsString('"35":[{"name":"Ryan","age":35}]', $result);
|
||||
$this->assertStringContainsString('"29":[{"name":"Sara","age":29},{"name":"Jimbob","age":29}]', $result);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -237,3 +237,91 @@ test('group_by filter handles mixed data types as keys', function () {
|
|||
'' => [['name' => 'Alice', 'active' => null]], // PHP converts null keys to empty string
|
||||
]);
|
||||
});
|
||||
|
||||
test('sample filter returns a random element from array', function () {
|
||||
$filter = new Data();
|
||||
$array = ['1', '2', '3', '4', '5'];
|
||||
|
||||
$result = $filter->sample($array);
|
||||
expect($result)->toBeIn($array);
|
||||
});
|
||||
|
||||
test('sample filter returns a random element from string array', function () {
|
||||
$filter = new Data();
|
||||
$array = ['cat', 'dog'];
|
||||
|
||||
$result = $filter->sample($array);
|
||||
expect($result)->toBeIn($array);
|
||||
});
|
||||
|
||||
test('sample filter returns null for empty array', function () {
|
||||
$filter = new Data();
|
||||
$array = [];
|
||||
|
||||
$result = $filter->sample($array);
|
||||
expect($result)->toBeNull();
|
||||
});
|
||||
|
||||
test('sample filter returns the only element from single element array', function () {
|
||||
$filter = new Data();
|
||||
$array = ['single'];
|
||||
|
||||
$result = $filter->sample($array);
|
||||
expect($result)->toBe('single');
|
||||
});
|
||||
|
||||
test('sample filter works with mixed data types', function () {
|
||||
$filter = new Data();
|
||||
$array = [1, 'string', true, null, ['nested']];
|
||||
|
||||
$result = $filter->sample($array);
|
||||
expect($result)->toBeIn($array);
|
||||
});
|
||||
|
||||
test('parse_json filter parses JSON string to array', function () {
|
||||
$filter = new Data();
|
||||
$jsonString = '[{"a":1,"b":"c"},"d"]';
|
||||
|
||||
$result = $filter->parse_json($jsonString);
|
||||
expect($result)->toBe([['a' => 1, 'b' => 'c'], 'd']);
|
||||
});
|
||||
|
||||
test('parse_json filter parses simple JSON object', function () {
|
||||
$filter = new Data();
|
||||
$jsonString = '{"name":"John","age":30,"city":"New York"}';
|
||||
|
||||
$result = $filter->parse_json($jsonString);
|
||||
expect($result)->toBe(['name' => 'John', 'age' => 30, 'city' => 'New York']);
|
||||
});
|
||||
|
||||
test('parse_json filter parses JSON array', function () {
|
||||
$filter = new Data();
|
||||
$jsonString = '["apple","banana","cherry"]';
|
||||
|
||||
$result = $filter->parse_json($jsonString);
|
||||
expect($result)->toBe(['apple', 'banana', 'cherry']);
|
||||
});
|
||||
|
||||
test('parse_json filter parses nested JSON structure', function () {
|
||||
$filter = new Data();
|
||||
$jsonString = '{"users":[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}],"total":2}';
|
||||
|
||||
$result = $filter->parse_json($jsonString);
|
||||
expect($result)->toBe([
|
||||
'users' => [
|
||||
['id' => 1, 'name' => 'Alice'],
|
||||
['id' => 2, 'name' => 'Bob'],
|
||||
],
|
||||
'total' => 2,
|
||||
]);
|
||||
});
|
||||
|
||||
test('parse_json filter handles primitive values', function () {
|
||||
$filter = new Data();
|
||||
|
||||
expect($filter->parse_json('"hello"'))->toBe('hello');
|
||||
expect($filter->parse_json('123'))->toBe(123);
|
||||
expect($filter->parse_json('true'))->toBe(true);
|
||||
expect($filter->parse_json('false'))->toBe(false);
|
||||
expect($filter->parse_json('null'))->toBe(null);
|
||||
});
|
||||
|
|
|
|||
32
tests/Unit/Liquid/Filters/DateTest.php
Normal file
32
tests/Unit/Liquid/Filters/DateTest.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use App\Liquid\Filters\Date;
|
||||
use Carbon\Carbon;
|
||||
|
||||
test('days_ago filter returns correct date', function () {
|
||||
$filter = new Date();
|
||||
$threeDaysAgo = Carbon::now()->subDays(3)->toDateString();
|
||||
|
||||
expect($filter->days_ago(3))->toBe($threeDaysAgo);
|
||||
});
|
||||
|
||||
test('days_ago filter handles string input', function () {
|
||||
$filter = new Date();
|
||||
$fiveDaysAgo = Carbon::now()->subDays(5)->toDateString();
|
||||
|
||||
expect($filter->days_ago('5'))->toBe($fiveDaysAgo);
|
||||
});
|
||||
|
||||
test('days_ago filter with zero days returns today', function () {
|
||||
$filter = new Date();
|
||||
$today = Carbon::now()->toDateString();
|
||||
|
||||
expect($filter->days_ago(0))->toBe($today);
|
||||
});
|
||||
|
||||
test('days_ago filter with large number works correctly', function () {
|
||||
$filter = new Date();
|
||||
$hundredDaysAgo = Carbon::now()->subDays(100)->toDateString();
|
||||
|
||||
expect($filter->days_ago(100))->toBe($hundredDaysAgo);
|
||||
});
|
||||
|
|
@ -6,9 +6,15 @@ namespace Tests\Unit\Liquid;
|
|||
|
||||
use App\Liquid\FileSystems\InlineTemplatesFileSystem;
|
||||
use App\Liquid\Filters\Data;
|
||||
use App\Liquid\Filters\Date;
|
||||
use App\Liquid\Filters\Localization;
|
||||
use App\Liquid\Filters\Numbers;
|
||||
use App\Liquid\Filters\StringMarkup;
|
||||
use App\Liquid\Filters\Uniqueness;
|
||||
use App\Liquid\Tags\TemplateTag;
|
||||
use Keepsuit\Liquid\Environment;
|
||||
use Keepsuit\Liquid\Exceptions\LiquidException;
|
||||
use Keepsuit\Liquid\Extensions\StandardExtension;
|
||||
use Keepsuit\Liquid\Tags\RenderTag;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
|
|
@ -24,11 +30,17 @@ class InlineTemplatesTest extends TestCase
|
|||
|
||||
$this->fileSystem = new InlineTemplatesFileSystem();
|
||||
$this->environment = new Environment(
|
||||
fileSystem: $this->fileSystem
|
||||
fileSystem: $this->fileSystem,
|
||||
extensions: [new StandardExtension()]
|
||||
);
|
||||
$this->environment->tagRegistry->register(TemplateTag::class);
|
||||
$this->environment->tagRegistry->register(RenderTag::class);
|
||||
$this->environment->filterRegistry->register(Data::class);
|
||||
$this->environment->filterRegistry->register(Date::class);
|
||||
$this->environment->filterRegistry->register(Localization::class);
|
||||
$this->environment->filterRegistry->register(Numbers::class);
|
||||
$this->environment->filterRegistry->register(StringMarkup::class);
|
||||
$this->environment->filterRegistry->register(Uniqueness::class);
|
||||
}
|
||||
|
||||
public function test_template_tag_registers_template(): void
|
||||
|
|
@ -296,4 +308,35 @@ LIQUID
|
|||
// Should not throw an error and should return empty string
|
||||
$this->assertEquals('', $result);
|
||||
}
|
||||
|
||||
public function test_quotes_template_with_modulo_filter(): void
|
||||
{
|
||||
$template = $this->environment->parseString(<<<'LIQUID'
|
||||
{% assign quotes_array = quotes[trmnl.plugin_settings.custom_fields_values.language] %}
|
||||
{% assign random_index = 'now' | date: '%s' | modulo: quotes_array.size %}
|
||||
{{ quotes_array[random_index] }}
|
||||
LIQUID
|
||||
);
|
||||
|
||||
$context = $this->environment->newRenderContext(
|
||||
data: [
|
||||
'quotes' => [
|
||||
'english' => ['Demo Quote'],
|
||||
'german' => ['Demo Zitat'],
|
||||
],
|
||||
'trmnl' => [
|
||||
'plugin_settings' => [
|
||||
'custom_fields_values' => [
|
||||
'language' => 'english',
|
||||
],
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$result = $template->render($context);
|
||||
// Should render a quote from the english array
|
||||
$this->assertStringContainsString('Demo Quote', $result);
|
||||
$this->assertStringNotContainsString('Demo Zitat', $result);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue