]> BookStack Code Mirror - bookstack/commitdiff
Updated tests to use ssddanbrown/asserthtml package
authorDan Brown <redacted>
Sat, 23 Jul 2022 14:10:18 +0000 (15:10 +0100)
committerDan Brown <redacted>
Sat, 23 Jul 2022 14:10:18 +0000 (15:10 +0100)
Closes #3519

48 files changed:
composer.json
composer.lock
tests/Actions/AuditLogTest.php
tests/Actions/WebhookManagementTest.php
tests/Auth/AuthTest.php
tests/Auth/LdapTest.php
tests/Auth/LoginAutoInitiateTest.php
tests/Auth/MfaConfigurationTest.php
tests/Auth/MfaVerificationTest.php
tests/Auth/OidcTest.php
tests/Auth/Saml2Test.php
tests/Auth/SocialAuthTest.php
tests/DebugViewTest.php
tests/Entity/BookShelfTest.php
tests/Entity/BookTest.php
tests/Entity/ChapterTest.php
tests/Entity/CommentSettingTest.php
tests/Entity/ConvertTest.php
tests/Entity/EntitySearchTest.php
tests/Entity/ExportTest.php
tests/Entity/PageContentTest.php
tests/Entity/PageDraftTest.php
tests/Entity/PageEditorTest.php
tests/Entity/PageRevisionTest.php
tests/Entity/PageTest.php
tests/Entity/SortTest.php
tests/Entity/TagTest.php
tests/FavouriteTest.php
tests/HelpTest.php
tests/HomepageTest.php
tests/OpenGraphTest.php
tests/Permissions/EntityPermissionsTest.php
tests/Permissions/RolesTest.php
tests/PublicActionTest.php
tests/RecycleBinTest.php
tests/SecurityHeaderTest.php
tests/Settings/FooterLinksTest.php
tests/Settings/SettingsTest.php
tests/SharedTestHelpers.php [deleted file]
tests/TestCase.php
tests/TestEmailTest.php
tests/TestResponse.php [deleted file]
tests/ThemeTest.php
tests/Uploads/ImageTest.php
tests/User/UserApiTokenTest.php
tests/User/UserManagementTest.php
tests/User/UserPreferencesTest.php
tests/User/UserProfileTest.php

index a549773217241a83dca804cc30121efa955bcdc3..6d4bb734d5f4f73828398468ea17d55a1b2609d9 100644 (file)
@@ -50,7 +50,7 @@
         "nunomaduro/collision": "^5.10",
         "nunomaduro/larastan": "^1.0",
         "phpunit/phpunit": "^9.5",
-        "symfony/dom-crawler": "^5.3"
+        "ssddanbrown/asserthtml": "^1.0"
     },
     "autoload": {
         "psr-4": {
index 040bce4a1ab84d4fd59929bbc31e7806a6e02618..9cd171488a1f3fb73f9c7d97434b88b6e233234b 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "23657e068ced89802ea578718478da3a",
+    "content-hash": "4ab21f732b2380ed1c3dd1a4eca2ef1a",
     "packages": [
         {
             "name": "aws/aws-crt-php",
             },
             "time": "2021-12-10T11:20:11+00:00"
         },
+        {
+            "name": "ssddanbrown/asserthtml",
+            "version": "v1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ssddanbrown/htmlassert.git",
+                "reference": "f7d4352bb3d69347097b2841fd71934182821928"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/ssddanbrown/htmlassert/zipball/f7d4352bb3d69347097b2841fd71934182821928",
+                "reference": "f7d4352bb3d69347097b2841fd71934182821928",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-json": "*",
+                "php": ">=7.4",
+                "phpunit/phpunit": "^9.0",
+                "symfony/css-selector": "^5.0|^6.0",
+                "symfony/dom-crawler": "^5.0|^6.0"
+            },
+            "require-dev": {
+                "vimeo/psalm": "^4.10"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Ssddanbrown\\AssertHtml\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Dan Brown",
+                    "email": "[email protected]",
+                    "role": "Developer"
+                }
+            ],
+            "description": "HTML Content Assertions for PHPUnit",
+            "homepage": "https://github.com/ssddanbrown/asserthtml",
+            "support": {
+                "issues": "https://github.com/ssddanbrown/htmlassert/issues",
+                "source": "https://github.com/ssddanbrown/htmlassert/tree/v1.0.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/ssddanbrown",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-04-09T13:31:13+00:00"
+        },
         {
             "name": "symfony/dom-crawler",
             "version": "v5.4.9",
index 92289cd4ffe44e34e4f53b38d35d0a16971df1c6..d699724f5129d1936e5f39f88fb1ff4f648eab17 100644 (file)
@@ -56,7 +56,7 @@ class AuditLogTest extends TestCase
         $resp->assertSeeText($page->name);
         $resp->assertSeeText('page_create');
         $resp->assertSeeText($activity->created_at->toDateTimeString());
-        $resp->assertElementContains('.table-user-item', $admin->name);
+        $this->withHtml($resp)->assertElementContains('.table-user-item', $admin->name);
     }
 
     public function test_shows_name_for_deleted_items()
index 1fbf9b7a962fcd71c3b8898ecd6bcecb35d2abd8..f106f303ace395cb39f75db7b75e59026dc5f616 100644 (file)
@@ -17,8 +17,8 @@ class WebhookManagementTest extends TestCase
 
         $resp = $this->asAdmin()->get('/settings/webhooks');
         $resp->assertOk();
-        $resp->assertElementContains('a[href$="/settings/webhooks/create"]', 'Create New Webhook');
-        $resp->assertElementExists('a[href="' . $webhook->getUrl() . '"]', $webhook->name);
+        $this->withHtml($resp)->assertElementContains('a[href$="/settings/webhooks/create"]', 'Create New Webhook');
+        $this->withHtml($resp)->assertElementContains('a[href="' . $webhook->getUrl() . '"]', $webhook->name);
         $resp->assertSee($webhook->endpoint);
         $resp->assertSee('All system events');
         $resp->assertSee('Active');
@@ -29,7 +29,7 @@ class WebhookManagementTest extends TestCase
         $resp = $this->asAdmin()->get('/settings/webhooks/create');
         $resp->assertOk();
         $resp->assertSee('Create New Webhook');
-        $resp->assertElementContains('form[action$="/settings/webhooks/create"] button', 'Save Webhook');
+        $this->withHtml($resp)->assertElementContains('form[action$="/settings/webhooks/create"] button', 'Save Webhook');
     }
 
     public function test_store()
@@ -70,9 +70,9 @@ class WebhookManagementTest extends TestCase
         $resp = $this->asAdmin()->get('/settings/webhooks/' . $webhook->id);
         $resp->assertOk();
         $resp->assertSee('Edit Webhook');
-        $resp->assertElementContains('form[action="' . $webhook->getUrl() . '"] button', 'Save Webhook');
-        $resp->assertElementContains('a[href="' . $webhook->getUrl('/delete') . '"]', 'Delete Webhook');
-        $resp->assertElementExists('input[type="checkbox"][value="all"][name="events[]"]');
+        $this->withHtml($resp)->assertElementContains('form[action="' . $webhook->getUrl() . '"] button', 'Save Webhook');
+        $this->withHtml($resp)->assertElementContains('a[href="' . $webhook->getUrl('/delete') . '"]', 'Delete Webhook');
+        $this->withHtml($resp)->assertElementExists('input[type="checkbox"][value="all"][name="events[]"]');
     }
 
     public function test_update()
@@ -114,7 +114,7 @@ class WebhookManagementTest extends TestCase
         $resp->assertOk();
         $resp->assertSee('Delete Webhook');
         $resp->assertSee('This will fully delete this webhook, with the name \'Webhook to delete\', from the system.');
-        $resp->assertElementContains('form[action$="/settings/webhooks/' . $webhook->id . '"]', 'Delete');
+        $this->withHtml($resp)->assertElementContains('form[action$="/settings/webhooks/' . $webhook->id . '"]', 'Delete');
     }
 
     public function test_destroy()
index 0ab6d0e8c61eec400a7c8afe2e9d2d2e8ec0501f..106b7187515f4ad3bdf9d210627225b4e3b1c693 100644 (file)
@@ -10,8 +10,8 @@ use BookStack\Notifications\ConfirmEmail;
 use BookStack\Notifications\ResetPassword;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Notification;
+use Illuminate\Testing\TestResponse;
 use Tests\TestCase;
-use Tests\TestResponse;
 
 class AuthTest extends TestCase
 {
@@ -37,8 +37,8 @@ class AuthTest extends TestCase
     {
         // Ensure registration form is showing
         $this->setSettings(['registration-enabled' => 'true']);
-        $this->get('/login')
-            ->assertElementContains('a[href="' . url('/register') . '"]', 'Sign up');
+        $resp = $this->get('/login');
+        $this->withHtml($resp)->assertElementContains('a[href="' . url('/register') . '"]', 'Sign up');
     }
 
     public function test_normal_registration()
@@ -51,9 +51,9 @@ class AuthTest extends TestCase
         $user = User::factory()->make();
 
         // Test form and ensure user is created
-        $this->get('/register')
-            ->assertSee('Sign Up')
-            ->assertElementContains('form[action="' . url('/register') . '"]', 'Create Account');
+        $resp = $this->get('/register')
+            ->assertSee('Sign Up');
+        $this->withHtml($resp)->assertElementContains('form[action="' . url('/register') . '"]', 'Create Account');
 
         $resp = $this->post('/register', $user->only('password', 'name', 'email'));
         $resp->assertRedirect('/');
@@ -128,7 +128,7 @@ class AuthTest extends TestCase
         $resp->assertRedirect('/register/confirm/awaiting');
 
         $resp = $this->get('/register/confirm/awaiting');
-        $resp->assertElementContains('form[action="' . url('/register/confirm/resend') . '"]', 'Resend');
+        $this->withHtml($resp)->assertElementContains('form[action="' . url('/register/confirm/resend') . '"]', 'Resend');
 
         $this->get('/books')->assertRedirect('/login');
         $this->post('/register/confirm/resend', $user->only('email'));
@@ -203,7 +203,7 @@ class AuthTest extends TestCase
         $this->assertFalse(setting('registration-role'));
 
         $resp = $this->asAdmin()->get('/settings/registration');
-        $resp->assertElementContains('select[name="setting-registration-role"] option[value="0"][selected]', '-- None --');
+        $this->withHtml($resp)->assertElementContains('select[name="setting-registration-role"] option[value="0"][selected]', '-- None --');
     }
 
     public function test_logout()
@@ -229,11 +229,11 @@ class AuthTest extends TestCase
     {
         Notification::fake();
 
-        $this->get('/login')
-            ->assertElementContains('a[href="' . url('/password/email') . '"]', 'Forgot Password?');
+        $resp = $this->get('/login');
+        $this->withHtml($resp)->assertElementContains('a[href="' . url('/password/email') . '"]', 'Forgot Password?');
 
-        $this->get('/password/email')
-            ->assertElementContains('form[action="' . url('/password/email') . '"]', 'Send Reset Link');
+        $resp = $this->get('/password/email');
+        $this->withHtml($resp)->assertElementContains('form[action="' . url('/password/email') . '"]', 'Send Reset Link');
 
         $resp = $this->post('/password/email', [
             'email' => '[email protected]',
@@ -294,8 +294,8 @@ class AuthTest extends TestCase
     public function test_reset_password_page_shows_sign_links()
     {
         $this->setSettings(['registration-enabled' => 'true']);
-        $this->get('/password/email')
-            ->assertElementContains('a', 'Log in')
+        $resp = $this->get('/password/email');
+        $this->withHtml($resp)->assertElementContains('a', 'Log in')
             ->assertElementContains('a', 'Sign up');
     }
 
index 96e10e4dae818a7155306c55f050c875b9d7596d..978420f869ede41d480cbe7258f1c6600773e3d5 100644 (file)
@@ -6,9 +6,9 @@ use BookStack\Auth\Access\Ldap;
 use BookStack\Auth\Access\LdapService;
 use BookStack\Auth\Role;
 use BookStack\Auth\User;
+use Illuminate\Testing\TestResponse;
 use Mockery\MockInterface;
 use Tests\TestCase;
-use Tests\TestResponse;
 
 class LdapTest extends TestCase
 {
@@ -106,7 +106,7 @@ class LdapTest extends TestCase
         $resp->assertSee($this->mockUser->name);
 
         $resp = $this->followingRedirects()->mockUserLogin($this->mockUser->email);
-        $resp->assertElementExists('#home-default');
+        $this->withHtml($resp)->assertElementExists('#home-default');
         $resp->assertSee($this->mockUser->name);
         $this->assertDatabaseHas('users', [
             'email'            => $this->mockUser->email,
@@ -251,7 +251,8 @@ class LdapTest extends TestCase
 
     public function test_registration_disabled()
     {
-        $this->followingRedirects()->get('/register')->assertElementContains('#content', 'Log In');
+        $resp = $this->followingRedirects()->get('/register');
+        $this->withHtml($resp)->assertElementContains('#content', 'Log In');
     }
 
     public function test_non_admins_cannot_change_auth_id()
index 86e1f93e2083ff0215b153eda7f37d26b7b7461a..2d03844356eb62b68c67d9a2333b2ed2a0e54126 100644 (file)
@@ -25,8 +25,8 @@ class LoginAutoInitiateTest extends TestCase
 
         $req = $this->get('/login');
         $req->assertSeeText('Attempting Login');
-        $req->assertElementExists('form[action$="/oidc/login"][method=POST][id="login-form"] button');
-        $req->assertElementExists('button[form="login-form"]');
+        $this->withHtml($req)->assertElementExists('form[action$="/oidc/login"][method=POST][id="login-form"] button');
+        $this->withHtml($req)->assertElementExists('button[form="login-form"]');
     }
 
     public function test_with_saml2()
@@ -37,8 +37,8 @@ class LoginAutoInitiateTest extends TestCase
 
         $req = $this->get('/login');
         $req->assertSeeText('Attempting Login');
-        $req->assertElementExists('form[action$="/saml2/login"][method=POST][id="login-form"] button');
-        $req->assertElementExists('button[form="login-form"]');
+        $this->withHtml($req)->assertElementExists('form[action$="/saml2/login"][method=POST][id="login-form"] button');
+        $this->withHtml($req)->assertElementExists('button[form="login-form"]');
     }
 
     public function test_it_does_not_run_if_social_provider_is_active()
index fab94817c4b651d6c1bd022c737984c0b742f915..3416263f3f44bac46579ec364007a5ea30444d2d 100644 (file)
@@ -18,15 +18,15 @@ class MfaConfigurationTest extends TestCase
 
         // Setup page state
         $resp = $this->actingAs($editor)->get('/mfa/setup');
-        $resp->assertElementContains('a[href$="/mfa/totp/generate"]', 'Setup');
+        $this->withHtml($resp)->assertElementContains('a[href$="/mfa/totp/generate"]', 'Setup');
 
         // Generate page access
         $resp = $this->get('/mfa/totp/generate');
         $resp->assertSee('Mobile App Setup');
         $resp->assertSee('Verify Setup');
-        $resp->assertElementExists('form[action$="/mfa/totp/confirm"] button');
+        $this->withHtml($resp)->assertElementExists('form[action$="/mfa/totp/confirm"] button');
         $this->assertSessionHas('mfa-setup-totp-secret');
-        $svg = $resp->getElementHtml('#main-content .card svg');
+        $svg = $this->withHtml($resp)->getOuterHtml('#main-content .card svg');
 
         // Validation error, code should remain the same
         $resp = $this->post('/mfa/totp/confirm', [
@@ -35,7 +35,7 @@ class MfaConfigurationTest extends TestCase
         $resp->assertRedirect('/mfa/totp/generate');
         $resp = $this->followRedirects($resp);
         $resp->assertSee('The provided code is not valid or has expired.');
-        $revisitSvg = $resp->getElementHtml('#main-content .card svg');
+        $revisitSvg = $this->withHtml($resp)->getOuterHtml('#main-content .card svg');
         $this->assertTrue($svg === $revisitSvg);
         $secret = decrypt(session()->get('mfa-setup-totp-secret'));
 
@@ -52,7 +52,7 @@ class MfaConfigurationTest extends TestCase
         // Confirmation of setup
         $resp = $this->followRedirects($resp);
         $resp->assertSee('Multi-factor method successfully configured');
-        $resp->assertElementContains('a[href$="/mfa/totp/generate"]', 'Reconfigure');
+        $this->withHtml($resp)->assertElementContains('a[href$="/mfa/totp/generate"]', 'Reconfigure');
 
         $this->assertDatabaseHas('mfa_values', [
             'user_id' => $editor->id,
@@ -71,12 +71,12 @@ class MfaConfigurationTest extends TestCase
 
         // Setup page state
         $resp = $this->actingAs($editor)->get('/mfa/setup');
-        $resp->assertElementContains('a[href$="/mfa/backup_codes/generate"]', 'Setup');
+        $this->withHtml($resp)->assertElementContains('a[href$="/mfa/backup_codes/generate"]', 'Setup');
 
         // Generate page access
         $resp = $this->get('/mfa/backup_codes/generate');
         $resp->assertSee('Backup Codes');
-        $resp->assertElementContains('form[action$="/mfa/backup_codes/confirm"]', 'Confirm and Enable');
+        $this->withHtml($resp)->assertElementContains('form[action$="/mfa/backup_codes/confirm"]', 'Confirm and Enable');
         $this->assertSessionHas('mfa-setup-backup-codes');
         $codes = decrypt(session()->get('mfa-setup-backup-codes'));
         // Check code format
@@ -92,7 +92,7 @@ class MfaConfigurationTest extends TestCase
         // Confirmation of setup
         $resp = $this->followRedirects($resp);
         $resp->assertSee('Multi-factor method successfully configured');
-        $resp->assertElementContains('a[href$="/mfa/backup_codes/generate"]', 'Reconfigure');
+        $this->withHtml($resp)->assertElementContains('a[href$="/mfa/backup_codes/generate"]', 'Reconfigure');
 
         $this->assertDatabaseHas('mfa_values', [
             'user_id' => $editor->id,
@@ -129,10 +129,10 @@ class MfaConfigurationTest extends TestCase
     {
         $admin = $this->getAdmin();
         $resp = $this->actingAs($admin)->get($admin->getEditUrl());
-        $resp->assertElementExists('a[href$="/mfa/setup"]');
+        $this->withHtml($resp)->assertElementExists('a[href$="/mfa/setup"]');
 
         $resp = $this->actingAs($admin)->get($this->getEditor()->getEditUrl());
-        $resp->assertElementNotExists('a[href$="/mfa/setup"]');
+        $this->withHtml($resp)->assertElementNotExists('a[href$="/mfa/setup"]');
     }
 
     public function test_mfa_indicator_shows_in_user_list()
@@ -141,11 +141,11 @@ class MfaConfigurationTest extends TestCase
         User::query()->where('id', '!=', $admin->id)->delete();
 
         $resp = $this->actingAs($admin)->get('/settings/users');
-        $resp->assertElementNotExists('[title="MFA Configured"] svg');
+        $this->withHtml($resp)->assertElementNotExists('[title="MFA Configured"] svg');
 
         MfaValue::upsertWithValue($admin, MfaValue::METHOD_TOTP, 'test');
         $resp = $this->actingAs($admin)->get('/settings/users');
-        $resp->assertElementExists('[title="MFA Configured"] svg');
+        $this->withHtml($resp)->assertElementExists('[title="MFA Configured"] svg');
     }
 
     public function test_remove_mfa_method()
@@ -155,7 +155,7 @@ class MfaConfigurationTest extends TestCase
         MfaValue::upsertWithValue($admin, MfaValue::METHOD_TOTP, 'test');
         $this->assertEquals(1, $admin->mfaValues()->count());
         $resp = $this->actingAs($admin)->get('/mfa/setup');
-        $resp->assertElementExists('form[action$="/mfa/totp/remove"]');
+        $this->withHtml($resp)->assertElementExists('form[action$="/mfa/totp/remove"]');
 
         $resp = $this->delete('/mfa/totp/remove');
         $resp->assertRedirect('/mfa/setup');
index 7286a1de8b997ee5dbc0295ac841a4e13da1fb3b..ba4c9b983a3feebce56e44c34cb5ca8904030d20 100644 (file)
@@ -23,7 +23,7 @@ class MfaVerificationTest extends TestCase
         $resp = $this->get('/mfa/verify');
         $resp->assertSee('Verify Access');
         $resp->assertSee('Enter the code, generated using your mobile app, below:');
-        $resp->assertElementExists('form[action$="/mfa/totp/verify"] input[name="code"][autofocus]');
+        $this->withHtml($resp)->assertElementExists('form[action$="/mfa/totp/verify"] input[name="code"][autofocus]');
 
         $google2fa = new Google2FA();
         $resp = $this->post('/mfa/totp/verify', [
@@ -66,7 +66,7 @@ class MfaVerificationTest extends TestCase
         $resp->assertSee('Verify Access');
         $resp->assertSee('Backup Code');
         $resp->assertSee('Enter one of your remaining backup codes below:');
-        $resp->assertElementExists('form[action$="/mfa/backup_codes/verify"] input[name="code"]');
+        $this->withHtml($resp)->assertElementExists('form[action$="/mfa/backup_codes/verify"] input[name="code"]');
 
         $resp = $this->post('/mfa/backup_codes/verify', [
             'code' => $codes[1],
@@ -154,13 +154,13 @@ class MfaVerificationTest extends TestCase
         ]);
 
         // Totp shown by default
-        $mfaView->assertElementExists('form[action$="/mfa/totp/verify"] input[name="code"]');
-        $mfaView->assertElementContains('a[href$="/mfa/verify?method=backup_codes"]', 'Verify using a backup code');
+        $this->withHtml($mfaView)->assertElementExists('form[action$="/mfa/totp/verify"] input[name="code"]');
+        $this->withHtml($mfaView)->assertElementContains('a[href$="/mfa/verify?method=backup_codes"]', 'Verify using a backup code');
 
         // Ensure can view backup_codes view
         $resp = $this->get('/mfa/verify?method=backup_codes');
-        $resp->assertElementExists('form[action$="/mfa/backup_codes/verify"] input[name="code"]');
-        $resp->assertElementContains('a[href$="/mfa/verify?method=totp"]', 'Verify using a mobile app');
+        $this->withHtml($resp)->assertElementExists('form[action$="/mfa/backup_codes/verify"] input[name="code"]');
+        $this->withHtml($resp)->assertElementContains('a[href$="/mfa/verify?method=totp"]', 'Verify using a mobile app');
     }
 
     public function test_mfa_required_with_no_methods_leads_to_setup()
@@ -184,7 +184,7 @@ class MfaVerificationTest extends TestCase
         ]);
 
         $resp->assertSeeText('No Methods Configured');
-        $resp->assertElementContains('a[href$="/mfa/setup"]', 'Configure');
+        $this->withHtml($resp)->assertElementContains('a[href$="/mfa/setup"]', 'Configure');
 
         $this->get('/mfa/backup_codes/generate');
         $resp = $this->post('/mfa/backup_codes/confirm');
index 9aebb4d04a6694c812c6d2a57f74f1f3660257bf..aa2c99a36dbf92268ec77dfc45f834fe6e7c82d7 100644 (file)
@@ -6,9 +6,9 @@ use BookStack\Actions\ActivityType;
 use BookStack\Auth\User;
 use GuzzleHttp\Psr7\Request;
 use GuzzleHttp\Psr7\Response;
+use Illuminate\Testing\TestResponse;
 use Tests\Helpers\OidcJwtHelper;
 use Tests\TestCase;
-use Tests\TestResponse;
 
 class OidcTest extends TestCase
 {
@@ -52,7 +52,7 @@ class OidcTest extends TestCase
     {
         $req = $this->get('/login');
         $req->assertSeeText('SingleSignOn-Testing');
-        $req->assertElementExists('form[action$="/oidc/login"][method=POST] button');
+        $this->withHtml($req)->assertElementExists('form[action$="/oidc/login"][method=POST] button');
     }
 
     public function test_oidc_routes_are_only_active_if_oidc_enabled()
index cb217585c5fc18f7018aa9a83a0bbdf4b984a361..885adf9e0a48fca8a40eab1824fe35ccd24459e3 100644 (file)
@@ -56,7 +56,7 @@ class Saml2Test extends TestCase
     {
         $req = $this->get('/login');
         $req->assertSeeText('SingleSignOn-Testing');
-        $req->assertElementExists('form[action$="/saml2/login"][method=POST] button');
+        $this->withHtml($req)->assertElementExists('form[action$="/saml2/login"][method=POST] button');
     }
 
     public function test_login()
@@ -157,7 +157,7 @@ class Saml2Test extends TestCase
         ]);
 
         $resp = $this->actingAs($this->getEditor())->get('/');
-        $resp->assertElementContains('form[action$="/saml2/logout"] button', 'Logout');
+        $this->withHtml($resp)->assertElementContains('form[action$="/saml2/logout"] button', 'Logout');
     }
 
     public function test_logout_sls_flow()
index 90d7e37aa5e85065588346e22e91fd319d5ccf80..67da771a5176f439200e95a9fbd27d257f79539f 100644 (file)
@@ -61,7 +61,7 @@ class SocialAuthTest extends TestCase
 
         // Test login routes
         $resp = $this->get('/login');
-        $resp->assertElementExists('a#social-login-google[href$="/login/service/google"]');
+        $this->withHtml($resp)->assertElementExists('a#social-login-google[href$="/login/service/google"]');
         $resp = $this->followingRedirects()->get('/login/service/google');
         $resp->assertSee('login-form');
 
@@ -71,7 +71,7 @@ class SocialAuthTest extends TestCase
         $resp->assertSee(trans('errors.social_account_not_used', ['socialAccount' => 'Google']));
 
         $resp = $this->get('/login');
-        $resp->assertElementExists('a#social-login-github[href$="/login/service/github"]');
+        $this->withHtml($resp)->assertElementExists('a#social-login-github[href$="/login/service/github"]');
         $resp = $this->followingRedirects()->get('/login/service/github');
         $resp->assertSee('login-form');
 
@@ -101,7 +101,7 @@ class SocialAuthTest extends TestCase
         ]);
 
         $resp = $this->actingAs($editor)->get($editor->getEditUrl());
-        $resp->assertElementContains('form[action$="/login/service/github/detach"]', 'Disconnect Account');
+        $this->withHtml($resp)->assertElementContains('form[action$="/login/service/github/detach"]', 'Disconnect Account');
 
         $resp = $this->post('/login/service/github/detach');
         $resp->assertRedirect($editor->getEditUrl());
index 63d6472b982c7d3efc5b12df538050485f4569a5..ec66de10a505e3f768e4e52a26ceb4be6a9143aa 100644 (file)
@@ -3,6 +3,7 @@
 namespace Tests;
 
 use BookStack\Auth\Access\SocialAuthService;
+use Illuminate\Testing\TestResponse;
 
 class DebugViewTest extends TestCase
 {
@@ -25,8 +26,8 @@ class DebugViewTest extends TestCase
         // BookStack version
         $resp->assertSeeText('BookStack Version: ' . trim(file_get_contents(base_path('version'))));
         // Dynamic help links
-        $resp->assertElementExists('a[href*="q=' . urlencode('BookStack An error occurred during testing') . '"]');
-        $resp->assertElementExists('a[href*="?q=is%3Aissue+' . urlencode('An error occurred during testing') . '"]');
+        $this->withHtml($resp)->assertElementExists('a[href*="q=' . urlencode('BookStack An error occurred during testing') . '"]');
+        $this->withHtml($resp)->assertElementExists('a[href*="?q=is%3Aissue+' . urlencode('An error occurred during testing') . '"]');
     }
 
     public function test_debug_view_only_shows_when_debug_mode_is_enabled()
index fcbc17ea94ba40ce4c0c89f811234cc829786bd3..5a7107ff0967166e3addd2c8a5cd7e7741a74609 100644 (file)
@@ -18,21 +18,21 @@ class BookShelfTest extends TestCase
     {
         $viewer = $this->getViewer();
         $resp = $this->actingAs($viewer)->get('/');
-        $resp->assertElementContains('header', 'Shelves');
+        $this->withHtml($resp)->assertElementContains('header', 'Shelves');
 
         $viewer->roles()->delete();
         $this->giveUserPermissions($viewer);
         $resp = $this->actingAs($viewer)->get('/');
-        $resp->assertElementNotContains('header', 'Shelves');
+        $this->withHtml($resp)->assertElementNotContains('header', 'Shelves');
 
         $this->giveUserPermissions($viewer, ['bookshelf-view-all']);
         $resp = $this->actingAs($viewer)->get('/');
-        $resp->assertElementContains('header', 'Shelves');
+        $this->withHtml($resp)->assertElementContains('header', 'Shelves');
 
         $viewer->roles()->delete();
         $this->giveUserPermissions($viewer, ['bookshelf-view-own']);
         $resp = $this->actingAs($viewer)->get('/');
-        $resp->assertElementContains('header', 'Shelves');
+        $this->withHtml($resp)->assertElementContains('header', 'Shelves');
     }
 
     public function test_shelves_shows_in_header_if_have_any_shelve_view_permission()
@@ -43,18 +43,18 @@ class BookShelfTest extends TestCase
         $userRole = $user->roles()->first();
 
         $resp = $this->actingAs($user)->get('/');
-        $resp->assertElementNotContains('header', 'Shelves');
+        $this->withHtml($resp)->assertElementNotContains('header', 'Shelves');
 
         $this->setEntityRestrictions($shelf, ['view'], [$userRole]);
 
         $resp = $this->get('/');
-        $resp->assertElementContains('header', 'Shelves');
+        $this->withHtml($resp)->assertElementContains('header', 'Shelves');
     }
 
     public function test_shelves_page_contains_create_link()
     {
         $resp = $this->asEditor()->get('/shelves');
-        $resp->assertElementContains('a', 'New Shelf');
+        $this->withHtml($resp)->assertElementContains('a', 'New Shelf');
     }
 
     public function test_book_not_visible_in_shelf_list_view_if_user_cant_view_shelf()
@@ -100,8 +100,8 @@ class BookShelfTest extends TestCase
         $shelfPage = $this->get($shelf->getUrl());
         $shelfPage->assertSee($shelfInfo['name']);
         $shelfPage->assertSee($shelfInfo['description']);
-        $shelfPage->assertElementContains('.tag-item', 'Test Category');
-        $shelfPage->assertElementContains('.tag-item', 'Test Tag Value');
+        $this->withHtml($shelfPage)->assertElementContains('.tag-item', 'Test Category');
+        $this->withHtml($shelfPage)->assertElementContains('.tag-item', 'Test Tag Value');
 
         $this->assertDatabaseHas('bookshelves_books', ['bookshelf_id' => $shelf->id, 'book_id' => $booksToInclude[0]->id]);
         $this->assertDatabaseHas('bookshelves_books', ['bookshelf_id' => $shelf->id, 'book_id' => $booksToInclude[1]->id]);
@@ -148,10 +148,10 @@ class BookShelfTest extends TestCase
         $resp->assertSee($shelf->getUrl('/edit'));
         $resp->assertSee($shelf->getUrl('/permissions'));
         $resp->assertSee($shelf->getUrl('/delete'));
-        $resp->assertElementContains('a', 'New Book');
-        $resp->assertElementContains('a', 'Edit');
-        $resp->assertElementContains('a', 'Permissions');
-        $resp->assertElementContains('a', 'Delete');
+        $this->withHtml($resp)->assertElementContains('a', 'New Book');
+        $this->withHtml($resp)->assertElementContains('a', 'Edit');
+        $this->withHtml($resp)->assertElementContains('a', 'Permissions');
+        $this->withHtml($resp)->assertElementContains('a', 'Delete');
 
         $resp = $this->asEditor()->get($shelf->getUrl());
         $resp->assertDontSee($shelf->getUrl('/permissions'));
@@ -161,8 +161,8 @@ class BookShelfTest extends TestCase
     {
         $shelf = Bookshelf::query()->first();
         $resp = $this->asAdmin()->get($shelf->getUrl());
-        $resp->assertElementExists('form[action$="change-sort/shelf_books"]');
-        $resp->assertElementContains('form[action$="change-sort/shelf_books"] [aria-haspopup="true"]', 'Default');
+        $this->withHtml($resp)->assertElementExists('form[action$="change-sort/shelf_books"]');
+        $this->withHtml($resp)->assertElementContains('form[action$="change-sort/shelf_books"] [aria-haspopup="true"]', 'Default');
     }
 
     public function test_shelf_view_sort_takes_action()
@@ -182,20 +182,20 @@ class BookShelfTest extends TestCase
         $shelf->refresh();
 
         $resp = $this->asEditor()->get($shelf->getUrl());
-        $resp->assertElementContains('.book-content a.grid-card', $books[0]->name, 1);
-        $resp->assertElementNotContains('.book-content a.grid-card', $books[0]->name, 3);
+        $this->withHtml($resp)->assertElementContains('.book-content a.grid-card:nth-child(1)', $books[0]->name);
+        $this->withHtml($resp)->assertElementNotContains('.book-content a.grid-card:nth-child(3)', $books[0]->name);
 
         setting()->putUser($this->getEditor(), 'shelf_books_sort_order', 'desc');
         $resp = $this->asEditor()->get($shelf->getUrl());
-        $resp->assertElementNotContains('.book-content a.grid-card', $books[0]->name, 1);
-        $resp->assertElementContains('.book-content a.grid-card', $books[0]->name, 3);
+        $this->withHtml($resp)->assertElementNotContains('.book-content a.grid-card:nth-child(1)', $books[0]->name);
+        $this->withHtml($resp)->assertElementContains('.book-content a.grid-card:nth-child(3)', $books[0]->name);
 
         setting()->putUser($this->getEditor(), 'shelf_books_sort_order', 'desc');
         setting()->putUser($this->getEditor(), 'shelf_books_sort', 'name');
         $resp = $this->asEditor()->get($shelf->getUrl());
-        $resp->assertElementContains('.book-content a.grid-card', 'hdgfgdfg', 1);
-        $resp->assertElementContains('.book-content a.grid-card', 'bsfsdfsdfsd', 2);
-        $resp->assertElementContains('.book-content a.grid-card', 'adsfsdfsdfsd', 3);
+        $this->withHtml($resp)->assertElementContains('.book-content a.grid-card:nth-child(1)', 'hdgfgdfg');
+        $this->withHtml($resp)->assertElementContains('.book-content a.grid-card:nth-child(2)', 'bsfsdfsdfsd');
+        $this->withHtml($resp)->assertElementContains('.book-content a.grid-card:nth-child(3)', 'adsfsdfsdfsd');
     }
 
     public function test_shelf_edit()
@@ -229,8 +229,8 @@ class BookShelfTest extends TestCase
         $shelfPage = $this->get($shelf->getUrl());
         $shelfPage->assertSee($shelfInfo['name']);
         $shelfPage->assertSee($shelfInfo['description']);
-        $shelfPage->assertElementContains('.tag-item', 'Test Category');
-        $shelfPage->assertElementContains('.tag-item', 'Test Tag Value');
+        $this->withHtml($shelfPage)->assertElementContains('.tag-item', 'Test Category');
+        $this->withHtml($shelfPage)->assertElementContains('.tag-item', 'Test Tag Value');
 
         $this->assertDatabaseHas('bookshelves_books', ['bookshelf_id' => $shelf->id, 'book_id' => $booksToInclude[0]->id]);
         $this->assertDatabaseHas('bookshelves_books', ['bookshelf_id' => $shelf->id, 'book_id' => $booksToInclude[1]->id]);
@@ -282,7 +282,7 @@ class BookShelfTest extends TestCase
         $this->assertTrue($shelf->deletions()->count() === 1);
 
         $redirectReq = $this->get($deleteReq->baseResponse->headers->get('location'));
-        $redirectReq->assertNotificationContains('Bookshelf Successfully Deleted');
+        $this->assertNotificationContains($redirectReq, 'Bookshelf Successfully Deleted');
     }
 
     public function test_shelf_copy_permissions()
@@ -323,22 +323,22 @@ class BookShelfTest extends TestCase
         $this->asAdmin();
 
         $bookVisit = $this->get($shelfBook->getUrl());
-        $bookVisit->assertElementNotContains('.breadcrumbs', 'Shelves');
-        $bookVisit->assertElementNotContains('.breadcrumbs', $shelf->getShortName());
+        $this->withHtml($bookVisit)->assertElementNotContains('.breadcrumbs', 'Shelves');
+        $this->withHtml($bookVisit)->assertElementNotContains('.breadcrumbs', $shelf->getShortName());
 
         $this->get($shelf->getUrl());
         $bookVisit = $this->get($shelfBook->getUrl());
-        $bookVisit->assertElementContains('.breadcrumbs', 'Shelves');
-        $bookVisit->assertElementContains('.breadcrumbs', $shelf->getShortName());
+        $this->withHtml($bookVisit)->assertElementContains('.breadcrumbs', 'Shelves');
+        $this->withHtml($bookVisit)->assertElementContains('.breadcrumbs', $shelf->getShortName());
 
         $pageVisit = $this->get($shelfPage->getUrl());
-        $pageVisit->assertElementContains('.breadcrumbs', 'Shelves');
-        $pageVisit->assertElementContains('.breadcrumbs', $shelf->getShortName());
+        $this->withHtml($pageVisit)->assertElementContains('.breadcrumbs', 'Shelves');
+        $this->withHtml($pageVisit)->assertElementContains('.breadcrumbs', $shelf->getShortName());
 
         $this->get('/books');
         $pageVisit = $this->get($shelfPage->getUrl());
-        $pageVisit->assertElementNotContains('.breadcrumbs', 'Shelves');
-        $pageVisit->assertElementNotContains('.breadcrumbs', $shelf->getShortName());
+        $this->withHtml($pageVisit)->assertElementNotContains('.breadcrumbs', 'Shelves');
+        $this->withHtml($pageVisit)->assertElementNotContains('.breadcrumbs', $shelf->getShortName());
     }
 
     public function test_bookshelves_show_on_book()
@@ -361,7 +361,7 @@ class BookShelfTest extends TestCase
         $newBook = Book::query()->orderBy('id', 'desc')->first();
 
         $resp = $this->asEditor()->get($newBook->getUrl());
-        $resp->assertElementContains('.tri-layout-left-contents', $shelfInfo['name']);
+        $this->withHtml($resp)->assertElementContains('.tri-layout-left-contents', $shelfInfo['name']);
 
         // Remove shelf
         $this->delete($shelf->getUrl());
@@ -375,6 +375,6 @@ class BookShelfTest extends TestCase
         /** @var Bookshelf $shelf */
         $shelf = Bookshelf::query()->first();
         $resp = $this->asEditor()->get($shelf->getUrl('/create-book'));
-        $resp->assertElementContains('form a[href="' . $shelf->getUrl() . '"]', 'Cancel');
+        $this->withHtml($resp)->assertElementContains('form a[href="' . $shelf->getUrl() . '"]', 'Cancel');
     }
 }
index 6b3c6aa388534e1d84fce61efdb04568efc8f56d..2e6f8e9dedc51670902d9c26ec155fd4ac9898ec 100644 (file)
@@ -19,10 +19,10 @@ class BookTest extends TestCase
         ]);
 
         $resp = $this->asEditor()->get('/books');
-        $resp->assertElementContains('a[href="' . url('/create-book') . '"]', 'Create New Book');
+        $this->withHtml($resp)->assertElementContains('a[href="' . url('/create-book') . '"]', 'Create New Book');
 
         $resp = $this->get('/create-book');
-        $resp->assertElementContains('form[action="' . url('/books') . '"][method="POST"]', 'Save Book');
+        $this->withHtml($resp)->assertElementContains('form[action="' . url('/books') . '"][method="POST"]', 'Save Book');
 
         $resp = $this->post('/books', $book->only('name', 'description'));
         $resp->assertRedirect('/books/my-first-book');
@@ -91,7 +91,7 @@ class BookTest extends TestCase
         $resp = $this->get($book->getUrl('/edit'));
         $resp->assertSee($book->name);
         $resp->assertSee($book->description);
-        $resp->assertElementContains('form[action="' . $book->getUrl() . '"]', 'Save Book');
+        $this->withHtml($resp)->assertElementContains('form[action="' . $book->getUrl() . '"]', 'Save Book');
 
         $resp = $this->put($book->getUrl(), ['name' => $newName, 'description' => $newDesc]);
         $resp->assertRedirect($book->getUrl() . '-updated');
@@ -155,13 +155,13 @@ class BookTest extends TestCase
         $this->assertTrue($book->deletions()->count() === 1);
 
         $redirectReq = $this->get($deleteReq->baseResponse->headers->get('location'));
-        $redirectReq->assertNotificationContains('Book Successfully Deleted');
+        $this->assertNotificationContains($redirectReq, 'Book Successfully Deleted');
     }
 
     public function test_cancel_on_create_page_leads_back_to_books_listing()
     {
         $resp = $this->asEditor()->get('/create-book');
-        $resp->assertElementContains('form a[href="' . url('/books') . '"]', 'Cancel');
+        $this->withHtml($resp)->assertElementContains('form a[href="' . url('/books') . '"]', 'Cancel');
     }
 
     public function test_cancel_on_edit_book_page_leads_back_to_book()
@@ -169,7 +169,7 @@ class BookTest extends TestCase
         /** @var Book $book */
         $book = Book::query()->first();
         $resp = $this->asEditor()->get($book->getUrl('/edit'));
-        $resp->assertElementContains('form a[href="' . $book->getUrl() . '"]', 'Cancel');
+        $this->withHtml($resp)->assertElementContains('form a[href="' . $book->getUrl() . '"]', 'Cancel');
     }
 
     public function test_next_previous_navigation_controls_show_within_book_content()
@@ -178,28 +178,28 @@ class BookTest extends TestCase
         $chapter = $book->chapters->first();
 
         $resp = $this->asEditor()->get($chapter->getUrl());
-        $resp->assertElementContains('#sibling-navigation', 'Next');
-        $resp->assertElementContains('#sibling-navigation', substr($chapter->pages[0]->name, 0, 20));
+        $this->withHtml($resp)->assertElementContains('#sibling-navigation', 'Next');
+        $this->withHtml($resp)->assertElementContains('#sibling-navigation', substr($chapter->pages[0]->name, 0, 20));
 
         $resp = $this->get($chapter->pages[0]->getUrl());
-        $resp->assertElementContains('#sibling-navigation', substr($chapter->pages[1]->name, 0, 20));
-        $resp->assertElementContains('#sibling-navigation', 'Previous');
-        $resp->assertElementContains('#sibling-navigation', substr($chapter->name, 0, 20));
+        $this->withHtml($resp)->assertElementContains('#sibling-navigation', substr($chapter->pages[1]->name, 0, 20));
+        $this->withHtml($resp)->assertElementContains('#sibling-navigation', 'Previous');
+        $this->withHtml($resp)->assertElementContains('#sibling-navigation', substr($chapter->name, 0, 20));
     }
 
     public function test_recently_viewed_books_updates_as_expected()
     {
         $books = Book::all()->take(2);
 
-        $this->asAdmin()->get('/books')
-            ->assertElementNotContains('#recents', $books[0]->name)
+        $resp = $this->asAdmin()->get('/books');
+        $this->withHtml($resp)->assertElementNotContains('#recents', $books[0]->name)
             ->assertElementNotContains('#recents', $books[1]->name);
 
         $this->get($books[0]->getUrl());
         $this->get($books[1]->getUrl());
 
-        $this->get('/books')
-            ->assertElementContains('#recents', $books[0]->name)
+        $resp = $this->get('/books');
+        $this->withHtml($resp)->assertElementContains('#recents', $books[0]->name)
             ->assertElementContains('#recents', $books[1]->name);
     }
 
@@ -207,16 +207,16 @@ class BookTest extends TestCase
     {
         $books = Book::all()->take(2);
 
-        $this->asAdmin()->get('/books')
-            ->assertElementNotContains('#popular', $books[0]->name)
+        $resp = $this->asAdmin()->get('/books');
+        $this->withHtml($resp)->assertElementNotContains('#popular', $books[0]->name)
             ->assertElementNotContains('#popular', $books[1]->name);
 
         $this->get($books[0]->getUrl());
         $this->get($books[1]->getUrl());
         $this->get($books[0]->getUrl());
 
-        $this->get('/books')
-            ->assertElementContains('#popular .book:nth-child(1)', $books[0]->name)
+        $resp = $this->get('/books');
+        $this->withHtml($resp)->assertElementContains('#popular .book:nth-child(1)', $books[0]->name)
             ->assertElementContains('#popular .book:nth-child(2)', $books[1]->name);
     }
 
@@ -227,16 +227,16 @@ class BookTest extends TestCase
         setting()->putUser($editor, 'books_view_type', 'list');
 
         $resp = $this->actingAs($editor)->get('/books');
-        $resp->assertElementContains('form[action$="/settings/users/' . $editor->id . '/switch-books-view"]', 'Grid View');
-        $resp->assertElementExists('input[name="view_type"][value="grid"]');
+        $this->withHtml($resp)->assertElementContains('form[action$="/settings/users/' . $editor->id . '/switch-books-view"]', 'Grid View');
+        $this->withHtml($resp)->assertElementExists('input[name="view_type"][value="grid"]');
 
         $resp = $this->patch("/settings/users/{$editor->id}/switch-books-view", ['view_type' => 'grid']);
         $resp->assertRedirect();
         $this->assertEquals('grid', setting()->getUser($editor, 'books_view_type'));
 
         $resp = $this->actingAs($editor)->get('/books');
-        $resp->assertElementContains('form[action$="/settings/users/' . $editor->id . '/switch-books-view"]', 'List View');
-        $resp->assertElementExists('input[name="view_type"][value="list"]');
+        $this->withHtml($resp)->assertElementContains('form[action$="/settings/users/' . $editor->id . '/switch-books-view"]', 'List View');
+        $this->withHtml($resp)->assertElementExists('input[name="view_type"][value="list"]');
 
         $resp = $this->patch("/settings/users/{$editor->id}/switch-books-view", ['view_type' => 'list']);
         $resp->assertRedirect();
@@ -273,7 +273,7 @@ class BookTest extends TestCase
         $book = Book::query()->first();
         $resp = $this->asEditor()->get($book->getUrl());
 
-        $resp->assertElementContains("a[href=\"{$book->getUrl('/copy')}\"]", 'Copy');
+        $this->withHtml($resp)->assertElementContains("a[href=\"{$book->getUrl('/copy')}\"]", 'Copy');
     }
 
     public function test_copy_view()
@@ -284,7 +284,7 @@ class BookTest extends TestCase
 
         $resp->assertOk();
         $resp->assertSee('Copy Book');
-        $resp->assertElementExists("input[name=\"name\"][value=\"{$book->name}\"]");
+        $this->withHtml($resp)->assertElementExists("input[name=\"name\"][value=\"{$book->name}\"]");
     }
 
     public function test_copy()
index f099ca2bbcbb3197a1bf409caba3b512e60857b9..5a761b94fdb67b5e1fb2f684e57b88aca761b140 100644 (file)
@@ -19,10 +19,10 @@ class ChapterTest extends TestCase
         ]);
 
         $resp = $this->asEditor()->get($book->getUrl());
-        $resp->assertElementContains('a[href="' . $book->getUrl('/create-chapter') . '"]', 'New Chapter');
+        $this->withHtml($resp)->assertElementContains('a[href="' . $book->getUrl('/create-chapter') . '"]', 'New Chapter');
 
         $resp = $this->get($book->getUrl('/create-chapter'));
-        $resp->assertElementContains('form[action="' . $book->getUrl('/create-chapter') . '"][method="POST"]', 'Save Chapter');
+        $this->withHtml($resp)->assertElementContains('form[action="' . $book->getUrl('/create-chapter') . '"][method="POST"]', 'Save Chapter');
 
         $resp = $this->post($book->getUrl('/create-chapter'), $chapter->only('name', 'description'));
         $resp->assertRedirect($book->getUrl('/chapter/my-first-chapter'));
@@ -53,7 +53,7 @@ class ChapterTest extends TestCase
         $this->assertTrue($chapter->deletions()->count() === 1);
 
         $redirectReq = $this->get($deleteReq->baseResponse->headers->get('location'));
-        $redirectReq->assertNotificationContains('Chapter Successfully Deleted');
+        $this->assertNotificationContains($redirectReq, 'Chapter Successfully Deleted');
     }
 
     public function test_show_view_has_copy_button()
@@ -62,7 +62,7 @@ class ChapterTest extends TestCase
         $chapter = Chapter::query()->first();
 
         $resp = $this->asEditor()->get($chapter->getUrl());
-        $resp->assertElementContains("a[href$=\"{$chapter->getUrl('/copy')}\"]", 'Copy');
+        $this->withHtml($resp)->assertElementContains("a[href$=\"{$chapter->getUrl('/copy')}\"]", 'Copy');
     }
 
     public function test_copy_view()
@@ -73,8 +73,8 @@ class ChapterTest extends TestCase
         $resp = $this->asEditor()->get($chapter->getUrl('/copy'));
         $resp->assertOk();
         $resp->assertSee('Copy Chapter');
-        $resp->assertElementExists("input[name=\"name\"][value=\"{$chapter->name}\"]");
-        $resp->assertElementExists('input[name="entity_selection"]');
+        $this->withHtml($resp)->assertElementExists("input[name=\"name\"][value=\"{$chapter->name}\"]");
+        $this->withHtml($resp)->assertElementExists('input[name="entity_selection"]');
     }
 
     public function test_copy()
index 23607f5a70f423b182946a06db0d2f3b4fee3778..0e3199979000b899d69fc5ac7c5fb5600eb10fe0 100644 (file)
@@ -20,8 +20,8 @@ class CommentSettingTest extends TestCase
         $this->setSettings(['app-disable-comments' => 'true']);
         $this->asAdmin();
 
-        $this->asAdmin()->get($this->page->getUrl())
-            ->assertElementNotExists('.comments-list');
+        $resp = $this->asAdmin()->get($this->page->getUrl());
+        $this->withHtml($resp)->assertElementNotExists('.comments-list');
     }
 
     public function test_comment_enable()
@@ -29,7 +29,7 @@ class CommentSettingTest extends TestCase
         $this->setSettings(['app-disable-comments' => 'false']);
         $this->asAdmin();
 
-        $this->asAdmin()->get($this->page->getUrl())
-            ->assertElementExists('.comments-list');
+        $resp = $this->asAdmin()->get($this->page->getUrl());
+        $this->withHtml($resp)->assertElementExists('.comments-list');
     }
 }
index 9791f77e44979f408049327db2b3675748127eaf..58f694f604adc9cbbd51dadc7a7982554bc536ad 100644 (file)
@@ -20,7 +20,7 @@ class ConvertTest extends TestCase
         $resp = $this->asEditor()->get($chapter->getUrl('/edit'));
         $resp->assertSee('Convert to Book');
         $resp->assertSee('Convert Chapter');
-        $resp->assertElementExists('form[action$="/convert-to-book"] button');
+        $this->withHtml($resp)->assertElementExists('form[action$="/convert-to-book"] button');
     }
 
     public function test_convert_chapter_to_book()
@@ -77,7 +77,7 @@ class ConvertTest extends TestCase
         $resp->assertSee('Convert to Shelf');
         $resp->assertSee('Convert Book');
         $resp->assertSee('Note that permissions on shelves do not auto-cascade to content');
-        $resp->assertElementExists('form[action$="/convert-to-shelf"] button');
+        $this->withHtml($resp)->assertElementExists('form[action$="/convert-to-shelf"] button');
     }
 
     public function test_book_convert_to_shelf()
index a23a2fd26d8fe39dad85d87584230be1ff400348..3a9b9f31ba477585092f1f9fbcccc1f35fa5d14d 100644 (file)
@@ -237,12 +237,12 @@ class EntitySearchTest extends TestCase
         $searchUrl = '/ajax/search/entities?permission=update&term=' . urlencode($page->name);
 
         $resp = $this->asEditor()->get($searchUrl);
-        $resp->assertElementContains($baseSelector, $page->name);
-        $resp->assertElementNotContains($baseSelector, "You don't have the required permissions to select this item");
+        $this->withHtml($resp)->assertElementContains($baseSelector, $page->name);
+        $this->withHtml($resp)->assertElementNotContains($baseSelector, "You don't have the required permissions to select this item");
 
         $resp = $this->actingAs($this->getViewer())->get($searchUrl);
-        $resp->assertElementContains($baseSelector, $page->name);
-        $resp->assertElementContains($baseSelector, "You don't have the required permissions to select this item");
+        $this->withHtml($resp)->assertElementContains($baseSelector, $page->name);
+        $this->withHtml($resp)->assertElementContains($baseSelector, "You don't have the required permissions to select this item");
     }
 
     public function test_sibling_search_for_pages()
@@ -338,16 +338,16 @@ class EntitySearchTest extends TestCase
         $this->newPage(['name' => 'Test page B', 'html' => '<p>cat biscuit</p>']);
 
         $search = $this->asEditor()->get('/search?term=cat+dog+biscuit');
-        $search->assertElementContains('.entity-list > .page', 'Test page A', 1);
-        $search->assertElementContains('.entity-list > .page', 'Test page B', 2);
+        $this->withHtml($search)->assertElementContains('.entity-list > .page:nth-child(1)', 'Test page A');
+        $this->withHtml($search)->assertElementContains('.entity-list > .page:nth-child(2)', 'Test page B');
 
         for ($i = 0; $i < 2; $i++) {
             $this->newPage(['name' => 'Test page ' . $i, 'html' => '<p>dog</p>']);
         }
 
         $search = $this->asEditor()->get('/search?term=cat+dog+biscuit');
-        $search->assertElementContains('.entity-list > .page', 'Test page B', 1);
-        $search->assertElementContains('.entity-list > .page', 'Test page A', 2);
+        $this->withHtml($search)->assertElementContains('.entity-list > .page:nth-child(1)', 'Test page B');
+        $this->withHtml($search)->assertElementContains('.entity-list > .page:nth-child(2)', 'Test page A');
     }
 
     public function test_terms_in_headers_have_an_adjusted_index_score()
@@ -413,9 +413,9 @@ class EntitySearchTest extends TestCase
         // Content
         $search->assertSee('A <strong>superimportant</strong> page about <strong>meowie</strong>able animals', false);
         // Tag name
-        $search->assertElementContains('.tag-name.highlight', 'SuperImportant');
+        $this->withHtml($search)->assertElementContains('.tag-name.highlight', 'SuperImportant');
         // Tag value
-        $search->assertElementContains('.tag-value.highlight', 'MeowieCat');
+        $this->withHtml($search)->assertElementContains('.tag-value.highlight', 'MeowieCat');
     }
 
     public function test_match_highlighting_works_with_multibyte_content()
@@ -452,7 +452,7 @@ class EntitySearchTest extends TestCase
     public function test_searches_with_user_filters_adds_them_into_advanced_search_form()
     {
         $resp = $this->asEditor()->get('/search?term=' . urlencode('test {updated_by:me} {created_by:dan}'));
-        $resp->assertElementExists('form input[type="hidden"][name="filters[updated_by]"][value="me"]');
-        $resp->assertElementExists('form input[type="hidden"][name="filters[created_by]"][value="dan"]');
+        $this->withHtml($resp)->assertElementExists('form input[type="hidden"][name="filters[updated_by]"][value="me"]');
+        $this->withHtml($resp)->assertElementExists('form input[type="hidden"][name="filters[created_by]"][value="dan"]');
     }
 }
index 826b69be5d22b307882ba9e4385fd85d599c8a99..0d13d208e9f0409fe2006c4471e1ea738a5008d9 100644 (file)
@@ -454,7 +454,7 @@ class ExportTest extends TestCase
 
         foreach ($entities as $entity) {
             $resp = $this->asEditor()->get($entity->getUrl('/export/html'));
-            $resp->assertElementExists('head meta[http-equiv="Content-Security-Policy"][content*="script-src "]');
+            $this->withHtml($resp)->assertElementExists('head meta[http-equiv="Content-Security-Policy"][content*="script-src "]');
         }
     }
 
@@ -463,6 +463,6 @@ class ExportTest extends TestCase
         $page = Page::query()->first();
 
         $resp = $this->asEditor()->get($page->getUrl('/export/html'));
-        $resp->assertElementExists('body.export.export-format-html.export-engine-none');
+        $this->withHtml($resp)->assertElementExists('body.export.export-format-html.export-engine-none');
     }
 }
index c18ae18f7ea3d7032e741e7ca2c6b3b30d2f2d91..d433c8b8805c68df652b691d6332c099fb447214 100644 (file)
@@ -149,8 +149,8 @@ class PageContentTest extends TestCase
 
             $pageView = $this->get($page->getUrl());
             $pageView->assertStatus(200);
-            $pageView->assertElementNotContains('.page-content', '<script>');
-            $pageView->assertElementNotContains('.page-content', '</script>');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', '<script>');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', '</script>');
         }
     }
 
@@ -185,13 +185,14 @@ class PageContentTest extends TestCase
 
             $pageView = $this->get($page->getUrl());
             $pageView->assertStatus(200);
-            $pageView->assertElementNotContains('.page-content', '<iframe>');
-            $pageView->assertElementNotContains('.page-content', '<img');
-            $pageView->assertElementNotContains('.page-content', '</iframe>');
-            $pageView->assertElementNotContains('.page-content', 'src=');
-            $pageView->assertElementNotContains('.page-content', 'javascript:');
-            $pageView->assertElementNotContains('.page-content', 'data:');
-            $pageView->assertElementNotContains('.page-content', 'base64');
+            $html = $this->withHtml($pageView);
+            $html->assertElementNotContains('.page-content', '<iframe>');
+            $html->assertElementNotContains('.page-content', '<img');
+            $html->assertElementNotContains('.page-content', '</iframe>');
+            $html->assertElementNotContains('.page-content', 'src=');
+            $html->assertElementNotContains('.page-content', 'javascript:');
+            $html->assertElementNotContains('.page-content', 'data:');
+            $html->assertElementNotContains('.page-content', 'base64');
         }
     }
 
@@ -213,8 +214,8 @@ class PageContentTest extends TestCase
 
             $pageView = $this->get($page->getUrl());
             $pageView->assertStatus(200);
-            $pageView->assertElementNotContains('.page-content', '<a id="xss"');
-            $pageView->assertElementNotContains('.page-content', 'href=javascript:');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', '<a id="xss"');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', 'href=javascript:');
         }
     }
 
@@ -237,11 +238,11 @@ class PageContentTest extends TestCase
 
             $pageView = $this->get($page->getUrl());
             $pageView->assertStatus(200);
-            $pageView->assertElementNotContains('.page-content', '<button id="xss"');
-            $pageView->assertElementNotContains('.page-content', '<input id="xss"');
-            $pageView->assertElementNotContains('.page-content', '<form id="xss"');
-            $pageView->assertElementNotContains('.page-content', 'action=javascript:');
-            $pageView->assertElementNotContains('.page-content', 'formaction=javascript:');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', '<button id="xss"');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', '<input id="xss"');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', '<form id="xss"');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', 'action=javascript:');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', 'formaction=javascript:');
         }
     }
 
@@ -262,10 +263,10 @@ class PageContentTest extends TestCase
 
             $pageView = $this->get($page->getUrl());
             $pageView->assertStatus(200);
-            $pageView->assertElementNotContains('.page-content', '<meta>');
-            $pageView->assertElementNotContains('.page-content', '</meta>');
-            $pageView->assertElementNotContains('.page-content', 'content=');
-            $pageView->assertElementNotContains('.page-content', 'external_url');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', '<meta>');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', '</meta>');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', 'content=');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', 'external_url');
         }
     }
 
@@ -305,7 +306,7 @@ class PageContentTest extends TestCase
 
             $pageView = $this->get($page->getUrl());
             $pageView->assertStatus(200);
-            $pageView->assertElementNotContains('.page-content', 'onclick');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', 'onclick');
         }
     }
 
@@ -340,9 +341,9 @@ class PageContentTest extends TestCase
 
             $pageView = $this->get($page->getUrl());
             $pageView->assertStatus(200);
-            $pageView->assertElementNotContains('.page-content', 'alert');
-            $pageView->assertElementNotContains('.page-content', 'xlink:href');
-            $pageView->assertElementNotContains('.page-content', 'application/xml');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', 'alert');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', 'xlink:href');
+            $this->withHtml($pageView)->assertElementNotContains('.page-content', 'application/xml');
         }
     }
 
@@ -506,7 +507,7 @@ class PageContentTest extends TestCase
         $this->assertStringContainsString('</tbody>', $page->html);
 
         $pageView = $this->get($page->getUrl());
-        $pageView->assertElementExists('.page-content table tbody td');
+        $this->withHtml($pageView)->assertElementExists('.page-content table tbody td');
     }
 
     public function test_page_markdown_task_list_rendering()
@@ -526,8 +527,8 @@ class PageContentTest extends TestCase
         $this->assertStringContainsString('type="checkbox"', $page->html);
 
         $pageView = $this->get($page->getUrl());
-        $pageView->assertElementExists('.page-content li.task-list-item input[type=checkbox]');
-        $pageView->assertElementExists('.page-content li.task-list-item input[type=checkbox][checked]');
+        $this->withHtml($pageView)->assertElementExists('.page-content li.task-list-item input[type=checkbox]');
+        $this->withHtml($pageView)->assertElementExists('.page-content li.task-list-item input[type=checkbox][checked]');
     }
 
     public function test_page_markdown_strikethrough_rendering()
@@ -545,7 +546,7 @@ class PageContentTest extends TestCase
         $this->assertStringMatchesFormat('%A<s%A>some crossed out text</s>%A', $page->html);
 
         $pageView = $this->get($page->getUrl());
-        $pageView->assertElementExists('.page-content p > s');
+        $this->withHtml($pageView)->assertElementExists('.page-content p > s');
     }
 
     public function test_page_markdown_single_html_comment_saving()
index cac1babea708f3340ac69e41f17f8cf5e582a88b..0b44e5f0b8eaa7d252619c5c886f241c9d02903a 100644 (file)
@@ -31,27 +31,27 @@ class PageDraftTest extends TestCase
     {
         $addedContent = '<p>test message content</p>';
 
-        $this->asAdmin()->get($this->page->getUrl('/edit'))
-            ->assertElementNotContains('[name="html"]', $addedContent);
+        $resp = $this->asAdmin()->get($this->page->getUrl('/edit'));
+        $this->withHtml($resp)->assertElementNotContains('[name="html"]', $addedContent);
 
         $newContent = $this->page->html . $addedContent;
         $this->pageRepo->updatePageDraft($this->page, ['html' => $newContent]);
-        $this->asAdmin()->get($this->page->getUrl('/edit'))
-            ->assertElementContains('[name="html"]', $newContent);
+        $resp = $this->asAdmin()->get($this->page->getUrl('/edit'));
+        $this->withHtml($resp)->assertElementContains('[name="html"]', $newContent);
     }
 
     public function test_draft_not_visible_by_others()
     {
         $addedContent = '<p>test message content</p>';
-        $this->asAdmin()->get($this->page->getUrl('/edit'))
-            ->assertElementNotContains('[name="html"]', $addedContent);
+        $resp = $this->asAdmin()->get($this->page->getUrl('/edit'));
+        $this->withHtml($resp)->assertElementNotContains('[name="html"]', $addedContent);
 
         $newContent = $this->page->html . $addedContent;
         $newUser = $this->getEditor();
         $this->pageRepo->updatePageDraft($this->page, ['html' => $newContent]);
 
-        $this->actingAs($newUser)->get($this->page->getUrl('/edit'))
-            ->assertElementNotContains('[name="html"]', $newContent);
+        $resp = $this->actingAs($newUser)->get($this->page->getUrl('/edit'));
+        $this->withHtml($resp)->assertElementNotContains('[name="html"]', $newContent);
     }
 
     public function test_alert_message_shows_if_editing_draft()
@@ -66,8 +66,8 @@ class PageDraftTest extends TestCase
     {
         $nonEditedPage = Page::query()->take(10)->get()->last();
         $addedContent = '<p>test message content</p>';
-        $this->asAdmin()->get($this->page->getUrl('/edit'))
-            ->assertElementNotContains('[name="html"]', $addedContent);
+        $resp = $this->asAdmin()->get($this->page->getUrl('/edit'));
+        $this->withHtml($resp)->assertElementNotContains('[name="html"]', $addedContent);
 
         $newContent = $this->page->html . $addedContent;
         $newUser = $this->getEditor();
@@ -77,8 +77,8 @@ class PageDraftTest extends TestCase
             ->get($this->page->getUrl('/edit'))
             ->assertSee('Admin has started editing this page');
         $this->flushSession();
-        $this->get($nonEditedPage->getUrl() . '/edit')
-            ->assertElementNotContains('.notification', 'Admin has started editing this page');
+        $resp = $this->get($nonEditedPage->getUrl() . '/edit');
+        $this->withHtml($resp)->assertElementNotContains('.notification', 'Admin has started editing this page');
     }
 
     public function test_draft_save_shows_alert_if_draft_older_than_last_page_update()
@@ -142,12 +142,12 @@ class PageDraftTest extends TestCase
     {
         /** @var Book $book */
         $book = Book::query()->first();
-        $this->asAdmin()->get('/')
-            ->assertElementNotContains('#recent-drafts', 'New Page');
+        $resp = $this->asAdmin()->get('/');
+        $this->withHtml($resp)->assertElementNotContains('#recent-drafts', 'New Page');
 
         $this->get($book->getUrl() . '/create-page');
 
-        $this->get('/')->assertElementContains('#recent-drafts', 'New Page');
+        $this->withHtml($this->get('/'))->assertElementContains('#recent-drafts', 'New Page');
     }
 
     public function test_draft_pages_not_visible_by_others()
@@ -159,13 +159,13 @@ class PageDraftTest extends TestCase
 
         $this->actingAs($newUser)->get($book->getUrl('/create-page'));
         $this->get($chapter->getUrl('/create-page'));
-        $this->get($book->getUrl())
-            ->assertElementContains('.book-contents', 'New Page');
+        $resp = $this->get($book->getUrl());
+        $this->withHtml($resp)->assertElementContains('.book-contents', 'New Page');
 
-        $this->asAdmin()->get($book->getUrl())
-            ->assertElementNotContains('.book-contents', 'New Page');
-        $this->get($chapter->getUrl())
-            ->assertElementNotContains('.book-contents', 'New Page');
+        $resp = $this->asAdmin()->get($book->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.book-contents', 'New Page');
+        $resp = $this->get($chapter->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.book-contents', 'New Page');
     }
 
     public function test_page_html_in_ajax_fetch_response()
index d4e5654359860098dfaf3fbd3008390ac53231d9..e5aa549b35e6d8f5b9a98e897872d835d6ec04b4 100644 (file)
@@ -22,7 +22,7 @@ class PageEditorTest extends TestCase
     {
         $this->assertEquals('wysiwyg', setting('app-editor'));
         $resp = $this->asAdmin()->get($this->page->book->getUrl('/create-page'));
-        $this->followRedirects($resp)->assertElementExists('#html-editor');
+        $this->withHtml($this->followRedirects($resp))->assertElementExists('#html-editor');
     }
 
     public function test_markdown_setting_shows_markdown_editor_for_new_pages()
@@ -30,7 +30,7 @@ class PageEditorTest extends TestCase
         $this->setSettings(['app-editor' => 'markdown']);
 
         $resp = $this->asAdmin()->get($this->page->book->getUrl('/create-page'));
-        $this->followRedirects($resp)
+        $this->withHtml($this->followRedirects($resp))
             ->assertElementNotExists('#html-editor')
             ->assertElementExists('#markdown-editor');
     }
@@ -42,8 +42,8 @@ class PageEditorTest extends TestCase
         $this->page->editor = 'markdown';
         $this->page->save();
 
-        $this->asAdmin()->get($this->page->getUrl('/edit'))
-            ->assertElementContains('[name="markdown"]', $mdContent);
+        $resp = $this->asAdmin()->get($this->page->getUrl('/edit'));
+        $this->withHtml($resp)->assertElementContains('[name="markdown"]', $mdContent);
     }
 
     public function test_html_content_given_to_editor_if_no_markdown()
@@ -51,8 +51,8 @@ class PageEditorTest extends TestCase
         $this->page->editor = 'markdown';
         $this->page->save();
 
-        $this->asAdmin()->get($this->page->getUrl() . '/edit')
-            ->assertElementContains('[name="markdown"]', $this->page->html);
+        $resp = $this->asAdmin()->get($this->page->getUrl() . '/edit');
+        $this->withHtml($resp)->assertElementContains('[name="markdown"]', $this->page->html);
     }
 
     public function test_empty_markdown_still_saves_without_error()
@@ -91,19 +91,19 @@ class PageEditorTest extends TestCase
 
         // Book draft goes back to book
         $resp = $this->get($book->getUrl("/draft/{$draft->id}"));
-        $resp->assertElementContains('a[href="' . $book->getUrl() . '"]', 'Back');
+        $this->withHtml($resp)->assertElementContains('a[href="' . $book->getUrl() . '"]', 'Back');
 
         // Chapter draft goes back to chapter
         $draft->chapter_id = $chapter->id;
         $draft->save();
         $resp = $this->get($book->getUrl("/draft/{$draft->id}"));
-        $resp->assertElementContains('a[href="' . $chapter->getUrl() . '"]', 'Back');
+        $this->withHtml($resp)->assertElementContains('a[href="' . $chapter->getUrl() . '"]', 'Back');
 
         // Saved page goes back to page
         $this->post($book->getUrl("/draft/{$draft->id}"), ['name' => 'Updated', 'html' => 'Updated']);
         $draft->refresh();
         $resp = $this->get($draft->getUrl('/edit'));
-        $resp->assertElementContains('a[href="' . $draft->getUrl() . '"]', 'Back');
+        $this->withHtml($resp)->assertElementContains('a[href="' . $draft->getUrl() . '"]', 'Back');
     }
 
     public function test_switching_from_html_to_clean_markdown_works()
@@ -116,7 +116,7 @@ class PageEditorTest extends TestCase
         $resp = $this->asAdmin()->get($page->getUrl('/edit?editor=markdown-clean'));
         $resp->assertStatus(200);
         $resp->assertSee("## A Header\n\nSome **bold** content.");
-        $resp->assertElementExists('#markdown-editor');
+        $this->withHtml($resp)->assertElementExists('#markdown-editor');
     }
 
     public function test_switching_from_html_to_stable_markdown_works()
@@ -129,7 +129,7 @@ class PageEditorTest extends TestCase
         $resp = $this->asAdmin()->get($page->getUrl('/edit?editor=markdown-stable'));
         $resp->assertStatus(200);
         $resp->assertSee('<h2>A Header</h2><p>Some <strong>bold</strong> content.</p>', true);
-        $resp->assertElementExists('[component="markdown-editor"]');
+        $this->withHtml($resp)->assertElementExists('[component="markdown-editor"]');
     }
 
     public function test_switching_from_markdown_to_wysiwyg_works()
@@ -142,40 +142,40 @@ class PageEditorTest extends TestCase
 
         $resp = $this->asAdmin()->get($page->getUrl('/edit?editor=wysiwyg'));
         $resp->assertStatus(200);
-        $resp->assertElementExists('[component="wysiwyg-editor"]');
+        $this->withHtml($resp)->assertElementExists('[component="wysiwyg-editor"]');
         $resp->assertSee("<h2>A Header</h2>\n<p>Some content with <strong>bold</strong> text!</p>", true);
     }
 
     public function test_page_editor_changes_with_editor_property()
     {
         $resp = $this->asAdmin()->get($this->page->getUrl('/edit'));
-        $resp->assertElementExists('[component="wysiwyg-editor"]');
+        $this->withHtml($resp)->assertElementExists('[component="wysiwyg-editor"]');
 
         $this->page->markdown = "## A Header\n\nSome content with **bold** text!";
         $this->page->editor = 'markdown';
         $this->page->save();
 
         $resp = $this->asAdmin()->get($this->page->getUrl('/edit'));
-        $resp->assertElementExists('[component="markdown-editor"]');
+        $this->withHtml($resp)->assertElementExists('[component="markdown-editor"]');
     }
 
     public function test_editor_type_switch_options_show()
     {
         $resp = $this->asAdmin()->get($this->page->getUrl('/edit'));
         $editLink = $this->page->getUrl('/edit') . '?editor=';
-        $resp->assertElementContains("a[href=\"${editLink}markdown-clean\"]", '(Clean Content)');
-        $resp->assertElementContains("a[href=\"${editLink}markdown-stable\"]", '(Stable Content)');
+        $this->withHtml($resp)->assertElementContains("a[href=\"${editLink}markdown-clean\"]", '(Clean Content)');
+        $this->withHtml($resp)->assertElementContains("a[href=\"${editLink}markdown-stable\"]", '(Stable Content)');
 
         $resp = $this->asAdmin()->get($this->page->getUrl('/edit?editor=markdown-stable'));
         $editLink = $this->page->getUrl('/edit') . '?editor=';
-        $resp->assertElementContains("a[href=\"${editLink}wysiwyg\"]", 'Switch to WYSIWYG Editor');
+        $this->withHtml($resp)->assertElementContains("a[href=\"${editLink}wysiwyg\"]", 'Switch to WYSIWYG Editor');
     }
 
     public function test_editor_type_switch_options_dont_show_if_without_change_editor_permissions()
     {
         $resp = $this->asEditor()->get($this->page->getUrl('/edit'));
         $editLink = $this->page->getUrl('/edit') . '?editor=';
-        $resp->assertElementNotExists("a[href*=\"${editLink}\"]");
+        $this->withHtml($resp)->assertElementNotExists("a[href*=\"${editLink}\"]");
     }
 
     public function test_page_editor_type_switch_does_not_work_without_change_editor_permissions()
@@ -187,8 +187,8 @@ class PageEditorTest extends TestCase
 
         $resp = $this->asEditor()->get($page->getUrl('/edit?editor=markdown-stable'));
         $resp->assertStatus(200);
-        $resp->assertElementExists('[component="wysiwyg-editor"]');
-        $resp->assertElementNotExists('[component="markdown-editor"]');
+        $this->withHtml($resp)->assertElementExists('[component="wysiwyg-editor"]');
+        $this->withHtml($resp)->assertElementNotExists('[component="markdown-editor"]');
     }
 
     public function test_page_save_does_not_change_active_editor_without_change_editor_permissions()
index ce203ea36d65a1805e13b4d106b2dc7dd5849d32..cc49002492cdbafd44128e905b5676de54c3e8b7 100644 (file)
@@ -211,11 +211,11 @@ class PageRevisionTest extends TestCase
         $this->asAdmin()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html']);
 
         $resp = $this->get($page->refresh()->getUrl('/revisions'));
-        $resp->assertElementContains('td', '(WYSIWYG)');
-        $resp->assertElementNotContains('td', '(Markdown)');
+        $this->withHtml($resp)->assertElementContains('td', '(WYSIWYG)');
+        $this->withHtml($resp)->assertElementNotContains('td', '(Markdown)');
 
         $this->asAdmin()->put($page->getUrl(), ['name' => 'Updated page', 'markdown' => '# Some markdown content']);
         $resp = $this->get($page->refresh()->getUrl('/revisions'));
-        $resp->assertElementContains('td', '(Markdown)');
+        $this->withHtml($resp)->assertElementContains('td', '(Markdown)');
     }
 }
index efe5400a0f6f8b2701a17d670927a5b116fa3a18..734516e872271ed6a6f22bf33377fe1ffcc41a42 100644 (file)
@@ -19,7 +19,7 @@ class PageTest extends TestCase
         ]);
 
         $resp = $this->asEditor()->get($chapter->getUrl());
-        $resp->assertElementContains('a[href="' . $chapter->getUrl('/create-page') . '"]', 'New Page');
+        $this->withHtml($resp)->assertElementContains('a[href="' . $chapter->getUrl('/create-page') . '"]', 'New Page');
 
         $resp = $this->get($chapter->getUrl('/create-page'));
         /** @var Page $draftPage */
@@ -30,7 +30,7 @@ class PageTest extends TestCase
         $resp->assertRedirect($draftPage->getUrl());
 
         $resp = $this->get($draftPage->getUrl());
-        $resp->assertElementContains('form[action="' . $draftPage->getUrl() . '"][method="POST"]', 'Save Page');
+        $this->withHtml($resp)->assertElementContains('form[action="' . $draftPage->getUrl() . '"][method="POST"]', 'Save Page');
 
         $resp = $this->post($draftPage->getUrl(), $draftPage->only('name', 'html'));
         $draftPage->refresh();
@@ -98,7 +98,7 @@ class PageTest extends TestCase
         $this->assertTrue($page->deletions()->count() === 1);
 
         $redirectReq = $this->get($deleteReq->baseResponse->headers->get('location'));
-        $redirectReq->assertNotificationContains('Page Successfully Deleted');
+        $this->assertNotificationContains($redirectReq, 'Page Successfully Deleted');
     }
 
     public function test_page_full_delete_removes_all_revisions()
@@ -257,8 +257,8 @@ class PageTest extends TestCase
         $user = $this->getEditor();
         $content = $this->createEntityChainBelongingToUser($user);
 
-        $this->asAdmin()->get('/pages/recently-updated')
-            ->assertElementContains('.entity-list .page:nth-child(1)', $content['page']->name);
+        $resp = $this->asAdmin()->get('/pages/recently-updated');
+        $this->withHtml($resp)->assertElementContains('.entity-list .page:nth-child(1)', $content['page']->name);
     }
 
     public function test_recently_updated_pages_view_shows_updated_by_details()
@@ -273,7 +273,7 @@ class PageTest extends TestCase
         ]);
 
         $resp = $this->asAdmin()->get('/pages/recently-updated');
-        $resp->assertElementContains('.entity-list .page:nth-child(1)', 'Updated 1 second ago by ' . $user->name);
+        $this->withHtml($resp)->assertElementContains('.entity-list .page:nth-child(1)', 'Updated 1 second ago by ' . $user->name);
     }
 
     public function test_recently_updated_pages_view_shows_parent_chain()
@@ -288,8 +288,8 @@ class PageTest extends TestCase
         ]);
 
         $resp = $this->asAdmin()->get('/pages/recently-updated');
-        $resp->assertElementContains('.entity-list .page:nth-child(1)', $page->chapter->getShortName(42));
-        $resp->assertElementContains('.entity-list .page:nth-child(1)', $page->book->getShortName(42));
+        $this->withHtml($resp)->assertElementContains('.entity-list .page:nth-child(1)', $page->chapter->getShortName(42));
+        $this->withHtml($resp)->assertElementContains('.entity-list .page:nth-child(1)', $page->book->getShortName(42));
     }
 
     public function test_recently_updated_pages_view_does_not_show_parent_if_not_visible()
@@ -309,7 +309,7 @@ class PageTest extends TestCase
         $resp = $this->get('/pages/recently-updated');
         $resp->assertDontSee($page->book->getShortName(42));
         $resp->assertDontSee($page->chapter->getShortName(42));
-        $resp->assertElementContains('.entity-list .page:nth-child(1)', 'Updated title');
+        $this->withHtml($resp)->assertElementContains('.entity-list .page:nth-child(1)', 'Updated title');
     }
 
     public function test_recently_updated_pages_on_home()
@@ -320,15 +320,15 @@ class PageTest extends TestCase
             'updated_at' => Carbon::now()->subSecond(1),
         ]);
 
-        $this->asAdmin()->get('/')
-            ->assertElementNotContains('#recently-updated-pages', $page->name);
+        $resp = $this->asAdmin()->get('/');
+        $this->withHtml($resp)->assertElementNotContains('#recently-updated-pages', $page->name);
 
         $this->put($page->getUrl(), [
             'name' => $page->name,
             'html' => $page->html,
         ]);
 
-        $this->get('/')
-            ->assertElementContains('#recently-updated-pages', $page->name);
+        $resp = $this->get('/');
+        $this->withHtml($resp)->assertElementContains('#recently-updated-pages', $page->name);
     }
 }
index 7b10278b06c8f422015af0630fcf5473a6caaa68..8792e70db31b57d2b678d625533a51af83c4f67a 100644 (file)
@@ -247,7 +247,7 @@ class SortTest extends TestCase
         $bookToSort = Book::query()->first();
 
         $resp = $this->asAdmin()->get($bookToSort->getUrl());
-        $resp->assertElementExists('a[href="' . $bookToSort->getUrl('/sort') . '"]');
+        $this->withHtml($resp)->assertElementExists('a[href="' . $bookToSort->getUrl('/sort') . '"]');
 
         $resp = $this->get($bookToSort->getUrl('/sort'));
         $resp->assertStatus(200);
@@ -456,14 +456,14 @@ class SortTest extends TestCase
         $book->pages()->whereNotIn('id', $pages->pluck('id'))->delete();
 
         $resp = $this->asEditor()->get($book->getUrl());
-        $resp->assertElementContains('.content-wrap a.page:nth-child(1)', $pages[0]->name);
-        $resp->assertElementContains('.content-wrap a.page:nth-child(2)', $pages[1]->name);
+        $this->withHtml($resp)->assertElementContains('.content-wrap a.page:nth-child(1)', $pages[0]->name);
+        $this->withHtml($resp)->assertElementContains('.content-wrap a.page:nth-child(2)', $pages[1]->name);
 
         $pages[0]->forceFill(['priority' => 10])->save();
         $pages[1]->forceFill(['priority' => 5])->save();
 
         $resp = $this->asEditor()->get($book->getUrl());
-        $resp->assertElementContains('.content-wrap a.page:nth-child(1)', $pages[1]->name);
-        $resp->assertElementContains('.content-wrap a.page:nth-child(2)', $pages[0]->name);
+        $this->withHtml($resp)->assertElementContains('.content-wrap a.page:nth-child(1)', $pages[1]->name);
+        $this->withHtml($resp)->assertElementContains('.content-wrap a.page:nth-child(2)', $pages[0]->name);
     }
 }
index 160dd62d8181c7f08a361502295755b47da02e23..6d03ed95ab24962fccb53b3d457ae94cc7036efa 100644 (file)
@@ -94,10 +94,10 @@ class TagTest extends TestCase
         $page = $this->getEntityWithTags(Page::class, $tags);
         $resp = $this->asEditor()->get('/search?term=[category]');
         $resp->assertSee($page->name);
-        $resp->assertElementContains('[href="' . $page->getUrl() . '"]', 'category');
-        $resp->assertElementContains('[href="' . $page->getUrl() . '"]', 'buckets');
-        $resp->assertElementContains('[href="' . $page->getUrl() . '"]', 'color');
-        $resp->assertElementContains('[href="' . $page->getUrl() . '"]', 'red');
+        $this->withHtml($resp)->assertElementContains('[href="' . $page->getUrl() . '"]', 'category');
+        $this->withHtml($resp)->assertElementContains('[href="' . $page->getUrl() . '"]', 'buckets');
+        $this->withHtml($resp)->assertElementContains('[href="' . $page->getUrl() . '"]', 'color');
+        $this->withHtml($resp)->assertElementContains('[href="' . $page->getUrl() . '"]', 'red');
     }
 
     public function test_tags_index_shows_tag_name_as_expected_with_right_counts()
@@ -109,23 +109,24 @@ class TagTest extends TestCase
 
         $resp = $this->asEditor()->get('/tags');
         $resp->assertSee('Category');
-        $resp->assertElementCount('.tag-item', 1);
+        $html = $this->withHtml($resp);
+        $html->assertElementCount('.tag-item', 1);
         $resp->assertDontSee('GreatTestContent');
         $resp->assertDontSee('OtherTestContent');
-        $resp->assertElementContains('a[title="Total tag usages"]', '2');
-        $resp->assertElementContains('a[title="Assigned to Pages"]', '2');
-        $resp->assertElementContains('a[title="Assigned to Books"]', '0');
-        $resp->assertElementContains('a[title="Assigned to Chapters"]', '0');
-        $resp->assertElementContains('a[title="Assigned to Shelves"]', '0');
-        $resp->assertElementContains('a[href$="/tags?name=Category"]', '2 unique values');
+        $html->assertElementContains('a[title="Total tag usages"]', '2');
+        $html->assertElementContains('a[title="Assigned to Pages"]', '2');
+        $html->assertElementContains('a[title="Assigned to Books"]', '0');
+        $html->assertElementContains('a[title="Assigned to Chapters"]', '0');
+        $html->assertElementContains('a[title="Assigned to Shelves"]', '0');
+        $html->assertElementContains('a[href$="/tags?name=Category"]', '2 unique values');
 
         /** @var Book $book */
         $book = Book::query()->first();
         $book->tags()->create(['name' => 'Category', 'value' => 'GreatTestContent']);
         $resp = $this->asEditor()->get('/tags');
-        $resp->assertElementContains('a[title="Total tag usages"]', '3');
-        $resp->assertElementContains('a[title="Assigned to Books"]', '1');
-        $resp->assertElementContains('a[href$="/tags?name=Category"]', '2 unique values');
+        $this->withHtml($resp)->assertElementContains('a[title="Total tag usages"]', '3');
+        $this->withHtml($resp)->assertElementContains('a[title="Assigned to Books"]', '1');
+        $this->withHtml($resp)->assertElementContains('a[href$="/tags?name=Category"]', '2 unique values');
     }
 
     public function test_tag_index_can_be_searched()
@@ -135,14 +136,14 @@ class TagTest extends TestCase
         $page->tags()->create(['name' => 'Category', 'value' => 'GreatTestContent']);
 
         $resp = $this->asEditor()->get('/tags?search=cat');
-        $resp->assertElementContains('.tag-item .tag-name', 'Category');
+        $this->withHtml($resp)->assertElementContains('.tag-item .tag-name', 'Category');
 
         $resp = $this->asEditor()->get('/tags?search=content');
-        $resp->assertElementContains('.tag-item .tag-name', 'Category');
-        $resp->assertElementContains('.tag-item .tag-value', 'GreatTestContent');
+        $this->withHtml($resp)->assertElementContains('.tag-item .tag-name', 'Category');
+        $this->withHtml($resp)->assertElementContains('.tag-item .tag-value', 'GreatTestContent');
 
         $resp = $this->asEditor()->get('/tags?search=other');
-        $resp->assertElementNotExists('.tag-item .tag-name');
+        $this->withHtml($resp)->assertElementNotExists('.tag-item .tag-name');
     }
 
     public function test_tag_index_search_will_show_mulitple_values_of_a_single_tag_name()
@@ -153,8 +154,8 @@ class TagTest extends TestCase
         $page->tags()->create(['name' => 'Animal', 'value' => 'Catdog']);
 
         $resp = $this->asEditor()->get('/tags?search=cat');
-        $resp->assertElementContains('.tag-item .tag-value', 'Catfish');
-        $resp->assertElementContains('.tag-item .tag-value', 'Catdog');
+        $this->withHtml($resp)->assertElementContains('.tag-item .tag-value', 'Catfish');
+        $this->withHtml($resp)->assertElementContains('.tag-item .tag-value', 'Catdog');
     }
 
     public function test_tag_index_can_be_scoped_to_specific_tag_name()
@@ -170,9 +171,9 @@ class TagTest extends TestCase
         $resp->assertSee('GreatTestContent');
         $resp->assertSee('OtherTestContent');
         $resp->assertDontSee('OtherTagName');
-        $resp->assertElementCount('table .tag-item', 2);
         $resp->assertSee('Active Filter:');
-        $resp->assertElementContains('form[action$="/tags"]', 'Clear Filter');
+        $this->withHtml($resp)->assertElementCount('table .tag-item', 2);
+        $this->withHtml($resp)->assertElementContains('form[action$="/tags"]', 'Clear Filter');
     }
 
     public function test_tags_index_adheres_to_page_permissions()
index a0f11886e5a23760c1e9122f2a76071c7df43df9..6a5c82eab58f64c3edfe2e4e55a0eb4e16aef2e7 100644 (file)
@@ -15,8 +15,8 @@ class FavouriteTest extends TestCase
         $editor = $this->getEditor();
 
         $resp = $this->actingAs($editor)->get($page->getUrl());
-        $resp->assertElementContains('button', 'Favourite');
-        $resp->assertElementExists('form[method="POST"][action$="/favourites/add"]');
+        $this->withHtml($resp)->assertElementContains('button', 'Favourite');
+        $this->withHtml($resp)->assertElementExists('form[method="POST"][action$="/favourites/add"]');
 
         $resp = $this->post('/favourites/add', [
             'type' => get_class($page),
@@ -43,8 +43,8 @@ class FavouriteTest extends TestCase
         ]);
 
         $resp = $this->actingAs($editor)->get($page->getUrl());
-        $resp->assertElementContains('button', 'Unfavourite');
-        $resp->assertElementExists('form[method="POST"][action$="/favourites/remove"]');
+        $this->withHtml($resp)->assertElementContains('button', 'Unfavourite');
+        $this->withHtml($resp)->assertElementExists('form[method="POST"][action$="/favourites/remove"]');
 
         $resp = $this->post('/favourites/remove', [
             'type' => get_class($page),
@@ -69,15 +69,17 @@ class FavouriteTest extends TestCase
 
         foreach ($entities as $entity) {
             $resp = $this->get($entity->getUrl());
-            $resp->assertElementExists('form[method="POST"][action$="/favourites/add"]');
+            $this->withHtml($resp)->assertElementExists('form[method="POST"][action$="/favourites/add"]');
         }
     }
 
     public function test_header_contains_link_to_favourites_page_when_logged_in()
     {
         $this->setSettings(['app-public' => 'true']);
-        $this->get('/')->assertElementNotContains('header', 'My Favourites');
-        $this->actingAs($this->getViewer())->get('/')->assertElementContains('header a', 'My Favourites');
+         $resp = $this->get('/');
+        $this->withHtml($resp)->assertElementNotContains('header', 'My Favourites');
+        $resp = $this->actingAs($this->getViewer())->get('/');
+        $this->withHtml($resp)->assertElementContains('header a', 'My Favourites');
     }
 
     public function test_favourites_shown_on_homepage()
@@ -85,15 +87,15 @@ class FavouriteTest extends TestCase
         $editor = $this->getEditor();
 
         $resp = $this->actingAs($editor)->get('/');
-        $resp->assertElementNotExists('#top-favourites');
+        $this->withHtml($resp)->assertElementNotExists('#top-favourites');
 
         /** @var Page $page */
         $page = Page::query()->first();
         $page->favourites()->save((new Favourite())->forceFill(['user_id' => $editor->id]));
 
         $resp = $this->get('/');
-        $resp->assertElementExists('#top-favourites');
-        $resp->assertElementContains('#top-favourites', $page->name);
+        $this->withHtml($resp)->assertElementExists('#top-favourites');
+        $this->withHtml($resp)->assertElementContains('#top-favourites', $page->name);
     }
 
     public function test_favourites_list_page_shows_favourites_and_has_working_pagination()
index cd983dbebe8de12e6d786f82fb2083e00a1373ac..9cf80717fe088ea43865a67cdddd62d5017b0102 100644 (file)
@@ -8,8 +8,8 @@ class HelpTest extends TestCase
     {
         $resp = $this->get('/help/wysiwyg');
         $resp->assertOk();
-        $resp->assertElementExists('a[href="https://www.tiny.cloud/"]');
-        $resp->assertElementExists('a[href="' . url('/libs/tinymce/license.txt') . '"]');
+        $this->withHtml($resp)->assertElementExists('a[href="https://www.tiny.cloud/"]');
+        $this->withHtml($resp)->assertElementExists('a[href="' . url('/libs/tinymce/license.txt') . '"]');
     }
 
     public function test_tiny_license_exists_where_expected()
index 900650a70537eaddd6da5b4d68a8d28dc91b1155..1d968a2c92fdcf79ea009f6165eafd8a31b6fb01 100644 (file)
@@ -49,7 +49,7 @@ class HomepageTest extends TestCase
 
         $homeVisit = $this->get('/');
         $homeVisit->assertSee($name);
-        $homeVisit->assertElementNotExists('#home-default');
+        $this->withHtml($homeVisit)->assertElementNotExists('#home-default');
 
         $pageDeleteReq = $this->delete($customPage->getUrl());
         $pageDeleteReq->assertStatus(302);
@@ -148,7 +148,7 @@ class HomepageTest extends TestCase
         $homeVisit->assertSee('Shelves');
         $homeVisit->assertSee('grid-card-content');
         $homeVisit->assertSee('featured-image-container');
-        $homeVisit->assertElementContains('.grid-card', $shelf->name);
+        $this->withHtml($homeVisit)->assertElementContains('.grid-card', $shelf->name);
 
         $this->setSettings(['app-homepage-type' => false]);
         $this->test_default_homepage_visible();
@@ -166,21 +166,21 @@ class HomepageTest extends TestCase
 
         // Ensure initially visible
         $homeVisit = $this->get('/');
-        $homeVisit->assertElementContains('.content-wrap', $shelf->name);
-        $homeVisit->assertElementContains('.content-wrap', $book->name);
+        $this->withHtml($homeVisit)->assertElementContains('.content-wrap', $shelf->name);
+        $this->withHtml($homeVisit)->assertElementContains('.content-wrap', $book->name);
 
         // Ensure book no longer visible without view permission
         $editor->roles()->detach();
         $this->giveUserPermissions($editor, ['bookshelf-view-all']);
         $homeVisit = $this->get('/');
-        $homeVisit->assertElementContains('.content-wrap', $shelf->name);
-        $homeVisit->assertElementNotContains('.content-wrap', $book->name);
+        $this->withHtml($homeVisit)->assertElementContains('.content-wrap', $shelf->name);
+        $this->withHtml($homeVisit)->assertElementNotContains('.content-wrap', $book->name);
 
         // Ensure is visible again with entity-level view permission
         $this->setEntityRestrictions($book, ['view'], [$editor->roles()->first()]);
         $homeVisit = $this->get('/');
-        $homeVisit->assertElementContains('.content-wrap', $shelf->name);
-        $homeVisit->assertElementContains('.content-wrap', $book->name);
+        $this->withHtml($homeVisit)->assertElementContains('.content-wrap', $shelf->name);
+        $this->withHtml($homeVisit)->assertElementContains('.content-wrap', $book->name);
     }
 
     public function test_new_users_dont_have_any_recently_viewed()
@@ -190,6 +190,6 @@ class HomepageTest extends TestCase
         $user->attachRole($viewRole);
 
         $homeVisit = $this->actingAs($user)->get('/');
-        $homeVisit->assertElementContains('#recently-viewed', 'You have not viewed any pages');
+        $this->withHtml($homeVisit)->assertElementContains('#recently-viewed', 'You have not viewed any pages');
     }
 }
index 43389ad787ccc245a9b1d6d980f790c723a09038..3f807f024ef9c6f5cc4b02b9ceb6ae4fa451fa37 100644 (file)
@@ -9,6 +9,7 @@ use BookStack\Entities\Models\Page;
 use BookStack\Entities\Repos\BaseRepo;
 use BookStack\Entities\Repos\BookRepo;
 use Illuminate\Support\Str;
+use Illuminate\Testing\TestResponse;
 use Tests\Uploads\UsesImages;
 
 class OpenGraphTest extends TestCase
index abd5065f50a244902bc1cd1f0a7080245a836dc6..7f8120106b8d5b69589539cce1de30909b6503e6 100644 (file)
@@ -138,13 +138,11 @@ class EntityPermissionsTest extends TestCase
         $book = Book::query()->first();
 
         $bookUrl = $book->getUrl();
-        $this->actingAs($this->viewer)
-            ->get($bookUrl)
-            ->assertElementNotContains('.actions', 'New Page')
+        $resp = $this->actingAs($this->viewer)->get($bookUrl);
+        $this->withHtml($resp)->assertElementNotContains('.actions', 'New Page')
             ->assertElementNotContains('.actions', 'New Chapter');
-        $this->actingAs($this->user)
-            ->get($bookUrl)
-            ->assertElementContains('.actions', 'New Page')
+        $resp = $this->actingAs($this->user)->get($bookUrl);
+        $this->withHtml($resp)->assertElementContains('.actions', 'New Page')
             ->assertElementContains('.actions', 'New Chapter');
 
         $this->setRestrictionsForTestRoles($book, ['view', 'delete', 'update']);
@@ -155,8 +153,8 @@ class EntityPermissionsTest extends TestCase
         $this->get($bookUrl . '/create-page')->assertRedirect('/');
         $this->get('/')->assertSee('You do not have permission');
 
-        $this->get($bookUrl)
-            ->assertElementNotContains('.actions', 'New Page')
+        $resp = $this->get($bookUrl);
+        $this->withHtml($resp)->assertElementNotContains('.actions', 'New Page')
             ->assertElementNotContains('.actions', 'New Chapter');
 
         $this->setRestrictionsForTestRoles($book, ['view', 'create']);
@@ -176,8 +174,8 @@ class EntityPermissionsTest extends TestCase
         ]);
         $resp->assertRedirect($book->getUrl('/page/test-page'));
 
-        $this->get($bookUrl)
-            ->assertElementContains('.actions', 'New Page')
+        $resp = $this->get($bookUrl);
+        $this->withHtml($resp)->assertElementContains('.actions', 'New Page')
             ->assertElementContains('.actions', 'New Chapter');
     }
 
@@ -262,15 +260,14 @@ class EntityPermissionsTest extends TestCase
         $chapter = Chapter::query()->first();
 
         $chapterUrl = $chapter->getUrl();
-        $this->actingAs($this->user)
-            ->get($chapterUrl)
-            ->assertElementContains('.actions', 'New Page');
+        $resp = $this->actingAs($this->user)->get($chapterUrl);
+        $this->withHtml($resp)->assertElementContains('.actions', 'New Page');
 
         $this->setRestrictionsForTestRoles($chapter, ['view', 'delete', 'update']);
 
         $this->get($chapterUrl . '/create-page')->assertRedirect('/');
         $this->get('/')->assertSee('You do not have permission');
-        $this->get($chapterUrl)->assertElementNotContains('.actions', 'New Page');
+        $this->withHtml($this->get($chapterUrl))->assertElementNotContains('.actions', 'New Page');
 
         $this->setRestrictionsForTestRoles($chapter, ['view', 'create']);
 
@@ -283,7 +280,7 @@ class EntityPermissionsTest extends TestCase
         ]);
         $resp->assertRedirect($chapter->book->getUrl('/page/test-page'));
 
-        $this->get($chapterUrl)->assertElementContains('.actions', 'New Page');
+        $this->withHtml($this->get($chapterUrl))->assertElementContains('.actions', 'New Page');
     }
 
     public function test_chapter_update_restriction()
@@ -356,9 +353,9 @@ class EntityPermissionsTest extends TestCase
         $page = Page::query()->first();
 
         $pageUrl = $page->getUrl();
-        $this->actingAs($this->user)
-            ->get($pageUrl . '/edit')
-            ->assertElementExists('input[name="name"][value="' . $page->name . '"]');
+        $resp = $this->actingAs($this->user)
+            ->get($pageUrl . '/edit');
+        $this->withHtml($resp)->assertElementExists('input[name="name"][value="' . $page->name . '"]');
 
         $this->setRestrictionsForTestRoles($page, ['view', 'delete']);
 
@@ -367,9 +364,9 @@ class EntityPermissionsTest extends TestCase
 
         $this->setRestrictionsForTestRoles($page, ['view', 'update']);
 
-        $this->get($pageUrl . '/edit')
-            ->assertOk()
-            ->assertElementExists('input[name="name"][value="' . $page->name . '"]');
+        $resp = $this->get($pageUrl . '/edit')
+            ->assertOk();
+        $this->withHtml($resp)->assertElementExists('input[name="name"][value="' . $page->name . '"]');
     }
 
     public function test_page_delete_restriction()
@@ -446,9 +443,8 @@ class EntityPermissionsTest extends TestCase
 
         $this->setRestrictionsForTestRoles($page, []);
 
-        $this->actingAs($this->user)
-            ->get($page2->getUrl())
-            ->assertElementNotContains('.sidebar-page-list', $page->name);
+        $resp = $this->actingAs($this->user)->get($page2->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.sidebar-page-list', $page->name);
     }
 
     public function test_restricted_pages_not_visible_in_book_navigation_on_chapters()
@@ -459,9 +455,8 @@ class EntityPermissionsTest extends TestCase
 
         $this->setRestrictionsForTestRoles($page, []);
 
-        $this->actingAs($this->user)
-            ->get($chapter->getUrl())
-            ->assertElementNotContains('.sidebar-page-list', $page->name);
+        $resp = $this->actingAs($this->user)->get($chapter->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.sidebar-page-list', $page->name);
     }
 
     public function test_restricted_pages_not_visible_on_chapter_pages()
@@ -538,9 +533,8 @@ class EntityPermissionsTest extends TestCase
         $book = Book::query()->first();
 
         $bookUrl = $book->getUrl();
-        $this->actingAs($this->viewer)
-            ->get($bookUrl)
-            ->assertElementNotContains('.actions', 'New Page')
+        $resp = $this->actingAs($this->viewer)->get($bookUrl);
+        $this->withHtml($resp)->assertElementNotContains('.actions', 'New Page')
             ->assertElementNotContains('.actions', 'New Chapter');
 
         $this->setRestrictionsForTestRoles($book, ['view', 'delete', 'update']);
@@ -549,7 +543,8 @@ class EntityPermissionsTest extends TestCase
         $this->get('/')->assertSee('You do not have permission');
         $this->get($bookUrl . '/create-page')->assertRedirect('/');
         $this->get('/')->assertSee('You do not have permission');
-        $this->get($bookUrl)->assertElementNotContains('.actions', 'New Page')
+         $resp = $this->get($bookUrl);
+        $this->withHtml($resp)->assertElementNotContains('.actions', 'New Page')
             ->assertElementNotContains('.actions', 'New Chapter');
 
         $this->setRestrictionsForTestRoles($book, ['view', 'create']);
@@ -569,8 +564,8 @@ class EntityPermissionsTest extends TestCase
         ]);
         $resp->assertRedirect($book->getUrl('/page/test-page'));
 
-        $this->get($bookUrl)
-            ->assertElementContains('.actions', 'New Page')
+        $resp = $this->get($bookUrl);
+        $this->withHtml($resp)->assertElementContains('.actions', 'New Page')
             ->assertElementContains('.actions', 'New Chapter');
     }
 
index fe2139e59e786f0038119ed0c4b4b3706a230b63..7593b7b11fc8a5a446a92139b85e9e572d509934 100644 (file)
@@ -12,8 +12,8 @@ use BookStack\Entities\Models\Chapter;
 use BookStack\Entities\Models\Entity;
 use BookStack\Entities\Models\Page;
 use BookStack\Uploads\Image;
+use Illuminate\Testing\TestResponse;
 use Tests\TestCase;
-use Tests\TestResponse;
 
 class RolesTest extends TestCase
 {
@@ -59,13 +59,13 @@ class RolesTest extends TestCase
 
         // Creation
         $resp = $this->asAdmin()->get('/settings/features');
-        $resp->assertElementContains('a[href="' . url('/settings/roles') . '"]', 'Roles');
+        $this->withHtml($resp)->assertElementContains('a[href="' . url('/settings/roles') . '"]', 'Roles');
 
         $resp = $this->get('/settings/roles');
-        $resp->assertElementContains('a[href="' . url('/settings/roles/new') . '"]', 'Create New Role');
+        $this->withHtml($resp)->assertElementContains('a[href="' . url('/settings/roles/new') . '"]', 'Create New Role');
 
         $resp = $this->get('/settings/roles/new');
-        $resp->assertElementContains('form[action="' . url('/settings/roles/new') . '"]', 'Save Role');
+        $this->withHtml($resp)->assertElementContains('form[action="' . url('/settings/roles/new') . '"]', 'Save Role');
 
         $resp = $this->post('/settings/roles/new', [
             'display_name' => $testRoleName,
@@ -89,7 +89,7 @@ class RolesTest extends TestCase
         $resp = $this->get('/settings/roles/' . $role->id);
         $resp->assertSee($testRoleName);
         $resp->assertSee($testRoleDesc);
-        $resp->assertElementContains('form[action="' . url('/settings/roles/' . $role->id) . '"]', 'Save Role');
+        $this->withHtml($resp)->assertElementContains('form[action="' . url('/settings/roles/' . $role->id) . '"]', 'Save Role');
 
         $resp = $this->put('/settings/roles/' . $role->id, [
             'display_name' => $testRoleUpdateName,
@@ -105,11 +105,11 @@ class RolesTest extends TestCase
 
         // Deleting
         $resp = $this->get('/settings/roles/' . $role->id);
-        $resp->assertElementContains('a[href="' . url("/settings/roles/delete/$role->id") . '"]', 'Delete Role');
+        $this->withHtml($resp)->assertElementContains('a[href="' . url("/settings/roles/delete/$role->id") . '"]', 'Delete Role');
 
         $resp = $this->get("/settings/roles/delete/$role->id");
         $resp->assertSee($testRoleUpdateName);
-        $resp->assertElementContains('form[action="' . url("/settings/roles/delete/$role->id") . '"]', 'Confirm');
+        $this->withHtml($resp)->assertElementContains('form[action="' . url("/settings/roles/delete/$role->id") . '"]', 'Confirm');
 
         $resp = $this->delete("/settings/roles/delete/$role->id");
         $resp->assertRedirect('/settings/roles');
@@ -154,7 +154,7 @@ class RolesTest extends TestCase
         $this->assertCount(1, $roleB->users()->get());
 
         $deletePage = $this->asAdmin()->get("/settings/roles/delete/$roleB->id");
-        $deletePage->assertElementExists('select[name=migrate_role_id]');
+        $this->withHtml($deletePage)->assertElementExists('select[name=migrate_role_id]');
         $this->asAdmin()->delete("/settings/roles/delete/$roleB->id", [
             'migrate_role_id' => $roleA->id,
         ]);
@@ -168,7 +168,7 @@ class RolesTest extends TestCase
         /** @var Role $role */
         $role = Role::query()->first();
         $resp = $this->asAdmin()->get("/settings/roles/{$role->id}");
-        $resp->assertElementContains('a[href$="/roles/new?copy_from=' . $role->id . '"]', 'Copy');
+        $this->withHtml($resp)->assertElementContains('a[href$="/roles/new?copy_from=' . $role->id . '"]', 'Copy');
     }
 
     public function test_copy_from_param_on_create_prefills_with_other_role_data()
@@ -177,7 +177,7 @@ class RolesTest extends TestCase
         $role = Role::query()->first();
         $resp = $this->asAdmin()->get("/settings/roles/new?copy_from={$role->id}");
         $resp->assertOk();
-        $resp->assertElementExists('input[name="display_name"][value="' . ($role->display_name . ' (Copy)') . '"]');
+        $this->withHtml($resp)->assertElementExists('input[name="display_name"][value="' . ($role->display_name . ' (Copy)') . '"]');
     }
 
     public function test_manage_user_permission()
@@ -203,9 +203,9 @@ class RolesTest extends TestCase
         $originalEmail = $this->user->email;
         $this->actingAs($this->user);
 
-        $this->get($userProfileUrl)
-            ->assertOk()
-            ->assertElementExists('input[name=email][disabled]');
+        $resp = $this->get($userProfileUrl)
+            ->assertOk();
+        $this->withHtml($resp)->assertElementExists('input[name=email][disabled]');
         $this->put($userProfileUrl, [
             'name'  => 'my_new_name',
             'email' => '[email protected]',
@@ -218,9 +218,9 @@ class RolesTest extends TestCase
 
         $this->giveUserPermissions($this->user, ['users-manage']);
 
-        $this->get($userProfileUrl)
-            ->assertOk()
-            ->assertElementNotExists('input[name=email][disabled]')
+        $resp = $this->get($userProfileUrl)
+            ->assertOk();
+        $this->withHtml($resp)->assertElementNotExists('input[name=email][disabled]')
             ->assertElementExists('input[name=email]');
         $this->put($userProfileUrl, [
             'name'  => 'my_new_name_2',
@@ -315,8 +315,8 @@ class RolesTest extends TestCase
         }
 
         foreach ($visibles as $url => $text) {
-            $this->actingAs($this->user)->get($url)
-                ->assertElementNotContains('.action-buttons', $text);
+            $resp = $this->actingAs($this->user)->get($url);
+            $this->withHtml($resp)->assertElementNotContains('.action-buttons', $text);
         }
 
         $this->giveUserPermissions($this->user, [$permission]);
@@ -357,7 +357,8 @@ class RolesTest extends TestCase
             $ownShelf->getUrl() => 'Edit',
         ]);
 
-        $this->get($otherShelf->getUrl())->assertElementNotContains('.action-buttons', 'Edit');
+         $resp = $this->get($otherShelf->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Edit');
         $this->get($otherShelf->getUrl('/edit'))->assertRedirect('/');
     }
 
@@ -387,7 +388,8 @@ class RolesTest extends TestCase
             $ownShelf->getUrl() => 'Delete',
         ]);
 
-        $this->get($otherShelf->getUrl())->assertElementNotContains('.action-buttons', 'Delete');
+         $resp = $this->get($otherShelf->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Delete');
         $this->get($otherShelf->getUrl('/delete'))->assertRedirect('/');
 
         $this->get($ownShelf->getUrl());
@@ -435,7 +437,8 @@ class RolesTest extends TestCase
             $ownBook->getUrl() => 'Edit',
         ]);
 
-        $this->get($otherBook->getUrl())->assertElementNotContains('.action-buttons', 'Edit');
+         $resp = $this->get($otherBook->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Edit');
         $this->get($otherBook->getUrl('/edit'))->assertRedirect('/');
     }
 
@@ -462,7 +465,8 @@ class RolesTest extends TestCase
             $ownBook->getUrl() => 'Delete',
         ]);
 
-        $this->get($otherBook->getUrl())->assertElementNotContains('.action-buttons', 'Delete');
+         $resp = $this->get($otherBook->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Delete');
         $this->get($otherBook->getUrl('/delete'))->assertRedirect('/');
         $this->get($ownBook->getUrl());
         $this->delete($ownBook->getUrl())->assertRedirect('/books');
@@ -501,7 +505,8 @@ class RolesTest extends TestCase
             'description' => 'chapter desc',
         ])->assertRedirect($ownBook->getUrl('/chapter/test-chapter'));
 
-        $this->get($book->getUrl())->assertElementNotContains('.action-buttons', 'New Chapter');
+         $resp = $this->get($book->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'New Chapter');
         $this->get($book->getUrl('/create-chapter'))->assertRedirect('/');
     }
 
@@ -532,7 +537,8 @@ class RolesTest extends TestCase
             $ownChapter->getUrl() => 'Edit',
         ]);
 
-        $this->get($otherChapter->getUrl())->assertElementNotContains('.action-buttons', 'Edit');
+         $resp = $this->get($otherChapter->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Edit');
         $this->get($otherChapter->getUrl('/edit'))->assertRedirect('/');
     }
 
@@ -560,11 +566,13 @@ class RolesTest extends TestCase
         ]);
 
         $bookUrl = $ownChapter->book->getUrl();
-        $this->get($otherChapter->getUrl())->assertElementNotContains('.action-buttons', 'Delete');
+         $resp = $this->get($otherChapter->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Delete');
         $this->get($otherChapter->getUrl('/delete'))->assertRedirect('/');
         $this->get($ownChapter->getUrl());
         $this->delete($ownChapter->getUrl())->assertRedirect($bookUrl);
-        $this->get($bookUrl)->assertElementNotContains('.book-content', $ownChapter->name);
+         $resp = $this->get($bookUrl);
+        $this->withHtml($resp)->assertElementNotContains('.book-content', $ownChapter->name);
     }
 
     public function test_chapter_delete_all_permission()
@@ -581,7 +589,8 @@ class RolesTest extends TestCase
         $bookUrl = $otherChapter->book->getUrl();
         $this->get($otherChapter->getUrl());
         $this->delete($otherChapter->getUrl())->assertRedirect($bookUrl);
-        $this->get($bookUrl)->assertElementNotContains('.book-content', $otherChapter->name);
+         $resp = $this->get($bookUrl);
+        $this->withHtml($resp)->assertElementNotContains('.book-content', $otherChapter->name);
     }
 
     public function test_page_create_own_permissions()
@@ -624,10 +633,12 @@ class RolesTest extends TestCase
             'html' => 'page desc',
         ])->assertRedirect($ownBook->getUrl('/page/test-page'));
 
-        $this->get($book->getUrl())->assertElementNotContains('.action-buttons', 'New Page');
+         $resp = $this->get($book->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'New Page');
         $this->get($book->getUrl('/create-page'))->assertRedirect('/');
 
-        $this->get($chapter->getUrl())->assertElementNotContains('.action-buttons', 'New Page');
+         $resp = $this->get($chapter->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'New Page');
         $this->get($chapter->getUrl('/create-page'))->assertRedirect('/');
     }
 
@@ -687,7 +698,8 @@ class RolesTest extends TestCase
             $ownPage->getUrl() => 'Edit',
         ]);
 
-        $this->get($otherPage->getUrl())->assertElementNotContains('.action-buttons', 'Edit');
+         $resp = $this->get($otherPage->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Edit');
         $this->get($otherPage->getUrl() . '/edit')->assertRedirect('/');
     }
 
@@ -715,11 +727,13 @@ class RolesTest extends TestCase
         ]);
 
         $parent = $ownPage->chapter ?? $ownPage->book;
-        $this->get($otherPage->getUrl())->assertElementNotContains('.action-buttons', 'Delete');
+         $resp = $this->get($otherPage->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Delete');
         $this->get($otherPage->getUrl('/delete'))->assertRedirect('/');
         $this->get($ownPage->getUrl());
         $this->delete($ownPage->getUrl())->assertRedirect($parent->getUrl());
-        $this->get($parent->getUrl())->assertElementNotContains('.book-content', $ownPage->name);
+         $resp = $this->get($parent->getUrl());
+        $this->withHtml($resp)->assertElementNotContains('.book-content', $ownPage->name);
     }
 
     public function test_page_delete_all_permission()
@@ -748,8 +762,8 @@ class RolesTest extends TestCase
         $user = User::query()->first();
         $adminRole = Role::getSystemRole('admin');
         $publicRole = Role::getSystemRole('public');
-        $this->asAdmin()->get('/settings/users/' . $user->id)
-            ->assertElementExists('[name="roles[' . $adminRole->id . ']"]')
+        $resp = $this->asAdmin()->get('/settings/users/' . $user->id);
+        $this->withHtml($resp)->assertElementExists('[name="roles[' . $adminRole->id . ']"]')
             ->assertElementExists('[name="roles[' . $publicRole->id . ']"]');
     }
 
@@ -762,8 +776,8 @@ class RolesTest extends TestCase
 
     public function test_public_role_visible_in_default_role_setting()
     {
-        $this->asAdmin()->get('/settings/registration')
-            ->assertElementExists('[data-system-role-name="admin"]')
+        $resp = $this->asAdmin()->get('/settings/registration');
+        $this->withHtml($resp)->assertElementExists('[data-system-role-name="admin"]')
             ->assertElementExists('[data-system-role-name="public"]');
     }
 
index ced40d0a8e96e133617370ec00a4c00df04d015e..178e23e2ebc804fd5484ba93d5d8a3b8d3d9d5fe 100644 (file)
@@ -28,7 +28,8 @@ class PublicActionTest extends TestCase
     public function test_login_link_visible()
     {
         $this->setSettings(['app-public' => 'true']);
-        $this->get('/')->assertElementExists('a[href="' . url('/login') . '"]');
+        $resp = $this->get('/');
+        $this->withHtml($resp)->assertElementExists('a[href="' . url('/login') . '"]');
     }
 
     public function test_register_link_visible_when_enabled()
@@ -96,12 +97,12 @@ class PublicActionTest extends TestCase
         $chapter = Chapter::query()->first();
         $resp = $this->get($chapter->getUrl());
         $resp->assertSee('New Page');
-        $resp->assertElementExists('a[href="' . $chapter->getUrl('/create-page') . '"]');
+        $this->withHtml($resp)->assertElementExists('a[href="' . $chapter->getUrl('/create-page') . '"]');
 
         $resp = $this->get($chapter->getUrl('/create-page'));
         $resp->assertSee('Continue');
         $resp->assertSee('Page Name');
-        $resp->assertElementExists('form[action="' . $chapter->getUrl('/create-guest-page') . '"]');
+        $this->withHtml($resp)->assertElementExists('form[action="' . $chapter->getUrl('/create-guest-page') . '"]');
 
         $resp = $this->post($chapter->getUrl('/create-guest-page'), ['name' => 'My guest page']);
         $resp->assertRedirect($chapter->book->getUrl('/page/my-guest-page/edit'));
index f3e30c0d07d442f894347f7599e97e3e1c9218fc..0e05243380f52cd2838d15b8889aa5a420f06b32 100644 (file)
@@ -63,11 +63,12 @@ class RecycleBinTest extends TestCase
         $this->actingAs($editor)->delete($book->getUrl());
 
         $viewReq = $this->asAdmin()->get('/settings/recycle-bin');
-        $viewReq->assertElementContains('table.table', $page->name);
-        $viewReq->assertElementContains('table.table', $editor->name);
-        $viewReq->assertElementContains('table.table', $book->name);
-        $viewReq->assertElementContains('table.table', $book->pages_count . ' Pages');
-        $viewReq->assertElementContains('table.table', $book->chapters_count . ' Chapters');
+        $html = $this->withHtml($viewReq);
+        $html->assertElementContains('table.table', $page->name);
+        $html->assertElementContains('table.table', $editor->name);
+        $html->assertElementContains('table.table', $book->name);
+        $html->assertElementContains('table.table', $book->pages_count . ' Pages');
+        $html->assertElementContains('table.table', $book->chapters_count . ' Chapters');
     }
 
     public function test_recycle_bin_empty()
@@ -90,7 +91,7 @@ class RecycleBinTest extends TestCase
 
         $itemCount = 2 + $book->pages->count() + $book->chapters->count();
         $redirectReq = $this->get('/settings/recycle-bin');
-        $redirectReq->assertNotificationContains('Deleted ' . $itemCount . ' total items from the recycle bin');
+        $this->assertNotificationContains($redirectReq, 'Deleted ' . $itemCount . ' total items from the recycle bin');
     }
 
     public function test_entity_restore()
@@ -111,7 +112,7 @@ class RecycleBinTest extends TestCase
 
         $itemCount = 1 + $book->pages->count() + $book->chapters->count();
         $redirectReq = $this->get('/settings/recycle-bin');
-        $redirectReq->assertNotificationContains('Restored ' . $itemCount . ' total items from the recycle bin');
+        $this->assertNotificationContains($redirectReq, 'Restored ' . $itemCount . ' total items from the recycle bin');
     }
 
     public function test_permanent_delete()
@@ -130,7 +131,7 @@ class RecycleBinTest extends TestCase
 
         $itemCount = 1 + $book->pages->count() + $book->chapters->count();
         $redirectReq = $this->get('/settings/recycle-bin');
-        $redirectReq->assertNotificationContains('Deleted ' . $itemCount . ' total items from the recycle bin');
+        $this->assertNotificationContains($redirectReq, 'Deleted ' . $itemCount . ' total items from the recycle bin');
     }
 
     public function test_permanent_delete_for_each_type()
@@ -264,6 +265,6 @@ class RecycleBinTest extends TestCase
 
         $pageRestoreView = $this->asAdmin()->get("/settings/recycle-bin/{$pageDeletion->id}/restore");
         $pageRestoreView->assertSee('The parent of this item has also been deleted.');
-        $pageRestoreView->assertElementContains('a[href$="/settings/recycle-bin/' . $bookDeletion->id . '/restore"]', 'Restore Parent');
+        $this->withHtml($pageRestoreView)->assertElementContains('a[href$="/settings/recycle-bin/' . $bookDeletion->id . '/restore"]', 'Restore Parent');
     }
 }
index d8ba5873fb85905c0afd00d2ec63a5ec09af3c19..00459ec694178fd98677cbb094aa7184df8d7431 100644 (file)
@@ -3,6 +3,7 @@
 namespace Tests;
 
 use BookStack\Util\CspService;
+use Illuminate\Testing\TestResponse;
 
 class SecurityHeaderTest extends TestCase
 {
index 4b822ba4ceb62faac0fc9c791b21796d95346c03..f0bf65e770dca3be224fe3ce9493e814afe1746c 100644 (file)
@@ -44,8 +44,11 @@ class FooterLinksTest extends TestCase
             ['label' => 'Another Link', 'url' => 'https://example.com/link-b'],
         ]]);
 
-        $this->get('/login')->assertElementContains('footer a[href="https://example.com/link-a"]', 'My custom link');
-        $this->asEditor()->get('/')->assertElementContains('footer a[href="https://example.com/link-b"]', 'Another link');
+        $resp = $this->get('/login');
+        $this->withHtml($resp)->assertElementContains('footer a[href="https://example.com/link-a"]', 'My custom link');
+
+        $resp = $this->asEditor()->get('/');
+        $this->withHtml($resp)->assertElementContains('footer a[href="https://example.com/link-b"]', 'Another link');
     }
 
     public function test_using_translation_system_for_labels()
@@ -56,7 +59,7 @@ class FooterLinksTest extends TestCase
         ]]);
 
         $resp = $this->get('/login');
-        $resp->assertElementContains('footer a[href="https://example.com/privacy"]', 'Privacy Policy');
-        $resp->assertElementContains('footer a[href="https://example.com/terms"]', 'Terms of Service');
+        $this->withHtml($resp)->assertElementContains('footer a[href="https://example.com/privacy"]', 'Privacy Policy');
+        $this->withHtml($resp)->assertElementContains('footer a[href="https://example.com/terms"]', 'Terms of Service');
     }
 }
index 48840fc0bcae93f5d6327289b8702c782174cc14..e2ac6f27c5c24fb7ead7aa21a5707c879f041c36 100644 (file)
@@ -28,8 +28,8 @@ class SettingsTest extends TestCase
 
         foreach ($categories as $category => $title) {
             $resp = $this->get("/settings/{$category}");
-            $resp->assertElementContains('h1', $title);
-            $resp->assertElementExists("form[action$=\"/settings/{$category}\"]");
+            $this->withHtml($resp)->assertElementContains('h1', $title);
+            $this->withHtml($resp)->assertElementExists("form[action$=\"/settings/{$category}\"]");
         }
     }
 
diff --git a/tests/SharedTestHelpers.php b/tests/SharedTestHelpers.php
deleted file mode 100644 (file)
index bc7b102..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-<?php
-
-namespace Tests;
-
-use BookStack\Auth\Permissions\JointPermissionBuilder;
-use BookStack\Auth\Permissions\PermissionsRepo;
-use BookStack\Auth\Permissions\RolePermission;
-use BookStack\Auth\Role;
-use BookStack\Auth\User;
-use BookStack\Entities\Models\Book;
-use BookStack\Entities\Models\Bookshelf;
-use BookStack\Entities\Models\Chapter;
-use BookStack\Entities\Models\Entity;
-use BookStack\Entities\Models\Page;
-use BookStack\Entities\Repos\BookRepo;
-use BookStack\Entities\Repos\BookshelfRepo;
-use BookStack\Entities\Repos\ChapterRepo;
-use BookStack\Entities\Repos\PageRepo;
-use BookStack\Settings\SettingService;
-use BookStack\Uploads\HttpFetcher;
-use GuzzleHttp\Client;
-use GuzzleHttp\Handler\MockHandler;
-use GuzzleHttp\HandlerStack;
-use GuzzleHttp\Middleware;
-use Illuminate\Http\JsonResponse;
-use Illuminate\Support\Env;
-use Illuminate\Support\Facades\Log;
-use Illuminate\Testing\Assert as PHPUnit;
-use Mockery;
-use Monolog\Handler\TestHandler;
-use Monolog\Logger;
-use Psr\Http\Client\ClientInterface;
-
-trait SharedTestHelpers
-{
-    protected $admin;
-    protected $editor;
-
-    /**
-     * Set the current user context to be an admin.
-     */
-    public function asAdmin()
-    {
-        return $this->actingAs($this->getAdmin());
-    }
-
-    /**
-     * Get the current admin user.
-     */
-    public function getAdmin(): User
-    {
-        if (is_null($this->admin)) {
-            $adminRole = Role::getSystemRole('admin');
-            $this->admin = $adminRole->users->first();
-        }
-
-        return $this->admin;
-    }
-
-    /**
-     * Set the current user context to be an editor.
-     */
-    public function asEditor()
-    {
-        return $this->actingAs($this->getEditor());
-    }
-
-    /**
-     * Get a editor user.
-     */
-    protected function getEditor(): User
-    {
-        if ($this->editor === null) {
-            $editorRole = Role::getRole('editor');
-            $this->editor = $editorRole->users->first();
-        }
-
-        return $this->editor;
-    }
-
-    /**
-     * Get an instance of a user with 'viewer' permissions.
-     */
-    protected function getViewer(array $attributes = []): User
-    {
-        $user = Role::getRole('viewer')->users()->first();
-        if (!empty($attributes)) {
-            $user->forceFill($attributes)->save();
-        }
-
-        return $user;
-    }
-
-    /**
-     * Get a user that's not a system user such as the guest user.
-     */
-    public function getNormalUser(): User
-    {
-        return User::query()->where('system_name', '=', null)->get()->last();
-    }
-
-    /**
-     * Regenerate the permission for an entity.
-     */
-    protected function regenEntityPermissions(Entity $entity): void
-    {
-        $entity->rebuildPermissions();
-        $entity->load('jointPermissions');
-    }
-
-    /**
-     * Create and return a new bookshelf.
-     */
-    public function newShelf(array $input = ['name' => 'test shelf', 'description' => 'My new test shelf']): Bookshelf
-    {
-        return app(BookshelfRepo::class)->create($input, []);
-    }
-
-    /**
-     * Create and return a new book.
-     */
-    public function newBook(array $input = ['name' => 'test book', 'description' => 'My new test book']): Book
-    {
-        return app(BookRepo::class)->create($input);
-    }
-
-    /**
-     * Create and return a new test chapter.
-     */
-    public function newChapter(array $input, Book $book): Chapter
-    {
-        return app(ChapterRepo::class)->create($input, $book);
-    }
-
-    /**
-     * Create and return a new test page.
-     */
-    public function newPage(array $input = ['name' => 'test page', 'html' => 'My new test page']): Page
-    {
-        $book = Book::query()->first();
-        $pageRepo = app(PageRepo::class);
-        $draftPage = $pageRepo->getNewDraftPage($book);
-
-        return $pageRepo->publishDraft($draftPage, $input);
-    }
-
-    /**
-     * Quickly sets an array of settings.
-     */
-    protected function setSettings(array $settingsArray): void
-    {
-        $settings = app(SettingService::class);
-        foreach ($settingsArray as $key => $value) {
-            $settings->put($key, $value);
-        }
-    }
-
-    /**
-     * Manually set some permissions on an entity.
-     */
-    protected function setEntityRestrictions(Entity $entity, array $actions = [], array $roles = []): void
-    {
-        $entity->restricted = true;
-        $entity->permissions()->delete();
-
-        $permissions = [];
-        foreach ($actions as $action) {
-            foreach ($roles as $role) {
-                $permissions[] = [
-                    'role_id' => $role->id,
-                    'action'  => strtolower($action),
-                ];
-            }
-        }
-        $entity->permissions()->createMany($permissions);
-
-        $entity->save();
-        $entity->load('permissions');
-        $this->app->make(JointPermissionBuilder::class)->rebuildForEntity($entity);
-        $entity->load('jointPermissions');
-    }
-
-    /**
-     * Give the given user some permissions.
-     */
-    protected function giveUserPermissions(User $user, array $permissions = []): void
-    {
-        $newRole = $this->createNewRole($permissions);
-        $user->attachRole($newRole);
-        $user->load('roles');
-        $user->clearPermissionCache();
-    }
-
-    /**
-     * Completely remove the given permission name from the given user.
-     */
-    protected function removePermissionFromUser(User $user, string $permissionName)
-    {
-        $permissionBuilder = app()->make(JointPermissionBuilder::class);
-
-        /** @var RolePermission $permission */
-        $permission = RolePermission::query()->where('name', '=', $permissionName)->firstOrFail();
-
-        $roles = $user->roles()->whereHas('permissions', function ($query) use ($permission) {
-            $query->where('id', '=', $permission->id);
-        })->get();
-
-        /** @var Role $role */
-        foreach ($roles as $role) {
-            $role->detachPermission($permission);
-            $permissionBuilder->rebuildForRole($role);
-        }
-
-        $user->clearPermissionCache();
-    }
-
-    /**
-     * Create a new basic role for testing purposes.
-     */
-    protected function createNewRole(array $permissions = []): Role
-    {
-        $permissionRepo = app(PermissionsRepo::class);
-        $roleData = Role::factory()->make()->toArray();
-        $roleData['permissions'] = array_flip($permissions);
-
-        return $permissionRepo->saveNewRole($roleData);
-    }
-
-    /**
-     * Create a group of entities that belong to a specific user.
-     *
-     * @return array{book: Book, chapter: Chapter, page: Page}
-     */
-    protected function createEntityChainBelongingToUser(User $creatorUser, ?User $updaterUser = null): array
-    {
-        if (empty($updaterUser)) {
-            $updaterUser = $creatorUser;
-        }
-
-        $userAttrs = ['created_by' => $creatorUser->id, 'owned_by' => $creatorUser->id, 'updated_by' => $updaterUser->id];
-        $book = Book::factory()->create($userAttrs);
-        $chapter = Chapter::factory()->create(array_merge(['book_id' => $book->id], $userAttrs));
-        $page = Page::factory()->create(array_merge(['book_id' => $book->id, 'chapter_id' => $chapter->id], $userAttrs));
-
-        $this->app->make(JointPermissionBuilder::class)->rebuildForEntity($book);
-
-        return compact('book', 'chapter', 'page');
-    }
-
-    /**
-     * Mock the HttpFetcher service and return the given data on fetch.
-     */
-    protected function mockHttpFetch($returnData, int $times = 1)
-    {
-        $mockHttp = Mockery::mock(HttpFetcher::class);
-        $this->app[HttpFetcher::class] = $mockHttp;
-        $mockHttp->shouldReceive('fetch')
-            ->times($times)
-            ->andReturn($returnData);
-    }
-
-    /**
-     * Mock the http client used in BookStack.
-     * Returns a reference to the container which holds all history of http transactions.
-     *
-     * @link https://docs.guzzlephp.org/en/stable/testing.html#history-middleware
-     */
-    protected function &mockHttpClient(array $responses = []): array
-    {
-        $container = [];
-        $history = Middleware::history($container);
-        $mock = new MockHandler($responses);
-        $handlerStack = new HandlerStack($mock);
-        $handlerStack->push($history);
-        $this->app[ClientInterface::class] = new Client(['handler' => $handlerStack]);
-
-        return $container;
-    }
-
-    /**
-     * Run a set test with the given env variable.
-     * Remembers the original and resets the value after test.
-     */
-    protected function runWithEnv(string $name, $value, callable $callback)
-    {
-        Env::disablePutenv();
-        $originalVal = $_SERVER[$name] ?? null;
-
-        if (is_null($value)) {
-            unset($_SERVER[$name]);
-        } else {
-            $_SERVER[$name] = $value;
-        }
-
-        $this->refreshApplication();
-        $callback();
-
-        if (is_null($originalVal)) {
-            unset($_SERVER[$name]);
-        } else {
-            $_SERVER[$name] = $originalVal;
-        }
-    }
-
-    /**
-     * Check the keys and properties in the given map to include
-     * exist, albeit not exclusively, within the map to check.
-     */
-    protected function assertArrayMapIncludes(array $mapToInclude, array $mapToCheck, string $message = ''): void
-    {
-        $passed = true;
-
-        foreach ($mapToInclude as $key => $value) {
-            if (!isset($mapToCheck[$key]) || $mapToCheck[$key] !== $mapToInclude[$key]) {
-                $passed = false;
-            }
-        }
-
-        $toIncludeStr = print_r($mapToInclude, true);
-        $toCheckStr = print_r($mapToCheck, true);
-        self::assertThat($passed, self::isTrue(), "Failed asserting that given map:\n\n{$toCheckStr}\n\nincludes:\n\n{$toIncludeStr}");
-    }
-
-    /**
-     * Assert a permission error has occurred.
-     */
-    protected function assertPermissionError($response)
-    {
-        PHPUnit::assertTrue($this->isPermissionError($response->baseResponse ?? $response->response), 'Failed asserting the response contains a permission error.');
-    }
-
-    /**
-     * Assert a permission error has occurred.
-     */
-    protected function assertNotPermissionError($response)
-    {
-        PHPUnit::assertFalse($this->isPermissionError($response->baseResponse ?? $response->response), 'Failed asserting the response does not contain a permission error.');
-    }
-
-    /**
-     * Check if the given response is a permission error.
-     */
-    private function isPermissionError($response): bool
-    {
-        return $response->status() === 302
-            && (
-                (
-                    $response->headers->get('Location') === url('/')
-                    && strpos(session()->pull('error', ''), 'You do not have permission to access') === 0
-                )
-                ||
-                (
-                    $response instanceof JsonResponse &&
-                    $response->json(['error' => 'You do not have permission to perform the requested action.'])
-                )
-            );
-    }
-
-    /**
-     * Assert that the session has a particular error notification message set.
-     */
-    protected function assertSessionError(string $message)
-    {
-        $error = session()->get('error');
-        PHPUnit::assertTrue($error === $message, "Failed asserting the session contains an error. \nFound: {$error}\nExpecting: {$message}");
-    }
-
-    /**
-     * Set a test handler as the logging interface for the application.
-     * Allows capture of logs for checking against during tests.
-     */
-    protected function withTestLogger(): TestHandler
-    {
-        $monolog = new Logger('testing');
-        $testHandler = new TestHandler();
-        $monolog->pushHandler($testHandler);
-
-        Log::extend('testing', function () use ($monolog) {
-            return $monolog;
-        });
-        Log::setDefaultDriver('testing');
-
-        return $testHandler;
-    }
-}
index 98e0dfbacf4c4cfb6321a55d9aa44fe9e491c6ef..95e58b267b812b6ecb8e06494316c371fe81d47d 100644 (file)
 
 namespace Tests;
 
+use BookStack\Auth\Permissions\JointPermissionBuilder;
+use BookStack\Auth\Permissions\PermissionsRepo;
+use BookStack\Auth\Permissions\RolePermission;
+use BookStack\Auth\Role;
+use BookStack\Auth\User;
+use BookStack\Entities\Models\Book;
+use BookStack\Entities\Models\Bookshelf;
+use BookStack\Entities\Models\Chapter;
 use BookStack\Entities\Models\Entity;
+use BookStack\Entities\Models\Page;
+use BookStack\Entities\Repos\BookRepo;
+use BookStack\Entities\Repos\BookshelfRepo;
+use BookStack\Entities\Repos\ChapterRepo;
+use BookStack\Entities\Repos\PageRepo;
+use BookStack\Settings\SettingService;
+use BookStack\Uploads\HttpFetcher;
+use GuzzleHttp\Client;
+use GuzzleHttp\Handler\MockHandler;
+use GuzzleHttp\HandlerStack;
+use GuzzleHttp\Middleware;
 use Illuminate\Foundation\Testing\DatabaseTransactions;
 use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Support\Env;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Testing\Assert as PHPUnit;
+use Monolog\Handler\TestHandler;
+use Monolog\Logger;
+use Psr\Http\Client\ClientInterface;
+use Ssddanbrown\AssertHtml\TestsHtml;
 
 abstract class TestCase extends BaseTestCase
 {
     use CreatesApplication;
     use DatabaseTransactions;
-    use SharedTestHelpers;
+    use TestsHtml;
+
+    protected ?User $admin = null;
+    protected ?User $editor = null;
 
     /**
      * The base URL to use while testing the application.
-     *
-     * @var string
      */
-    protected $baseUrl = 'http://localhost';
+    protected string $baseUrl = 'http://localhost';
 
     /**
-     * Assert the session contains a specific entry.
-     *
-     * @param string $key
-     *
-     * @return $this
+     * Set the current user context to be an admin.
      */
-    protected function assertSessionHas(string $key)
+    public function asAdmin()
     {
-        $this->assertTrue(session()->has($key), "Session does not contain a [{$key}] entry");
+        return $this->actingAs($this->getAdmin());
+    }
 
-        return $this;
+    /**
+     * Get the current admin user.
+     */
+    public function getAdmin(): User
+    {
+        if (is_null($this->admin)) {
+            $adminRole = Role::getSystemRole('admin');
+            $this->admin = $adminRole->users->first();
+        }
+
+        return $this->admin;
     }
 
     /**
-     * Override of the get method so we can get visibility of custom TestResponse methods.
-     *
-     * @param string $uri
-     * @param array  $headers
-     *
-     * @return TestResponse
+     * Set the current user context to be an editor.
+     */
+    public function asEditor()
+    {
+        return $this->actingAs($this->getEditor());
+    }
+
+    /**
+     * Get a editor user.
+     */
+    protected function getEditor(): User
+    {
+        if ($this->editor === null) {
+            $editorRole = Role::getRole('editor');
+            $this->editor = $editorRole->users->first();
+        }
+
+        return $this->editor;
+    }
+
+    /**
+     * Get an instance of a user with 'viewer' permissions.
+     */
+    protected function getViewer(array $attributes = []): User
+    {
+        $user = Role::getRole('viewer')->users()->first();
+        if (!empty($attributes)) {
+            $user->forceFill($attributes)->save();
+        }
+
+        return $user;
+    }
+
+    /**
+     * Get a user that's not a system user such as the guest user.
+     */
+    public function getNormalUser(): User
+    {
+        return User::query()->where('system_name', '=', null)->get()->last();
+    }
+
+    /**
+     * Regenerate the permission for an entity.
+     */
+    protected function regenEntityPermissions(Entity $entity): void
+    {
+        $entity->rebuildPermissions();
+        $entity->load('jointPermissions');
+    }
+
+    /**
+     * Create and return a new bookshelf.
+     */
+    public function newShelf(array $input = ['name' => 'test shelf', 'description' => 'My new test shelf']): Bookshelf
+    {
+        return app(BookshelfRepo::class)->create($input, []);
+    }
+
+    /**
+     * Create and return a new book.
+     */
+    public function newBook(array $input = ['name' => 'test book', 'description' => 'My new test book']): Book
+    {
+        return app(BookRepo::class)->create($input);
+    }
+
+    /**
+     * Create and return a new test chapter.
+     */
+    public function newChapter(array $input, Book $book): Chapter
+    {
+        return app(ChapterRepo::class)->create($input, $book);
+    }
+
+    /**
+     * Create and return a new test page.
+     */
+    public function newPage(array $input = ['name' => 'test page', 'html' => 'My new test page']): Page
+    {
+        $book = Book::query()->first();
+        $pageRepo = app(PageRepo::class);
+        $draftPage = $pageRepo->getNewDraftPage($book);
+
+        return $pageRepo->publishDraft($draftPage, $input);
+    }
+
+    /**
+     * Quickly sets an array of settings.
      */
-    public function get($uri, array $headers = [])
+    protected function setSettings(array $settingsArray): void
     {
-        return parent::get($uri, $headers);
+        $settings = app(SettingService::class);
+        foreach ($settingsArray as $key => $value) {
+            $settings->put($key, $value);
+        }
+    }
+
+    /**
+     * Manually set some permissions on an entity.
+     */
+    protected function setEntityRestrictions(Entity $entity, array $actions = [], array $roles = []): void
+    {
+        $entity->restricted = true;
+        $entity->permissions()->delete();
+
+        $permissions = [];
+        foreach ($actions as $action) {
+            foreach ($roles as $role) {
+                $permissions[] = [
+                    'role_id' => $role->id,
+                    'action'  => strtolower($action),
+                ];
+            }
+        }
+        $entity->permissions()->createMany($permissions);
+
+        $entity->save();
+        $entity->load('permissions');
+        $this->app->make(JointPermissionBuilder::class)->rebuildForEntity($entity);
+        $entity->load('jointPermissions');
     }
 
     /**
-     * Create the test response instance from the given response.
+     * Give the given user some permissions.
+     */
+    protected function giveUserPermissions(User $user, array $permissions = []): void
+    {
+        $newRole = $this->createNewRole($permissions);
+        $user->attachRole($newRole);
+        $user->load('roles');
+        $user->clearPermissionCache();
+    }
+
+    /**
+     * Completely remove the given permission name from the given user.
+     */
+    protected function removePermissionFromUser(User $user, string $permissionName)
+    {
+        $permissionBuilder = app()->make(JointPermissionBuilder::class);
+
+        /** @var RolePermission $permission */
+        $permission = RolePermission::query()->where('name', '=', $permissionName)->firstOrFail();
+
+        $roles = $user->roles()->whereHas('permissions', function ($query) use ($permission) {
+            $query->where('id', '=', $permission->id);
+        })->get();
+
+        /** @var Role $role */
+        foreach ($roles as $role) {
+            $role->detachPermission($permission);
+            $permissionBuilder->rebuildForRole($role);
+        }
+
+        $user->clearPermissionCache();
+    }
+
+    /**
+     * Create a new basic role for testing purposes.
+     */
+    protected function createNewRole(array $permissions = []): Role
+    {
+        $permissionRepo = app(PermissionsRepo::class);
+        $roleData = Role::factory()->make()->toArray();
+        $roleData['permissions'] = array_flip($permissions);
+
+        return $permissionRepo->saveNewRole($roleData);
+    }
+
+    /**
+     * Create a group of entities that belong to a specific user.
      *
-     * @param \Illuminate\Http\Response $response
+     * @return array{book: Book, chapter: Chapter, page: Page}
+     */
+    protected function createEntityChainBelongingToUser(User $creatorUser, ?User $updaterUser = null): array
+    {
+        if (empty($updaterUser)) {
+            $updaterUser = $creatorUser;
+        }
+
+        $userAttrs = ['created_by' => $creatorUser->id, 'owned_by' => $creatorUser->id, 'updated_by' => $updaterUser->id];
+        $book = Book::factory()->create($userAttrs);
+        $chapter = Chapter::factory()->create(array_merge(['book_id' => $book->id], $userAttrs));
+        $page = Page::factory()->create(array_merge(['book_id' => $book->id, 'chapter_id' => $chapter->id], $userAttrs));
+
+        $this->app->make(JointPermissionBuilder::class)->rebuildForEntity($book);
+
+        return compact('book', 'chapter', 'page');
+    }
+
+    /**
+     * Mock the HttpFetcher service and return the given data on fetch.
+     */
+    protected function mockHttpFetch($returnData, int $times = 1)
+    {
+        $mockHttp = Mockery::mock(HttpFetcher::class);
+        $this->app[HttpFetcher::class] = $mockHttp;
+        $mockHttp->shouldReceive('fetch')
+            ->times($times)
+            ->andReturn($returnData);
+    }
+
+    /**
+     * Mock the http client used in BookStack.
+     * Returns a reference to the container which holds all history of http transactions.
      *
-     * @return TestResponse
+     * @link https://docs.guzzlephp.org/en/stable/testing.html#history-middleware
      */
-    protected function createTestResponse($response)
+    protected function &mockHttpClient(array $responses = []): array
     {
-        return TestResponse::fromBaseResponse($response);
+        $container = [];
+        $history = Middleware::history($container);
+        $mock = new MockHandler($responses);
+        $handlerStack = new HandlerStack($mock);
+        $handlerStack->push($history);
+        $this->app[ClientInterface::class] = new Client(['handler' => $handlerStack]);
+
+        return $container;
+    }
+
+    /**
+     * Run a set test with the given env variable.
+     * Remembers the original and resets the value after test.
+     */
+    protected function runWithEnv(string $name, $value, callable $callback)
+    {
+        Env::disablePutenv();
+        $originalVal = $_SERVER[$name] ?? null;
+
+        if (is_null($value)) {
+            unset($_SERVER[$name]);
+        } else {
+            $_SERVER[$name] = $value;
+        }
+
+        $this->refreshApplication();
+        $callback();
+
+        if (is_null($originalVal)) {
+            unset($_SERVER[$name]);
+        } else {
+            $_SERVER[$name] = $originalVal;
+        }
+    }
+
+    /**
+     * Check the keys and properties in the given map to include
+     * exist, albeit not exclusively, within the map to check.
+     */
+    protected function assertArrayMapIncludes(array $mapToInclude, array $mapToCheck, string $message = ''): void
+    {
+        $passed = true;
+
+        foreach ($mapToInclude as $key => $value) {
+            if (!isset($mapToCheck[$key]) || $mapToCheck[$key] !== $mapToInclude[$key]) {
+                $passed = false;
+            }
+        }
+
+        $toIncludeStr = print_r($mapToInclude, true);
+        $toCheckStr = print_r($mapToCheck, true);
+        self::assertThat($passed, self::isTrue(), "Failed asserting that given map:\n\n{$toCheckStr}\n\nincludes:\n\n{$toIncludeStr}");
+    }
+
+    /**
+     * Assert a permission error has occurred.
+     */
+    protected function assertPermissionError($response)
+    {
+        PHPUnit::assertTrue($this->isPermissionError($response->baseResponse ?? $response->response), 'Failed asserting the response contains a permission error.');
+    }
+
+    /**
+     * Assert a permission error has occurred.
+     */
+    protected function assertNotPermissionError($response)
+    {
+        PHPUnit::assertFalse($this->isPermissionError($response->baseResponse ?? $response->response), 'Failed asserting the response does not contain a permission error.');
+    }
+
+    /**
+     * Check if the given response is a permission error.
+     */
+    private function isPermissionError($response): bool
+    {
+        return $response->status() === 302
+            && (
+                (
+                    $response->headers->get('Location') === url('/')
+                    && strpos(session()->pull('error', ''), 'You do not have permission to access') === 0
+                )
+                ||
+                (
+                    $response instanceof JsonResponse &&
+                    $response->json(['error' => 'You do not have permission to perform the requested action.'])
+                )
+            );
+    }
+
+    /**
+     * Assert that the session has a particular error notification message set.
+     */
+    protected function assertSessionError(string $message)
+    {
+        $error = session()->get('error');
+        PHPUnit::assertTrue($error === $message, "Failed asserting the session contains an error. \nFound: {$error}\nExpecting: {$message}");
+    }
+
+    /**
+     * Assert the session contains a specific entry.
+     */
+    protected function assertSessionHas(string $key): self
+    {
+        $this->assertTrue(session()->has($key), "Session does not contain a [{$key}] entry");
+
+        return $this;
+    }
+
+    protected function assertNotificationContains(\Illuminate\Testing\TestResponse $resp, string $text)
+    {
+        return $this->withHtml($resp)->assertElementContains('[notification]', $text);
+    }
+
+    /**
+     * Set a test handler as the logging interface for the application.
+     * Allows capture of logs for checking against during tests.
+     */
+    protected function withTestLogger(): TestHandler
+    {
+        $monolog = new Logger('testing');
+        $testHandler = new TestHandler();
+        $monolog->pushHandler($testHandler);
+
+        Log::extend('testing', function () use ($monolog) {
+            return $monolog;
+        });
+        Log::setDefaultDriver('testing');
+
+        return $testHandler;
     }
 
     /**
index e0350371afe00707ce8eb87f6597018e3f94f424..97f98225d4fe8b82920a2eb4b5d1cfc14f17c9fe 100644 (file)
@@ -12,8 +12,8 @@ class TestEmailTest extends TestCase
     {
         $pageView = $this->asAdmin()->get('/settings/maintenance');
         $formCssSelector = 'form[action$="/settings/maintenance/send-test-email"]';
-        $pageView->assertElementExists($formCssSelector);
-        $pageView->assertElementContains($formCssSelector . ' button', 'Send Test Email');
+        $this->withHtml($pageView)->assertElementExists($formCssSelector);
+        $this->withHtml($pageView)->assertElementContains($formCssSelector . ' button', 'Send Test Email');
     }
 
     public function test_send_test_email_endpoint_sends_email_and_redirects_user_and_shows_notification()
diff --git a/tests/TestResponse.php b/tests/TestResponse.php
deleted file mode 100644 (file)
index 888bacd..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-<?php
-
-namespace Tests;
-
-use Illuminate\Testing\TestResponse as BaseTestResponse;
-use PHPUnit\Framework\Assert as PHPUnit;
-use Symfony\Component\DomCrawler\Crawler;
-
-/**
- * Class TestResponse
- * Custom extension of the default Laravel TestResponse class.
- */
-class TestResponse extends BaseTestResponse
-{
-    protected $crawlerInstance;
-
-    /**
-     * Get the DOM Crawler for the response content.
-     */
-    protected function crawler(): Crawler
-    {
-        if (!is_object($this->crawlerInstance)) {
-            $this->crawlerInstance = new Crawler($this->getContent());
-        }
-
-        return $this->crawlerInstance;
-    }
-
-    /**
-     * Get the HTML of the first element at the given selector.
-     */
-    public function getElementHtml(string $selector): string
-    {
-        return $this->crawler()->filter($selector)->first()->outerHtml();
-    }
-
-    /**
-     * Assert the response contains the specified element.
-     *
-     * @return $this
-     */
-    public function assertElementExists(string $selector)
-    {
-        $elements = $this->crawler()->filter($selector);
-        PHPUnit::assertTrue(
-            $elements->count() > 0,
-            'Unable to find element matching the selector: ' . PHP_EOL . PHP_EOL .
-            "[{$selector}]" . PHP_EOL . PHP_EOL .
-            'within' . PHP_EOL . PHP_EOL .
-            "[{$this->getContent()}]."
-        );
-
-        return $this;
-    }
-
-    /**
-     * Assert the response contains the given count of elements
-     * that match the given css selector.
-     *
-     * @return $this
-     */
-    public function assertElementCount(string $selector, int $count)
-    {
-        $elements = $this->crawler()->filter($selector);
-        PHPUnit::assertTrue(
-            $elements->count() === $count,
-            'Unable to ' . $count . ' element(s) matching the selector: ' . PHP_EOL . PHP_EOL .
-            "[{$selector}]" . PHP_EOL . PHP_EOL .
-            'found ' . $elements->count() . ' within' . PHP_EOL . PHP_EOL .
-            "[{$this->getContent()}]."
-        );
-
-        return $this;
-    }
-
-    /**
-     * Assert the response does not contain the specified element.
-     *
-     * @return $this
-     */
-    public function assertElementNotExists(string $selector)
-    {
-        $elements = $this->crawler()->filter($selector);
-        PHPUnit::assertTrue(
-            $elements->count() === 0,
-            'Found elements matching the selector: ' . PHP_EOL . PHP_EOL .
-            "[{$selector}]" . PHP_EOL . PHP_EOL .
-            'within' . PHP_EOL . PHP_EOL .
-            "[{$this->getContent()}]."
-        );
-
-        return $this;
-    }
-
-    /**
-     * Assert the response includes a specific element containing the given text.
-     * If an nth match is provided, only that will be checked otherwise all matching
-     * elements will be checked for the given text.
-     *
-     * @return $this
-     */
-    public function assertElementContains(string $selector, string $text, ?int $nthMatch = null)
-    {
-        $elements = $this->crawler()->filter($selector);
-        $matched = false;
-        $pattern = $this->getEscapedPattern($text);
-
-        if (!is_null($nthMatch)) {
-            $elements = $elements->eq($nthMatch - 1);
-        }
-
-        foreach ($elements as $element) {
-            $element = new Crawler($element);
-            if (preg_match("/$pattern/i", $element->text())) {
-                $matched = true;
-                break;
-            }
-        }
-
-        PHPUnit::assertTrue(
-            $matched,
-            'Unable to find element of selector: ' . PHP_EOL . PHP_EOL .
-            ($nthMatch ? ("at position {$nthMatch}" . PHP_EOL . PHP_EOL) : '') .
-            "[{$selector}]" . PHP_EOL . PHP_EOL .
-            'containing text' . PHP_EOL . PHP_EOL .
-            "[{$text}]" . PHP_EOL . PHP_EOL .
-            'within' . PHP_EOL . PHP_EOL .
-            "[{$this->getContent()}]."
-        );
-
-        return $this;
-    }
-
-    /**
-     * Assert the response does not include a specific element containing the given text.
-     * If an nth match is provided, only that will be checked otherwise all matching
-     * elements will be checked for the given text.
-     *
-     * @return $this
-     */
-    public function assertElementNotContains(string $selector, string $text, ?int $nthMatch = null)
-    {
-        $elements = $this->crawler()->filter($selector);
-        $matched = false;
-        $pattern = $this->getEscapedPattern($text);
-
-        if (!is_null($nthMatch)) {
-            $elements = $elements->eq($nthMatch - 1);
-        }
-
-        foreach ($elements as $element) {
-            $element = new Crawler($element);
-            if (preg_match("/$pattern/i", $element->html())) {
-                $matched = true;
-                break;
-            }
-        }
-
-        PHPUnit::assertTrue(
-            !$matched,
-            'Found element of selector: ' . PHP_EOL . PHP_EOL .
-            ($nthMatch ? ("at position {$nthMatch}" . PHP_EOL . PHP_EOL) : '') .
-            "[{$selector}]" . PHP_EOL . PHP_EOL .
-            'containing text' . PHP_EOL . PHP_EOL .
-            "[{$text}]" . PHP_EOL . PHP_EOL .
-            'within' . PHP_EOL . PHP_EOL .
-            "[{$this->getContent()}]."
-        );
-
-        return $this;
-    }
-
-    /**
-     * Assert there's a notification within the view containing the given text.
-     *
-     * @return $this
-     */
-    public function assertNotificationContains(string $text)
-    {
-        return $this->assertElementContains('[notification]', $text);
-    }
-
-    /**
-     * Get the escaped text pattern for the constraint.
-     *
-     * @return string
-     */
-    protected function getEscapedPattern(string $text)
-    {
-        $rawPattern = preg_quote($text, '/');
-        $escapedPattern = preg_quote(e($text), '/');
-
-        return $rawPattern == $escapedPattern
-            ? $rawPattern : "({$rawPattern}|{$escapedPattern})";
-    }
-}
index 23b55a8baf219c609eec769c8470cb0c61f9f5d2..12a25a6d425131b2d52d21408d283721bafc244d 100644 (file)
@@ -37,7 +37,7 @@ class ThemeTest extends TestCase
             file_put_contents($translationPath . '/entities.php', $customTranslations);
 
             $homeRequest = $this->actingAs($this->getViewer())->get('/');
-            $homeRequest->assertElementContains('header nav', 'Sandwiches');
+            $this->withHtml($homeRequest)->assertElementContains('header nav', 'Sandwiches');
         });
     }
 
index 01754d2dec13c4dba843501723b3f9c0c1a9fcf1..c006f961240b42175baaf76014d80e0f2d206bd2 100644 (file)
@@ -104,11 +104,13 @@ class ImageTest extends TestCase
 
         $pageId = $imgDetails['page']->id;
         $firstPageRequest = $this->get("/images/gallery?page=1&uploaded_to={$pageId}");
-        $firstPageRequest->assertSuccessful()->assertElementExists('div');
+        $firstPageRequest->assertSuccessful();
+        $this->withHtml($firstPageRequest)->assertElementExists('div');
         $firstPageRequest->assertSuccessful()->assertSeeText($image->name);
 
         $secondPageRequest = $this->get("/images/gallery?page=2&uploaded_to={$pageId}");
-        $secondPageRequest->assertSuccessful()->assertElementNotExists('div');
+        $secondPageRequest->assertSuccessful();
+        $this->withHtml($secondPageRequest)->assertElementNotExists('div');
 
         $namePartial = substr($imgDetails['name'], 0, 3);
         $searchHitRequest = $this->get("/images/gallery?page=1&uploaded_to={$pageId}&search={$namePartial}");
@@ -117,7 +119,8 @@ class ImageTest extends TestCase
         $namePartial = Str::random(16);
         $searchFailRequest = $this->get("/images/gallery?page=1&uploaded_to={$pageId}&search={$namePartial}");
         $searchFailRequest->assertSuccessful()->assertDontSee($imgDetails['name']);
-        $searchFailRequest->assertSuccessful()->assertElementNotExists('div');
+        $searchFailRequest->assertSuccessful();
+        $this->withHtml($searchFailRequest)->assertElementNotExists('div');
     }
 
     public function test_image_usage()
index d3404b72ef14a11e21af96408d190b2d88f544f3..716f3614cb214f52a50fadb51e8468268d50c7c7 100644 (file)
@@ -93,10 +93,10 @@ class UserApiTokenTest extends TestCase
         $token = ApiToken::query()->latest()->first();
 
         $resp = $this->get($editor->getEditUrl());
-        $resp->assertElementExists('#api_tokens');
-        $resp->assertElementContains('#api_tokens', $token->name);
-        $resp->assertElementContains('#api_tokens', $token->token_id);
-        $resp->assertElementContains('#api_tokens', $token->expires_at->format('Y-m-d'));
+        $this->withHtml($resp)->assertElementExists('#api_tokens');
+        $this->withHtml($resp)->assertElementContains('#api_tokens', $token->name);
+        $this->withHtml($resp)->assertElementContains('#api_tokens', $token->token_id);
+        $this->withHtml($resp)->assertElementContains('#api_tokens', $token->expires_at->format('Y-m-d'));
     }
 
     public function test_secret_shown_once_after_creation()
@@ -161,7 +161,7 @@ class UserApiTokenTest extends TestCase
         $resp = $this->get($tokenUrl . '/delete');
         $resp->assertSeeText('Delete Token');
         $resp->assertSeeText($token->name);
-        $resp->assertElementExists('form[action="' . $tokenUrl . '"]');
+        $this->withHtml($resp)->assertElementExists('form[action="' . $tokenUrl . '"]');
 
         $resp = $this->delete($tokenUrl);
         $resp->assertRedirect($editor->getEditUrl('#api_tokens'));
index 5870b6827c763567fc4096aa151901ca6e442557..3102b7bde2856a95877cfcb675b868a753b90b17 100644 (file)
@@ -22,10 +22,10 @@ class UserManagementTest extends TestCase
         $adminRole = Role::getRole('admin');
 
         $resp = $this->asAdmin()->get('/settings/users');
-        $resp->assertElementContains('a[href="' . url('/settings/users/create') . '"]', 'Add New User');
+        $this->withHtml($resp)->assertElementContains('a[href="' . url('/settings/users/create') . '"]', 'Add New User');
 
-        $this->get('/settings/users/create')
-            ->assertElementContains('form[action="' . url('/settings/users/create') . '"]', 'Save');
+        $resp =$this->get('/settings/users/create');
+        $this->withHtml($resp)->assertElementContains('form[action="' . url('/settings/users/create') . '"]', 'Save');
 
         $resp = $this->post('/settings/users/create', [
             'name'                          => $user->name,
@@ -166,7 +166,7 @@ class UserManagementTest extends TestCase
         $guest = User::getDefault();
         $resp = $this->asAdmin()->get('/settings/users/' . $guest->id);
         $resp->assertSee('Guest');
-        $resp->assertElementNotExists('#password');
+        $this->withHtml($resp)->assertElementNotExists('#password');
     }
 
     public function test_guest_profile_cannot_be_deleted()
@@ -175,7 +175,7 @@ class UserManagementTest extends TestCase
         $resp = $this->asAdmin()->get('/settings/users/' . $guestUser->id . '/delete');
         $resp->assertSee('Delete User');
         $resp->assertSee('Guest');
-        $resp->assertElementContains('form[action$="/settings/users/' . $guestUser->id . '"] button', 'Confirm');
+        $this->withHtml($resp)->assertElementContains('form[action$="/settings/users/' . $guestUser->id . '"] button', 'Confirm');
 
         $resp = $this->delete('/settings/users/' . $guestUser->id);
         $resp->assertRedirect('/settings/users/' . $guestUser->id);
@@ -189,7 +189,7 @@ class UserManagementTest extends TestCase
         foreach ($langs as $lang) {
             config()->set('app.locale', $lang);
             $resp = $this->asAdmin()->get('/settings/users/create');
-            $resp->assertElementExists('select[name="language"] option[value="' . $lang . '"][selected]');
+            $this->withHtml($resp)->assertElementExists('select[name="language"] option[value="' . $lang . '"][selected]');
         }
     }
 
index b39c2c47c84bee8145b0340baade7a183d5bdac9..7f305285a4fc830cc1ff3f6f83871c54c7fda7fd 100644 (file)
@@ -81,8 +81,8 @@ class UserPreferencesTest extends TestCase
     public function test_toggle_dark_mode()
     {
         $home = $this->actingAs($this->getEditor())->get('/');
-        $home->assertElementNotExists('.dark-mode');
         $home->assertSee('Dark Mode');
+        $this->withHtml($home)->assertElementNotExists('.dark-mode');
 
         $this->assertEquals(false, setting()->getForCurrentUser('dark-mode-enabled', false));
         $prefChange = $this->patch('/settings/users/toggle-dark-mode');
@@ -90,7 +90,7 @@ class UserPreferencesTest extends TestCase
         $this->assertEquals(true, setting()->getForCurrentUser('dark-mode-enabled'));
 
         $home = $this->actingAs($this->getEditor())->get('/');
-        $home->assertElementExists('.dark-mode');
+        $this->withHtml($home)->assertElementExists('.dark-mode');
         $home->assertDontSee('Dark Mode');
         $home->assertSee('Light Mode');
     }
@@ -100,12 +100,12 @@ class UserPreferencesTest extends TestCase
         config()->set('setting-defaults.user.dark-mode-enabled', false);
         $this->assertEquals(false, setting()->getForCurrentUser('dark-mode-enabled'));
         $home = $this->get('/login');
-        $home->assertElementNotExists('.dark-mode');
+        $this->withHtml($home)->assertElementNotExists('.dark-mode');
 
         config()->set('setting-defaults.user.dark-mode-enabled', true);
         $this->assertEquals(true, setting()->getForCurrentUser('dark-mode-enabled'));
         $home = $this->get('/login');
-        $home->assertElementExists('.dark-mode');
+        $this->withHtml($home)->assertElementExists('.dark-mode');
     }
 
     public function test_books_view_type_preferences_when_list()
@@ -113,7 +113,8 @@ class UserPreferencesTest extends TestCase
         $editor = $this->getEditor();
         setting()->putUser($editor, 'books_view_type', 'list');
 
-        $this->actingAs($editor)->get('/books')
+        $resp = $this->actingAs($editor)->get('/books');
+        $this->withHtml($resp)
             ->assertElementNotExists('.featured-image-container')
             ->assertElementExists('.content-wrap .entity-list-item');
     }
@@ -123,8 +124,8 @@ class UserPreferencesTest extends TestCase
         $editor = $this->getEditor();
         setting()->putUser($editor, 'books_view_type', 'grid');
 
-        $this->actingAs($editor)->get('/books')
-            ->assertElementExists('.featured-image-container');
+        $resp = $this->actingAs($editor)->get('/books');
+        $this->withHtml($resp)->assertElementExists('.featured-image-container');
     }
 
     public function test_shelf_view_type_change()
@@ -134,17 +135,20 @@ class UserPreferencesTest extends TestCase
         $shelf = Bookshelf::query()->first();
         setting()->putUser($editor, 'bookshelf_view_type', 'list');
 
-        $this->actingAs($editor)->get($shelf->getUrl())
+        $resp = $this->actingAs($editor)->get($shelf->getUrl())->assertSee('Grid View');
+        $this->withHtml($resp)
             ->assertElementNotExists('.featured-image-container')
-            ->assertElementExists('.content-wrap .entity-list-item')
-            ->assertSee('Grid View');
+            ->assertElementExists('.content-wrap .entity-list-item');
 
         $req = $this->patch("/settings/users/{$editor->id}/switch-shelf-view", ['view_type' => 'grid']);
         $req->assertRedirect($shelf->getUrl());
 
-        $this->actingAs($editor)->get($shelf->getUrl())
-            ->assertElementExists('.featured-image-container')
-            ->assertElementNotExists('.content-wrap .entity-list-item')
+        $resp = $this->actingAs($editor)->get($shelf->getUrl())
             ->assertSee('List View');
+
+        $this->withHtml($resp)
+            ->assertElementExists('.featured-image-container')
+            ->assertElementNotExists('.content-wrap .entity-list-item');
+
     }
 }
index 8693689759dac65884d355db94977aae67c52524..e6136962ad9c51fb45891b35130a5d8912f95221 100644 (file)
@@ -44,17 +44,17 @@ class UserProfileTest extends TestCase
     {
         $newUser = User::factory()->create();
 
-        $this->asAdmin()->get('/user/' . $newUser->slug)
-            ->assertSee($newUser->name)
-            ->assertElementContains('#content-counts', '0 Books')
+        $resp = $this->asAdmin()->get('/user/' . $newUser->slug)
+            ->assertSee($newUser->name);
+        $this->withHtml($resp)->assertElementContains('#content-counts', '0 Books')
             ->assertElementContains('#content-counts', '0 Chapters')
             ->assertElementContains('#content-counts', '0 Pages');
 
         $this->createEntityChainBelongingToUser($newUser, $newUser);
 
-        $this->asAdmin()->get('/user/' . $newUser->slug)
-            ->assertSee($newUser->name)
-            ->assertElementContains('#content-counts', '1 Book')
+        $resp = $this->asAdmin()->get('/user/' . $newUser->slug)
+            ->assertSee($newUser->name);
+        $this->withHtml($resp)->assertElementContains('#content-counts', '1 Book')
             ->assertElementContains('#content-counts', '1 Chapter')
             ->assertElementContains('#content-counts', '1 Page');
     }
@@ -67,8 +67,8 @@ class UserProfileTest extends TestCase
         Activity::add(ActivityType::BOOK_UPDATE, $entities['book']);
         Activity::add(ActivityType::PAGE_CREATE, $entities['page']);
 
-        $this->asAdmin()->get('/user/' . $newUser->slug)
-            ->assertElementContains('#recent-user-activity', 'updated book')
+        $resp = $this->asAdmin()->get('/user/' . $newUser->slug);
+        $this->withHtml($resp)->assertElementContains('#recent-user-activity', 'updated book')
             ->assertElementContains('#recent-user-activity', 'created page')
             ->assertElementContains('#recent-user-activity', $entities['page']->name);
     }
@@ -82,8 +82,8 @@ class UserProfileTest extends TestCase
         Activity::add(ActivityType::PAGE_CREATE, $entities['page']);
 
         $linkSelector = '#recent-activity a[href$="/user/' . $newUser->slug . '"]';
-        $this->asAdmin()->get('/')
-            ->assertElementContains($linkSelector, $newUser->name);
+        $resp = $this->asAdmin()->get('/');
+        $this->withHtml($resp)->assertElementContains($linkSelector, $newUser->name);
     }
 
     public function test_profile_has_search_links_in_created_entity_lists()
@@ -99,7 +99,7 @@ class UserProfileTest extends TestCase
         ];
 
         foreach ($expectedLinks as $link) {
-            $resp->assertElementContains('[href$="' . $link . '"]', 'View All');
+            $this->withHtml($resp)->assertElementContains('[href$="' . $link . '"]', 'View All');
         }
     }
 }