diff --git a/app/javascript/src/components/AlertsContainer/index.jsx b/app/javascript/src/components/AlertsContainer/index.jsx index 0577b1ad0..04587fb83 100644 --- a/app/javascript/src/components/AlertsContainer/index.jsx +++ b/app/javascript/src/components/AlertsContainer/index.jsx @@ -32,7 +32,7 @@ class AlertsContainer extends Component { render() { return ( - + {this.props.alerts.map((alert) => ({ alerts }); -export default connect(mapStateToProps, { clearAlert })(AlertsContainer); \ No newline at end of file +export default connect(mapStateToProps, { clearAlert })(AlertsContainer); diff --git a/app/javascript/src/config/locales/messages.js b/app/javascript/src/config/locales/messages.js index cc46e69f2..c4fdca779 100644 --- a/app/javascript/src/config/locales/messages.js +++ b/app/javascript/src/config/locales/messages.js @@ -68,6 +68,7 @@ export default { shows_total_entries: "Showing {start} to {to} of {total} entries.", leave_team: "Leave team", account: "Account", + success_update_flash: "Your account has been updated successfully", team: "Team", avatar: "Avatar", edit_avatar: "Edit Avatar", diff --git a/app/javascript/src/scenes/SettingsPage/components/InputDisabled.jsx b/app/javascript/src/scenes/SettingsPage/components/InputDisabled.jsx index 5e9c6c98e..d30afc21b 100644 --- a/app/javascript/src/scenes/SettingsPage/components/InputDisabled.jsx +++ b/app/javascript/src/scenes/SettingsPage/components/InputDisabled.jsx @@ -3,8 +3,11 @@ import { string, func } from "prop-types"; import { FormGroup, FormControl, ControlLabel, Button } from "react-bootstrap"; import styled from "styled-components"; import { FormattedMessage } from "react-intl"; +import { transformName } from "../../../services/helpers/string_helper"; -const Wrapper = styled.div`margin-top: 19px;`; +const Wrapper = styled.div` + margin-top: 19px; +`; const MyFormControl = styled(FormControl)` width: 160px; @@ -17,10 +20,10 @@ const MyButton = styled(Button)` margin-left: -3px; `; -const InputDisabled = props => +const InputDisabled = props => (
- + @@ -36,7 +39,8 @@ const InputDisabled = props =>
-
; +
+); InputDisabled.defaultProps = { inputValue: "" diff --git a/app/javascript/src/scenes/SettingsPage/scenes/profile/components/AvatarInputField.jsx b/app/javascript/src/scenes/SettingsPage/scenes/profile/components/AvatarInputField.jsx index 3fa0396df..e4d857f4f 100644 --- a/app/javascript/src/scenes/SettingsPage/scenes/profile/components/AvatarInputField.jsx +++ b/app/javascript/src/scenes/SettingsPage/scenes/profile/components/AvatarInputField.jsx @@ -56,7 +56,7 @@ class AvatarInputField extends Component { render() { if (this.state.disabled) { return ( - + default avatar { this.props.reloadInfo(); this.props.disableEdit(); + this.props.addAlert( + , + "success" + ); if (this.props.forceRerender) { this.props.forceRerender(); } @@ -297,6 +306,7 @@ class InputEnabled extends Component {

+

@@ -392,6 +405,7 @@ class InputEnabled extends Component { } InputEnabled.propTypes = { + addAlert: func.isRequired, inputType: string.isRequired, labelValue: string.isRequired, inputValue: string.isRequired, @@ -406,4 +420,4 @@ InputEnabled.defaultProps = { forceRerender: () => false }; -export default InputEnabled; +export default connect(null, { addAlert })(InputEnabled); diff --git a/app/javascript/src/services/helpers/string_helper.js b/app/javascript/src/services/helpers/string_helper.js new file mode 100644 index 000000000..6d4196474 --- /dev/null +++ b/app/javascript/src/services/helpers/string_helper.js @@ -0,0 +1,5 @@ +// @flow + +export function transformName(name: string ): string { + return name ? name.replace(/\s+/g, "-").toLowerCase() : "" +} diff --git a/app/models/user.rb b/app/models/user.rb index f90185283..daefcc8da 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -33,7 +33,7 @@ class User < ApplicationRecord validates_attachment :avatar, :content_type => { :content_type => ["image/jpeg", "image/png"] }, - size: { less_than: Constants::AVATAR_MAX_SIZE_MB.megabytes } + size: { less_than: Constants::AVATAR_MAX_SIZE_MB.megabyte, message: "Avatar file size must be less than 0.2 MB" } validate :time_zone_check store_accessor :settings, :time_zone, :notifications diff --git a/app/services/client_api/user_service.rb b/app/services/client_api/user_service.rb index 6cf20839c..15d87f27f 100644 --- a/app/services/client_api/user_service.rb +++ b/app/services/client_api/user_service.rb @@ -1,7 +1,7 @@ module ClientApi class UserService < BaseService def update_user! - error = I18n.t('client_api.user.passwords_dont_match') + error = I18n.t('client_api.user.password_invalid') raise CustomUserError, error unless check_current_password @params.delete(:current_password) # removes unneeded element @current_user.update(@params) diff --git a/config/locales/en.yml b/config/locales/en.yml index 881dc8f0f..0613274d2 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1828,5 +1828,6 @@ en: user: blank_password_error: "Password can't be blank!" passwords_dont_match: "Passwords don't match" + password_invalid: "Password is invalid!" invite_users: permission_error: "You don't have permission to invite additional users to team. Contact its administrator/s." diff --git a/features/assets/Moon.png b/features/assets/Moon.png index d29b0458d..72e0c5359 100644 Binary files a/features/assets/Moon.png and b/features/assets/Moon.png differ diff --git a/features/assets/star.png b/features/assets/Star.png similarity index 100% rename from features/assets/star.png rename to features/assets/Star.png diff --git a/features/settings_page/profile.feature b/features/settings_page/profile.feature index c186a81cd..b4f77fba6 100644 --- a/features/settings_page/profile.feature +++ b/features/settings_page/profile.feature @@ -19,93 +19,98 @@ Background: Then I should see "My Profile" @javascript -Scenario: Unsuccessful add avatar, file is too big +Scenario: Unsuccessful avatar image upload, file is too big Given I'm on the profile page Then I click on image within ".avatar-container" element - And I attach a "Moon.png" file to "input#user_avatar" field - Then I click "Upload" button - And I should see "You can upload max 0.2 MB of files at one time. Please remove one or more files and try to submit again" error message under "input#user_avatar" field + And I attach a "Moon.png" file to "user_avatar_input" field + Then I click "Update" button + And I should see "Avatar file size must be less than 0.2 MB" error message under "user_avatar_input" field -Scenario: Unsuccessful add avatar, file is invalid - Given My profile page of a Karli Novak user - Then I click to Avatar - Then I click to Browse button - And I select a File.txt file - Then I click to Open button - Then I click to Upload button - And I should see "Avatar content type is invalid" error message under "Avatar" field +@javascript +Scenario: Unsuccessful avatar image upload, file is invalid + Given I'm on the profile page + Then I click on image within ".avatar-container" element + And I attach a "File.txt" file to "user_avatar_input" field + Then I click "Update" button + And I should see "Avatar content type is invalid" error message under "user_avatar_input" field -Scenario: Successful add avatar - Given My profile page of a Karli Novak user - Then I click to Avatar - Then I click to Browse button - And I select a Star.png file - Then I click to Open button - Then I click to Upload button +@javascript +Scenario: Successful upload avatar image + Given I'm on the profile page + Then I click on image within ".avatar-container" element + And I attach a "Star.png" file to "user_avatar_input" field + Then I click "Update" button And I should see "Your account has been updated successfully" flash message -Scenario: Successful Full name Change - Given My profile page of a Karli Novak user - Then I click to Edit button under Full name field - And I fill in "Novakovic" - Then I click to Update button - And I should see "Karli Novak Novakovic" in Full name field +@javascript +Scenario: Successfully changes user full name + Given I'm on the profile page + Then I click on Edit on "settings_page.full_name" input field + And I fill in "Karli Novak Novakovic" in "settings_page.full_name" input field + Then I click "Update" button + And I should see "Karli Novak Novakovic" in "settings_page.full_name" input field -Scenario: Unsuccessful Initials Change, is too long - Given My profile page of a Karli Novak user - Then I click to Edit button under Initials field - And I fill in "KNOCK" - Then I click to Update button - And I should see "is too long (maximum is 4 characters)" flash message +@javascript +Scenario: Unsuccessfully changes user initials, text is too long + Given I'm on the profile page + Then I click on Edit on "settings_page.initials" input field + And I fill in "KNOCK" in "settings_page.initials" input field + Then I click "Update" button + And I should see "is too long (maximum is 4 characters)" error message under "settings_page.initials" field -Scenario: Successful Initials Change - Given My profile page of a Karli Novak user - Then I click to Edit button under Initials field - And I fill in "KN" - Then I click to Update button - And I should see "KNKN" in Full name field +@javascript +Scenario: Successfully changes user initials + Given I'm on the profile page + Then I click on Edit on "settings_page.initials" input field + And I fill in "KN" in "settings_page.initials" input field + Then I click "Update" button + And I should see "KN" in "settings_page.initials" input field -Scenario: Successful Email Change - Given My profile page of a Karli Novak user - Then I click to Edit button under Email field - And I Change "nonadmin@myorg.com" with "user@myorg.com" +@javascript +Scenario: Successfully changes user email + Given I'm on the profile page + Then I click on Edit on "settings_page.new_email" input field + And I change "nonadmin@myorg.com" with "user@myorg.com" email And I fill in "mypassword1234" in Current password field - Then I click to Update button - And I should see "user@myorg.com" in Email field + Then I click "Update" button + And I should see "user@myorg.com" in "settings_page.new_email" input field -Scenario: Unsuccessful Password Change, is too short - Given My profile page of a Karli Novak user - Then I click to Edit button under Password field - And I fill in "mypassword1234" in Current pasword field - And I fill in "mypass" in New pasword field - And I fill in "mypass" in New pasword confiramtion field - Then I click to Update button - And I should see "is too short (minimum is 8 characters)" flash message under New password field - And I should see "is too short (minimum is 8 characters)" flash message under New password confiramtion field +@javascript +Scenario: Unsuccessful Password Change, password is too short + Given I'm on the profile page + Then I click on Edit on "settings_page.change_password" input field + And I fill in "mypassword1234" in Current password field + And I fill in "mypass" in New password field + And I fill in "mypass" in New password confirmation field + Then I click "Update" button + And I should see "is too short (minimum is 8 characters)" -Scenario: Unsuccessful Password Change, does not match - Given My profile page of a Karli Novak user - Then I click to Edit button under Password field - And I fill in "mypassword1234" in Current pasword field - And I fill in "mypassword5678" in New pasword field - And I fill in "mypassword56788" in New pasword confiramtion field - Then I click to Update button - And I should see "doesn't match Password" flash message under New password confiramtion field +@javascript +Scenario: Unsuccessful Password Change, passwords does not match + Given I'm on the profile page + Then I click on Edit on "settings_page.change_password" input field + And I fill in "mypassword1234" in Current password field + And I fill in "mypassword5678" in New password field + And I fill in "mypassword56788" in New password confirmation field + Then I click "Update" button + And I should see "Passwords don't match" +@javascript Scenario: Unsuccessful Password Change, current password is invalid - Given My profile page of a Karli Novak user - Then I click to Edit button under Password field - And I fill in "mypassword123" in Current pasword field - And I fill in "mypassword5678" in New pasword field - And I fill in "mypassword5678" in New pasword confiramtion field - Then I click to Update button - And I should see "is invalid" flash message under Current password field + Given I'm on the profile page + Then I click on Edit on "settings_page.change_password" input field + And I fill in "mypassword123" in Current password field + And I fill in "mypassword5678" in New password field + And I fill in "mypassword5678" in New password confirmation field + Then I click "Update" button + And I should see "Password is invalid!" +@javascript Scenario: Successful Password Change - Given My profile page of a Karli Novak user - Then I click to Edit button under Password field - And I fill in "mypassword1234" in Current pasword field - And I fill in "mypassword5678" in New pasword field - And I fill in "mypassword5678" in New pasword confiramtion field - Then I click to Update button - And I should see "XXXXX" + Given I'm on the profile page + Then I click on Edit on "settings_page.change_password" input field + And I fill in "mypassword1234" in Current password field + And I fill in "mypassword5678" in New password field + And I fill in "mypassword5678" in New password confirmation field + Then I click "Update" button + And I should see "Your account has been updated successfully" flash message diff --git a/features/step_definitions/profile_steps.rb b/features/step_definitions/profile_steps.rb index bb9480678..028d0fcb3 100644 --- a/features/step_definitions/profile_steps.rb +++ b/features/step_definitions/profile_steps.rb @@ -3,9 +3,29 @@ Then(/^I click on Avatar$/) do end Given(/^I'm on the profile page$/) do - visit edit_user_registration_path + # visit '/settings/account/profile' randomly rises an EOFError + visit root_path + find('img.avatar').click + within('#user-account-dropdown') { click_link('Settings') } end Then(/^I click on Browse button$/) do find('input#user_avatar').click end + +Then(/^I change "([^"]*)" with "([^"]*)" email$/) do |prev_email, new_email| + find(:xpath, "//input[@value='#{prev_email}']").set(new_email) +end + +Then(/^I fill in "([^"]*)" in Current password field$/) do |password| + find(:xpath, '//input[@id="settings_page.current_password"]').set(password) +end + +Then(/^I fill in "([^"]*)" in New password field$/) do |password| + find(:xpath, '//input[@id="settings_page.new_password"]').set(password) +end + +Then(/^I fill in "([^"]*)" in New password confirmation field$/) do |password| + find(:xpath, + '//input[@id="settings_page.new_password_confirmation"]').set(password) +end diff --git a/features/step_definitions/shared_steps.rb b/features/step_definitions/shared_steps.rb index ce105546a..3f5f5ea92 100644 --- a/features/step_definitions/shared_steps.rb +++ b/features/step_definitions/shared_steps.rb @@ -2,6 +2,10 @@ When(/^I click "(.+)" button$/) do |button| click_on button end +Given(/^Show me the page$/) do + save_and_open_page +end + Then(/^I should be redirected to the homepage$/) do current_path.should =~ /^\/$/ end @@ -42,12 +46,12 @@ Given(/^"([^"]*)" is in "([^"]*)" team as a "([^"]*)"$/) do |user_email, team_na role: UserTeam.roles.fetch(role)) end -Then(/^I attach a "([^"]*)" file to "([^"]*)" field$/) do |file, field| - attach_file(field, Rails.root.join('features', 'assets', file)) +Then(/^I attach a "([^"]*)" file to "([^"]*)" field$/) do |file, field_id| + attach_file(field_id, Rails.root.join('features', 'assets', file)) end -Then(/^I should see "([^"]*)" error message under "([^"]*)" field$/) do |message, field| - parent = find(field).first(:xpath, './/..') +Then(/^I should see "([^"]*)" error message under "([^"]*)" field$/) do |message, field_id| + parent = find_by_id(field_id).first(:xpath, './/..') expect(parent).to have_content(message) end @@ -61,74 +65,23 @@ Then(/^I click on image within "([^"]*)" element$/) do |container| end end -Then(/^I select a Star\.png file$/) do - pending # Write code here that turns the phrase above into concrete actions +Then(/^I should see "([^"]*)" flash message$/) do |message| + expect(find_by_id('alert-flash')).to have_content(message) end -Then(/^I should see "([^"]*)" flash message$/) do |arg1| - pending # Write code here that turns the phrase above into concrete actions +Then(/^I click on Edit on "([^"]*)" input field$/) do |container_id| + container = page.find_by_id(container_id) + within(container) do + find('button').click + end end -Then(/^I click to Edit button under Full name field$/) do - pending # Write code here that turns the phrase above into concrete actions +Then(/^I fill in "([^"]*)" in "([^"]*)" input field$/) do |text, container_id| + container = page.find_by_id(container_id) + container.find('input').set(text) end -Then(/^I fill in "([^"]*)"$/) do |arg1| - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I click to Update button$/) do - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I should see "([^"]*)" in Full name field$/) do |arg1| - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I click to Edit button under Initials field$/) do - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I click to Edit button under Email field$/) do - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I Change "([^"]*)" with "([^"]*)"$/) do |arg1, arg2| - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I fill in "([^"]*)" in Current password field$/) do |arg1| - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I should see "([^"]*)" in Email field$/) do |arg1| - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I click to Edit button under Password field$/) do - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I fill in "([^"]*)" in Current pasword field$/) do |arg1| - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I fill in "([^"]*)" in New pasword field$/) do |arg1| - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I fill in "([^"]*)" in New pasword confiramtion field$/) do |arg1| - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I should see "([^"]*)" flash message under New password field$/) do |arg1| - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I should see "([^"]*)" flash message under New password confiramtion field$/) do |arg1| - pending # Write code here that turns the phrase above into concrete actions -end - -Then(/^I should see "([^"]*)" flash message under Current password field$/) do |arg1| - pending # Write code here that turns the phrase above into concrete actions +Then(/^I should see "([^"]*)" in "([^"]*)" input field$/) do |text, container_id| + container = page.find_by_id(container_id) + expect(container).to have_xpath("//input[@value='#{text}']") end diff --git a/features/support/env.rb b/features/support/env.rb index 7ed037c52..a826047a2 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -17,23 +17,22 @@ Capybara::Webkit.configure do |config| # Enable debug mode. Prints a log of everything the driver is doing. config.debug = false - # Silently return an empty 200 response for any requests to unknown URLs. - config.block_unknown_urls - # Allow pages to make requests to any URL without issuing a warning. config.allow_unknown_urls # Timeout if requests take longer than 5 seconds - config.timeout = 15 + config.timeout = 30 # Don't raise errors when SSL certificates can't be validated config.ignore_ssl_errors # Raise JavaScript errors as exceptions - config.raise_javascript_errors = true + config.raise_javascript_errors = false end Capybara.javascript_driver = :webkit +Capybara.default_max_wait_time = 30 + # Capybara defaults to CSS3 selectors rather than XPath. # If you'd prefer to use XPath, just uncomment this line and adjust any