]> BookStack Code Mirror - bookstack/blob - tests/ThemeTest.php
Added test for logical-theme-system command registration
[bookstack] / tests / ThemeTest.php
1 <?php
2
3 namespace Tests;
4
5 use BookStack\Auth\User;
6 use BookStack\Entities\Models\Page;
7 use BookStack\Entities\Tools\PageContent;
8 use BookStack\Facades\Theme;
9 use BookStack\Theming\ThemeEvents;
10 use Illuminate\Console\Command;
11 use Illuminate\Http\Request;
12 use Illuminate\Http\Response;
13 use Illuminate\Support\Facades\Artisan;
14 use Illuminate\Support\Facades\File;
15 use League\CommonMark\ConfigurableEnvironmentInterface;
16
17 class ThemeTest extends TestCase
18 {
19     protected $themeFolderName;
20     protected $themeFolderPath;
21
22     public function test_translation_text_can_be_overridden_via_theme()
23     {
24         $this->usingThemeFolder(function () {
25             $translationPath = theme_path('/lang/en');
26             File::makeDirectory($translationPath, 0777, true);
27
28             $customTranslations = '<?php
29             return [\'books\' => \'Sandwiches\'];
30         ';
31             file_put_contents($translationPath . '/entities.php', $customTranslations);
32
33             $homeRequest = $this->actingAs($this->getViewer())->get('/');
34             $homeRequest->assertElementContains('header nav', 'Sandwiches');
35         });
36     }
37
38     public function test_theme_functions_file_used_and_app_boot_event_runs()
39     {
40         $this->usingThemeFolder(function ($themeFolder) {
41             $functionsFile = theme_path('functions.php');
42             app()->alias('cat', 'dog');
43             file_put_contents($functionsFile, "<?php\nTheme::listen(\BookStack\Theming\ThemeEvents::APP_BOOT, function(\$app) { \$app->alias('cat', 'dog');});");
44             $this->runWithEnv('APP_THEME', $themeFolder, function () {
45                 $this->assertEquals('cat', $this->app->getAlias('dog'));
46             });
47         });
48     }
49
50     public function test_event_commonmark_environment_configure()
51     {
52         $callbackCalled = false;
53         $callback = function ($environment) use (&$callbackCalled) {
54             $this->assertInstanceOf(ConfigurableEnvironmentInterface::class, $environment);
55             $callbackCalled = true;
56
57             return $environment;
58         };
59         Theme::listen(ThemeEvents::COMMONMARK_ENVIRONMENT_CONFIGURE, $callback);
60
61         $page = Page::query()->first();
62         $content = new PageContent($page);
63         $content->setNewMarkdown('# test');
64
65         $this->assertTrue($callbackCalled);
66     }
67
68     public function test_event_web_middleware_before()
69     {
70         $callbackCalled = false;
71         $requestParam = null;
72         $callback = function ($request) use (&$callbackCalled, &$requestParam) {
73             $requestParam = $request;
74             $callbackCalled = true;
75         };
76
77         Theme::listen(ThemeEvents::WEB_MIDDLEWARE_BEFORE, $callback);
78         $this->get('/login', ['Donkey' => 'cat']);
79
80         $this->assertTrue($callbackCalled);
81         $this->assertInstanceOf(Request::class, $requestParam);
82         $this->assertEquals('cat', $requestParam->header('donkey'));
83     }
84
85     public function test_event_web_middleware_before_return_val_used_as_response()
86     {
87         $callback = function (Request $request) {
88             return response('cat', 412);
89         };
90
91         Theme::listen(ThemeEvents::WEB_MIDDLEWARE_BEFORE, $callback);
92         $resp = $this->get('/login', ['Donkey' => 'cat']);
93         $resp->assertSee('cat');
94         $resp->assertStatus(412);
95     }
96
97     public function test_event_web_middleware_after()
98     {
99         $callbackCalled = false;
100         $requestParam = null;
101         $responseParam = null;
102         $callback = function ($request, Response $response) use (&$callbackCalled, &$requestParam, &$responseParam) {
103             $requestParam = $request;
104             $responseParam = $response;
105             $callbackCalled = true;
106             $response->header('donkey', 'cat123');
107         };
108
109         Theme::listen(ThemeEvents::WEB_MIDDLEWARE_AFTER, $callback);
110
111         $resp = $this->get('/login', ['Donkey' => 'cat']);
112         $this->assertTrue($callbackCalled);
113         $this->assertInstanceOf(Request::class, $requestParam);
114         $this->assertInstanceOf(Response::class, $responseParam);
115         $resp->assertHeader('donkey', 'cat123');
116     }
117
118     public function test_event_web_middleware_after_return_val_used_as_response()
119     {
120         $callback = function () {
121             return response('cat456', 443);
122         };
123
124         Theme::listen(ThemeEvents::WEB_MIDDLEWARE_AFTER, $callback);
125
126         $resp = $this->get('/login', ['Donkey' => 'cat']);
127         $resp->assertSee('cat456');
128         $resp->assertStatus(443);
129     }
130
131     public function test_event_auth_login_standard()
132     {
133         $args = [];
134         $callback = function (...$eventArgs) use (&$args) {
135             $args = $eventArgs;
136         };
137
138         Theme::listen(ThemeEvents::AUTH_LOGIN, $callback);
139         $this->post('/login', ['email' => 'admin@admin.com', 'password' => 'password']);
140
141         $this->assertCount(2, $args);
142         $this->assertEquals('standard', $args[0]);
143         $this->assertInstanceOf(User::class, $args[1]);
144     }
145
146     public function test_event_auth_register_standard()
147     {
148         $args = [];
149         $callback = function (...$eventArgs) use (&$args) {
150             $args = $eventArgs;
151         };
152         Theme::listen(ThemeEvents::AUTH_REGISTER, $callback);
153         $this->setSettings(['registration-enabled' => 'true']);
154
155         $user = User::factory()->make();
156         $this->post('/register', ['email' => $user->email, 'name' => $user->name, 'password' => 'password']);
157
158         $this->assertCount(2, $args);
159         $this->assertEquals('standard', $args[0]);
160         $this->assertInstanceOf(User::class, $args[1]);
161     }
162
163     public function test_add_social_driver()
164     {
165         Theme::addSocialDriver('catnet', [
166             'client_id'     => 'abc123',
167             'client_secret' => 'def456',
168         ], 'SocialiteProviders\Discord\DiscordExtendSocialite@handleTesting');
169
170         $this->assertEquals('catnet', config('services.catnet.name'));
171         $this->assertEquals('abc123', config('services.catnet.client_id'));
172         $this->assertEquals(url('/login/service/catnet/callback'), config('services.catnet.redirect'));
173
174         $loginResp = $this->get('/login');
175         $loginResp->assertSee('login/service/catnet');
176     }
177
178     public function test_add_social_driver_uses_name_in_config_if_given()
179     {
180         Theme::addSocialDriver('catnet', [
181             'client_id'     => 'abc123',
182             'client_secret' => 'def456',
183             'name'          => 'Super Cat Name',
184         ], 'SocialiteProviders\Discord\DiscordExtendSocialite@handleTesting');
185
186         $this->assertEquals('Super Cat Name', config('services.catnet.name'));
187         $loginResp = $this->get('/login');
188         $loginResp->assertSee('Super Cat Name');
189     }
190
191     public function test_add_social_driver_allows_a_configure_for_redirect_callback_to_be_passed()
192     {
193         Theme::addSocialDriver(
194             'discord',
195             [
196                 'client_id'     => 'abc123',
197                 'client_secret' => 'def456',
198                 'name'          => 'Super Cat Name',
199             ],
200             'SocialiteProviders\Discord\DiscordExtendSocialite@handle',
201             function ($driver) {
202                 $driver->with(['donkey' => 'donut']);
203             }
204         );
205
206         $loginResp = $this->get('/login/service/discord');
207         $redirect = $loginResp->headers->get('location');
208         $this->assertStringContainsString('donkey=donut', $redirect);
209     }
210
211     public function test_register_command_allows_provided_command_to_be_usable_via_artisan()
212     {
213         Theme::registerCommand(new MyCustomCommand);
214
215         Artisan::call('bookstack:test-custom-command', []);
216         $output = Artisan::output();
217
218         $this->assertStringContainsString('Command ran!', $output);
219     }
220
221     protected function usingThemeFolder(callable $callback)
222     {
223         // Create a folder and configure a theme
224         $themeFolderName = 'testing_theme_' . rtrim(base64_encode(time()), '=');
225         config()->set('view.theme', $themeFolderName);
226         $themeFolderPath = theme_path('');
227         File::makeDirectory($themeFolderPath);
228
229         call_user_func($callback, $themeFolderName);
230
231         // Cleanup the custom theme folder we created
232         File::deleteDirectory($themeFolderPath);
233     }
234 }
235
236 class MyCustomCommand extends Command {
237     protected $signature = 'bookstack:test-custom-command';
238     public function handle() {
239         $this->line('Command ran!');
240     }
241 }
Morty Proxy This is a proxified and sanitized view of the page, visit original site.