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
a217ce30
Commit
a217ce30
authored
Dec 13, 2021
by
Ammar Alakkad
Committed by
Natalia Tepluhina
Dec 13, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Show pending members in Seats Usage -> Pending Members
parent
60f4f450
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
576 additions
and
3 deletions
+576
-3
ee/app/assets/javascripts/api/groups_api.js
ee/app/assets/javascripts/api/groups_api.js
+19
-0
ee/app/assets/javascripts/pages/groups/usage_quotas/pending_members/index.js
...cripts/pages/groups/usage_quotas/pending_members/index.js
+5
-0
ee/app/assets/javascripts/pending_members/components/app.vue
ee/app/assets/javascripts/pending_members/components/app.vue
+86
-0
ee/app/assets/javascripts/pending_members/constants.js
ee/app/assets/javascripts/pending_members/constants.js
+11
-0
ee/app/assets/javascripts/pending_members/index.js
ee/app/assets/javascripts/pending_members/index.js
+25
-0
ee/app/assets/javascripts/pending_members/store/actions.js
ee/app/assets/javascripts/pending_members/store/actions.js
+25
-0
ee/app/assets/javascripts/pending_members/store/getters.js
ee/app/assets/javascripts/pending_members/store/getters.js
+3
-0
ee/app/assets/javascripts/pending_members/store/index.js
ee/app/assets/javascripts/pending_members/store/index.js
+11
-0
ee/app/assets/javascripts/pending_members/store/mutation_types.js
...ssets/javascripts/pending_members/store/mutation_types.js
+5
-0
ee/app/assets/javascripts/pending_members/store/mutations.js
ee/app/assets/javascripts/pending_members/store/mutations.js
+29
-0
ee/app/assets/javascripts/pending_members/store/state.js
ee/app/assets/javascripts/pending_members/store/state.js
+10
-0
ee/app/views/groups/usage_quotas/pending_members.html.haml
ee/app/views/groups/usage_quotas/pending_members.html.haml
+2
-1
ee/spec/frontend/api/groups_api_spec.js
ee/spec/frontend/api/groups_api_spec.js
+17
-2
ee/spec/frontend/pending_members/components/__snapshots__/app_spec.js.snap
...pending_members/components/__snapshots__/app_spec.js.snap
+16
-0
ee/spec/frontend/pending_members/components/app_spec.js
ee/spec/frontend/pending_members/components/app_spec.js
+87
-0
ee/spec/frontend/pending_members/mock_data.js
ee/spec/frontend/pending_members/mock_data.js
+42
-0
ee/spec/frontend/pending_members/store/actions_spec.js
ee/spec/frontend/pending_members/store/actions_spec.js
+86
-0
ee/spec/frontend/pending_members/store/getters_spec.js
ee/spec/frontend/pending_members/store/getters_spec.js
+25
-0
ee/spec/frontend/pending_members/store/mutations_spec.js
ee/spec/frontend/pending_members/store/mutations_spec.js
+66
-0
locale/gitlab.pot
locale/gitlab.pot
+6
-0
No files found.
ee/app/assets/javascripts/api/groups_api.js
View file @
a217ce30
...
@@ -37,3 +37,22 @@ export const removeBillableMemberFromGroup = (groupId, memberId) => {
...
@@ -37,3 +37,22 @@ export const removeBillableMemberFromGroup = (groupId, memberId) => {
return
axios
.
delete
(
url
);
return
axios
.
delete
(
url
);
};
};
const
GROUPS_PENDING_MEMBERS_PATH
=
'
/api/:version/groups/:id/pending_members
'
;
const
GROUPS_PENDING_MEMBERS_STATE
=
'
awaiting
'
;
export
const
fetchPendingGroupMembersList
=
(
namespaceId
,
options
=
{})
=>
{
const
url
=
buildApiUrl
(
GROUPS_PENDING_MEMBERS_PATH
).
replace
(
'
:id
'
,
namespaceId
);
const
defaults
=
{
state
:
GROUPS_PENDING_MEMBERS_STATE
,
per_page
:
DEFAULT_PER_PAGE
,
page
:
1
,
};
return
axios
.
get
(
url
,
{
params
:
{
...
defaults
,
...
options
,
},
});
};
ee/app/assets/javascripts/pages/groups/usage_quotas/pending_members/index.js
0 → 100644
View file @
a217ce30
import
initPendingMembersApp
from
'
ee/pending_members
'
;
if
(
document
.
querySelector
(
'
#js-pending-members-app
'
))
{
initPendingMembersApp
();
}
ee/app/assets/javascripts/pending_members/components/app.vue
0 → 100644
View file @
a217ce30
<
script
>
import
{
mapActions
,
mapState
,
mapGetters
}
from
'
vuex
'
;
import
{
GlAvatarLabeled
,
GlAvatarLink
,
GlBadge
,
GlPagination
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
{
AVATAR_SIZE
}
from
'
ee/seat_usage/constants
'
;
import
{
AWAITING_MEMBER_SIGNUP_TEXT
}
from
'
ee/pending_members/constants
'
;
export
default
{
name
:
'
PendingMembersApp
'
,
components
:
{
GlAvatarLabeled
,
GlAvatarLink
,
GlBadge
,
GlPagination
,
GlLoadingIcon
},
computed
:
{
...
mapState
([
'
isLoading
'
,
'
page
'
,
'
perPage
'
,
'
total
'
,
'
namespaceName
'
,
'
namespaceId
'
,
'
seatUsageExportPath
'
,
'
pendingMembersPagePath
'
,
'
pendingMembersCount
'
,
'
search
'
,
]),
...
mapGetters
([
'
tableItems
'
]),
currentPage
:
{
get
()
{
return
this
.
page
;
},
set
(
val
)
{
this
.
setCurrentPage
(
val
);
},
},
},
created
()
{
this
.
fetchPendingMembersList
();
},
AWAITING_MEMBER_SIGNUP_TEXT
,
methods
:
{
...
mapActions
([
'
fetchPendingMembersList
'
,
'
setCurrentPage
'
]),
avatarLabel
(
member
)
{
if
(
member
.
invited
)
{
return
member
.
email
;
}
return
member
.
name
??
''
;
},
},
avatarSize
:
AVATAR_SIZE
,
};
</
script
>
<
template
>
<div>
<div
v-if=
"isLoading"
class=
"gl-text-center loading"
>
<gl-loading-icon
class=
"mt-5"
size=
"lg"
/>
</div>
<template
v-else
>
<div
v-for=
"item in tableItems"
:key=
"item.id"
class=
"gl-p-5 gl-border-0 gl-border-b-1! gl-border-gray-100 gl-border-solid"
data-testid=
"pending-members-row"
>
<gl-avatar-link
target=
"blank"
:href=
"item.web_url"
:alt=
"item.name"
>
<gl-avatar-labeled
:src=
"item.avatar_url"
:size=
"$options.avatarSize"
:label=
"avatarLabel(item)"
>
<template
#meta
>
<gl-badge
v-if=
"item.invited && item.approved"
size=
"sm"
variant=
"muted"
>
{{
$options
.
AWAITING_MEMBER_SIGNUP_TEXT
}}
</gl-badge>
</
template
>
</gl-avatar-labeled>
</gl-avatar-link>
</div>
</template>
<gl-pagination
v-if=
"currentPage"
v-model=
"currentPage"
:per-page=
"perPage"
:total-items=
"total"
align=
"center"
class=
"gl-mt-5"
/>
</div>
</template>
ee/app/assets/javascripts/pending_members/constants.js
0 → 100644
View file @
a217ce30
import
{
s__
}
from
'
~/locale
'
;
// Pending members HTTP headers
export
const
HEADER_TOTAL_ENTRIES
=
'
x-total
'
;
export
const
HEADER_PAGE_NUMBER
=
'
x-page
'
;
export
const
HEADER_ITEMS_PER_PAGE
=
'
x-per-page
'
;
export
const
AWAITING_MEMBER_SIGNUP_TEXT
=
s__
(
'
Billing|Awaiting member signup
'
);
export
const
PENDING_MEMBERS_LIST_ERROR
=
s__
(
'
Billing|An error occurred while loading pending members list
'
,
);
ee/app/assets/javascripts/pending_members/index.js
0 → 100644
View file @
a217ce30
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
PendingMembersApp
from
'
./components/app.vue
'
;
import
initialStore
from
'
./store
'
;
Vue
.
use
(
Vuex
);
export
default
(
containerId
=
'
js-pending-members-app
'
)
=>
{
const
el
=
document
.
getElementById
(
containerId
);
if
(
!
el
)
{
return
false
;
}
const
{
namespaceId
,
namespaceName
}
=
el
.
dataset
;
return
new
Vue
({
el
,
apolloProvider
:
{},
store
:
new
Vuex
.
Store
(
initialStore
({
namespaceId
,
namespaceName
})),
render
(
createElement
)
{
return
createElement
(
PendingMembersApp
);
},
});
};
ee/app/assets/javascripts/pending_members/store/actions.js
0 → 100644
View file @
a217ce30
import
*
as
GroupsApi
from
'
ee/api/groups_api
'
;
import
createFlash
from
'
~/flash
'
;
import
{
PENDING_MEMBERS_LIST_ERROR
}
from
'
ee/pending_members/constants
'
;
import
*
as
types
from
'
./mutation_types
'
;
export
const
fetchPendingMembersList
=
({
commit
,
state
})
=>
{
commit
(
types
.
REQUEST_PENDING_MEMBERS
);
const
{
page
,
search
}
=
state
;
return
GroupsApi
.
fetchPendingGroupMembersList
(
state
.
namespaceId
,
{
page
,
search
})
.
then
(({
data
,
headers
})
=>
commit
(
types
.
RECEIVE_PENDING_MEMBERS_SUCCESS
,
{
data
,
headers
}))
.
catch
(()
=>
{
commit
(
types
.
RECEIVE_PENDING_MEMBERS_ERROR
);
createFlash
({
message
:
PENDING_MEMBERS_LIST_ERROR
,
});
});
};
export
const
setCurrentPage
=
({
commit
,
dispatch
},
page
)
=>
{
commit
(
types
.
SET_CURRENT_PAGE
,
page
);
dispatch
(
'
fetchPendingMembersList
'
);
};
ee/app/assets/javascripts/pending_members/store/getters.js
0 → 100644
View file @
a217ce30
export
const
tableItems
=
(
state
)
=>
{
return
state
.
members
??
[];
};
ee/app/assets/javascripts/pending_members/store/index.js
0 → 100644
View file @
a217ce30
import
*
as
actions
from
'
./actions
'
;
import
*
as
getters
from
'
./getters
'
;
import
mutations
from
'
./mutations
'
;
import
state
from
'
./state
'
;
export
default
(
initState
=
{})
=>
({
actions
,
mutations
,
getters
,
state
:
state
(
initState
),
});
ee/app/assets/javascripts/pending_members/store/mutation_types.js
0 → 100644
View file @
a217ce30
export
const
REQUEST_PENDING_MEMBERS
=
'
REQUEST_PENDING_MEMBERS
'
;
export
const
RECEIVE_PENDING_MEMBERS_SUCCESS
=
'
RECEIVE_PENDING_MEMBERS_SUCCESS
'
;
export
const
RECEIVE_PENDING_MEMBERS_ERROR
=
'
RECEIVE_PENDING_MEMBERS_ERROR
'
;
export
const
SET_CURRENT_PAGE
=
'
SET_CURRENT_PAGE
'
;
ee/app/assets/javascripts/pending_members/store/mutations.js
0 → 100644
View file @
a217ce30
import
{
HEADER_TOTAL_ENTRIES
,
HEADER_PAGE_NUMBER
,
HEADER_ITEMS_PER_PAGE
}
from
'
../constants
'
;
import
*
as
types
from
'
./mutation_types
'
;
export
default
{
[
types
.
REQUEST_PENDING_MEMBERS
](
state
)
{
state
.
isLoading
=
true
;
state
.
hasError
=
false
;
},
[
types
.
RECEIVE_PENDING_MEMBERS_SUCCESS
](
state
,
payload
)
{
const
{
data
,
headers
}
=
payload
;
state
.
members
=
data
;
state
.
total
=
Number
(
headers
[
HEADER_TOTAL_ENTRIES
]);
state
.
page
=
Number
(
headers
[
HEADER_PAGE_NUMBER
]);
state
.
perPage
=
Number
(
headers
[
HEADER_ITEMS_PER_PAGE
]);
state
.
isLoading
=
false
;
},
[
types
.
RECEIVE_PENDING_MEMBERS_ERROR
](
state
)
{
state
.
isLoading
=
false
;
state
.
hasError
=
true
;
},
[
types
.
SET_CURRENT_PAGE
](
state
,
pageNumber
)
{
state
.
page
=
pageNumber
;
},
};
ee/app/assets/javascripts/pending_members/store/state.js
0 → 100644
View file @
a217ce30
export
default
({
namespaceId
=
null
,
namespaceName
=
null
}
=
{})
=>
({
isLoading
:
false
,
hasError
:
false
,
namespaceId
,
namespaceName
,
members
:
[],
total
:
null
,
page
:
null
,
perPage
:
null
,
});
ee/app/views/groups/usage_quotas/pending_members.html.haml
View file @
a217ce30
-
page_title
s_
(
"UsageQuota|Pending Members"
)
-
page_title
s_
(
"UsageQuota|Pending Members"
)
-
add_to_breadcrumbs
s_
(
'UsageQuota|Usage Quotas'
),
group_usage_quotas_path
(
@group
)
%h3
.page-title
%h3
.page-title
=
s_
(
'UsageQuota|Pending Members'
)
=
s_
(
'UsageQuota|Pending Members'
)
#js-pending-members-app
{
data:
{
}
}
#js-pending-members-app
{
data:
{
namespace_id:
@group
.
id
,
namespace_name:
@group
.
name
}
}
ee/spec/frontend/api/groups_api_spec.js
View file @
a217ce30
...
@@ -11,6 +11,7 @@ describe('GroupsApi', () => {
...
@@ -11,6 +11,7 @@ describe('GroupsApi', () => {
api_version
:
dummyApiVersion
,
api_version
:
dummyApiVersion
,
relative_url_root
:
dummyUrlRoot
,
relative_url_root
:
dummyUrlRoot
,
};
};
const
namespaceId
=
1000
;
let
originalGon
;
let
originalGon
;
let
mock
;
let
mock
;
...
@@ -27,8 +28,6 @@ describe('GroupsApi', () => {
...
@@ -27,8 +28,6 @@ describe('GroupsApi', () => {
});
});
describe
(
'
Billable members list
'
,
()
=>
{
describe
(
'
Billable members list
'
,
()
=>
{
const
namespaceId
=
1000
;
describe
(
'
fetchBillableGroupMembersList
'
,
()
=>
{
describe
(
'
fetchBillableGroupMembersList
'
,
()
=>
{
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/groups/
${
namespaceId
}
/billable_members`
;
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/groups/
${
namespaceId
}
/billable_members`
;
...
@@ -75,4 +74,20 @@ describe('GroupsApi', () => {
...
@@ -75,4 +74,20 @@ describe('GroupsApi', () => {
});
});
});
});
});
});
describe
(
'
Pending group members list
'
,
()
=>
{
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/groups/
${
namespaceId
}
/pending_members`
;
it
(
'
sends GET request using the right URL
'
,
async
()
=>
{
jest
.
spyOn
(
axios
,
'
get
'
);
mock
.
onGet
(
expectedUrl
).
replyOnce
(
httpStatus
.
OK
,
[]);
const
{
data
}
=
await
GroupsApi
.
fetchPendingGroupMembersList
(
namespaceId
);
expect
(
data
).
toEqual
([]);
expect
(
axios
.
get
).
toHaveBeenCalledWith
(
expectedUrl
,
{
params
:
{
page
:
1
,
per_page
:
DEFAULT_PER_PAGE
,
state
:
'
awaiting
'
},
});
});
});
});
});
ee/spec/frontend/pending_members/components/__snapshots__/app_spec.js.snap
0 → 100644
View file @
a217ce30
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PendingMembersApp renders pending members 1`] = `
Array [
"<div data-testid=\\"pending-members-row\\" class=\\"gl-p-5 gl-border-0 gl-border-b-1! gl-border-gray-100 gl-border-solid\\">
<gl-avatar-link-stub target=\\"blank\\" href=\\"http://127.0.0.1:3000/334050-1\\" alt=\\"334050-1 334050-1\\">
<gl-avatar-labeled-stub label=\\"334050-1 334050-1\\" sublabel=\\"\\" labellink=\\"\\" sublabellink=\\"\\" src=\\"https://www.gravatar.com/avatar/9987bae8f71451bb2d422d0596367b25?s=80&d=identicon\\" size=\\"32\\"></gl-avatar-labeled-stub>
</gl-avatar-link-stub>
</div>",
"<div data-testid=\\"pending-members-row\\" class=\\"gl-p-5 gl-border-0 gl-border-b-1! gl-border-gray-100 gl-border-solid\\">
<gl-avatar-link-stub target=\\"blank\\">
<gl-avatar-labeled-stub label=\\"first-invite@gitlab.com\\" sublabel=\\"\\" labellink=\\"\\" sublabellink=\\"\\" src=\\"https://www.gravatar.com/avatar/8bad6be3d5070e7f7865d91a50f44f1f?s=80&d=identicon\\" size=\\"32\\"></gl-avatar-labeled-stub>
</gl-avatar-link-stub>
</div>",
]
`;
ee/spec/frontend/pending_members/components/app_spec.js
0 → 100644
View file @
a217ce30
import
{
GlPagination
,
GlBadge
,
GlAvatarLabeled
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
{
mockDataMembers
,
mockInvitedApprovedMember
}
from
'
ee_jest/pending_members/mock_data
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
import
PendingMembersApp
from
'
ee/pending_members/components/app.vue
'
;
Vue
.
use
(
Vuex
);
const
actionSpies
=
{
fetchPendingMembersList
:
jest
.
fn
(),
};
const
providedFields
=
{
namespaceId
:
'
1000
'
,
namespaceName
:
'
Test Group Name
'
,
};
const
fakeStore
=
({
initialState
,
initialGetters
})
=>
new
Vuex
.
Store
({
actions
:
actionSpies
,
getters
:
{
tableItems
:
()
=>
mockDataMembers
.
data
,
...
initialGetters
,
},
state
:
{
isLoading
:
false
,
hasError
:
false
,
namespaceId
:
1
,
members
:
mockDataMembers
.
data
,
total
:
300
,
page
:
1
,
perPage
:
5
,
...
providedFields
,
...
initialState
,
},
});
describe
(
'
PendingMembersApp
'
,
()
=>
{
let
wrapper
;
const
createComponent
=
({
initialState
=
{},
initialGetters
=
{},
stubs
=
{}
}
=
{})
=>
{
wrapper
=
extendedWrapper
(
shallowMount
(
PendingMembersApp
,
{
store
:
fakeStore
({
initialState
,
initialGetters
}),
stubs
,
}),
);
};
const
findMemberRows
=
()
=>
wrapper
.
findAllByTestId
(
'
pending-members-row
'
);
const
findPagination
=
()
=>
wrapper
.
findComponent
(
GlPagination
);
beforeEach
(()
=>
{
createComponent
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
it
(
'
renders pending members
'
,
()
=>
{
const
memberRows
=
findMemberRows
();
expect
(
memberRows
.
length
).
toBe
(
mockDataMembers
.
data
.
length
);
expect
(
findMemberRows
().
wrappers
.
map
((
w
)
=>
w
.
html
())).
toMatchSnapshot
();
});
it
(
'
pagination is rendered and passed correct values
'
,
()
=>
{
const
pagination
=
findPagination
();
expect
(
pagination
.
props
()).
toMatchObject
({
perPage
:
5
,
totalItems
:
300
,
});
});
it
(
'
render badge for approved invited members
'
,
()
=>
{
createComponent
({
stubs
:
{
GlBadge
,
GlAvatarLabeled
},
initialGetters
:
{
tableItems
:
()
=>
[
mockInvitedApprovedMember
]
},
initialState
:
{
members
:
[
mockInvitedApprovedMember
]
},
});
expect
(
wrapper
.
find
(
GlBadge
).
text
()).
toEqual
(
'
Awaiting member signup
'
);
});
});
ee/spec/frontend/pending_members/mock_data.js
0 → 100644
View file @
a217ce30
import
{
HEADER_TOTAL_ENTRIES
,
HEADER_PAGE_NUMBER
,
HEADER_ITEMS_PER_PAGE
,
}
from
'
ee/pending_members/constants
'
;
export
const
mockDataMembers
=
{
data
:
[
{
id
:
177
,
name
:
'
334050-1 334050-1
'
,
username
:
'
334050-1
'
,
email
:
'
334050-1@gitlab.com
'
,
web_url
:
'
http://127.0.0.1:3000/334050-1
'
,
avatar_url
:
'
https://www.gravatar.com/avatar/9987bae8f71451bb2d422d0596367b25?s=80&d=identicon
'
,
approved
:
false
,
invited
:
false
,
},
{
id
:
178
,
email
:
'
first-invite@gitlab.com
'
,
avatar_url
:
'
https://www.gravatar.com/avatar/8bad6be3d5070e7f7865d91a50f44f1f?s=80&d=identicon
'
,
approved
:
false
,
invited
:
true
,
},
],
headers
:
{
[
HEADER_TOTAL_ENTRIES
]:
'
3
'
,
[
HEADER_PAGE_NUMBER
]:
'
1
'
,
[
HEADER_ITEMS_PER_PAGE
]:
'
1
'
,
},
};
export
const
mockInvitedApprovedMember
=
{
id
:
179
,
email
:
'
second-invite@gitlab.com
'
,
avatar_url
:
'
https://www.gravatar.com/avatar/c96806e80ab8c4ea4c668d795fcfed0f?s=80&d=identicon
'
,
approved
:
true
,
invited
:
true
,
};
ee/spec/frontend/pending_members/store/actions_spec.js
0 → 100644
View file @
a217ce30
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
State
from
'
ee/pending_members/store/state
'
;
import
*
as
GroupsApi
from
'
ee/api/groups_api
'
;
import
*
as
actions
from
'
ee/pending_members/store/actions
'
;
import
*
as
types
from
'
ee/pending_members/store/mutation_types
'
;
import
{
mockDataMembers
}
from
'
ee_jest/pending_members/mock_data
'
;
import
testAction
from
'
helpers/vuex_action_helper
'
;
import
createFlash
from
'
~/flash
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
httpStatusCodes
from
'
~/lib/utils/http_status
'
;
jest
.
mock
(
'
~/flash
'
);
describe
(
'
Pending members actions
'
,
()
=>
{
let
state
;
let
mock
;
beforeEach
(()
=>
{
state
=
State
();
mock
=
new
MockAdapter
(
axios
);
});
afterEach
(()
=>
{
mock
.
reset
();
});
describe
(
'
fetchPendingGroupMembersList
'
,
()
=>
{
beforeEach
(()
=>
{
gon
.
api_version
=
'
v4
'
;
state
.
namespaceId
=
1
;
});
it
(
'
passes correct arguments to API call
'
,
()
=>
{
const
payload
=
{
page
:
5
};
state
=
Object
.
assign
(
state
,
payload
);
const
spy
=
jest
.
spyOn
(
GroupsApi
,
'
fetchPendingGroupMembersList
'
);
testAction
({
action
:
actions
.
fetchPendingMembersList
,
payload
,
state
,
expectedMutations
:
expect
.
anything
(),
expectedActions
:
expect
.
anything
(),
});
expect
(
spy
).
toBeCalledWith
(
state
.
namespaceId
,
expect
.
objectContaining
(
payload
));
});
describe
(
'
on success
'
,
()
=>
{
beforeEach
(()
=>
{
mock
.
onGet
(
'
/api/v4/groups/1/pending_members
'
)
.
replyOnce
(
httpStatusCodes
.
OK
,
mockDataMembers
.
data
,
mockDataMembers
.
headers
);
});
it
(
'
dispatches the request and success action
'
,
()
=>
{
testAction
({
action
:
actions
.
fetchPendingMembersList
,
state
,
expectedMutations
:
[
{
type
:
types
.
REQUEST_PENDING_MEMBERS
},
{
type
:
types
.
RECEIVE_PENDING_MEMBERS_SUCCESS
,
payload
:
mockDataMembers
},
],
});
});
});
describe
(
'
on error
'
,
()
=>
{
beforeEach
(()
=>
{
mock
.
onGet
(
'
/api/v4/groups/1/pending_members
'
).
replyOnce
(
httpStatusCodes
.
NOT_FOUND
,
{});
});
it
(
'
dispatches the request and error action
'
,
async
()
=>
{
await
testAction
({
action
:
actions
.
fetchPendingMembersList
,
state
,
expectedMutations
:
[
{
type
:
types
.
REQUEST_PENDING_MEMBERS
},
{
type
:
types
.
RECEIVE_PENDING_MEMBERS_ERROR
},
],
});
expect
(
createFlash
).
toHaveBeenCalled
();
});
});
});
});
ee/spec/frontend/pending_members/store/getters_spec.js
0 → 100644
View file @
a217ce30
import
*
as
getters
from
'
ee/pending_members/store/getters
'
;
import
State
from
'
ee/pending_members/store/state
'
;
import
{
mockDataMembers
}
from
'
ee_jest/pending_members/mock_data
'
;
describe
(
'
Pending members getters
'
,
()
=>
{
let
state
;
beforeEach
(()
=>
{
state
=
State
();
});
describe
(
'
Table items
'
,
()
=>
{
it
(
'
returns the expected value if data is provided
'
,
()
=>
{
state
.
members
=
[...
mockDataMembers
.
data
];
expect
(
getters
.
tableItems
(
state
)).
toEqual
(
mockDataMembers
.
data
);
});
it
(
'
returns an empty array if data is not provided
'
,
()
=>
{
state
.
members
=
[];
expect
(
getters
.
tableItems
(
state
)).
toEqual
([]);
});
});
});
ee/spec/frontend/pending_members/store/mutations_spec.js
0 → 100644
View file @
a217ce30
import
{
mockDataMembers
}
from
'
ee_jest/pending_members/mock_data
'
;
import
*
as
types
from
'
ee/pending_members/store/mutation_types
'
;
import
mutations
from
'
ee/pending_members/store/mutations
'
;
import
createState
from
'
ee/pending_members/store/state
'
;
describe
(
'
Pending members mutations
'
,
()
=>
{
let
state
;
beforeEach
(()
=>
{
state
=
createState
();
});
describe
(
types
.
REQUEST_PENDING_MEMBERS
,
()
=>
{
beforeEach
(()
=>
{
mutations
[
types
.
REQUEST_PENDING_MEMBERS
](
state
);
});
it
(
'
sets isLoading to true
'
,
()
=>
{
expect
(
state
.
isLoading
).
toBeTruthy
();
});
it
(
'
sets hasError to false
'
,
()
=>
{
expect
(
state
.
hasError
).
toBeFalsy
();
});
});
describe
(
types
.
RECEIVE_PENDING_MEMBERS_SUCCESS
,
()
=>
{
beforeEach
(()
=>
{
mutations
[
types
.
RECEIVE_PENDING_MEMBERS_SUCCESS
](
state
,
mockDataMembers
);
});
it
(
'
sets state as expected
'
,
()
=>
{
expect
(
state
.
members
).
toMatchObject
(
mockDataMembers
.
data
);
expect
(
state
.
total
).
toBe
(
3
);
expect
(
state
.
page
).
toBe
(
1
);
expect
(
state
.
perPage
).
toBe
(
1
);
});
it
(
'
sets isLoading to false
'
,
()
=>
{
expect
(
state
.
isLoading
).
toBeFalsy
();
});
});
describe
(
types
.
RECEIVE_PENDING_MEMBERS_ERROR
,
()
=>
{
beforeEach
(()
=>
{
mutations
[
types
.
RECEIVE_PENDING_MEMBERS_ERROR
](
state
);
});
it
(
'
sets isLoading to false
'
,
()
=>
{
expect
(
state
.
isLoading
).
toBeFalsy
();
});
it
(
'
sets hasError to true
'
,
()
=>
{
expect
(
state
.
hasError
).
toBeTruthy
();
});
});
describe
(
types
.
SET_CURRENT_PAGE
,
()
=>
{
it
(
'
sets the page state
'
,
()
=>
{
mutations
[
types
.
SET_CURRENT_PAGE
](
state
,
1
);
expect
(
state
.
page
).
toBe
(
1
);
});
});
});
locale/gitlab.pot
View file @
a217ce30
...
@@ -5481,9 +5481,15 @@ msgstr ""
...
@@ -5481,9 +5481,15 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list"
msgid "Billing|An error occurred while loading billable members list"
msgstr ""
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
msgstr ""
msgid "Billing|An error occurred while removing a billable member"
msgid "Billing|An error occurred while removing a billable member"
msgstr ""
msgstr ""
msgid "Billing|Awaiting member signup"
msgstr ""
msgid "Billing|Cannot remove user"
msgid "Billing|Cannot remove user"
msgstr ""
msgstr ""
...
...
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