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
bef42d9a
Commit
bef42d9a
authored
May 05, 2017
by
Luke "Jared" Bennett
Committed by
Phil Hughes
May 05, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fallback localstorage cases
parent
b8153535
Changes
19
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
684 additions
and
41 deletions
+684
-41
app/assets/javascripts/autosave.js
app/assets/javascripts/autosave.js
+19
-25
app/assets/javascripts/behaviors/gl_emoji/unicode_support_map.js
...ets/javascripts/behaviors/gl_emoji/unicode_support_map.js
+14
-3
app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.js
...red_search/components/recent_searches_dropdown_content.js
+11
-1
app/assets/javascripts/filtered_search/filtered_search_manager.js
...ts/javascripts/filtered_search/filtered_search_manager.js
+6
-5
app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js
...ascripts/filtered_search/filtered_search_visual_tokens.js
+3
-0
app/assets/javascripts/filtered_search/recent_searches_root.js
...ssets/javascripts/filtered_search/recent_searches_root.js
+5
-2
app/assets/javascripts/filtered_search/services/recent_searches_service.js
...ripts/filtered_search/services/recent_searches_service.js
+14
-0
app/assets/javascripts/filtered_search/services/recent_searches_service_error.js
...filtered_search/services/recent_searches_service_error.js
+11
-0
app/assets/javascripts/lib/utils/accessor.js
app/assets/javascripts/lib/utils/accessor.js
+47
-0
app/assets/javascripts/signin_tabs_memoizer.js
app/assets/javascripts/signin_tabs_memoizer.js
+10
-2
spec/javascripts/autosave_spec.js
spec/javascripts/autosave_spec.js
+134
-0
spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js
...avascripts/behaviors/gl_emoji/unicode_support_map_spec.js
+47
-0
spec/javascripts/filtered_search/components/recent_searches_dropdown_content_spec.js
...earch/components/recent_searches_dropdown_content_spec.js
+20
-0
spec/javascripts/filtered_search/filtered_search_manager_spec.js
...vascripts/filtered_search/filtered_search_manager_spec.js
+34
-0
spec/javascripts/filtered_search/recent_searches_root_spec.js
.../javascripts/filtered_search/recent_searches_root_spec.js
+31
-0
spec/javascripts/filtered_search/services/recent_searches_service_error_spec.js
...red_search/services/recent_searches_service_error_spec.js
+18
-0
spec/javascripts/filtered_search/services/recent_searches_service_spec.js
.../filtered_search/services/recent_searches_service_spec.js
+92
-3
spec/javascripts/lib/utils/accessor_spec.js
spec/javascripts/lib/utils/accessor_spec.js
+78
-0
spec/javascripts/signin_tabs_memoizer_spec.js
spec/javascripts/signin_tabs_memoizer_spec.js
+90
-0
No files found.
app/assets/javascripts/autosave.js
View file @
bef42d9a
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-param-reassign, quotes, prefer-template, no-var, one-var, no-unused-vars, one-var-declaration-per-line, no-void, consistent-return, no-empty, max-len */
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-param-reassign, quotes, prefer-template, no-var, one-var, no-unused-vars, one-var-declaration-per-line, no-void, consistent-return, no-empty, max-len */
import
AccessorUtilities
from
'
./lib/utils/accessor
'
;
window
.
Autosave
=
(
function
()
{
window
.
Autosave
=
(
function
()
{
function
Autosave
(
field
,
key
)
{
function
Autosave
(
field
,
key
)
{
this
.
field
=
field
;
this
.
field
=
field
;
this
.
isLocalStorageAvailable
=
AccessorUtilities
.
isLocalStorageAccessSafe
();
if
(
key
.
join
!=
null
)
{
if
(
key
.
join
!=
null
)
{
key
=
key
.
join
(
"
/
"
);
key
=
key
.
join
(
"
/
"
);
}
}
...
@@ -17,16 +20,12 @@ window.Autosave = (function() {
...
@@ -17,16 +20,12 @@ window.Autosave = (function() {
}
}
Autosave
.
prototype
.
restore
=
function
()
{
Autosave
.
prototype
.
restore
=
function
()
{
var
e
,
text
;
var
text
;
if
(
window
.
localStorage
==
null
)
{
return
;
if
(
!
this
.
isLocalStorageAvailable
)
return
;
}
try
{
text
=
window
.
localStorage
.
getItem
(
this
.
key
);
text
=
window
.
localStorage
.
getItem
(
this
.
key
);
}
catch
(
error
)
{
e
=
error
;
return
;
}
if
((
text
!=
null
?
text
.
length
:
void
0
)
>
0
)
{
if
((
text
!=
null
?
text
.
length
:
void
0
)
>
0
)
{
this
.
field
.
val
(
text
);
this
.
field
.
val
(
text
);
}
}
...
@@ -35,27 +34,22 @@ window.Autosave = (function() {
...
@@ -35,27 +34,22 @@ window.Autosave = (function() {
Autosave
.
prototype
.
save
=
function
()
{
Autosave
.
prototype
.
save
=
function
()
{
var
text
;
var
text
;
if
(
window
.
localStorage
==
null
)
{
return
;
}
text
=
this
.
field
.
val
();
text
=
this
.
field
.
val
();
if
((
text
!=
null
?
text
.
length
:
void
0
)
>
0
)
{
try
{
if
(
this
.
isLocalStorageAvailable
&&
(
text
!=
null
?
text
.
length
:
void
0
)
>
0
)
{
return
window
.
localStorage
.
setItem
(
this
.
key
,
text
);
return
window
.
localStorage
.
setItem
(
this
.
key
,
text
);
}
catch
(
error
)
{}
}
else
{
return
this
.
reset
();
}
}
return
this
.
reset
();
};
};
Autosave
.
prototype
.
reset
=
function
()
{
Autosave
.
prototype
.
reset
=
function
()
{
if
(
window
.
localStorage
==
null
)
{
if
(
!
this
.
isLocalStorageAvailable
)
return
;
return
;
}
try
{
return
window
.
localStorage
.
removeItem
(
this
.
key
);
return
window
.
localStorage
.
removeItem
(
this
.
key
);
}
catch
(
error
)
{}
};
};
return
Autosave
;
return
Autosave
;
})();
})();
export
default
window
.
Autosave
;
app/assets/javascripts/behaviors/gl_emoji/unicode_support_map.js
View file @
bef42d9a
import
AccessorUtilities
from
'
../../lib/utils/accessor
'
;
const
unicodeSupportTestMap
=
{
const
unicodeSupportTestMap
=
{
// man, student (emojione does not have any of these yet), http://emojipedia.org/emoji-zwj-sequences/
// man, student (emojione does not have any of these yet), http://emojipedia.org/emoji-zwj-sequences/
// occupationZwj: '\u{1F468}\u{200D}\u{1F393}',
// occupationZwj: '\u{1F468}\u{200D}\u{1F393}',
...
@@ -140,17 +142,26 @@ function generateUnicodeSupportMap(testMap) {
...
@@ -140,17 +142,26 @@ function generateUnicodeSupportMap(testMap) {
function
getUnicodeSupportMap
()
{
function
getUnicodeSupportMap
()
{
let
unicodeSupportMap
;
let
unicodeSupportMap
;
const
userAgentFromCache
=
window
.
localStorage
.
getItem
(
'
gl-emoji-user-agent
'
);
let
userAgentFromCache
;
const
isLocalStorageAvailable
=
AccessorUtilities
.
isLocalStorageAccessSafe
();
if
(
isLocalStorageAvailable
)
userAgentFromCache
=
window
.
localStorage
.
getItem
(
'
gl-emoji-user-agent
'
);
try
{
try
{
unicodeSupportMap
=
JSON
.
parse
(
window
.
localStorage
.
getItem
(
'
gl-emoji-unicode-support-map
'
));
unicodeSupportMap
=
JSON
.
parse
(
window
.
localStorage
.
getItem
(
'
gl-emoji-unicode-support-map
'
));
}
catch
(
err
)
{
}
catch
(
err
)
{
// swallow
// swallow
}
}
if
(
!
unicodeSupportMap
||
userAgentFromCache
!==
navigator
.
userAgent
)
{
if
(
!
unicodeSupportMap
||
userAgentFromCache
!==
navigator
.
userAgent
)
{
unicodeSupportMap
=
generateUnicodeSupportMap
(
unicodeSupportTestMap
);
unicodeSupportMap
=
generateUnicodeSupportMap
(
unicodeSupportTestMap
);
if
(
isLocalStorageAvailable
)
{
window
.
localStorage
.
setItem
(
'
gl-emoji-user-agent
'
,
navigator
.
userAgent
);
window
.
localStorage
.
setItem
(
'
gl-emoji-user-agent
'
,
navigator
.
userAgent
);
window
.
localStorage
.
setItem
(
'
gl-emoji-unicode-support-map
'
,
JSON
.
stringify
(
unicodeSupportMap
));
window
.
localStorage
.
setItem
(
'
gl-emoji-unicode-support-map
'
,
JSON
.
stringify
(
unicodeSupportMap
));
}
}
}
return
unicodeSupportMap
;
return
unicodeSupportMap
;
}
}
...
...
app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.js
View file @
bef42d9a
...
@@ -8,6 +8,11 @@ export default {
...
@@ -8,6 +8,11 @@ export default {
type
:
Array
,
type
:
Array
,
required
:
true
,
required
:
true
,
},
},
isLocalStorageAvailable
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
},
},
computed
:
{
computed
:
{
...
@@ -47,7 +52,12 @@ export default {
...
@@ -47,7 +52,12 @@ export default {
template
:
`
template
:
`
<div>
<div>
<ul v-if="hasItems">
<div
v-if="!isLocalStorageAvailable"
class="dropdown-info-note">
This feature requires local storage to be enabled
</div>
<ul v-else-if="hasItems">
<li
<li
v-for="(item, index) in processedItems"
v-for="(item, index) in processedItems"
:key="index">
:key="index">
...
...
app/assets/javascripts/filtered_search/filtered_search_manager.js
View file @
bef42d9a
/* global Flash */
import
FilteredSearchContainer
from
'
./container
'
;
import
FilteredSearchContainer
from
'
./container
'
;
import
RecentSearchesRoot
from
'
./recent_searches_root
'
;
import
RecentSearchesRoot
from
'
./recent_searches_root
'
;
import
RecentSearchesStore
from
'
./stores/recent_searches_store
'
;
import
RecentSearchesStore
from
'
./stores/recent_searches_store
'
;
...
@@ -15,7 +13,9 @@ class FilteredSearchManager {
...
@@ -15,7 +13,9 @@ class FilteredSearchManager {
this
.
tokensContainer
=
this
.
container
.
querySelector
(
'
.tokens-container
'
);
this
.
tokensContainer
=
this
.
container
.
querySelector
(
'
.tokens-container
'
);
this
.
filteredSearchTokenKeys
=
gl
.
FilteredSearchTokenKeys
;
this
.
filteredSearchTokenKeys
=
gl
.
FilteredSearchTokenKeys
;
this
.
recentSearchesStore
=
new
RecentSearchesStore
();
this
.
recentSearchesStore
=
new
RecentSearchesStore
({
isLocalStorageAvailable
:
RecentSearchesService
.
isAvailable
(),
});
let
recentSearchesKey
=
'
issue-recent-searches
'
;
let
recentSearchesKey
=
'
issue-recent-searches
'
;
if
(
page
===
'
merge_requests
'
)
{
if
(
page
===
'
merge_requests
'
)
{
recentSearchesKey
=
'
merge-request-recent-searches
'
;
recentSearchesKey
=
'
merge-request-recent-searches
'
;
...
@@ -24,9 +24,10 @@ class FilteredSearchManager {
...
@@ -24,9 +24,10 @@ class FilteredSearchManager {
// Fetch recent searches from localStorage
// Fetch recent searches from localStorage
this
.
fetchingRecentSearchesPromise
=
this
.
recentSearchesService
.
fetch
()
this
.
fetchingRecentSearchesPromise
=
this
.
recentSearchesService
.
fetch
()
.
catch
(()
=>
{
.
catch
((
error
)
=>
{
if
(
error
.
name
===
'
RecentSearchesServiceError
'
)
return
undefined
;
// eslint-disable-next-line no-new
// eslint-disable-next-line no-new
new
Flash
(
'
An error occured while parsing recent searches
'
);
new
window
.
Flash
(
'
An error occured while parsing recent searches
'
);
// Gracefully fail to empty array
// Gracefully fail to empty array
return
[];
return
[];
})
})
...
...
app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js
View file @
bef42d9a
...
@@ -183,6 +183,9 @@ class FilteredSearchVisualTokens {
...
@@ -183,6 +183,9 @@ class FilteredSearchVisualTokens {
static
moveInputToTheRight
()
{
static
moveInputToTheRight
()
{
const
input
=
FilteredSearchContainer
.
container
.
querySelector
(
'
.filtered-search
'
);
const
input
=
FilteredSearchContainer
.
container
.
querySelector
(
'
.filtered-search
'
);
if
(
!
input
)
return
;
const
inputLi
=
input
.
parentElement
;
const
inputLi
=
input
.
parentElement
;
const
tokenContainer
=
FilteredSearchContainer
.
container
.
querySelector
(
'
.tokens-container
'
);
const
tokenContainer
=
FilteredSearchContainer
.
container
.
querySelector
(
'
.tokens-container
'
);
...
...
app/assets/javascripts/filtered_search/recent_searches_root.js
View file @
bef42d9a
...
@@ -29,12 +29,15 @@ class RecentSearchesRoot {
...
@@ -29,12 +29,15 @@ class RecentSearchesRoot {
}
}
render
()
{
render
()
{
const
state
=
this
.
store
.
state
;
this
.
vm
=
new
Vue
({
this
.
vm
=
new
Vue
({
el
:
this
.
wrapperElement
,
el
:
this
.
wrapperElement
,
data
:
this
.
store
.
state
,
data
()
{
return
state
;
}
,
template
:
`
template
:
`
<recent-searches-dropdown-content
<recent-searches-dropdown-content
:items="recentSearches" />
:items="recentSearches"
:is-local-storage-available="isLocalStorageAvailable"
/>
`
,
`
,
components
:
{
components
:
{
'
recent-searches-dropdown-content
'
:
RecentSearchesDropdownContent
,
'
recent-searches-dropdown-content
'
:
RecentSearchesDropdownContent
,
...
...
app/assets/javascripts/filtered_search/services/recent_searches_service.js
View file @
bef42d9a
import
RecentSearchesServiceError
from
'
./recent_searches_service_error
'
;
import
AccessorUtilities
from
'
../../lib/utils/accessor
'
;
class
RecentSearchesService
{
class
RecentSearchesService
{
constructor
(
localStorageKey
=
'
issuable-recent-searches
'
)
{
constructor
(
localStorageKey
=
'
issuable-recent-searches
'
)
{
this
.
localStorageKey
=
localStorageKey
;
this
.
localStorageKey
=
localStorageKey
;
}
}
fetch
()
{
fetch
()
{
if
(
!
RecentSearchesService
.
isAvailable
())
{
const
error
=
new
RecentSearchesServiceError
();
return
Promise
.
reject
(
error
);
}
const
input
=
window
.
localStorage
.
getItem
(
this
.
localStorageKey
);
const
input
=
window
.
localStorage
.
getItem
(
this
.
localStorageKey
);
let
searches
=
[];
let
searches
=
[];
...
@@ -19,8 +27,14 @@ class RecentSearchesService {
...
@@ -19,8 +27,14 @@ class RecentSearchesService {
}
}
save
(
searches
=
[])
{
save
(
searches
=
[])
{
if
(
!
RecentSearchesService
.
isAvailable
())
return
;
window
.
localStorage
.
setItem
(
this
.
localStorageKey
,
JSON
.
stringify
(
searches
));
window
.
localStorage
.
setItem
(
this
.
localStorageKey
,
JSON
.
stringify
(
searches
));
}
}
static
isAvailable
()
{
return
AccessorUtilities
.
isLocalStorageAccessSafe
();
}
}
}
export
default
RecentSearchesService
;
export
default
RecentSearchesService
;
app/assets/javascripts/filtered_search/services/recent_searches_service_error.js
0 → 100644
View file @
bef42d9a
class
RecentSearchesServiceError
{
constructor
(
message
)
{
this
.
name
=
'
RecentSearchesServiceError
'
;
this
.
message
=
message
||
'
Recent Searches Service is unavailable
'
;
}
}
// Can't use `extends` for builtin prototypes and get true inheritance yet
RecentSearchesServiceError
.
prototype
=
Error
.
prototype
;
export
default
RecentSearchesServiceError
;
app/assets/javascripts/lib/utils/accessor.js
0 → 100644
View file @
bef42d9a
function
isPropertyAccessSafe
(
base
,
property
)
{
let
safe
;
try
{
safe
=
!!
base
[
property
];
}
catch
(
error
)
{
safe
=
false
;
}
return
safe
;
}
function
isFunctionCallSafe
(
base
,
functionName
,
...
args
)
{
let
safe
=
true
;
try
{
base
[
functionName
](...
args
);
}
catch
(
error
)
{
safe
=
false
;
}
return
safe
;
}
function
isLocalStorageAccessSafe
()
{
let
safe
;
const
TEST_KEY
=
'
isLocalStorageAccessSafe
'
;
const
TEST_VALUE
=
'
true
'
;
safe
=
isPropertyAccessSafe
(
window
,
'
localStorage
'
);
if
(
!
safe
)
return
safe
;
safe
=
isFunctionCallSafe
(
window
.
localStorage
,
'
setItem
'
,
TEST_KEY
,
TEST_VALUE
);
if
(
safe
)
window
.
localStorage
.
removeItem
(
TEST_KEY
);
return
safe
;
}
const
AccessorUtilities
=
{
isPropertyAccessSafe
,
isFunctionCallSafe
,
isLocalStorageAccessSafe
,
};
export
default
AccessorUtilities
;
app/assets/javascripts/signin_tabs_memoizer.js
View file @
bef42d9a
/* eslint no-param-reassign: ["error", { "props": false }]*/
/* eslint no-param-reassign: ["error", { "props": false }]*/
/* eslint no-new: "off" */
/* eslint no-new: "off" */
import
AccessorUtilities
from
'
./lib/utils/accessor
'
;
((
global
)
=>
{
((
global
)
=>
{
/**
/**
* Memorize the last selected tab after reloading a page.
* Memorize the last selected tab after reloading a page.
...
@@ -9,6 +11,8 @@
...
@@ -9,6 +11,8 @@
constructor
({
currentTabKey
=
'
current_signin_tab
'
,
tabSelector
=
'
ul.nav-tabs
'
}
=
{})
{
constructor
({
currentTabKey
=
'
current_signin_tab
'
,
tabSelector
=
'
ul.nav-tabs
'
}
=
{})
{
this
.
currentTabKey
=
currentTabKey
;
this
.
currentTabKey
=
currentTabKey
;
this
.
tabSelector
=
tabSelector
;
this
.
tabSelector
=
tabSelector
;
this
.
isLocalStorageAvailable
=
AccessorUtilities
.
isLocalStorageAccessSafe
();
this
.
bootstrap
();
this
.
bootstrap
();
}
}
...
@@ -37,11 +41,15 @@
...
@@ -37,11 +41,15 @@
}
}
saveData
(
val
)
{
saveData
(
val
)
{
localStorage
.
setItem
(
this
.
currentTabKey
,
val
);
if
(
!
this
.
isLocalStorageAvailable
)
return
undefined
;
return
window
.
localStorage
.
setItem
(
this
.
currentTabKey
,
val
);
}
}
readData
()
{
readData
()
{
return
localStorage
.
getItem
(
this
.
currentTabKey
);
if
(
!
this
.
isLocalStorageAvailable
)
return
null
;
return
window
.
localStorage
.
getItem
(
this
.
currentTabKey
);
}
}
}
}
...
...
spec/javascripts/autosave_spec.js
0 → 100644
View file @
bef42d9a
import
Autosave
from
'
~/autosave
'
;
import
AccessorUtilities
from
'
~/lib/utils/accessor
'
;
describe
(
'
Autosave
'
,
()
=>
{
let
autosave
;
describe
(
'
class constructor
'
,
()
=>
{
const
key
=
'
key
'
;
const
field
=
jasmine
.
createSpyObj
(
'
field
'
,
[
'
data
'
,
'
on
'
]);
beforeEach
(()
=>
{
spyOn
(
AccessorUtilities
,
'
isLocalStorageAccessSafe
'
).
and
.
returnValue
(
true
);
spyOn
(
Autosave
.
prototype
,
'
restore
'
);
autosave
=
new
Autosave
(
field
,
key
);
});
it
(
'
should set .isLocalStorageAvailable
'
,
()
=>
{
expect
(
AccessorUtilities
.
isLocalStorageAccessSafe
).
toHaveBeenCalled
();
expect
(
autosave
.
isLocalStorageAvailable
).
toBe
(
true
);
});
});
describe
(
'
restore
'
,
()
=>
{
const
key
=
'
key
'
;
const
field
=
jasmine
.
createSpyObj
(
'
field
'
,
[
'
trigger
'
]);
beforeEach
(()
=>
{
autosave
=
{
field
,
key
,
};
spyOn
(
window
.
localStorage
,
'
getItem
'
);
});
describe
(
'
if .isLocalStorageAvailable is `false`
'
,
()
=>
{
beforeEach
(()
=>
{
autosave
.
isLocalStorageAvailable
=
false
;
Autosave
.
prototype
.
restore
.
call
(
autosave
);
});
it
(
'
should not call .getItem
'
,
()
=>
{
expect
(
window
.
localStorage
.
getItem
).
not
.
toHaveBeenCalled
();
});
});
describe
(
'
if .isLocalStorageAvailable is `true`
'
,
()
=>
{
beforeEach
(()
=>
{
autosave
.
isLocalStorageAvailable
=
true
;
Autosave
.
prototype
.
restore
.
call
(
autosave
);
});
it
(
'
should call .getItem
'
,
()
=>
{
expect
(
window
.
localStorage
.
getItem
).
toHaveBeenCalledWith
(
key
);
});
});
});
describe
(
'
save
'
,
()
=>
{
const
field
=
jasmine
.
createSpyObj
(
'
field
'
,
[
'
val
'
]);
beforeEach
(()
=>
{
autosave
=
jasmine
.
createSpyObj
(
'
autosave
'
,
[
'
reset
'
]);
autosave
.
field
=
field
;
field
.
val
.
and
.
returnValue
(
'
value
'
);
spyOn
(
window
.
localStorage
,
'
setItem
'
);
});
describe
(
'
if .isLocalStorageAvailable is `false`
'
,
()
=>
{
beforeEach
(()
=>
{
autosave
.
isLocalStorageAvailable
=
false
;
Autosave
.
prototype
.
save
.
call
(
autosave
);
});
it
(
'
should not call .setItem
'
,
()
=>
{
expect
(
window
.
localStorage
.
setItem
).
not
.
toHaveBeenCalled
();
});
});
describe
(
'
if .isLocalStorageAvailable is `true`
'
,
()
=>
{
beforeEach
(()
=>
{
autosave
.
isLocalStorageAvailable
=
true
;
Autosave
.
prototype
.
save
.
call
(
autosave
);
});
it
(
'
should call .setItem
'
,
()
=>
{
expect
(
window
.
localStorage
.
setItem
).
toHaveBeenCalled
();
});
});
});
describe
(
'
reset
'
,
()
=>
{
const
key
=
'
key
'
;
beforeEach
(()
=>
{
autosave
=
{
key
,
};
spyOn
(
window
.
localStorage
,
'
removeItem
'
);
});
describe
(
'
if .isLocalStorageAvailable is `false`
'
,
()
=>
{
beforeEach
(()
=>
{
autosave
.
isLocalStorageAvailable
=
false
;
Autosave
.
prototype
.
reset
.
call
(
autosave
);
});
it
(
'
should not call .removeItem
'
,
()
=>
{
expect
(
window
.
localStorage
.
removeItem
).
not
.
toHaveBeenCalled
();
});
});
describe
(
'
if .isLocalStorageAvailable is `true`
'
,
()
=>
{
beforeEach
(()
=>
{
autosave
.
isLocalStorageAvailable
=
true
;
Autosave
.
prototype
.
reset
.
call
(
autosave
);
});
it
(
'
should call .removeItem
'
,
()
=>
{
expect
(
window
.
localStorage
.
removeItem
).
toHaveBeenCalledWith
(
key
);
});
});
});
});
spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js
0 → 100644
View file @
bef42d9a
import
{
getUnicodeSupportMap
}
from
'
~/behaviors/gl_emoji/unicode_support_map
'
;
import
AccessorUtilities
from
'
~/lib/utils/accessor
'
;
describe
(
'
Unicode Support Map
'
,
()
=>
{
describe
(
'
getUnicodeSupportMap
'
,
()
=>
{
const
stringSupportMap
=
'
stringSupportMap
'
;
beforeEach
(()
=>
{
spyOn
(
AccessorUtilities
,
'
isLocalStorageAccessSafe
'
);
spyOn
(
window
.
localStorage
,
'
getItem
'
);
spyOn
(
window
.
localStorage
,
'
setItem
'
);
spyOn
(
JSON
,
'
parse
'
);
spyOn
(
JSON
,
'
stringify
'
).
and
.
returnValue
(
stringSupportMap
);
});
describe
(
'
if isLocalStorageAvailable is `true`
'
,
function
()
{
beforeEach
(()
=>
{
AccessorUtilities
.
isLocalStorageAccessSafe
.
and
.
returnValue
(
true
);
getUnicodeSupportMap
();
});
it
(
'
should call .getItem and .setItem
'
,
()
=>
{
const
allArgs
=
window
.
localStorage
.
setItem
.
calls
.
allArgs
();
expect
(
window
.
localStorage
.
getItem
).
toHaveBeenCalledWith
(
'
gl-emoji-user-agent
'
);
expect
(
allArgs
[
0
][
0
]).
toBe
(
'
gl-emoji-user-agent
'
);
expect
(
allArgs
[
0
][
1
]).
toBe
(
navigator
.
userAgent
);
expect
(
allArgs
[
1
][
0
]).
toBe
(
'
gl-emoji-unicode-support-map
'
);
expect
(
allArgs
[
1
][
1
]).
toBe
(
stringSupportMap
);
});
});
describe
(
'
if isLocalStorageAvailable is `false`
'
,
function
()
{
beforeEach
(()
=>
{
AccessorUtilities
.
isLocalStorageAccessSafe
.
and
.
returnValue
(
false
);
getUnicodeSupportMap
();
});
it
(
'
should not call .getItem or .setItem
'
,
()
=>
{
expect
(
window
.
localStorage
.
getItem
.
calls
.
count
()).
toBe
(
1
);
expect
(
window
.
localStorage
.
setItem
).
not
.
toHaveBeenCalled
();
});
});
});
});
spec/javascripts/filtered_search/components/recent_searches_dropdown_content_spec.js
View file @
bef42d9a
...
@@ -76,6 +76,26 @@ describe('RecentSearchesDropdownContent', () => {
...
@@ -76,6 +76,26 @@ describe('RecentSearchesDropdownContent', () => {
});
});
});
});
describe
(
'
if isLocalStorageAvailable is `false`
'
,
()
=>
{
let
el
;
beforeEach
(()
=>
{
const
props
=
Object
.
assign
({
isLocalStorageAvailable
:
false
},
propsDataWithItems
);
vm
=
createComponent
(
props
);
el
=
vm
.
$el
;
});
it
(
'
should render an info note
'
,
()
=>
{
const
note
=
el
.
querySelector
(
'
.dropdown-info-note
'
);
const
items
=
el
.
querySelectorAll
(
'
.filtered-search-history-dropdown-item
'
);
expect
(
note
).
toBeDefined
();
expect
(
note
.
innerText
.
trim
()).
toBe
(
'
This feature requires local storage to be enabled
'
);
expect
(
items
.
length
).
toEqual
(
propsDataWithoutItems
.
items
.
length
);
});
});
describe
(
'
computed
'
,
()
=>
{
describe
(
'
computed
'
,
()
=>
{
describe
(
'
processedItems
'
,
()
=>
{
describe
(
'
processedItems
'
,
()
=>
{
it
(
'
with items
'
,
()
=>
{
it
(
'
with items
'
,
()
=>
{
...
...
spec/javascripts/filtered_search/filtered_search_manager_spec.js
View file @
bef42d9a
import
*
as
recentSearchesStoreSrc
from
'
~/filtered_search/stores/recent_searches_store
'
;
import
RecentSearchesService
from
'
~/filtered_search/services/recent_searches_service
'
;
import
RecentSearchesServiceError
from
'
~/filtered_search/services/recent_searches_service_error
'
;
require
(
'
~/lib/utils/url_utility
'
);
require
(
'
~/lib/utils/url_utility
'
);
require
(
'
~/lib/utils/common_utils
'
);
require
(
'
~/lib/utils/common_utils
'
);
require
(
'
~/filtered_search/filtered_search_token_keys
'
);
require
(
'
~/filtered_search/filtered_search_token_keys
'
);
...
@@ -60,6 +64,36 @@ describe('Filtered Search Manager', () => {
...
@@ -60,6 +64,36 @@ describe('Filtered Search Manager', () => {
manager
.
cleanup
();
manager
.
cleanup
();
});
});
describe
(
'
class constructor
'
,
()
=>
{
const
isLocalStorageAvailable
=
'
isLocalStorageAvailable
'
;
let
filteredSearchManager
;
beforeEach
(()
=>
{
spyOn
(
RecentSearchesService
,
'
isAvailable
'
).
and
.
returnValue
(
isLocalStorageAvailable
);
spyOn
(
recentSearchesStoreSrc
,
'
default
'
);
filteredSearchManager
=
new
gl
.
FilteredSearchManager
();
return
filteredSearchManager
;
});
it
(
'
should instantiate RecentSearchesStore with isLocalStorageAvailable
'
,
()
=>
{
expect
(
RecentSearchesService
.
isAvailable
).
toHaveBeenCalled
();
expect
(
recentSearchesStoreSrc
.
default
).
toHaveBeenCalledWith
({
isLocalStorageAvailable
,
});
});
it
(
'
should not instantiate Flash if an RecentSearchesServiceError is caught
'
,
()
=>
{
spyOn
(
RecentSearchesService
.
prototype
,
'
fetch
'
).
and
.
callFake
(()
=>
Promise
.
reject
(
new
RecentSearchesServiceError
()));
spyOn
(
window
,
'
Flash
'
);
filteredSearchManager
=
new
gl
.
FilteredSearchManager
();
expect
(
window
.
Flash
).
not
.
toHaveBeenCalled
();
});
});
describe
(
'
search
'
,
()
=>
{
describe
(
'
search
'
,
()
=>
{
const
defaultParams
=
'
?scope=all&utf8=%E2%9C%93&state=opened
'
;
const
defaultParams
=
'
?scope=all&utf8=%E2%9C%93&state=opened
'
;
...
...
spec/javascripts/filtered_search/recent_searches_root_spec.js
0 → 100644
View file @
bef42d9a
import
RecentSearchesRoot
from
'
~/filtered_search/recent_searches_root
'
;
import
*
as
vueSrc
from
'
vue
'
;
describe
(
'
RecentSearchesRoot
'
,
()
=>
{
describe
(
'
render
'
,
()
=>
{
let
recentSearchesRoot
;
let
data
;
let
template
;
beforeEach
(()
=>
{
recentSearchesRoot
=
{
store
:
{
state
:
'
state
'
,
},
};
spyOn
(
vueSrc
,
'
default
'
).
and
.
callFake
((
options
)
=>
{
data
=
options
.
data
;
template
=
options
.
template
;
});
RecentSearchesRoot
.
prototype
.
render
.
call
(
recentSearchesRoot
);
});
it
(
'
should instantiate Vue
'
,
()
=>
{
expect
(
vueSrc
.
default
).
toHaveBeenCalled
();
expect
(
data
()).
toBe
(
recentSearchesRoot
.
store
.
state
);
expect
(
template
).
toContain
(
'
:is-local-storage-available="isLocalStorageAvailable"
'
);
});
});
});
spec/javascripts/filtered_search/services/recent_searches_service_error_spec.js
0 → 100644
View file @
bef42d9a
import
RecentSearchesServiceError
from
'
~/filtered_search/services/recent_searches_service_error
'
;
describe
(
'
RecentSearchesServiceError
'
,
()
=>
{
let
recentSearchesServiceError
;
beforeEach
(()
=>
{
recentSearchesServiceError
=
new
RecentSearchesServiceError
();
});
it
(
'
instantiates an instance of RecentSearchesServiceError and not an Error
'
,
()
=>
{
expect
(
recentSearchesServiceError
).
toEqual
(
jasmine
.
any
(
RecentSearchesServiceError
));
expect
(
recentSearchesServiceError
.
name
).
toBe
(
'
RecentSearchesServiceError
'
);
});
it
(
'
should set a default message
'
,
()
=>
{
expect
(
recentSearchesServiceError
.
message
).
toBe
(
'
Recent Searches Service is unavailable
'
);
});
});
spec/javascripts/filtered_search/services/recent_searches_service_spec.js
View file @
bef42d9a
/* eslint-disable promise/catch-or-return */
/* eslint-disable promise/catch-or-return */
import
RecentSearchesService
from
'
~/filtered_search/services/recent_searches_service
'
;
import
RecentSearchesService
from
'
~/filtered_search/services/recent_searches_service
'
;
import
AccessorUtilities
from
'
~/lib/utils/accessor
'
;
describe
(
'
RecentSearchesService
'
,
()
=>
{
describe
(
'
RecentSearchesService
'
,
()
=>
{
let
service
;
let
service
;
...
@@ -11,6 +12,10 @@ describe('RecentSearchesService', () => {
...
@@ -11,6 +12,10 @@ describe('RecentSearchesService', () => {
});
});
describe
(
'
fetch
'
,
()
=>
{
describe
(
'
fetch
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
RecentSearchesService
,
'
isAvailable
'
).
and
.
returnValue
(
true
);
});
it
(
'
should default to empty array
'
,
(
done
)
=>
{
it
(
'
should default to empty array
'
,
(
done
)
=>
{
const
fetchItemsPromise
=
service
.
fetch
();
const
fetchItemsPromise
=
service
.
fetch
();
...
@@ -29,7 +34,17 @@ describe('RecentSearchesService', () => {
...
@@ -29,7 +34,17 @@ describe('RecentSearchesService', () => {
const
fetchItemsPromise
=
service
.
fetch
();
const
fetchItemsPromise
=
service
.
fetch
();
fetchItemsPromise
fetchItemsPromise
.
catch
(()
=>
{
.
catch
((
error
)
=>
{
expect
(
error
).
toEqual
(
jasmine
.
any
(
SyntaxError
));
done
();
});
});
it
(
'
should reject when service is unavailable
'
,
(
done
)
=>
{
RecentSearchesService
.
isAvailable
.
and
.
returnValue
(
false
);
service
.
fetch
().
catch
((
error
)
=>
{
expect
(
error
).
toEqual
(
jasmine
.
any
(
Error
));
done
();
done
();
});
});
});
});
...
@@ -44,15 +59,89 @@ describe('RecentSearchesService', () => {
...
@@ -44,15 +59,89 @@ describe('RecentSearchesService', () => {
done
();
done
();
});
});
});
});
describe
(
'
if .isAvailable returns `false`
'
,
()
=>
{
beforeEach
(()
=>
{
RecentSearchesService
.
isAvailable
.
and
.
returnValue
(
false
);
spyOn
(
window
.
localStorage
,
'
getItem
'
);
RecentSearchesService
.
prototype
.
fetch
();
});
it
(
'
should not call .getItem
'
,
()
=>
{
expect
(
window
.
localStorage
.
getItem
).
not
.
toHaveBeenCalled
();
});
});
});
});
describe
(
'
setRecentSearches
'
,
()
=>
{
describe
(
'
setRecentSearches
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
RecentSearchesService
,
'
isAvailable
'
).
and
.
returnValue
(
true
);
});
it
(
'
should save things in localStorage
'
,
()
=>
{
it
(
'
should save things in localStorage
'
,
()
=>
{
const
items
=
[
'
foo
'
,
'
bar
'
];
const
items
=
[
'
foo
'
,
'
bar
'
];
service
.
save
(
items
);
service
.
save
(
items
);
const
newLocalStorageValue
=
const
newLocalStorageValue
=
window
.
localStorage
.
getItem
(
service
.
localStorageKey
);
window
.
localStorage
.
getItem
(
service
.
localStorageKey
);
expect
(
JSON
.
parse
(
newLocalStorageValue
)).
toEqual
(
items
);
expect
(
JSON
.
parse
(
newLocalStorageValue
)).
toEqual
(
items
);
});
});
});
});
describe
(
'
save
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
window
.
localStorage
,
'
setItem
'
);
spyOn
(
RecentSearchesService
,
'
isAvailable
'
);
});
describe
(
'
if .isAvailable returns `true`
'
,
()
=>
{
const
searchesString
=
'
searchesString
'
;
const
localStorageKey
=
'
localStorageKey
'
;
const
recentSearchesService
=
{
localStorageKey
,
};
beforeEach
(()
=>
{
RecentSearchesService
.
isAvailable
.
and
.
returnValue
(
true
);
spyOn
(
JSON
,
'
stringify
'
).
and
.
returnValue
(
searchesString
);
RecentSearchesService
.
prototype
.
save
.
call
(
recentSearchesService
);
});
it
(
'
should call .setItem
'
,
()
=>
{
expect
(
window
.
localStorage
.
setItem
).
toHaveBeenCalledWith
(
localStorageKey
,
searchesString
);
});
});
describe
(
'
if .isAvailable returns `false`
'
,
()
=>
{
beforeEach
(()
=>
{
RecentSearchesService
.
isAvailable
.
and
.
returnValue
(
false
);
RecentSearchesService
.
prototype
.
save
();
});
it
(
'
should not call .setItem
'
,
()
=>
{
expect
(
window
.
localStorage
.
setItem
).
not
.
toHaveBeenCalled
();
});
});
});
describe
(
'
isAvailable
'
,
()
=>
{
let
isAvailable
;
beforeEach
(()
=>
{
spyOn
(
AccessorUtilities
,
'
isLocalStorageAccessSafe
'
).
and
.
callThrough
();
isAvailable
=
RecentSearchesService
.
isAvailable
();
});
it
(
'
should call .isLocalStorageAccessSafe
'
,
()
=>
{
expect
(
AccessorUtilities
.
isLocalStorageAccessSafe
).
toHaveBeenCalled
();
});
it
(
'
should return a boolean
'
,
()
=>
{
expect
(
typeof
isAvailable
).
toBe
(
'
boolean
'
);
});
});
});
});
spec/javascripts/lib/utils/accessor_spec.js
0 → 100644
View file @
bef42d9a
import
AccessorUtilities
from
'
~/lib/utils/accessor
'
;
describe
(
'
AccessorUtilities
'
,
()
=>
{
const
testError
=
new
Error
(
'
test error
'
);
describe
(
'
isPropertyAccessSafe
'
,
()
=>
{
let
base
;
it
(
'
should return `true` if access is safe
'
,
()
=>
{
base
=
{
testProp
:
'
testProp
'
};
expect
(
AccessorUtilities
.
isPropertyAccessSafe
(
base
,
'
testProp
'
)).
toBe
(
true
);
});
it
(
'
should return `false` if access throws an error
'
,
()
=>
{
base
=
{
get
testProp
()
{
throw
testError
;
}
};
expect
(
AccessorUtilities
.
isPropertyAccessSafe
(
base
,
'
testProp
'
)).
toBe
(
false
);
});
it
(
'
should return `false` if property is undefined
'
,
()
=>
{
base
=
{};
expect
(
AccessorUtilities
.
isPropertyAccessSafe
(
base
,
'
testProp
'
)).
toBe
(
false
);
});
});
describe
(
'
isFunctionCallSafe
'
,
()
=>
{
const
base
=
{};
it
(
'
should return `true` if calling is safe
'
,
()
=>
{
base
.
func
=
()
=>
{};
expect
(
AccessorUtilities
.
isFunctionCallSafe
(
base
,
'
func
'
)).
toBe
(
true
);
});
it
(
'
should return `false` if calling throws an error
'
,
()
=>
{
base
.
func
=
()
=>
{
throw
new
Error
(
'
test error
'
);
};
expect
(
AccessorUtilities
.
isFunctionCallSafe
(
base
,
'
func
'
)).
toBe
(
false
);
});
it
(
'
should return `false` if function is undefined
'
,
()
=>
{
base
.
func
=
undefined
;
expect
(
AccessorUtilities
.
isFunctionCallSafe
(
base
,
'
func
'
)).
toBe
(
false
);
});
});
describe
(
'
isLocalStorageAccessSafe
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
window
.
localStorage
,
'
setItem
'
);
spyOn
(
window
.
localStorage
,
'
removeItem
'
);
});
it
(
'
should return `true` if access is safe
'
,
()
=>
{
expect
(
AccessorUtilities
.
isLocalStorageAccessSafe
()).
toBe
(
true
);
});
it
(
'
should return `false` if access to .setItem isnt safe
'
,
()
=>
{
window
.
localStorage
.
setItem
.
and
.
callFake
(()
=>
{
throw
testError
;
});
expect
(
AccessorUtilities
.
isLocalStorageAccessSafe
()).
toBe
(
false
);
});
it
(
'
should set a test item if access is safe
'
,
()
=>
{
AccessorUtilities
.
isLocalStorageAccessSafe
();
expect
(
window
.
localStorage
.
setItem
).
toHaveBeenCalledWith
(
'
isLocalStorageAccessSafe
'
,
'
true
'
);
});
it
(
'
should remove the test item if access is safe
'
,
()
=>
{
AccessorUtilities
.
isLocalStorageAccessSafe
();
expect
(
window
.
localStorage
.
removeItem
).
toHaveBeenCalledWith
(
'
isLocalStorageAccessSafe
'
);
});
});
});
spec/javascripts/signin_tabs_memoizer_spec.js
View file @
bef42d9a
import
AccessorUtilities
from
'
~/lib/utils/accessor
'
;
require
(
'
~/signin_tabs_memoizer
'
);
require
(
'
~/signin_tabs_memoizer
'
);
((
global
)
=>
{
((
global
)
=>
{
...
@@ -19,6 +21,8 @@ require('~/signin_tabs_memoizer');
...
@@ -19,6 +21,8 @@ require('~/signin_tabs_memoizer');
beforeEach
(()
=>
{
beforeEach
(()
=>
{
loadFixtures
(
fixtureTemplate
);
loadFixtures
(
fixtureTemplate
);
spyOn
(
AccessorUtilities
,
'
isLocalStorageAccessSafe
'
).
and
.
returnValue
(
true
);
});
});
it
(
'
does nothing if no tab was previously selected
'
,
()
=>
{
it
(
'
does nothing if no tab was previously selected
'
,
()
=>
{
...
@@ -49,5 +53,91 @@ require('~/signin_tabs_memoizer');
...
@@ -49,5 +53,91 @@ require('~/signin_tabs_memoizer');
expect
(
memo
.
readData
()).
toEqual
(
'
#standard
'
);
expect
(
memo
.
readData
()).
toEqual
(
'
#standard
'
);
});
});
describe
(
'
class constructor
'
,
()
=>
{
beforeEach
(()
=>
{
memo
=
createMemoizer
();
});
it
(
'
should set .isLocalStorageAvailable
'
,
()
=>
{
expect
(
AccessorUtilities
.
isLocalStorageAccessSafe
).
toHaveBeenCalled
();
expect
(
memo
.
isLocalStorageAvailable
).
toBe
(
true
);
});
});
describe
(
'
saveData
'
,
()
=>
{
beforeEach
(()
=>
{
memo
=
{
currentTabKey
,
};
spyOn
(
localStorage
,
'
setItem
'
);
});
describe
(
'
if .isLocalStorageAvailable is `false`
'
,
()
=>
{
beforeEach
(
function
()
{
memo
.
isLocalStorageAvailable
=
false
;
global
.
ActiveTabMemoizer
.
prototype
.
saveData
.
call
(
memo
);
});
it
(
'
should not call .setItem
'
,
()
=>
{
expect
(
localStorage
.
setItem
).
not
.
toHaveBeenCalled
();
});
});
describe
(
'
if .isLocalStorageAvailable is `true`
'
,
()
=>
{
const
value
=
'
value
'
;
beforeEach
(
function
()
{
memo
.
isLocalStorageAvailable
=
true
;
global
.
ActiveTabMemoizer
.
prototype
.
saveData
.
call
(
memo
,
value
);
});
it
(
'
should call .setItem
'
,
()
=>
{
expect
(
localStorage
.
setItem
).
toHaveBeenCalledWith
(
currentTabKey
,
value
);
});
});
});
describe
(
'
readData
'
,
()
=>
{
const
itemValue
=
'
itemValue
'
;
let
readData
;
beforeEach
(()
=>
{
memo
=
{
currentTabKey
,
};
spyOn
(
localStorage
,
'
getItem
'
).
and
.
returnValue
(
itemValue
);
});
describe
(
'
if .isLocalStorageAvailable is `false`
'
,
()
=>
{
beforeEach
(
function
()
{
memo
.
isLocalStorageAvailable
=
false
;
readData
=
global
.
ActiveTabMemoizer
.
prototype
.
readData
.
call
(
memo
);
});
it
(
'
should not call .getItem and should return `null`
'
,
()
=>
{
expect
(
localStorage
.
getItem
).
not
.
toHaveBeenCalled
();
expect
(
readData
).
toBe
(
null
);
});
});
describe
(
'
if .isLocalStorageAvailable is `true`
'
,
()
=>
{
beforeEach
(
function
()
{
memo
.
isLocalStorageAvailable
=
true
;
readData
=
global
.
ActiveTabMemoizer
.
prototype
.
readData
.
call
(
memo
);
});
it
(
'
should call .getItem and return the localStorage value
'
,
()
=>
{
expect
(
window
.
localStorage
.
getItem
).
toHaveBeenCalledWith
(
currentTabKey
);
expect
(
readData
).
toBe
(
itemValue
);
});
});
});
});
});
})(
window
);
})(
window
);
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