Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
6912e757
Commit
6912e757
authored
Feb 15, 2021
by
Michael Lunøe
Committed by
Jose Ivan Vargas
Feb 15, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor(profile preferences): migrate rails eval
Migrate rails eval'ed js to form event listeners
parent
8822a07e
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
321 additions
and
258 deletions
+321
-258
app/assets/javascripts/profile/preferences/components/profile_preferences.vue
...ts/profile/preferences/components/profile_preferences.vue
+90
-15
app/assets/javascripts/profile/preferences/constants.js
app/assets/javascripts/profile/preferences/constants.js
+22
-0
app/assets/javascripts/profile/preferences/profile_preferences_bundle.js
...scripts/profile/preferences/profile_preferences_bundle.js
+12
-8
app/controllers/profiles/preferences_controller.rb
app/controllers/profiles/preferences_controller.rb
+10
-15
app/views/profiles/preferences/show.html.haml
app/views/profiles/preferences/show.html.haml
+5
-10
app/views/profiles/preferences/update.js.erb
app/views/profiles/preferences/update.js.erb
+0
-20
ee/spec/controllers/ee/profiles/preferences_controller_spec.rb
...ec/controllers/ee/profiles/preferences_controller_spec.rb
+6
-3
locale/gitlab.pot
locale/gitlab.pot
+21
-18
spec/controllers/profiles/preferences_controller_spec.rb
spec/controllers/profiles/preferences_controller_spec.rb
+14
-21
spec/features/profiles/user_edit_preferences_spec.rb
spec/features/profiles/user_edit_preferences_spec.rb
+9
-2
spec/features/profiles/user_visits_profile_preferences_page_spec.rb
...res/profiles/user_visits_profile_preferences_page_spec.rb
+7
-5
spec/frontend/profile/preferences/components/__snapshots__/integration_view_spec.js.snap
...es/components/__snapshots__/integration_view_spec.js.snap
+0
-67
spec/frontend/profile/preferences/components/__snapshots__/profile_preferences_spec.js.snap
...components/__snapshots__/profile_preferences_spec.js.snap
+0
-51
spec/frontend/profile/preferences/components/integration_view_spec.js
...d/profile/preferences/components/integration_view_spec.js
+0
-6
spec/frontend/profile/preferences/components/profile_preferences_spec.js
...rofile/preferences/components/profile_preferences_spec.js
+123
-17
spec/frontend/profile/preferences/mock_data.js
spec/frontend/profile/preferences/mock_data.js
+2
-0
No files found.
app/assets/javascripts/profile/preferences/components/profile_preferences.vue
View file @
6912e757
<
script
>
import
{
s__
}
from
'
~/locale
'
;
import
{
GlButton
}
from
'
@gitlab/ui
'
;
import
createFlash
,
{
FLASH_TYPES
}
from
'
~/flash
'
;
import
{
INTEGRATION_VIEW_CONFIGS
,
i18n
}
from
'
../constants
'
;
import
IntegrationView
from
'
./integration_view.vue
'
;
const
INTEGRATION_VIEW_CONFIGS
=
{
sourcegraph
:
{
title
:
s__
(
'
ProfilePreferences|Sourcegraph
'
),
label
:
s__
(
'
ProfilePreferences|Enable integrated code intelligence on code views
'
),
formName
:
'
sourcegraph_enabled
'
,
},
gitpod
:
{
title
:
s__
(
'
ProfilePreferences|Gitpod
'
),
label
:
s__
(
'
ProfilePreferences|Enable Gitpod integration
'
),
formName
:
'
gitpod_enabled
'
,
},
};
function
updateClasses
(
bodyClasses
=
''
,
applicationTheme
,
layout
)
{
// Remove body class for any previous theme, re-add current one
document
.
body
.
classList
.
remove
(...
bodyClasses
.
split
(
'
'
));
document
.
body
.
classList
.
add
(
applicationTheme
);
// Toggle container-fluid class
if
(
layout
===
'
fluid
'
)
{
document
.
querySelector
(
'
.content-wrapper .container-fluid
'
)
.
classList
.
remove
(
'
container-limited
'
);
}
else
{
document
.
querySelector
(
'
.content-wrapper .container-fluid
'
).
classList
.
add
(
'
container-limited
'
);
}
}
export
default
{
name
:
'
ProfilePreferences
'
,
components
:
{
IntegrationView
,
GlButton
,
},
inject
:
{
integrationViews
:
{
default
:
[],
},
themes
:
{
default
:
[],
},
userFields
:
{
default
:
{},
},
formEl
:
'
formEl
'
,
profilePreferencesPath
:
'
profilePreferencesPath
'
,
bodyClasses
:
'
bodyClasses
'
,
},
integrationViewConfigs
:
INTEGRATION_VIEW_CONFIGS
,
i18n
,
data
()
{
return
{
isSubmitEnabled
:
true
,
};
},
computed
:
{
applicationThemes
()
{
return
this
.
themes
.
reduce
((
themes
,
theme
)
=>
{
const
{
id
,
...
rest
}
=
theme
;
return
{
...
themes
,
[
id
]:
rest
};
},
{});
},
},
created
()
{
this
.
formEl
.
addEventListener
(
'
ajax:beforeSend
'
,
this
.
handleLoading
);
this
.
formEl
.
addEventListener
(
'
ajax:success
'
,
this
.
handleSuccess
);
this
.
formEl
.
addEventListener
(
'
ajax:error
'
,
this
.
handleError
);
},
beforeDestroy
()
{
this
.
formEl
.
removeEventListener
(
'
ajax:beforeSend
'
,
this
.
handleLoading
);
this
.
formEl
.
removeEventListener
(
'
ajax:success
'
,
this
.
handleSuccess
);
this
.
formEl
.
removeEventListener
(
'
ajax:error
'
,
this
.
handleError
);
},
methods
:
{
handleLoading
()
{
this
.
isSubmitEnabled
=
false
;
},
handleSuccess
(
customEvent
)
{
const
formData
=
new
FormData
(
this
.
formEl
);
updateClasses
(
this
.
bodyClasses
,
this
.
applicationThemes
[
formData
.
get
(
'
user[theme_id]
'
)].
css_class
,
this
.
selectedLayout
,
);
const
{
message
=
this
.
$options
.
i18n
.
defaultSuccess
,
type
=
FLASH_TYPES
.
NOTICE
}
=
customEvent
?.
detail
?.[
0
]
||
{};
createFlash
({
message
,
type
});
this
.
isSubmitEnabled
=
true
;
},
handleError
(
customEvent
)
{
const
{
message
=
this
.
$options
.
i18n
.
defaultError
,
type
=
FLASH_TYPES
.
ALERT
}
=
customEvent
?.
detail
?.[
0
]
||
{};
createFlash
({
message
,
type
});
this
.
isSubmitEnabled
=
true
;
},
},
};
</
script
>
...
...
@@ -36,10 +97,10 @@ export default {
</div>
<div
v-if=
"integrationViews.length"
class=
"col-lg-4 profile-settings-sidebar"
>
<h4
class=
"gl-mt-0"
data-testid=
"profile-preferences-integrations-heading"
>
{{
s__
(
'
ProfilePreferences|Integrations
'
)
}}
{{
$options
.
i18n
.
integrations
}}
</h4>
<p>
{{
s__
(
'
ProfilePreferences|Customize integrations with third party services.
'
)
}}
{{
$options
.
i18n
.
integrationsDescription
}}
</p>
</div>
<div
v-if=
"integrationViews.length"
class=
"col-lg-8"
>
...
...
@@ -52,5 +113,19 @@ export default {
:config=
"$options.integrationViewConfigs[view.name]"
/>
</div>
<div
class=
"col-lg-4 profile-settings-sidebar"
></div>
<div
class=
"col-lg-8"
>
<div
class=
"form-group"
>
<gl-button
variant=
"success"
name=
"commit"
type=
"submit"
:disabled=
"!isSubmitEnabled"
:value=
"$options.i18n.saveChanges"
>
{{
$options
.
i18n
.
saveChanges
}}
</gl-button>
</div>
</div>
</div>
</
template
>
app/assets/javascripts/profile/preferences/constants.js
0 → 100644
View file @
6912e757
import
{
s__
,
__
}
from
'
~/locale
'
;
export
const
INTEGRATION_VIEW_CONFIGS
=
{
sourcegraph
:
{
title
:
s__
(
'
Preferences|Sourcegraph
'
),
label
:
s__
(
'
Preferences|Enable integrated code intelligence on code views
'
),
formName
:
'
sourcegraph_enabled
'
,
},
gitpod
:
{
title
:
s__
(
'
Preferences|Gitpod
'
),
label
:
s__
(
'
Preferences|Enable Gitpod integration
'
),
formName
:
'
gitpod_enabled
'
,
},
};
export
const
i18n
=
{
saveChanges
:
__
(
'
Save changes
'
),
defaultSuccess
:
__
(
'
Preferences saved.
'
),
defaultError
:
s__
(
'
Preferences|Failed to save preferences.
'
),
integrations
:
s__
(
'
Preferences|Integrations
'
),
integrationsDescription
:
s__
(
'
Preferences|Customize integrations with third party services.
'
),
};
app/assets/javascripts/profile/preferences/profile_preferences_bundle.js
View file @
6912e757
...
...
@@ -3,16 +3,20 @@ import ProfilePreferences from './components/profile_preferences.vue';
export
default
()
=>
{
const
el
=
document
.
querySelector
(
'
#js-profile-preferences-app
'
);
const
shouldParse
=
[
'
integrationViews
'
,
'
userFields
'
];
const
formEl
=
document
.
querySelector
(
'
#profile-preferences-form
'
);
const
shouldParse
=
[
'
integrationViews
'
,
'
themes
'
,
'
userFields
'
];
const
provide
=
Object
.
keys
(
el
.
dataset
).
reduce
((
memo
,
key
)
=>
{
const
provide
=
Object
.
keys
(
el
.
dataset
).
reduce
(
(
memo
,
key
)
=>
{
let
value
=
el
.
dataset
[
key
];
if
(
shouldParse
.
includes
(
key
))
{
value
=
JSON
.
parse
(
value
);
}
return
{
...
memo
,
[
key
]:
value
};
},
{});
},
{
formEl
},
);
return
new
Vue
({
el
,
...
...
app/controllers/profiles/preferences_controller.rb
View file @
6912e757
...
...
@@ -9,23 +9,18 @@ class Profiles::PreferencesController < Profiles::ApplicationController
end
def
update
begin
result
=
Users
::
UpdateService
.
new
(
current_user
,
preferences_params
.
merge
(
user:
user
)).
execute
if
result
[
:status
]
==
:success
flash
[
:notice
]
=
_
(
'Preferences saved.'
)
message
=
_
(
'Preferences saved.'
)
render
json:
{
type: :notice
,
message:
message
}
else
flash
[
:alert
]
=
_
(
'Failed to save preferences.'
)
render
status: :bad_request
,
json:
{
type: :alert
,
message:
_
(
'Failed to save preferences.'
)
}
end
rescue
ArgumentError
=>
e
# Raised when `dashboard` is given an invalid value.
flash
[
:alert
]
=
_
(
"Failed to save preferences (%{error_message})."
)
%
{
error_message:
e
.
message
}
end
respond_to
do
|
format
|
format
.
html
{
redirect_to
profile_preferences_path
}
format
.
js
end
message
=
_
(
"Failed to save preferences (%{error_message})."
)
%
{
error_message:
e
.
message
}
render
status: :bad_request
,
json:
{
type: :alert
,
message:
message
}
end
private
...
...
app/views/profiles/preferences/show.html.haml
View file @
6912e757
-
page_title
_
(
'Preferences'
)
-
@content_class
=
"limit-container-width"
unless
fluid_layout
-
user_fields
=
{
gitpod_enabled:
@user
.
gitpod_enabled
,
sourcegraph_enabled:
@user
.
sourcegraph_enabled
}
-
user_theme_id
=
Gitlab
::
Themes
.
for_user
(
@user
).
id
-
data_attributes
=
{
integration_views:
integration_views
.
to_json
,
user_fields:
user_fields
.
to_json
}
-
user_fields
=
{
theme:
user_theme_id
,
gitpod_enabled:
@user
.
gitpod_enabled
,
sourcegraph_enabled:
@user
.
sourcegraph_enabled
}.
to_json
-
@themes
=
Gitlab
::
Themes
::
THEMES
.
to_json
-
data_attributes
=
{
themes:
@themes
,
integration_views:
integration_views
.
to_json
,
user_fields:
user_fields
,
body_classes:
Gitlab
::
Themes
.
body_classes
,
profile_preferences_path:
profile_preferences_path
}
-
Gitlab
::
Themes
.
each
do
|
theme
|
=
stylesheet_link_tag
"themes/
#{
theme
.
css_filename
}
"
if
theme
.
css_filename
=
form_for
@user
,
url:
profile_preferences_path
,
remote:
true
,
method: :put
do
|
f
|
=
form_for
@user
,
url:
profile_preferences_path
,
remote:
true
,
method: :put
,
html:
{
id:
"profile-preferences-form"
}
do
|
f
|
.row.gl-mt-3.js-preferences-form.js-search-settings-section
.col-lg-4.application-theme
#navigation-theme
%h4
.gl-mt-0
...
...
@@ -143,10 +144,4 @@
.form-text.text-muted
=
s_
(
'Preferences|For example: 30 mins ago.'
)
#js-profile-preferences-app
{
data:
data_attributes
,
user_fields:
user_fields
.
to_json
}
.row.gl-mt-3.js-preferences-form
.col-lg-4.profile-settings-sidebar
.col-lg-8
.form-group
=
f
.
submit
_
(
'Save changes'
),
class:
'gl-button btn btn-success'
#js-profile-preferences-app
{
data:
data_attributes
}
app/views/profiles/preferences/update.js.erb
deleted
100644 → 0
View file @
8822a07e
// Remove body class for any previous theme, re-add current one
$('body').removeClass('
<%=
Gitlab
::
Themes
.
body_classes
%>
')
$('body').addClass('
<%=
user_application_theme
%>
')
// Toggle container-fluid class
if ('
<%=
current_user
.
layout
%>
' === 'fluid') {
$('.content-wrapper .container-fluid').removeClass('container-limited')
} else {
$('.content-wrapper .container-fluid').addClass('container-limited')
}
// Re-enable the "Save" button
$('input[type=submit]').enable()
// Show flash messages
<%
if
flash
.
notice
%>
new Flash({ message: '
<%=
flash
.
discard
(
:notice
)
%>
', type: 'notice'})
<%
elsif
flash
.
alert
%>
new Flash({ message: '
<%=
flash
.
discard
(
:alert
)
%>
', type: 'alert'})
<%
end
%>
ee/spec/controllers/ee/profiles/preferences_controller_spec.rb
View file @
6912e757
...
...
@@ -10,7 +10,7 @@ RSpec.describe Profiles::PreferencesController do
end
describe
'PATCH update'
do
subject
{
patch
:update
,
params:
{
user:
{
group_view:
group_view
}
},
format: :js
}
subject
{
patch
:update
,
params:
{
user:
{
group_view:
group_view
}
},
format: :js
on
}
let
(
:group_view
)
{
'security_dashboard'
}
...
...
@@ -27,9 +27,12 @@ RSpec.describe Profiles::PreferencesController do
context
'and an invalid group view choice is submitted'
do
let
(
:group_view
)
{
'foo'
}
it
'
sets the flash
'
do
it
'
responds with an error message
'
do
subject
expect
(
flash
[
:alert
]).
to
match
(
/Failed to save preferences/
)
expect
(
response
).
to
have_gitlab_http_status
(
:bad_request
)
expect
(
response
.
parsed_body
[
'message'
]).
to
match
(
/Failed to save preferences/
)
expect
(
response
.
parsed_body
[
'type'
]).
to
eq
(
'alert'
)
end
end
end
...
...
locale/gitlab.pot
View file @
6912e757
...
...
@@ -22218,21 +22218,39 @@ msgstr ""
msgid "Preferences|Choose what content you want to see on your homepage."
msgstr ""
msgid "Preferences|Customize integrations with third party services."
msgstr ""
msgid "Preferences|Customize the appearance of the application header and navigation sidebar."
msgstr ""
msgid "Preferences|Display time in 24-hour format"
msgstr ""
msgid "Preferences|Enable Gitpod integration"
msgstr ""
msgid "Preferences|Enable integrated code intelligence on code views"
msgstr ""
msgid "Preferences|Failed to save preferences."
msgstr ""
msgid "Preferences|For example: 30 mins ago."
msgstr ""
msgid "Preferences|Gitpod"
msgstr ""
msgid "Preferences|Homepage content"
msgstr ""
msgid "Preferences|Instead of all the files changed, show only one file at a time. To switch between files, use the file browser."
msgstr ""
msgid "Preferences|Integrations"
msgstr ""
msgid "Preferences|Layout width"
msgstr ""
...
...
@@ -22254,6 +22272,9 @@ msgstr ""
msgid "Preferences|Show whitespace changes in diffs"
msgstr ""
msgid "Preferences|Sourcegraph"
msgstr ""
msgid "Preferences|Syntax highlighting theme"
msgstr ""
...
...
@@ -22446,24 +22467,6 @@ msgstr ""
msgid "Profile Settings"
msgstr ""
msgid "ProfilePreferences|Customize integrations with third party services."
msgstr ""
msgid "ProfilePreferences|Enable Gitpod integration"
msgstr ""
msgid "ProfilePreferences|Enable integrated code intelligence on code views"
msgstr ""
msgid "ProfilePreferences|Gitpod"
msgstr ""
msgid "ProfilePreferences|Integrations"
msgstr ""
msgid "ProfilePreferences|Sourcegraph"
msgstr ""
msgid "ProfileSession|on"
msgstr ""
...
...
spec/controllers/profiles/preferences_controller_spec.rb
View file @
6912e757
...
...
@@ -24,7 +24,7 @@ RSpec.describe Profiles::PreferencesController do
end
describe
'PATCH update'
do
def
go
(
params:
{},
format: :js
)
def
go
(
params:
{},
format: :js
on
)
params
.
reverse_merge!
(
color_scheme_id:
'1'
,
dashboard:
'stars'
,
...
...
@@ -35,9 +35,12 @@ RSpec.describe Profiles::PreferencesController do
end
context
'on successful update'
do
it
'
sets the flash
'
do
it
'
responds with success
'
do
go
expect
(
flash
[
:notice
]).
to
eq
_
(
'Preferences saved.'
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
response
.
parsed_body
[
'message'
]).
to
eq
_
(
'Preferences saved.'
)
expect
(
response
.
parsed_body
[
'type'
]).
to
eq
(
'notice'
)
end
it
"changes the user's preferences"
do
...
...
@@ -59,36 +62,26 @@ RSpec.describe Profiles::PreferencesController do
end
context
'on failed update'
do
it
'
sets the flash
'
do
it
'
responds with error
'
do
expect
(
user
).
to
receive
(
:save
).
and_return
(
false
)
go
expect
(
flash
[
:alert
]).
to
eq
(
_
(
'Failed to save preferences.'
))
expect
(
response
).
to
have_gitlab_http_status
(
:bad_request
)
expect
(
response
.
parsed_body
[
'message'
]).
to
eq
_
(
'Failed to save preferences.'
)
expect
(
response
.
parsed_body
[
'type'
]).
to
eq
(
'alert'
)
end
end
context
'on invalid dashboard setting'
do
it
'
sets the flash
'
do
it
'
responds with error
'
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
)
expect
(
response
).
to
have_gitlab_http_status
(
:bad_request
)
expect
(
response
.
parsed_body
[
'message'
]).
to
match
(
/\AFailed to save preferences \(.+\)\.\z/
)
expect
(
response
.
parsed_body
[
'type'
]).
to
eq
(
'alert'
)
end
end
end
...
...
spec/features/profiles/user_edit_preferences_spec.rb
View file @
6912e757
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
'User edit preferences profile'
do
RSpec
.
describe
'User edit preferences profile'
,
:js
do
let
(
:user
)
{
create
(
:user
)
}
before
do
...
...
@@ -53,7 +53,14 @@ RSpec.describe 'User edit preferences profile' do
fill_in
'Tab width'
,
with:
-
1
click_button
'Save changes'
expect
(
page
).
to
have_content
(
'Failed to save preferences'
)
field
=
page
.
find_field
(
'user[tab_width]'
)
message
=
field
.
native
.
attribute
(
"validationMessage"
)
expect
(
message
).
to
eq
"Value must be greater than or equal to 1."
# User trying to hack an invalid value
page
.
execute_script
(
"document.querySelector('#user_tab_width').setAttribute('min', '-1')"
)
click_button
'Save changes'
expect
(
page
).
to
have_content
(
'Failed to save preferences.'
)
end
end
...
...
spec/features/profiles/user_visits_profile_preferences_page_spec.rb
View file @
6912e757
...
...
@@ -2,7 +2,7 @@
require
'spec_helper'
RSpec
.
describe
'User visits the profile preferences page'
do
RSpec
.
describe
'User visits the profile preferences page'
,
:js
do
include
Select2Helper
let
(
:user
)
{
create
(
:user
)
}
...
...
@@ -39,7 +39,7 @@ RSpec.describe 'User visits the profile preferences page' do
describe
'User changes their default dashboard'
,
:js
do
it
'creates a flash message'
do
select2
(
'stars'
,
from:
'#user_dashboard'
)
click_button
'Save'
click_button
'Save
changes
'
wait_for_requests
...
...
@@ -48,7 +48,7 @@ RSpec.describe 'User visits the profile preferences page' do
it
'updates their preference'
do
select2
(
'stars'
,
from:
'#user_dashboard'
)
click_button
'Save'
click_button
'Save
changes
'
wait_for_requests
...
...
@@ -67,7 +67,7 @@ RSpec.describe 'User visits the profile preferences page' do
describe
'User changes their language'
,
:js
do
it
'creates a flash message'
,
quarantine:
'https://gitlab.com/gitlab-org/gitlab/-/issues/31404'
do
select2
(
'en'
,
from:
'#user_preferred_language'
)
click_button
'Save'
click_button
'Save
changes
'
wait_for_requests
...
...
@@ -77,7 +77,7 @@ RSpec.describe 'User visits the profile preferences page' do
it
'updates their preference'
do
wait_for_requests
select2
(
'pt_BR'
,
from:
'#user_preferred_language'
)
click_button
'Save'
click_button
'Save
changes
'
wait_for_requests
refresh
...
...
@@ -94,6 +94,8 @@ RSpec.describe 'User visits the profile preferences page' do
click_button
'Save changes'
wait_for_requests
expect
(
user
.
reload
.
render_whitespace_in_code
).
to
be
(
true
)
expect
(
render_whitespace_field
).
to
be_checked
end
...
...
spec/frontend/profile/preferences/components/__snapshots__/integration_view_spec.js.snap
deleted
100644 → 0
View file @
8822a07e
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`IntegrationView component should render IntegrationView properly 1`] = `
<div
name="sourcegraph"
>
<label
class="label-bold"
>
Foo
</label>
<gl-link-stub
class="has-tooltip"
href="http://foo.com/help"
title="More information"
>
<gl-icon-stub
class="vertical-align-middle"
name="question-o"
size="16"
/>
</gl-link-stub>
<div
class="form-group form-check"
data-testid="profile-preferences-integration-form-group"
>
<input
data-testid="profile-preferences-integration-hidden-field"
name="user[foo_enabled]"
type="hidden"
value="0"
/>
<input
class="form-check-input"
data-testid="profile-preferences-integration-checkbox"
id="user_foo_enabled"
name="user[foo_enabled]"
type="checkbox"
value="1"
/>
<label
class="form-check-label"
for="user_foo_enabled"
>
Enable foo
</label>
<gl-form-text-stub
tag="div"
textvariant="muted"
>
<integration-help-text-stub
message="Click %{linkStart}Foo%{linkEnd}!"
messageurl="http://foo.com"
/>
</gl-form-text-stub>
</div>
</div>
`;
spec/frontend/profile/preferences/components/__snapshots__/profile_preferences_spec.js.snap
deleted
100644 → 0
View file @
8822a07e
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ProfilePreferences component should render ProfilePreferences properly 1`] = `
<div
class="row gl-mt-3 js-preferences-form"
>
<div
class="col-sm-12"
>
<hr
data-testid="profile-preferences-integrations-rule"
/>
</div>
<div
class="col-lg-4 profile-settings-sidebar"
>
<h4
class="gl-mt-0"
data-testid="profile-preferences-integrations-heading"
>
Integrations
</h4>
<p>
Customize integrations with third party services.
</p>
</div>
<div
class="col-lg-8"
>
<integration-view-stub
config="[object Object]"
helplink="http://foo.com/help"
message="Click %{linkStart}Foo%{linkEnd}!"
messageurl="http://foo.com"
/>
<integration-view-stub
config="[object Object]"
helplink="http://bar.com/help"
message="Click %{linkStart}Bar%{linkEnd}!"
messageurl="http://bar.com"
/>
</div>
</div>
`;
spec/frontend/profile/preferences/components/integration_view_spec.js
View file @
6912e757
...
...
@@ -115,10 +115,4 @@ describe('IntegrationView component', () => {
expect
(
findFormGroupLabel
().
text
()).
toBe
(
'
Enable foo
'
);
});
it
(
'
should render IntegrationView properly
'
,
()
=>
{
wrapper
=
createComponent
();
expect
(
wrapper
.
element
).
toMatchSnapshot
();
});
});
spec/frontend/profile/preferences/components/profile_preferences_spec.js
View file @
6912e757
import
{
GlButton
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
import
IntegrationView
from
'
~/profile/preferences/components/integration_view.vue
'
;
import
ProfilePreferences
from
'
~/profile/preferences/components/profile_preferences.vue
'
;
import
{
integrationViews
,
userFields
}
from
'
../mock_data
'
;
import
{
i18n
}
from
'
~/profile/preferences/constants
'
;
import
{
integrationViews
,
userFields
,
bodyClasses
}
from
'
../mock_data
'
;
const
expectedUrl
=
'
/foo
'
;
describe
(
'
ProfilePreferences component
'
,
()
=>
{
let
wrapper
;
const
defaultProvide
=
{
integrationViews
:
[],
userFields
,
bodyClasses
,
themes
:
[{
id
:
1
,
css_class
:
'
foo
'
}],
profilePreferencesPath
:
'
/update-profile
'
,
formEl
:
document
.
createElement
(
'
form
'
),
};
function
createComponent
(
options
=
{})
{
const
{
props
=
{},
provide
=
{}
}
=
options
;
return
shallowMount
(
ProfilePreferences
,
{
const
{
props
=
{},
provide
=
{},
attachTo
}
=
options
;
return
extendedWrapper
(
shallowMount
(
ProfilePreferences
,
{
provide
:
{
...
defaultProvide
,
...
provide
,
},
propsData
:
props
,
});
attachTo
,
}),
);
}
function
findIntegrationsDivider
()
{
return
wrapper
.
findByTestId
(
'
profile-preferences-integrations-rule
'
);
}
function
findIntegrationsHeading
()
{
return
wrapper
.
findByTestId
(
'
profile-preferences-integrations-heading
'
);
}
function
findSubmitButton
()
{
return
wrapper
.
findComponent
(
GlButton
);
}
function
findFlashError
()
{
return
document
.
querySelector
(
'
.flash-container .flash-text
'
);
}
beforeEach
(()
=>
{
setFixtures
(
'
<div class="flash-container"></div>
'
);
});
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
=
null
;
...
...
@@ -30,8 +61,8 @@ describe('ProfilePreferences component', () => {
it
(
'
should not render Integrations section
'
,
()
=>
{
wrapper
=
createComponent
();
const
views
=
wrapper
.
findAll
(
IntegrationView
);
const
divider
=
wrapper
.
find
(
'
[data-testid="profile-preferences-integrations-rule"]
'
);
const
heading
=
wrapper
.
find
(
'
[data-testid="profile-preferences-integrations-heading"]
'
);
const
divider
=
findIntegrationsDivider
(
);
const
heading
=
findIntegrationsHeading
(
);
expect
(
divider
.
exists
()).
toBe
(
false
);
expect
(
heading
.
exists
()).
toBe
(
false
);
...
...
@@ -40,8 +71,8 @@ describe('ProfilePreferences component', () => {
it
(
'
should render Integration section
'
,
()
=>
{
wrapper
=
createComponent
({
provide
:
{
integrationViews
}
});
const
divider
=
wrapper
.
find
(
'
[data-testid="profile-preferences-integrations-rule"]
'
);
const
heading
=
wrapper
.
find
(
'
[data-testid="profile-preferences-integrations-heading"]
'
);
const
divider
=
findIntegrationsDivider
(
);
const
heading
=
findIntegrationsHeading
(
);
const
views
=
wrapper
.
findAll
(
IntegrationView
);
expect
(
divider
.
exists
()).
toBe
(
true
);
...
...
@@ -49,9 +80,84 @@ describe('ProfilePreferences component', () => {
expect
(
views
).
toHaveLength
(
integrationViews
.
length
);
});
it
(
'
should render ProfilePreferences properly
'
,
()
=>
{
wrapper
=
createComponent
({
provide
:
{
integrationViews
}
});
describe
(
'
form submit
'
,
()
=>
{
let
form
;
beforeEach
(()
=>
{
const
div
=
document
.
createElement
(
'
div
'
);
div
.
classList
.
add
(
'
container-fluid
'
);
document
.
body
.
appendChild
(
div
);
document
.
body
.
classList
.
add
(
'
content-wrapper
'
);
form
=
document
.
createElement
(
'
form
'
);
form
.
setAttribute
(
'
url
'
,
expectedUrl
);
form
.
setAttribute
(
'
method
'
,
'
put
'
);
const
input
=
document
.
createElement
(
'
input
'
);
input
.
setAttribute
(
'
name
'
,
'
user[theme_id]
'
);
input
.
setAttribute
(
'
type
'
,
'
radio
'
);
input
.
setAttribute
(
'
value
'
,
'
1
'
);
input
.
setAttribute
(
'
checked
'
,
'
checked
'
);
form
.
appendChild
(
input
);
wrapper
=
createComponent
({
provide
:
{
formEl
:
form
},
attachTo
:
document
.
body
});
const
beforeSendEvent
=
new
CustomEvent
(
'
ajax:beforeSend
'
);
form
.
dispatchEvent
(
beforeSendEvent
);
});
expect
(
wrapper
.
element
).
toMatchSnapshot
();
it
(
'
disables the submit button
'
,
async
()
=>
{
await
wrapper
.
vm
.
$nextTick
();
const
button
=
findSubmitButton
();
expect
(
button
.
props
(
'
disabled
'
)).
toBe
(
true
);
});
it
(
'
success re-enables the submit button
'
,
async
()
=>
{
const
successEvent
=
new
CustomEvent
(
'
ajax:success
'
);
form
.
dispatchEvent
(
successEvent
);
await
wrapper
.
vm
.
$nextTick
();
const
button
=
findSubmitButton
();
expect
(
button
.
props
(
'
disabled
'
)).
toBe
(
false
);
});
it
(
'
error re-enables the submit button
'
,
async
()
=>
{
const
errorEvent
=
new
CustomEvent
(
'
ajax:error
'
);
form
.
dispatchEvent
(
errorEvent
);
await
wrapper
.
vm
.
$nextTick
();
const
button
=
findSubmitButton
();
expect
(
button
.
props
(
'
disabled
'
)).
toBe
(
false
);
});
it
(
'
displays the default success message
'
,
()
=>
{
const
successEvent
=
new
CustomEvent
(
'
ajax:success
'
);
form
.
dispatchEvent
(
successEvent
);
expect
(
findFlashError
().
innerText
.
trim
()).
toEqual
(
i18n
.
defaultSuccess
);
});
it
(
'
displays the custom success message
'
,
()
=>
{
const
message
=
'
foo
'
;
const
successEvent
=
new
CustomEvent
(
'
ajax:success
'
,
{
detail
:
[{
message
}]
});
form
.
dispatchEvent
(
successEvent
);
expect
(
findFlashError
().
innerText
.
trim
()).
toEqual
(
message
);
});
it
(
'
displays the default error message
'
,
()
=>
{
const
errorEvent
=
new
CustomEvent
(
'
ajax:error
'
);
form
.
dispatchEvent
(
errorEvent
);
expect
(
findFlashError
().
innerText
.
trim
()).
toEqual
(
i18n
.
defaultError
);
});
it
(
'
displays the custom error message
'
,
()
=>
{
const
message
=
'
bar
'
;
const
errorEvent
=
new
CustomEvent
(
'
ajax:error
'
,
{
detail
:
[{
message
}]
});
form
.
dispatchEvent
(
errorEvent
);
expect
(
findFlashError
().
innerText
.
trim
()).
toEqual
(
message
);
});
});
});
spec/frontend/profile/preferences/mock_data.js
View file @
6912e757
...
...
@@ -16,3 +16,5 @@ export const integrationViews = [
export
const
userFields
=
{
foo_enabled
:
true
,
};
export
const
bodyClasses
=
'
ui-light-indigo ui-light gl-dark
'
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment