1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-08-07 23:03:00 +03:00

My Account: Updated and started adding to tests

- Updated existing tests now affected by my-account changes.
- Updated some existing tests to more accuractly check the scenario.
- Updated some code styling in SocialController.
- Fixed redirects for social account flows to fit my-account.
- Added test for social account attaching.
- Added test for api token redirect handling.
This commit is contained in:
Dan Brown
2023-10-19 14:18:42 +01:00
parent 12946414b0
commit fabc854390
14 changed files with 302 additions and 227 deletions

View File

@@ -51,7 +51,7 @@ class WebhookCallTest extends TestCase
{
// This test must not fake the queue/bus since this covers an issue
// around handling and serialization of items now deleted from the database.
$this->newWebhook(['active' => true, 'endpoint' => 'https://wh.example.com'], ['all']);
$webhook = $this->newWebhook(['active' => true, 'endpoint' => 'https://wh.example.com'], ['all']);
$this->mockHttpClient([new Response(500)]);
$user = $this->users->newUser();
@@ -61,8 +61,10 @@ class WebhookCallTest extends TestCase
/** @var ApiToken $apiToken */
$editor = $this->users->editor();
$apiToken = ApiToken::factory()->create(['user_id' => $editor]);
$resp = $this->delete($editor->getEditUrl('/api-tokens/' . $apiToken->id));
$resp->assertRedirect($editor->getEditUrl('#api_tokens'));
$this->delete($apiToken->getUrl())->assertRedirect();
$webhook->refresh();
$this->assertEquals('Response status from endpoint was 500', $webhook->last_error);
}
public function test_failed_webhook_call_logs_error()

View File

@@ -18,7 +18,7 @@ class SocialAuthTest extends TestCase
$user = User::factory()->make();
$this->setSettings(['registration-enabled' => 'true']);
config(['GOOGLE_APP_ID' => 'abc123', 'GOOGLE_APP_SECRET' => '123abc', 'APP_URL' => 'http://localhost']);
config(['GOOGLE_APP_ID' => 'abc123', 'GOOGLE_APP_SECRET' => '123abc']);
$mockSocialite = $this->mock(Factory::class);
$mockSocialDriver = Mockery::mock(Provider::class);
@@ -45,7 +45,6 @@ class SocialAuthTest extends TestCase
config([
'GOOGLE_APP_ID' => 'abc123', 'GOOGLE_APP_SECRET' => '123abc',
'GITHUB_APP_ID' => 'abc123', 'GITHUB_APP_SECRET' => '123abc',
'APP_URL' => 'http://localhost',
]);
$mockSocialite = $this->mock(Factory::class);
@@ -86,12 +85,41 @@ class SocialAuthTest extends TestCase
$this->assertActivityExists(ActivityType::AUTH_LOGIN, null, 'github; (' . $this->users->admin()->id . ') ' . $this->users->admin()->name);
}
public function test_social_account_attach()
{
config([
'GOOGLE_APP_ID' => 'abc123', 'GOOGLE_APP_SECRET' => '123abc',
]);
$editor = $this->users->editor();
$mockSocialite = $this->mock(Factory::class);
$mockSocialDriver = Mockery::mock(Provider::class);
$mockSocialUser = Mockery::mock(\Laravel\Socialite\Contracts\User::class);
$mockSocialUser->shouldReceive('getId')->twice()->andReturn('logintest123');
$mockSocialUser->shouldReceive('getAvatar')->andReturn(null);
$mockSocialite->shouldReceive('driver')->twice()->with('google')->andReturn($mockSocialDriver);
$mockSocialDriver->shouldReceive('redirect')->once()->andReturn(redirect('/login/service/google/callback'));
$mockSocialDriver->shouldReceive('user')->once()->andReturn($mockSocialUser);
// Test login routes
$resp = $this->actingAs($editor)->followingRedirects()->get('/login/service/google');
$resp->assertSee('Access & Security');
// Test social callback with matching social account
$this->assertDatabaseHas('social_accounts', [
'user_id' => $editor->id,
'driver' => 'google',
'driver_id' => 'logintest123',
]);
}
public function test_social_account_detach()
{
$editor = $this->users->editor();
config([
'GITHUB_APP_ID' => 'abc123', 'GITHUB_APP_SECRET' => '123abc',
'APP_URL' => 'http://localhost',
]);
$socialAccount = SocialAccount::query()->forceCreate([
@@ -100,11 +128,11 @@ class SocialAuthTest extends TestCase
'driver_id' => 'logintest123',
]);
$resp = $this->actingAs($editor)->get($editor->getEditUrl());
$resp = $this->actingAs($editor)->get('/my-account/auth');
$this->withHtml($resp)->assertElementContains('form[action$="/login/service/github/detach"]', 'Disconnect Account');
$resp = $this->post('/login/service/github/detach');
$resp->assertRedirect($editor->getEditUrl());
$resp->assertRedirect('/my-account/auth#social-accounts');
$resp = $this->followRedirects($resp);
$resp->assertSee('Github account was successfully disconnected from your profile.');
@@ -115,7 +143,6 @@ class SocialAuthTest extends TestCase
{
config([
'services.google.client_id' => 'abc123', 'services.google.client_secret' => '123abc',
'APP_URL' => 'http://localhost',
]);
$user = User::factory()->make();
@@ -153,7 +180,7 @@ class SocialAuthTest extends TestCase
{
config([
'services.google.client_id' => 'abc123', 'services.google.client_secret' => '123abc',
'APP_URL' => 'http://localhost', 'services.google.auto_register' => true, 'services.google.auto_confirm' => true,
'services.google.auto_register' => true, 'services.google.auto_confirm' => true,
]);
$user = User::factory()->make();
@@ -191,7 +218,7 @@ class SocialAuthTest extends TestCase
$user = User::factory()->make(['email' => 'nonameuser@example.com']);
$this->setSettings(['registration-enabled' => 'true']);
config(['GITHUB_APP_ID' => 'abc123', 'GITHUB_APP_SECRET' => '123abc', 'APP_URL' => 'http://localhost']);
config(['GITHUB_APP_ID' => 'abc123', 'GITHUB_APP_SECRET' => '123abc']);
$mockSocialite = $this->mock(Factory::class);
$mockSocialDriver = Mockery::mock(Provider::class);

View File

@@ -44,14 +44,12 @@ class RolePermissionsTest extends TestCase
public function test_user_cannot_change_email_unless_they_have_manage_users_permission()
{
$userProfileUrl = '/settings/users/' . $this->user->id;
$originalEmail = $this->user->email;
$this->actingAs($this->user);
$resp = $this->get($userProfileUrl)
->assertOk();
$resp = $this->get('/my-account/profile')->assertOk();
$this->withHtml($resp)->assertElementExists('input[name=email][disabled]');
$this->put($userProfileUrl, [
$this->put('/my-account/profile', [
'name' => 'my_new_name',
'email' => 'new_email@example.com',
]);
@@ -63,11 +61,12 @@ class RolePermissionsTest extends TestCase
$this->permissions->grantUserRolePermissions($this->user, ['users-manage']);
$resp = $this->get($userProfileUrl)
->assertOk();
$this->withHtml($resp)->assertElementNotExists('input[name=email][disabled]')
$resp = $this->get('/my-account/profile')->assertOk();
$this->withHtml($resp)
->assertElementNotExists('input[name=email][disabled]')
->assertElementExists('input[name=email]');
$this->put($userProfileUrl, [
$this->put('/my-account/profile', [
'name' => 'my_new_name_2',
'email' => 'new_email@example.com',
]);

View File

@@ -607,7 +607,7 @@ class ImageTest extends TestCase
$this->actingAs($editor);
$file = $this->getTestProfileImage();
$this->call('PUT', '/settings/users/' . $editor->id, [], [], ['profile_image' => $file], []);
$this->call('PUT', '/my-account/profile', [], [], ['profile_image' => $file], []);
$profileImages = Image::where('type', '=', 'user')->where('created_by', '=', $editor->id)->get();
$this->assertTrue($profileImages->count() === 1, 'Found profile images does not match upload count');
@@ -615,7 +615,7 @@ class ImageTest extends TestCase
$imagePath = public_path($profileImages->first()->path);
$this->assertTrue(file_exists($imagePath));
$userDelete = $this->asAdmin()->delete("/settings/users/{$editor->id}");
$userDelete = $this->asAdmin()->delete($editor->getEditUrl());
$userDelete->assertStatus(302);
$this->assertDatabaseMissing('images', [

View File

@@ -5,25 +5,26 @@ namespace Tests\User;
use BookStack\Activity\ActivityType;
use BookStack\Api\ApiToken;
use Carbon\Carbon;
use Illuminate\Support\Facades\Hash;
use Tests\TestCase;
class UserApiTokenTest extends TestCase
{
protected $testTokenData = [
protected array $testTokenData = [
'name' => 'My test API token',
'expires_at' => '2050-04-01',
];
public function test_tokens_section_not_visible_without_access_api_permission()
public function test_tokens_section_not_visible_in_my_account_without_access_api_permission()
{
$user = $this->users->viewer();
$resp = $this->actingAs($user)->get($user->getEditUrl());
$resp = $this->actingAs($user)->get('/my-account/auth');
$resp->assertDontSeeText('API Tokens');
$this->permissions->grantUserRolePermissions($user, ['access-api']);
$resp = $this->actingAs($user)->get($user->getEditUrl());
$resp = $this->actingAs($user)->get('/my-account/auth');
$resp->assertSeeText('API Tokens');
$resp->assertSeeText('Create Token');
}
@@ -43,14 +44,14 @@ class UserApiTokenTest extends TestCase
{
$editor = $this->users->editor();
$resp = $this->asAdmin()->get($editor->getEditUrl('/create-api-token'));
$resp = $this->asAdmin()->get("/api-tokens/{$editor->id}/create");
$resp->assertStatus(200);
$resp->assertSee('Create API Token');
$resp->assertSee('Token Secret');
$resp = $this->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
$resp = $this->post("/api-tokens/{$editor->id}/create", $this->testTokenData);
$token = ApiToken::query()->latest()->first();
$resp->assertRedirect($editor->getEditUrl('/api-tokens/' . $token->id));
$resp->assertRedirect("/api-tokens/{$editor->id}/{$token->id}");
$this->assertDatabaseHas('api_tokens', [
'user_id' => $editor->id,
'name' => $this->testTokenData['name'],
@@ -63,7 +64,7 @@ class UserApiTokenTest extends TestCase
$this->assertDatabaseMissing('api_tokens', [
'secret' => $secret,
]);
$this->assertTrue(\Hash::check($secret, $token->secret));
$this->assertTrue(Hash::check($secret, $token->secret));
$this->assertTrue(strlen($token->token_id) === 32);
$this->assertTrue(strlen($secret) === 32);
@@ -75,7 +76,10 @@ class UserApiTokenTest extends TestCase
public function test_create_with_no_expiry_sets_expiry_hundred_years_away()
{
$editor = $this->users->editor();
$this->asAdmin()->post($editor->getEditUrl('/create-api-token'), ['name' => 'No expiry token', 'expires_at' => '']);
$resp = $this->asAdmin()->post("/api-tokens/{$editor->id}/create", ['name' => 'No expiry token', 'expires_at' => '']);
$resp->assertRedirect();
$token = ApiToken::query()->latest()->first();
$over = Carbon::now()->addYears(101);
@@ -89,7 +93,9 @@ class UserApiTokenTest extends TestCase
public function test_created_token_displays_on_profile_page()
{
$editor = $this->users->editor();
$this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
$resp = $this->asAdmin()->post("/api-tokens/{$editor->id}/create", $this->testTokenData);
$resp->assertRedirect();
$token = ApiToken::query()->latest()->first();
$resp = $this->get($editor->getEditUrl());
@@ -102,28 +108,29 @@ class UserApiTokenTest extends TestCase
public function test_secret_shown_once_after_creation()
{
$editor = $this->users->editor();
$resp = $this->asAdmin()->followingRedirects()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
$resp = $this->asAdmin()->followingRedirects()->post("/api-tokens/{$editor->id}/create", $this->testTokenData);
$resp->assertSeeText('Token Secret');
$token = ApiToken::query()->latest()->first();
$this->assertNull(session('api-token-secret:' . $token->id));
$resp = $this->get($editor->getEditUrl('/api-tokens/' . $token->id));
$resp = $this->get("/api-tokens/{$editor->id}/{$token->id}");
$resp->assertOk();
$resp->assertDontSeeText('Client Secret');
}
public function test_token_update()
{
$editor = $this->users->editor();
$this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
$this->asAdmin()->post("/api-tokens/{$editor->id}/create", $this->testTokenData);
$token = ApiToken::query()->latest()->first();
$updateData = [
'name' => 'My updated token',
'expires_at' => '2011-01-01',
];
$resp = $this->put($editor->getEditUrl('/api-tokens/' . $token->id), $updateData);
$resp->assertRedirect($editor->getEditUrl('/api-tokens/' . $token->id));
$resp = $this->put("/api-tokens/{$editor->id}/{$token->id}", $updateData);
$resp->assertRedirect("/api-tokens/{$editor->id}/{$token->id}");
$this->assertDatabaseHas('api_tokens', array_merge($updateData, ['id' => $token->id]));
$this->assertSessionHas('success');
@@ -133,13 +140,13 @@ class UserApiTokenTest extends TestCase
public function test_token_update_with_blank_expiry_sets_to_hundred_years_away()
{
$editor = $this->users->editor();
$this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
$this->asAdmin()->post("/api-tokens/{$editor->id}/create", $this->testTokenData);
$token = ApiToken::query()->latest()->first();
$resp = $this->put($editor->getEditUrl('/api-tokens/' . $token->id), [
$this->put("/api-tokens/{$editor->id}/{$token->id}", [
'name' => 'My updated token',
'expires_at' => '',
]);
])->assertRedirect();
$token->refresh();
$over = Carbon::now()->addYears(101);
@@ -153,15 +160,15 @@ class UserApiTokenTest extends TestCase
public function test_token_delete()
{
$editor = $this->users->editor();
$this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
$this->asAdmin()->post("/api-tokens/{$editor->id}/create", $this->testTokenData);
$token = ApiToken::query()->latest()->first();
$tokenUrl = $editor->getEditUrl('/api-tokens/' . $token->id);
$tokenUrl = "/api-tokens/{$editor->id}/{$token->id}";
$resp = $this->get($tokenUrl . '/delete');
$resp->assertSeeText('Delete Token');
$resp->assertSeeText($token->name);
$this->withHtml($resp)->assertElementExists('form[action="' . $tokenUrl . '"]');
$this->withHtml($resp)->assertElementExists('form[action$="' . $tokenUrl . '"]');
$resp = $this->delete($tokenUrl);
$resp->assertRedirect($editor->getEditUrl('#api_tokens'));
@@ -175,15 +182,46 @@ class UserApiTokenTest extends TestCase
$editor = $this->users->editor();
$this->permissions->grantUserRolePermissions($editor, ['users-manage']);
$this->asAdmin()->post($viewer->getEditUrl('/create-api-token'), $this->testTokenData);
$this->asAdmin()->post("/api-tokens/{$viewer->id}/create", $this->testTokenData);
$token = ApiToken::query()->latest()->first();
$resp = $this->actingAs($editor)->get($viewer->getEditUrl('/api-tokens/' . $token->id));
$resp = $this->actingAs($editor)->get("/api-tokens/{$viewer->id}/{$token->id}");
$resp->assertStatus(200);
$resp->assertSeeText('Delete Token');
$resp = $this->actingAs($editor)->delete($viewer->getEditUrl('/api-tokens/' . $token->id));
$resp = $this->actingAs($editor)->delete("/api-tokens/{$viewer->id}/{$token->id}");
$resp->assertRedirect($viewer->getEditUrl('#api_tokens'));
$this->assertDatabaseMissing('api_tokens', ['id' => $token->id]);
}
public function test_return_routes_change_depending_on_entry_context()
{
$user = $this->users->admin();
$returnByContext = [
'settings' => url("/settings/users/{$user->id}/#api_tokens"),
'my-account' => url('/my-account/auth#api_tokens'),
];
foreach ($returnByContext as $context => $returnUrl) {
$resp = $this->actingAs($user)->get("/api-tokens/{$user->id}/create?context={$context}");
$this->withHtml($resp)->assertLinkExists($returnUrl, 'Cancel');
$this->post("/api-tokens/{$user->id}/create", $this->testTokenData);
$token = $user->apiTokens()->latest()->first();
$resp = $this->get($token->getUrl());
$this->withHtml($resp)->assertLinkExists($returnUrl, 'Back');
$resp = $this->delete($token->getUrl());
$resp->assertRedirect($returnUrl);
}
}
public function test_context_assumed_for_editing_tokens_of_another_user()
{
$user = $this->users->viewer();
$resp = $this->asAdmin()->get("/api-tokens/{$user->id}/create?context=my-account");
$this->withHtml($resp)->assertLinkExists($user->getEditUrl('#api_tokens'), 'Cancel');
}
}

View File

@@ -0,0 +1,174 @@
<?php
namespace Tests\User;
use BookStack\Activity\Tools\UserEntityWatchOptions;
use BookStack\Activity\WatchLevels;
use Tests\TestCase;
class UserMyAccountTest extends TestCase
{
public function test_index_view()
{
$resp = $this->asEditor()->get('/my-account');
$resp->assertRedirect('/my-account/profile');
}
public function test_views_not_accessible_to_guest_user()
{
$categories = ['profile', 'auth', 'shortcuts', 'notifications', ''];
$this->setSettings(['app-public' => 'true']);
$this->permissions->grantUserRolePermissions($this->users->guest(), ['receive-notifications']);
foreach ($categories as $category) {
$resp = $this->get('/my-account/' . $category);
$resp->assertRedirect('/');
}
}
public function test_interface_shortcuts_updating()
{
$this->asEditor();
// View preferences with defaults
$resp = $this->get('/my-account/shortcuts');
$resp->assertSee('UI Shortcut Preferences');
$html = $this->withHtml($resp);
$html->assertFieldHasValue('enabled', 'false');
$html->assertFieldHasValue('shortcut[home_view]', '1');
// Update preferences
$resp = $this->put('/my-account/shortcuts', [
'enabled' => 'true',
'shortcut' => ['home_view' => 'Ctrl + 1'],
]);
$resp->assertRedirect('/my-account/shortcuts');
$resp->assertSessionHas('success', 'Shortcut preferences have been updated!');
// View updates to preferences page
$resp = $this->get('/my-account/shortcuts');
$html = $this->withHtml($resp);
$html->assertFieldHasValue('enabled', 'true');
$html->assertFieldHasValue('shortcut[home_view]', 'Ctrl + 1');
}
public function test_body_has_shortcuts_component_when_active()
{
$editor = $this->users->editor();
$this->actingAs($editor);
$this->withHtml($this->get('/'))->assertElementNotExists('body[component="shortcuts"]');
setting()->putUser($editor, 'ui-shortcuts-enabled', 'true');
$this->withHtml($this->get('/'))->assertElementExists('body[component="shortcuts"]');
}
public function test_notification_routes_requires_notification_permission()
{
$viewer = $this->users->viewer();
$resp = $this->actingAs($viewer)->get('/my-account/notifications');
$this->assertPermissionError($resp);
$resp = $this->actingAs($viewer)->get('/my-account/profile');
$resp->assertDontSeeText('Notification Preferences');
$resp = $this->put('/my-account/notifications');
$this->assertPermissionError($resp);
$this->permissions->grantUserRolePermissions($viewer, ['receive-notifications']);
$resp = $this->get('/my-account/notifications');
$resp->assertOk();
$resp->assertSee('Notification Preferences');
}
public function test_notification_preferences_updating()
{
$editor = $this->users->editor();
// View preferences with defaults
$resp = $this->actingAs($editor)->get('/my-account/notifications');
$resp->assertSee('Notification Preferences');
$html = $this->withHtml($resp);
$html->assertFieldHasValue('preferences[comment-replies]', 'false');
// Update preferences
$resp = $this->put('/my-account/notifications', [
'preferences' => ['comment-replies' => 'true'],
]);
$resp->assertRedirect('/my-account/notifications');
$resp->assertSessionHas('success', 'Notification preferences have been updated!');
// View updates to preferences page
$resp = $this->get('/my-account/notifications');
$html = $this->withHtml($resp);
$html->assertFieldHasValue('preferences[comment-replies]', 'true');
}
public function test_notification_preferences_show_watches()
{
$editor = $this->users->editor();
$book = $this->entities->book();
$options = new UserEntityWatchOptions($editor, $book);
$options->updateLevelByValue(WatchLevels::COMMENTS);
$resp = $this->actingAs($editor)->get('/my-account/notifications');
$resp->assertSee($book->name);
$resp->assertSee('All Page Updates & Comments');
$options->updateLevelByValue(WatchLevels::DEFAULT);
$resp = $this->actingAs($editor)->get('/my-account/notifications');
$resp->assertDontSee($book->name);
$resp->assertDontSee('All Page Updates & Comments');
}
public function test_notification_preferences_dont_error_on_deleted_items()
{
$editor = $this->users->editor();
$book = $this->entities->book();
$options = new UserEntityWatchOptions($editor, $book);
$options->updateLevelByValue(WatchLevels::COMMENTS);
$this->actingAs($editor)->delete($book->getUrl());
$book->refresh();
$this->assertNotNull($book->deleted_at);
$resp = $this->actingAs($editor)->get('/my-account/notifications');
$resp->assertOk();
$resp->assertDontSee($book->name);
}
public function test_notification_preferences_not_accessible_to_guest()
{
$this->setSettings(['app-public' => 'true']);
$guest = $this->users->guest();
$this->permissions->grantUserRolePermissions($guest, ['receive-notifications']);
$resp = $this->get('/my-account/notifications');
$this->assertPermissionError($resp);
$resp = $this->put('/my-account/notifications', [
'preferences' => ['comment-replies' => 'true'],
]);
$this->assertPermissionError($resp);
}
public function test_notification_comment_options_only_exist_if_comments_active()
{
$resp = $this->asEditor()->get('/my-account/notifications');
$resp->assertSee('Notify upon comments');
$resp->assertSee('Notify upon replies');
setting()->put('app-disable-comments', true);
$resp = $this->get('/my-account/notifications');
$resp->assertDontSee('Notify upon comments');
$resp->assertDontSee('Notify upon replies');
}
}

View File

@@ -8,167 +8,6 @@ use Tests\TestCase;
class UserPreferencesTest extends TestCase
{
public function test_index_view()
{
$resp = $this->asEditor()->get('/preferences');
$resp->assertOk();
$resp->assertSee('Interface Keyboard Shortcuts');
$resp->assertSee('Edit Profile');
}
public function test_index_view_accessible_but_without_profile_and_notifications_for_guest_user()
{
$this->setSettings(['app-public' => 'true']);
$this->permissions->grantUserRolePermissions($this->users->guest(), ['receive-notifications']);
$resp = $this->get('/preferences');
$resp->assertOk();
$resp->assertSee('Interface Keyboard Shortcuts');
$resp->assertDontSee('Edit Profile');
$resp->assertDontSee('Notification');
}
public function test_interface_shortcuts_updating()
{
$this->asEditor();
// View preferences with defaults
$resp = $this->get('/preferences/shortcuts');
$resp->assertSee('Interface Keyboard Shortcuts');
$html = $this->withHtml($resp);
$html->assertFieldHasValue('enabled', 'false');
$html->assertFieldHasValue('shortcut[home_view]', '1');
// Update preferences
$resp = $this->put('/preferences/shortcuts', [
'enabled' => 'true',
'shortcut' => ['home_view' => 'Ctrl + 1'],
]);
$resp->assertRedirect('/preferences/shortcuts');
$resp->assertSessionHas('success', 'Shortcut preferences have been updated!');
// View updates to preferences page
$resp = $this->get('/preferences/shortcuts');
$html = $this->withHtml($resp);
$html->assertFieldHasValue('enabled', 'true');
$html->assertFieldHasValue('shortcut[home_view]', 'Ctrl + 1');
}
public function test_body_has_shortcuts_component_when_active()
{
$editor = $this->users->editor();
$this->actingAs($editor);
$this->withHtml($this->get('/'))->assertElementNotExists('body[component="shortcuts"]');
setting()->putUser($editor, 'ui-shortcuts-enabled', 'true');
$this->withHtml($this->get('/'))->assertElementExists('body[component="shortcuts"]');
}
public function test_notification_routes_requires_notification_permission()
{
$viewer = $this->users->viewer();
$resp = $this->actingAs($viewer)->get('/preferences/notifications');
$this->assertPermissionError($resp);
$resp = $this->put('/preferences/notifications');
$this->assertPermissionError($resp);
$this->permissions->grantUserRolePermissions($viewer, ['receive-notifications']);
$resp = $this->get('/preferences/notifications');
$resp->assertOk();
$resp->assertSee('Notification Preferences');
}
public function test_notification_preferences_updating()
{
$editor = $this->users->editor();
// View preferences with defaults
$resp = $this->actingAs($editor)->get('/preferences/notifications');
$resp->assertSee('Notification Preferences');
$html = $this->withHtml($resp);
$html->assertFieldHasValue('preferences[comment-replies]', 'false');
// Update preferences
$resp = $this->put('/preferences/notifications', [
'preferences' => ['comment-replies' => 'true'],
]);
$resp->assertRedirect('/preferences/notifications');
$resp->assertSessionHas('success', 'Notification preferences have been updated!');
// View updates to preferences page
$resp = $this->get('/preferences/notifications');
$html = $this->withHtml($resp);
$html->assertFieldHasValue('preferences[comment-replies]', 'true');
}
public function test_notification_preferences_show_watches()
{
$editor = $this->users->editor();
$book = $this->entities->book();
$options = new UserEntityWatchOptions($editor, $book);
$options->updateLevelByValue(WatchLevels::COMMENTS);
$resp = $this->actingAs($editor)->get('/preferences/notifications');
$resp->assertSee($book->name);
$resp->assertSee('All Page Updates & Comments');
$options->updateLevelByValue(WatchLevels::DEFAULT);
$resp = $this->actingAs($editor)->get('/preferences/notifications');
$resp->assertDontSee($book->name);
$resp->assertDontSee('All Page Updates & Comments');
}
public function test_notification_preferences_dont_error_on_deleted_items()
{
$editor = $this->users->editor();
$book = $this->entities->book();
$options = new UserEntityWatchOptions($editor, $book);
$options->updateLevelByValue(WatchLevels::COMMENTS);
$this->actingAs($editor)->delete($book->getUrl());
$book->refresh();
$this->assertNotNull($book->deleted_at);
$resp = $this->actingAs($editor)->get('/preferences/notifications');
$resp->assertOk();
$resp->assertDontSee($book->name);
}
public function test_notification_preferences_not_accessible_to_guest()
{
$this->setSettings(['app-public' => 'true']);
$guest = $this->users->guest();
$this->permissions->grantUserRolePermissions($guest, ['receive-notifications']);
$resp = $this->get('/preferences/notifications');
$this->assertPermissionError($resp);
$resp = $this->put('/preferences/notifications', [
'preferences' => ['comment-replies' => 'true'],
]);
$this->assertPermissionError($resp);
}
public function test_notification_comment_options_only_exist_if_comments_active()
{
$resp = $this->asEditor()->get('/preferences/notifications');
$resp->assertSee('Notify upon comments');
$resp->assertSee('Notify upon replies');
setting()->put('app-disable-comments', true);
$resp = $this->get('/preferences/notifications');
$resp->assertDontSee('Notify upon comments');
$resp->assertDontSee('Notify upon replies');
}
public function test_update_sort_preference()
{
$editor = $this->users->editor();