diff options
author | Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> | 2015-06-15 11:29:36 +0000 |
---|---|---|
committer | Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> | 2015-06-15 11:29:36 +0000 |
commit | 7300729190f4e61c4e71f18d0a81ea044eaad98a (patch) | |
tree | 03cef3fbfd21712f1b19ea21c84ab62253940671 /spec | |
parent | 168d5eabd40f5767d1287fe194e57ed05ef5d990 (diff) | |
parent | 9eec51d914bc79fed479a4e3e7b86fda58ad77c8 (diff) | |
download | gitlab-ce-7300729190f4e61c4e71f18d0a81ea044eaad98a.tar.gz |
Merge branch 'rs-dev-issue-2228' into 'master'
Allow user to customize default Dashboard page
Renames the "Design" profile page to "Preferences" and adds a field to customize the default Dashboard page:
> ![Screen_Shot_2015-06-11_at_11.12.53_PM](https://gitlab.com/gitlab-org/gitlab-ce/uploads/b5282a3be7861d1148528c6bc9e7a0e0/Screen_Shot_2015-06-11_at_11.12.53_PM.png)
See merge request !778
Diffstat (limited to 'spec')
-rw-r--r-- | spec/controllers/profiles/preferences_controller_spec.rb | 88 | ||||
-rw-r--r-- | spec/controllers/root_controller_spec.rb | 32 | ||||
-rw-r--r-- | spec/features/profiles/preferences_spec.rb | 82 | ||||
-rw-r--r-- | spec/features/security/profile_access_spec.rb | 4 | ||||
-rw-r--r-- | spec/helpers/application_helper_spec.rb | 21 | ||||
-rw-r--r-- | spec/helpers/preferences_helper_spec.rb | 72 | ||||
-rw-r--r-- | spec/lib/gitlab/themes_spec.rb | 51 | ||||
-rw-r--r-- | spec/models/user_spec.rb | 7 | ||||
-rw-r--r-- | spec/routing/routing_spec.rb | 25 | ||||
-rw-r--r-- | spec/support/capybara.rb | 33 | ||||
-rw-r--r-- | spec/support/login_helpers.rb | 24 |
11 files changed, 404 insertions, 35 deletions
diff --git a/spec/controllers/profiles/preferences_controller_spec.rb b/spec/controllers/profiles/preferences_controller_spec.rb new file mode 100644 index 00000000000..1f0943c93d8 --- /dev/null +++ b/spec/controllers/profiles/preferences_controller_spec.rb @@ -0,0 +1,88 @@ +require 'spec_helper' + +describe Profiles::PreferencesController do + let(:user) { create(:user) } + + before do + sign_in(user) + + allow(subject).to receive(:current_user).and_return(user) + end + + describe 'GET show' do + it 'renders' do + get :show + expect(response).to render_template :show + end + + it 'assigns user' do + get :show + expect(assigns[:user]).to eq user + end + end + + describe 'PATCH update' do + def go(params: {}, format: :js) + params.reverse_merge!( + color_scheme_id: '1', + dashboard: 'stars', + theme_id: '1' + ) + + patch :update, user: params, format: format + end + + context 'on successful update' do + it 'sets the flash' do + go + expect(flash[:notice]).to eq 'Preferences saved.' + end + + it "changes the user's preferences" do + prefs = { + color_scheme_id: '1', + dashboard: 'stars', + theme_id: '2' + }.with_indifferent_access + + expect(user).to receive(:update_attributes).with(prefs) + + go params: prefs + end + end + + context 'on failed update' do + it 'sets the flash' do + expect(user).to receive(:update_attributes).and_return(false) + + go + + expect(flash[:alert]).to eq('Failed to save preferences.') + end + end + + context 'on invalid dashboard setting' do + it 'sets the flash' do + prefs = {dashboard: 'invalid'} + + go params: prefs + + expect(flash[:alert]).to match(/\AFailed to save preferences \(.+\)\.\z/) + end + end + + context 'as js' do + it 'renders' do + go + expect(response).to render_template :update + end + end + + context 'as html' do + it 'redirects' do + go format: :html + expect(response).to redirect_to(profile_preferences_path) + end + end + end +end diff --git a/spec/controllers/root_controller_spec.rb b/spec/controllers/root_controller_spec.rb new file mode 100644 index 00000000000..abbbf6855fc --- /dev/null +++ b/spec/controllers/root_controller_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe RootController do + describe 'GET show' do + context 'with a user' do + let(:user) { create(:user) } + + before do + sign_in(user) + allow(subject).to receive(:current_user).and_return(user) + end + + context 'who has customized their dashboard setting' do + before do + user.update_attribute(:dashboard, 'stars') + end + + it 'redirects to their specified dashboard' do + get :show + expect(response).to redirect_to starred_dashboard_projects_path + end + end + + context 'who uses the default dashboard setting' do + it 'renders the default dashboard' do + get :show + expect(response).to render_template 'dashboard/show' + end + end + end + end +end diff --git a/spec/features/profiles/preferences_spec.rb b/spec/features/profiles/preferences_spec.rb new file mode 100644 index 00000000000..69d15f41706 --- /dev/null +++ b/spec/features/profiles/preferences_spec.rb @@ -0,0 +1,82 @@ +require 'spec_helper' + +describe 'Profile > Preferences' do + let(:user) { create(:user) } + + before do + login_as(user) + visit profile_preferences_path + end + + describe 'User changes their application theme', js: true do + let(:default) { Gitlab::Themes.default } + let(:theme) { Gitlab::Themes.by_id(5) } + + it 'creates a flash message' do + choose "user_theme_id_#{theme.id}" + + expect_preferences_saved_message + end + + it 'updates their preference' do + choose "user_theme_id_#{theme.id}" + + allowing_for_delay do + visit page.current_path + expect(page).to have_checked_field("user_theme_id_#{theme.id}") + end + end + + it 'reflects the changes immediately' do + expect(page).to have_selector("body.#{default.css_class}") + + choose "user_theme_id_#{theme.id}" + + expect(page).not_to have_selector("body.#{default.css_class}") + expect(page).to have_selector("body.#{theme.css_class}") + end + end + + describe 'User changes their syntax highlighting theme', js: true do + it 'creates a flash message' do + choose 'user_color_scheme_id_5' + + expect_preferences_saved_message + end + + it 'updates their preference' do + choose 'user_color_scheme_id_5' + + allowing_for_delay do + visit page.current_path + expect(page).to have_checked_field('user_color_scheme_id_5') + end + end + end + + describe 'User changes their default dashboard' do + it 'creates a flash message' do + select 'Starred Projects', from: 'user_dashboard' + click_button 'Save' + + expect_preferences_saved_message + end + + it 'updates their preference' do + select 'Starred Projects', from: 'user_dashboard' + click_button 'Save' + + click_link 'Dashboard' + expect(page.current_path).to eq starred_dashboard_projects_path + + click_link 'Your Projects' + expect(page.current_path).to eq dashboard_path + end + end + + def expect_preferences_saved_message + within('.flash-container') do + expect(page).to have_content('Preferences saved.') + end + end +end diff --git a/spec/features/security/profile_access_spec.rb b/spec/features/security/profile_access_spec.rb index 2512a9c0e3d..2b09771851e 100644 --- a/spec/features/security/profile_access_spec.rb +++ b/spec/features/security/profile_access_spec.rb @@ -36,8 +36,8 @@ describe "Profile access", feature: true do it { is_expected.to be_denied_for :visitor } end - describe "GET /profile/design" do - subject { design_profile_path } + describe "GET /profile/preferences" do + subject { profile_preferences_path } it { is_expected.to be_allowed_for @u1 } it { is_expected.to be_allowed_for :admin } diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 3307ac776fc..47e10197f5c 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -185,27 +185,6 @@ describe ApplicationHelper do end end - describe 'user_color_scheme_class' do - context 'with current_user is nil' do - it 'should return a string' do - allow(self).to receive(:current_user).and_return(nil) - expect(user_color_scheme_class).to be_kind_of(String) - end - end - - context 'with a current_user' do - (1..5).each do |color_scheme_id| - context "with color_scheme_id == #{color_scheme_id}" do - it 'should return a string' do - current_user = double(:color_scheme_id => color_scheme_id) - allow(self).to receive(:current_user).and_return(current_user) - expect(user_color_scheme_class).to be_kind_of(String) - end - end - end - end - end - describe 'simple_sanitize' do let(:a_tag) { '<a href="#">Foo</a>' } diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb new file mode 100644 index 00000000000..920de8c4325 --- /dev/null +++ b/spec/helpers/preferences_helper_spec.rb @@ -0,0 +1,72 @@ +require 'spec_helper' + +describe PreferencesHelper do + describe 'user_application_theme' do + context 'with a user' do + it "returns user's theme's css_class" do + user = double('user', theme_id: 3) + allow(self).to receive(:current_user).and_return(user) + expect(user_application_theme).to eq 'ui_green' + end + + it 'returns the default when id is invalid' do + user = double('user', theme_id: Gitlab::Themes::THEMES.size + 5) + + allow(Gitlab.config.gitlab).to receive(:default_theme).and_return(2) + allow(self).to receive(:current_user).and_return(user) + + expect(user_application_theme).to eq 'ui_charcoal' + end + end + + context 'without a user' do + before do + allow(self).to receive(:current_user).and_return(nil) + end + + it 'returns the default theme' do + expect(user_application_theme).to eq Gitlab::Themes.default.css_class + end + end + end + + describe 'dashboard_choices' do + it 'raises an exception when defined choices may be missing' do + expect(User).to receive(:dashboards).and_return(foo: 'foo') + expect { dashboard_choices }.to raise_error(RuntimeError) + end + + it 'raises an exception when defined choices may be using the wrong key' do + expect(User).to receive(:dashboards).and_return(foo: 'foo', bar: 'bar') + expect { dashboard_choices }.to raise_error(KeyError) + end + + it 'provides better option descriptions' do + expect(dashboard_choices).to match_array [ + ['Your Projects (default)', 'projects'], + ['Starred Projects', 'stars'] + ] + end + end + + describe 'user_color_scheme_class' do + context 'with current_user is nil' do + it 'should return a string' do + allow(self).to receive(:current_user).and_return(nil) + expect(user_color_scheme_class).to be_kind_of(String) + end + end + + context 'with a current_user' do + (1..5).each do |color_scheme_id| + context "with color_scheme_id == #{color_scheme_id}" do + it 'should return a string' do + current_user = double(:color_scheme_id => color_scheme_id) + allow(self).to receive(:current_user).and_return(current_user) + expect(user_color_scheme_class).to be_kind_of(String) + end + end + end + end + end +end diff --git a/spec/lib/gitlab/themes_spec.rb b/spec/lib/gitlab/themes_spec.rb new file mode 100644 index 00000000000..9c6c3fd8104 --- /dev/null +++ b/spec/lib/gitlab/themes_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +describe Gitlab::Themes do + describe '.body_classes' do + it 'returns a space-separated list of class names' do + css = described_class.body_classes + + expect(css).to include('ui_graphite') + expect(css).to include(' ui_charcoal ') + expect(css).to include(' ui_blue') + end + end + + describe '.by_id' do + it 'returns a Theme by its ID' do + expect(described_class.by_id(1).name).to eq 'Graphite' + expect(described_class.by_id(6).name).to eq 'Blue' + end + end + + describe '.default' do + it 'returns the default application theme' do + allow(described_class).to receive(:default_id).and_return(2) + expect(described_class.default.id).to eq 2 + end + + it 'prevents an infinite loop when configuration default is invalid' do + default = described_class::APPLICATION_DEFAULT + themes = described_class::THEMES + + config = double(default_theme: 0).as_null_object + allow(Gitlab).to receive(:config).and_return(config) + expect(described_class.default.id).to eq default + + config = double(default_theme: themes.size + 5).as_null_object + allow(Gitlab).to receive(:config).and_return(config) + expect(described_class.default.id).to eq default + end + end + + describe '.each' do + it 'passes the block to the THEMES Array' do + ids = [] + described_class.each { |theme| ids << theme.id } + expect(ids).not_to be_empty + + # TODO (rspeicher): RSpec 3.x + # expect(described_class.each).to yield_with_arg(described_class::Theme) + end + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index f1b8afa5854..f3e278e5c5f 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -50,12 +50,13 @@ # bitbucket_access_token :string(255) # bitbucket_access_token_secret :string(255) # location :string(255) +# public_email :string(255) default(""), not null # encrypted_otp_secret :string(255) # encrypted_otp_secret_iv :string(255) # encrypted_otp_secret_salt :string(255) # otp_required_for_login :boolean # otp_backup_codes :text -# public_email :string(255) default(""), not null +# dashboard :integer default(0) # require 'spec_helper' @@ -329,12 +330,12 @@ describe User do end describe 'with default overrides' do - let(:user) { User.new(projects_limit: 123, can_create_group: false, can_create_team: true, theme_id: Gitlab::Theme::BASIC) } + let(:user) { User.new(projects_limit: 123, can_create_group: false, can_create_team: true, theme_id: 1) } it "should apply defaults to user" do expect(user.projects_limit).to eq(123) expect(user.can_create_group).to be_falsey - expect(user.theme_id).to eq(Gitlab::Theme::BASIC) + expect(user.theme_id).to eq(1) end end end diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index 953c8dd8ddc..f268e4755d1 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -102,7 +102,6 @@ end # profile_token GET /profile/token(.:format) profile#token # profile_reset_private_token PUT /profile/reset_private_token(.:format) profile#reset_private_token # profile GET /profile(.:format) profile#show -# profile_design GET /profile/design(.:format) profile#design # profile_update PUT /profile/update(.:format) profile#update describe ProfilesController, "routing" do it "to #account" do @@ -120,9 +119,19 @@ describe ProfilesController, "routing" do it "to #show" do expect(get("/profile")).to route_to('profiles#show') end +end - it "to #design" do - expect(get("/profile/design")).to route_to('profiles#design') +# profile_preferences GET /profile/preferences(.:format) profiles/preferences#show +# PATCH /profile/preferences(.:format) profiles/preferences#update +# PUT /profile/preferences(.:format) profiles/preferences#update +describe Profiles::PreferencesController, 'routing' do + it 'to #show' do + expect(get('/profile/preferences')).to route_to('profiles/preferences#show') + end + + it 'to #update' do + expect(put('/profile/preferences')).to route_to('profiles/preferences#update') + expect(patch('/profile/preferences')).to route_to('profiles/preferences#update') end end @@ -195,11 +204,9 @@ end # dashboard GET /dashboard(.:format) dashboard#show # dashboard_issues GET /dashboard/issues(.:format) dashboard#issues # dashboard_merge_requests GET /dashboard/merge_requests(.:format) dashboard#merge_requests -# root / dashboard#show describe DashboardController, "routing" do it "to #index" do expect(get("/dashboard")).to route_to('dashboard#show') - expect(get("/")).to route_to('dashboard#show') end it "to #issues" do @@ -211,6 +218,14 @@ describe DashboardController, "routing" do end end +# root / root#show +describe RootController, 'routing' do + it 'to #show' do + expect(get('/')).to route_to('root#show') + end +end + + # new_user_session GET /users/sign_in(.:format) devise/sessions#new # user_session POST /users/sign_in(.:format) devise/sessions#create # destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index fed1ab6ee33..3e41aec425a 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -19,3 +19,36 @@ unless ENV['CI'] || ENV['CI_SERVER'] # Keep only the screenshots generated from the last failing test suite Capybara::Screenshot.prune_strategy = :keep_last_run end + +module CapybaraHelpers + # Execute a block a certain number of times before considering it a failure + # + # The given block is called, and if it raises a `Capybara::ExpectationNotMet` + # error, we wait `interval` seconds and then try again, until `retries` is + # met. + # + # This allows for better handling of timing-sensitive expectations in a + # sketchy CI environment, for example. + # + # interval - Delay between retries in seconds (default: 0.5) + # retries - Number of times to execute before failing (default: 5) + def allowing_for_delay(interval: 0.5, retries: 5) + tries = 0 + + begin + yield + rescue Capybara::ExpectationNotMet => ex + if tries <= retries + tries += 1 + sleep interval + retry + else + raise ex + end + end + end +end + +RSpec.configure do |config| + config.include CapybaraHelpers, type: :feature +end diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb index 791d2a1fd64..1bd68552012 100644 --- a/spec/support/login_helpers.rb +++ b/spec/support/login_helpers.rb @@ -1,9 +1,25 @@ module LoginHelpers - # Internal: Create and log in as a user of the specified role + # Internal: Log in as a specific user or a new user of a specific role # - # role - User role (e.g., :admin, :user) - def login_as(role) - @user = create(role) + # user_or_role - User object, or a role to create (e.g., :admin, :user) + # + # Examples: + # + # # Create a user automatically + # login_as(:user) + # + # # Create an admin automatically + # login_as(:admin) + # + # # Provide an existing User record + # user = create(:user) + # login_as(user) + def login_as(user_or_role) + if user_or_role.kind_of?(User) + @user = user_or_role + else + @user = create(user_or_role) + end login_with(@user) end |