"nunomaduro/collision": "^5.10",
"nunomaduro/larastan": "^1.0",
"phpunit/phpunit": "^9.5",
- "symfony/dom-crawler": "^5.3"
+ "ssddanbrown/asserthtml": "^1.0"
},
"autoload": {
"psr-4": {
"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",
+ "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",
$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()
$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');
$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()
$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()
$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()
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
{
{
// 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()
$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('/');
$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'));
$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()
{
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', [
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');
}
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
{
$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,
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()
$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()
$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()
// 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', [
$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'));
// 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,
// 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
// 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,
{
$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()
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()
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');
$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', [
$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],
]);
// 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()
]);
$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');
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
{
{
$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()
{
$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()
]);
$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()
// 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');
$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');
]);
$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());
namespace Tests;
use BookStack\Auth\Access\SocialAuthService;
+use Illuminate\Testing\TestResponse;
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()
{
$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()
$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()
$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]);
$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'));
{
$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()
$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()
$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]);
$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()
$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()
$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());
/** @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');
}
}
]);
$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');
$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');
$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()
/** @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()
$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);
}
{
$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);
}
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();
$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()
$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()
]);
$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'));
$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()
$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()
$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()
$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()
$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');
}
}
$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()
$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()
$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()
$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()
// 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()
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"]');
}
}
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 "]');
}
}
$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');
}
}
$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>');
}
}
$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');
}
}
$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:');
}
}
$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:');
}
}
$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');
}
}
$pageView = $this->get($page->getUrl());
$pageView->assertStatus(200);
- $pageView->assertElementNotContains('.page-content', 'onclick');
+ $this->withHtml($pageView)->assertElementNotContains('.page-content', 'onclick');
}
}
$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');
}
}
$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()
$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()
$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()
{
$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()
{
$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();
->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()
{
/** @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()
$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()
{
$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()
$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');
}
$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()
$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()
// 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()
$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()
$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()
$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()
$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()
$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)');
}
}
]);
$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 */
$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();
$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()
$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()
]);
$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()
]);
$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()
$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()
'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);
}
}
$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);
$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);
}
}
$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()
$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()
$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()
$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()
$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()
$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),
]);
$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),
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()
$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()
{
$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()
$homeVisit = $this->get('/');
$homeVisit->assertSee($name);
- $homeVisit->assertElementNotExists('#home-default');
+ $this->withHtml($homeVisit)->assertElementNotExists('#home-default');
$pageDeleteReq = $this->delete($customPage->getUrl());
$pageDeleteReq->assertStatus(302);
$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();
// 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()
$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');
}
}
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
$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']);
$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']);
]);
$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');
}
$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']);
]);
$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()
$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']);
$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()
$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()
$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()
$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']);
$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']);
]);
$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');
}
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
{
// 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,
$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,
// 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');
$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,
]);
/** @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()
$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()
$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',
$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',
}
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]);
$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('/');
}
$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());
$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('/');
}
$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');
'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('/');
}
$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('/');
}
]);
$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()
$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()
'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('/');
}
$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('/');
}
]);
$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()
$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 . ']"]');
}
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"]');
}
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()
$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'));
$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()
$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()
$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()
$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()
$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');
}
}
namespace Tests;
use BookStack\Util\CspService;
+use Illuminate\Testing\TestResponse;
class SecurityHeaderTest 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()
]]);
$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');
}
}
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}\"]");
}
}
+++ /dev/null
-<?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;
- }
-}
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;
}
/**
{
$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()
+++ /dev/null
-<?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})";
- }
-}
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');
});
}
$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}");
$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()
$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()
$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'));
$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,
$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()
$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);
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]');
}
}
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');
$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');
}
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()
$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');
}
$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()
$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');
+
}
}
{
$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');
}
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);
}
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()
];
foreach ($expectedLinks as $link) {
- $resp->assertElementContains('[href$="' . $link . '"]', 'View All');
+ $this->withHtml($resp)->assertElementContains('[href$="' . $link . '"]', 'View All');
}
}
}