Skip to content

Commit eb72265

Browse files
committed
test: convert groups.feature test to playwright
1 parent 588e69d commit eb72265

12 files changed

Lines changed: 441 additions & 80 deletions

File tree

.drone.star

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ config = {
146146
"cucumber/features/admin-settings/users.feature:131",
147147
"cucumber/features/admin-settings/users.feature:185",
148148
"cucumber/features/admin-settings/spaces.feature",
149-
"cucumber/features/keycloak",
150149
],
151150
"extraServerEnvironment": {
152151
"PROXY_AUTOPROVISION_ACCOUNTS": "true",
@@ -212,6 +211,27 @@ config = {
212211
"IDP_ACCESS_TOKEN_EXPIRATION": 30,
213212
},
214213
},
214+
"keycloak": {
215+
"earlyFail": True,
216+
"skip": False,
217+
"suites": [
218+
"keycloak",
219+
],
220+
"extraServerEnvironment": {
221+
"PROXY_AUTOPROVISION_ACCOUNTS": "true",
222+
"PROXY_ROLE_ASSIGNMENT_DRIVER": "oidc",
223+
"OCIS_OIDC_ISSUER": "https://keycloak:8443/realms/oCIS",
224+
"PROXY_OIDC_REWRITE_WELLKNOWN": "true",
225+
"WEB_OIDC_CLIENT_ID": "web",
226+
"PROXY_USER_OIDC_CLAIM": "preferred_username",
227+
"PROXY_USER_CS3_CLAIM": "username",
228+
"OCIS_ADMIN_USER_ID": "",
229+
"OCIS_EXCLUDE_RUN_SERVICES": "idp",
230+
"GRAPH_ASSIGN_DEFAULT_USER_ROLE": "false",
231+
"GRAPH_USERNAME_MATCH": "none",
232+
"KEYCLOAK_DOMAIN": "keycloak:8443",
233+
},
234+
},
215235
},
216236
"build": True,
217237
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
import { expect } from '@playwright/test'
2+
import { test } from '../../support/test'
3+
import { config } from '../../../e2e/config.js'
4+
import { ActorsEnvironment, UsersEnvironment } from '../../../e2e/support/environment/index.js'
5+
import { setAccessAndRefreshToken } from '../../helpers/setAccessAndRefreshToken.js'
6+
import * as api from '../../steps/api/api.js'
7+
import * as ui from '../../steps/ui/index'
8+
9+
// For synchronization-related details, see https://owncloud.dev/services/proxy/#claim-updates
10+
test.describe('groups management', () => {
11+
let actorsEnvironment
12+
const usersEnvironment = new UsersEnvironment()
13+
14+
test.beforeEach(async ({ browser }) => {
15+
actorsEnvironment = new ActorsEnvironment({
16+
context: {
17+
acceptDownloads: config.acceptDownloads,
18+
reportDir: config.reportDir,
19+
tracingReportDir: config.tracingReportDir,
20+
reportHar: config.reportHar,
21+
reportTracing: config.reportTracing,
22+
reportVideo: config.reportVideo,
23+
failOnUncaughtConsoleError: config.failOnUncaughtConsoleError
24+
},
25+
browser: browser
26+
})
27+
28+
await setAccessAndRefreshToken(usersEnvironment)
29+
})
30+
31+
test.afterEach(async () => {
32+
await api.deleteUser({ usersEnvironment, stepUser: 'Admin', targetUser: 'Alice' })
33+
await api.deleteUser({ usersEnvironment, stepUser: 'Admin', targetUser: 'Brian' })
34+
})
35+
36+
test('keycloak group sync with oCIS', async () => {
37+
// Given "Admin" creates following user using API
38+
// | id |
39+
// | Alice |
40+
// | Brian |
41+
await api.userHasBeenCreated({ usersEnvironment, stepUser: 'Admin', userToBeCreated: 'Alice' })
42+
await api.userHasBeenCreated({ usersEnvironment, stepUser: 'Admin', userToBeCreated: 'Brian' })
43+
44+
// And "Alice" creates the following files into personal space using API
45+
// | pathToFile | content |
46+
// | shareToSales.txt | Keycloak group share |
47+
// | shareToSecurity.txt | Keycloak group share |
48+
await api.userHasCreatedFile({
49+
usersEnvironment,
50+
stepUser: 'Alice',
51+
filename: 'shareToSales.txt',
52+
content: 'Keycloak group share'
53+
})
54+
await api.userHasCreatedFile({
55+
usersEnvironment,
56+
stepUser: 'Alice',
57+
filename: 'shareToSecurity.txt',
58+
content: 'Keycloak group share'
59+
})
60+
// When "Admin" logs in
61+
await ui.logInUser({ usersEnvironment, actorsEnvironment, stepUser: 'Admin' })
62+
63+
// And "Admin" opens the "admin-settings" app
64+
await ui.userOpensApplication({ actorsEnvironment, stepUser: 'Admin', name: 'admin-settings' })
65+
66+
// And "Admin" navigates to the groups management page
67+
await ui.userNavigatesToGroupsManagementPage({ actorsEnvironment, stepUser: 'Admin' })
68+
69+
// When "Admin" creates the following groups
70+
// | id |
71+
// | security |
72+
// | sales |
73+
await ui.userCreatesGroups({
74+
actorsEnvironment,
75+
stepUser: 'Admin',
76+
groupIds: ['security', 'sales']
77+
})
78+
79+
// Then "Admin" should see the following group
80+
// | group |
81+
// | security |
82+
// | keycloak sales |
83+
// | keycloak finance |
84+
expect(
85+
await ui.checkGroupsPresenceByName({
86+
actorsEnvironment,
87+
stepUser: 'Admin',
88+
expectedGroupIds: ['security', 'keycloak sales', 'keycloak finance']
89+
})
90+
).toBeTruthy()
91+
92+
// When "Admin" navigates to the users management page
93+
await ui.userNavigatesToUserManagementPage({ actorsEnvironment, stepUser: 'Admin' })
94+
// And "Admin" adds the user "Brian" to the groups "security,keycloak sales" using the sidebar panel
95+
await ui.userAddsUserToGroup({
96+
actorsEnvironment,
97+
stepUser: 'Admin',
98+
action: 'adds',
99+
groups: ['security', 'keycloak sales'],
100+
user: 'Brian'
101+
})
102+
103+
// And "Admin" logs out
104+
await ui.logOutUser({ actorsEnvironment, stepUser: 'Admin' })
105+
// And "Alice" logs in
106+
await ui.logInUser({ usersEnvironment, actorsEnvironment, stepUser: 'Alice' })
107+
108+
// And "Alice" shares the following resource using the sidebar panel
109+
// | resource | recipient | type | role | resourceType |
110+
// | shareToSales.txt | keycloak sales | group | Can edit without versions | file |
111+
// | shareToSecurity.txt | security | group | Can edit without versions | file |
112+
await ui.shareResource({
113+
actorsEnvironment,
114+
usersEnvironment,
115+
stepUser: 'Alice',
116+
actionType: 'SIDEBAR_PANEL',
117+
resource: 'shareToSales.txt',
118+
recipient: 'keycloak sales',
119+
type: 'group',
120+
role: 'Can edit without versions',
121+
resourceType: 'file'
122+
})
123+
124+
await ui.shareResource({
125+
actorsEnvironment,
126+
usersEnvironment,
127+
stepUser: 'Alice',
128+
actionType: 'SIDEBAR_PANEL',
129+
resource: 'shareToSecurity.txt',
130+
recipient: 'security',
131+
type: 'group',
132+
role: 'Can edit without versions',
133+
resourceType: 'file'
134+
})
135+
136+
// And "Alice" logs out
137+
await ui.logOutUser({ actorsEnvironment, stepUser: 'Alice' })
138+
139+
// And "Brian" logs in
140+
await ui.logInUser({ usersEnvironment, actorsEnvironment, stepUser: 'Brian' })
141+
// And "Brian" navigates to the shared with me page
142+
await ui.navigateToSharedWithMePage({ actorsEnvironment, stepUser: 'Brian' })
143+
144+
// user should have access to unsynced shares
145+
// When "Brian" opens the following file in texteditor
146+
// | resource |
147+
// | shareToSales.txt |
148+
await ui.userOpensFileInViewer({
149+
actorsEnvironment,
150+
stepUser: 'Brian',
151+
resource: 'shareToSales.txt',
152+
actionType: 'texteditor'
153+
})
154+
// And "Brian" closes the file viewer
155+
await ui.userClosesTextEditor({ actorsEnvironment, stepUser: 'Brian' })
156+
// And "Brian" edits the following resources
157+
// | resource | content |
158+
// | shareToSecurity.txt | new content |
159+
await ui.userEditsFile({
160+
actorsEnvironment,
161+
stepUser: 'Brian',
162+
resource: 'shareToSecurity.txt',
163+
content: 'new content'
164+
})
165+
// And "Brian" logs out
166+
await ui.logOutUser({ actorsEnvironment, stepUser: 'Brian' })
167+
168+
// When "Admin" logs in
169+
await ui.logInUser({ usersEnvironment, actorsEnvironment, stepUser: 'Admin' })
170+
171+
// And "Admin" opens the "admin-settings" app
172+
await ui.userOpensApplication({ actorsEnvironment, stepUser: 'Admin', name: 'admin-settings' })
173+
174+
// And "Admin" navigates to the groups management page
175+
await ui.userNavigatesToGroupsManagementPage({ actorsEnvironment, stepUser: 'Admin' })
176+
177+
// Renaming a Keycloak group results in the creation of a new group on the oCIS server (see https://github.com/owncloud/ocis/issues/10445).
178+
// After renaming a group, it may take up to 5 minutes for the changes to sync, so avoid using the renamed group in the subsequent steps.
179+
// And "Admin" changes displayName to "a renamed group" for group "keycloak finance" using the sidebar panel
180+
await ui.userRenamesGroup({
181+
actorsEnvironment,
182+
stepUser: 'Admin',
183+
attribute: 'displayName',
184+
value: 'a renamed group',
185+
user: 'keycloak finance'
186+
})
187+
188+
// When "Admin" deletes the following group using the context menu
189+
// | group |
190+
// | sales |
191+
await ui.userDeletesGroup({
192+
actorsEnvironment,
193+
stepUser: 'Admin',
194+
actionType: 'context menu',
195+
group: 'sales'
196+
})
197+
// Then "Admin" should not see the following group
198+
// | group |
199+
// | sales |
200+
expect(
201+
await ui.checkGroupsPresenceById({
202+
actorsEnvironment,
203+
stepUser: 'Admin',
204+
expectedGroupIds: ['sales']
205+
})
206+
).toBeFalsy()
207+
// And "Admin" logs out
208+
await ui.logOutUser({ actorsEnvironment, stepUser: 'Admin' })
209+
})
210+
})
File renamed without changes.

tests/e2e-playwright/specs/spaces/pagination.spec.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,7 @@ test.describe('check files pagination in project space', () => {
133133
})
134134

135135
// And "Alice" closes the file viewer
136-
const { page } = actorsEnvironment.getActor({ key: 'Alice' })
137-
await editor.close(page)
136+
await ui.userClosesTextEditor({ actorsEnvironment, stepUser: 'Alice' })
138137

139138
// Then "Alice" should be on page "2"
140139
const currentPage = await ui.getCurrentPageNumber({

tests/e2e-playwright/steps/ui/adminSettings.ts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { objects } from '../../../e2e/support'
22
import { ActorsEnvironment, FilesEnvironment } from '../../../e2e/support/environment'
3+
import { expect } from '@playwright/test'
34

45
export async function navigateToGeneralManagementPage({
56
actorsEnvironment,
@@ -90,6 +91,23 @@ export async function checkGroupsPresenceById({
9091
return true
9192
}
9293

94+
export async function checkGroupsPresenceByName({
95+
actorsEnvironment,
96+
stepUser,
97+
expectedGroupIds
98+
}: {
99+
actorsEnvironment: ActorsEnvironment
100+
stepUser: string
101+
expectedGroupIds: string[]
102+
}): Promise<void> {
103+
const { page } = actorsEnvironment.getActor({ key: stepUser })
104+
const groupsObject = new objects.applicationAdminSettings.Groups({ page })
105+
const actualGroupsIds = await (await groupsObject.getGroupsDisplayName())
106+
.split(',')
107+
.map((item) => item.trim())
108+
expect(actualGroupsIds).toEqual(expect.arrayContaining(expectedGroupIds))
109+
}
110+
93111
export async function groupDisplayNameExists({
94112
actorsEnvironment,
95113
stepUser,
@@ -161,3 +179,103 @@ export async function userChangesGroup({
161179
action
162180
})
163181
}
182+
183+
export async function userNavigatesToUserManagementPage({
184+
actorsEnvironment,
185+
stepUser
186+
}: {
187+
actorsEnvironment: ActorsEnvironment
188+
stepUser: string
189+
}): Promise<void> {
190+
const { page } = actorsEnvironment.getActor({ key: stepUser })
191+
const pageObject = new objects.applicationAdminSettings.page.Users({ page })
192+
await pageObject.navigate()
193+
}
194+
195+
export async function userDeletesGroup({
196+
actorsEnvironment,
197+
stepUser,
198+
actionType,
199+
group
200+
}: {
201+
actorsEnvironment: ActorsEnvironment
202+
stepUser: string
203+
actionType: 'batch actions' | 'context menu'
204+
group: string
205+
}): Promise<void> {
206+
const { page } = actorsEnvironment.getActor({ key: stepUser })
207+
const groupsObject = new objects.applicationAdminSettings.Groups({ page })
208+
const groupIds = []
209+
210+
switch (actionType) {
211+
case 'batch actions':
212+
groupIds.push(groupsObject.getUUID({ key: group }))
213+
await groupsObject.selectGroup({ key: group })
214+
await groupsObject.deleteGroupUsingBatchAction({ groupIds })
215+
break
216+
case 'context menu':
217+
await groupsObject.deleteGroupUsingContextMenu({ key: group })
218+
break
219+
default:
220+
throw new Error(`'${actionType}' not implemented`)
221+
}
222+
}
223+
224+
export async function userRenamesGroup({
225+
actorsEnvironment,
226+
stepUser,
227+
attribute,
228+
value,
229+
user
230+
}: {
231+
actorsEnvironment: ActorsEnvironment
232+
stepUser: string
233+
attribute: string
234+
value: string
235+
user: string
236+
}): Promise<void> {
237+
const { page } = actorsEnvironment.getActor({ key: stepUser })
238+
const groupsObject = new objects.applicationAdminSettings.Groups({ page })
239+
240+
await groupsObject.changeGroup({
241+
key: user,
242+
attribute: attribute,
243+
value: value,
244+
action: 'context-menu'
245+
})
246+
}
247+
248+
export async function userAddsUserToGroup({
249+
actorsEnvironment,
250+
stepUser,
251+
action,
252+
groups,
253+
user
254+
}: {
255+
actorsEnvironment: ActorsEnvironment
256+
stepUser: string
257+
action: string
258+
groups: string[]
259+
user: string
260+
}): Promise<void> {
261+
const { page } = actorsEnvironment.getActor({ key: stepUser })
262+
const usersObject = new objects.applicationAdminSettings.Users({ page })
263+
switch (action) {
264+
case 'adds':
265+
await usersObject.addToGroups({
266+
key: user,
267+
groups,
268+
action: 'context-menu'
269+
})
270+
break
271+
case 'removes':
272+
await usersObject.removeFromGroups({
273+
key: user,
274+
groups,
275+
action: 'context-menu'
276+
})
277+
break
278+
default:
279+
throw new Error(`'${action}' not implemented`)
280+
}
281+
}

0 commit comments

Comments
 (0)