Skip to content

Commit be31630

Browse files
committed
test: replace cucumber with playwright for internalLink.feature
Signed-off-by: Ashim Shrestha <[email protected]>
1 parent b8e01de commit be31630

File tree

13 files changed

+568
-2
lines changed

13 files changed

+568
-2
lines changed

.drone.star

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,10 @@ def stagePipelines(ctx):
223223
if (determineReleasePackage(ctx) != None):
224224
return unit_test_pipelines
225225

226+
e2e_playwright_pipeline = e2eTestsOnPlaywright(ctx)
226227
e2e_pipelines = e2eTests(ctx)
227228
keycloak_pipelines = e2eTestsOnKeycloak(ctx)
228-
return unit_test_pipelines + pipelinesDependsOn(e2e_pipelines + keycloak_pipelines, unit_test_pipelines)
229+
return unit_test_pipelines + e2e_playwright_pipeline + pipelinesDependsOn(e2e_pipelines + keycloak_pipelines, unit_test_pipelines)
229230

230231
def afterPipelines(ctx):
231232
return build(ctx) + pipelinesDependsOn(notify(ctx), build(ctx))
@@ -535,6 +536,70 @@ def unitTests(ctx):
535536
},
536537
}]
537538

539+
def e2eTestsOnPlaywright(ctx):
540+
e2e_workspace = {
541+
"base": dir["base"],
542+
"path": config["app"],
543+
}
544+
545+
e2e_trigger = {
546+
"ref": [
547+
"refs/heads/master",
548+
"refs/heads/stable-*",
549+
"refs/tags/**",
550+
"refs/pull/**",
551+
],
552+
}
553+
554+
pipelines = []
555+
556+
# pipeline steps
557+
steps = skipIfUnchanged(ctx, "e2e-tests-playwright")
558+
559+
environment = {
560+
"HEADLESS": "true",
561+
"RETRY": "1",
562+
"BASE_URL_OCIS": "ocis:9200",
563+
"FAIL_ON_UNCAUGHT_CONSOLE_ERR": "true",
564+
"PLAYWRIGHT_BROWSERS_PATH": ".playwright",
565+
"BROWSER": "chromium",
566+
"FEDERATED_BASE_URL_OCIS": "federation-ocis:9200",
567+
}
568+
569+
steps += restoreBuildArtifactCache(ctx, "pnpm", ".pnpm-store") + \
570+
installPnpm() + \
571+
restoreBrowsersCache() + \
572+
restoreBuildArtifactCache(ctx, "web-dist", "dist")
573+
574+
if ctx.build.event == "cron":
575+
steps += restoreBuildArtifactCache(ctx, "ocis", "ocis")
576+
else:
577+
steps += restoreOcisCache()
578+
579+
steps += tikaService() + \
580+
ocisService()
581+
582+
steps += [{
583+
"name": "e2e-tests-playwright",
584+
"image": OC_CI_NODEJS_IMAGE,
585+
"environment": environment,
586+
"commands": [
587+
"pnpm test:e2e:playwright",
588+
],
589+
}]
590+
591+
pipelines.append({
592+
"kind": "pipeline",
593+
"type": "docker",
594+
"name": "e2e-tests-playwright",
595+
"workspace": e2e_workspace,
596+
"steps": steps,
597+
"depends_on": ["cache-ocis"],
598+
"trigger": e2e_trigger,
599+
})
600+
601+
return pipelines
602+
538603
def e2eTests(ctx):
539604
e2e_workspace = {
540605
"base": dir["base"],

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"lint": "eslint vite.config.ts '{packages,tests}/**/*.{js,ts,vue}' --color",
1313
"serve": "SERVER=true pnpm build:w",
1414
"test:e2e:cucumber": "NODE_TLS_REJECT_UNAUTHORIZED=0 TS_NODE_PROJECT=./tests/e2e/cucumber/tsconfig.json cucumber-js --profile=e2e -f json:tests/e2e/cucumber/report/cucumber_report.json",
15+
"test:e2e:playwright": "NODE_TLS_REJECT_UNAUTHORIZED=0 npx playwright test --config=tests/e2e-playwright/ --project=chromium",
1516
"test:unit": "NODE_OPTIONS=--unhandled-rejections=throw vitest",
1617
"licenses:check": "license-checker-rseidelsohn --summary --relativeLicensePath --onlyAllow 'Python-2.0;Apache*;Apache License, Version 2.0;Apache-2.0;Apache 2.0;Artistic-2.0;BSD;BSD-3-Clause;CC-BY-3.0;CC-BY-4.0;CC0-1.0;ISC;MIT;MPL-2.0;Public Domain;Unicode-TOU;Unlicense;WTFPL;BlueOak-1.0.0' --excludePackages '@ownclouders/babel-preset;@ownclouders/eslint-config;@ownclouders/prettier-config;@ownclouders/tsconfig;@ownclouders/web-client;@ownclouders/web-pkg;external;web-app-files;text-editor;preview;web-app-ocm;@ownclouders/design-system;pdf-viewer;web-app-search;admin-settings;webfinger;web-runtime;@ownclouders/web-test-helpers'",
1718
"licenses:csv": "license-checker-rseidelsohn --relativeLicensePath --csv --out ./third-party-licenses/third-party-licenses.csv",

test-results/.last-run.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"status": "passed",
3+
"failedTests": []
4+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { config } from '../../e2e/config.js'
2+
import { api, environment, store } from '../../e2e/support'
3+
import { User, UserState } from '../../e2e/support/types'
4+
5+
const cleanupPredefinedUser = async (userKey: string, user: User) => {
6+
// delete the personal space resources
7+
const resources = await api.dav.listSpaceResources({ user, spaceType: 'personal' })
8+
for (const fileId in resources) {
9+
await api.dav.deleteSpaceResource({ user, fileId })
10+
}
11+
12+
// cleanup trashbin if resources have been deleted
13+
if (Object.keys(resources).length) {
14+
await api.dav.emptyTrashbin({ user, spaceType: 'personal' })
15+
}
16+
17+
// revert user state
18+
const usersEnvironment = new environment.UsersEnvironment()
19+
const userState: UserState = usersEnvironment.getUserState(userKey)
20+
if (userState.hasOwnProperty('autoAcceptShare')) {
21+
await api.settings.configureAutoAcceptShare({ user, state: userState.autoAcceptShare })
22+
}
23+
if (userState.hasOwnProperty('language')) {
24+
await api.settings.changeLanguage({ user, language: userState.language })
25+
}
26+
}
27+
28+
export const cleanUpUser = async (createdUserStore, adminUser: User) => {
29+
const requests: Promise<User>[] = []
30+
for (const [key, user] of createdUserStore.entries()) {
31+
console.log(`Cleanup user: ${user.id}`)
32+
if (!config.predefinedUsers) {
33+
requests.push(api.provision.deleteUser({ user, admin: adminUser }))
34+
} else {
35+
await cleanupPredefinedUser(key, user)
36+
}
37+
}
38+
await Promise.all(requests)
39+
createdUserStore.clear()
40+
store.keycloakCreatedUser.clear()
41+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { config } from '../../e2e/config.js'
2+
import { api, store } from '../../e2e/support'
3+
import { User } from '../../e2e/support/types'
4+
import { UsersEnvironment } from '../../e2e/support/environment'
5+
6+
const storeKeycloakGroups = async (adminUser: User, usersEnvironment) => {
7+
const groups = await api.graph.getGroups(adminUser)
8+
9+
store.dummyKeycloakGroupStore.forEach((dummyGroup) => {
10+
const matchingGroup = groups.find((group) => group.displayName === dummyGroup.displayName)
11+
if (matchingGroup) {
12+
usersEnvironment.storeCreatedGroup({ group: { ...dummyGroup, uuid: matchingGroup.id } })
13+
}
14+
})
15+
}
16+
17+
export async function setAccessAndRefreshToken(usersEnvironment: UsersEnvironment) {
18+
if (!config.basicAuth && !config.predefinedUsers) {
19+
let user = usersEnvironment.getUser({ key: config.adminUsername })
20+
if (config.keycloak) {
21+
user = usersEnvironment.getUser({ key: config.keycloakAdminUser })
22+
await api.keycloak.setAccessTokenForKeycloakOcisUser(user)
23+
await api.keycloak.setAccessTokenForKeycloakUser(user)
24+
await storeKeycloakGroups(user, usersEnvironment)
25+
} else {
26+
await api.token.setAccessAndRefreshToken(user)
27+
}
28+
}
29+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { defineConfig, devices } from '@playwright/test'
2+
3+
/**
4+
* See https://playwright.dev/docs/test-configuration.
5+
*/
6+
export default defineConfig({
7+
// Look for test files in the "tests" directory, relative to this configuration file.
8+
testDir: 'spec',
9+
10+
// Run all tests in parallel.
11+
fullyParallel: true,
12+
13+
// Fail the build on CI if you accidentally left test.only in the source code.
14+
forbidOnly: !!process.env.CI,
15+
16+
// Retry on CI only.
17+
retries: process.env.CI ? 1 : 0,
18+
19+
// Opt out of parallel tests on CI.
20+
workers: process.env.CI ? 1 : undefined,
21+
22+
// Reporter to use
23+
reporter: 'html',
24+
25+
use: {
26+
ignoreHTTPSErrors: true,
27+
28+
// Collect trace when retrying the failed test.
29+
trace: 'on-first-retry'
30+
},
31+
// Configure projects for major browsers.
32+
projects: [
33+
{
34+
name: 'chromium',
35+
use: { ...devices['Desktop Chrome'] }
36+
},
37+
{
38+
name: 'firefox',
39+
use: { ...devices['Desktop Firefox'] }
40+
},
41+
{
42+
name: 'webkit',
43+
use: { ...devices['Desktop Safari'] }
44+
}
45+
]
46+
})
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { expect, test } from '@playwright/test'
2+
import { config } from '../../e2e/config.js'
3+
import { store } from '../../e2e/support'
4+
import {
5+
ActorsEnvironment,
6+
UsersEnvironment,
7+
LinksEnvironment,
8+
FilesEnvironment
9+
} from '../../e2e/support/environment'
10+
import {
11+
userHasBeenCreated,
12+
createFolderInPersonalSpaceUsingAPI,
13+
shareResourceUsingAPI,
14+
createPublicLinkOfResourceUsingAPI
15+
} from '../steps/api'
16+
import { setAccessAndRefreshToken } from '../helper/setAccessAndRefreshToken'
17+
import { cleanUpUser } from '../helper/cleanup'
18+
import { openPublicLink } from '../steps/ui/public'
19+
import { navigateToSharedWithMePage, updateShareeRole } from '../steps/ui/shares'
20+
import { uploadResource, isAbleToEditFileOrFolder } from '../steps/ui/resources'
21+
import { LogInUser, LogOutUser } from '../steps/ui/session'
22+
23+
test.describe('internal link share', () => {
24+
let actorsEnvironment
25+
const usersEnvironment = new UsersEnvironment()
26+
const linksEnvironment = new LinksEnvironment()
27+
const filesEnvironment = new FilesEnvironment()
28+
29+
test.beforeEach(async ({ browser }) => {
30+
actorsEnvironment = new ActorsEnvironment({
31+
context: {
32+
acceptDownloads: config.acceptDownloads,
33+
reportDir: config.reportDir,
34+
tracingReportDir: config.tracingReportDir,
35+
reportHar: config.reportHar,
36+
reportTracing: config.reportTracing,
37+
reportVideo: config.reportVideo,
38+
failOnUncaughtConsoleError: config.failOnUncaughtConsoleError
39+
},
40+
browser: browser
41+
})
42+
43+
await setAccessAndRefreshToken(usersEnvironment)
44+
45+
await userHasBeenCreated(usersEnvironment, 'Admin', 'Alice')
46+
await userHasBeenCreated(usersEnvironment, 'Admin', 'Brian')
47+
48+
await LogInUser(usersEnvironment, actorsEnvironment, 'Alice')
49+
await LogInUser(usersEnvironment, actorsEnvironment, 'Brian')
50+
51+
await createFolderInPersonalSpaceUsingAPI(usersEnvironment, 'Alice', 'myfolder')
52+
53+
await shareResourceUsingAPI(
54+
usersEnvironment,
55+
'Alice',
56+
'myfolder',
57+
'Brian',
58+
'user',
59+
'Can edit',
60+
'folder'
61+
)
62+
63+
await createPublicLinkOfResourceUsingAPI(
64+
usersEnvironment,
65+
'Alice',
66+
'myfolder',
67+
'Invited people'
68+
)
69+
})
70+
71+
test('opening a link with internal role', async () => {
72+
await openPublicLink(actorsEnvironment, linksEnvironment, 'Brian', 'Unnamed link')
73+
await navigateToSharedWithMePage(actorsEnvironment, 'Brian')
74+
await uploadResource(actorsEnvironment, filesEnvironment, 'Brian', 'simple.pdf', 'myfolder')
75+
await updateShareeRole(
76+
usersEnvironment,
77+
actorsEnvironment,
78+
'Alice',
79+
'myfolder',
80+
'Brian',
81+
'user',
82+
'Can view',
83+
'folder'
84+
)
85+
await LogOutUser(actorsEnvironment, 'Alice')
86+
87+
expect(await isAbleToEditFileOrFolder(actorsEnvironment, 'Brian', 'myfolder')).toBeFalsy()
88+
await LogOutUser(actorsEnvironment, 'Brian')
89+
})
90+
91+
test.afterAll(async () => {
92+
await cleanUpUser(
93+
store.createdUserStore,
94+
usersEnvironment.getUser({ key: config.adminUsername })
95+
)
96+
})
97+
})

tests/e2e-playwright/steps/api.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { config } from '../../e2e/config.js'
2+
import { UsersEnvironment } from '../../e2e/support/environment'
3+
import { api } from '../../e2e/support'
4+
import { ResourceType } from '../../e2e/support/api/share/share'
5+
6+
export async function userHasBeenCreated(
7+
usersEnvironment: UsersEnvironment,
8+
stepUser: string,
9+
userToBeCreated: string
10+
): Promise<void> {
11+
const admin = usersEnvironment.getUser({ key: stepUser })
12+
const user = usersEnvironment.getUser({ key: userToBeCreated })
13+
// do not try to create users when using predefined users
14+
if (!config.predefinedUsers) {
15+
await api.provision.createUser({ user, admin })
16+
}
17+
}
18+
19+
export async function createFolderInPersonalSpaceUsingAPI(
20+
usersEnvironment: UsersEnvironment,
21+
stepUser: string,
22+
folderName: string
23+
): Promise<void> {
24+
const user = usersEnvironment.getUser({ key: stepUser })
25+
await api.dav.createFolderInsidePersonalSpace({ user, folder: folderName })
26+
}
27+
28+
export async function shareResourceUsingAPI(
29+
usersEnvironment: UsersEnvironment,
30+
stepUser: string,
31+
resource: string,
32+
recipient: string,
33+
type: string,
34+
role: string,
35+
resourceType: ResourceType
36+
): Promise<void> {
37+
const user = usersEnvironment.getUser({ key: stepUser })
38+
await api.share.createShare({
39+
user,
40+
path: resource,
41+
shareType: type,
42+
shareWith: recipient,
43+
role: role,
44+
resourceType: resourceType as ResourceType
45+
})
46+
}
47+
48+
export async function createPublicLinkOfResourceUsingAPI(
49+
usersEnvironment: UsersEnvironment,
50+
stepUser: string,
51+
resource: string,
52+
role: string,
53+
name?: string,
54+
password?: undefined,
55+
space?: 'Personal'
56+
) {
57+
const user = usersEnvironment.getUser({ key: stepUser })
58+
59+
await api.share.createLinkShare({
60+
user,
61+
path: resource,
62+
password: password,
63+
name: name ? name : 'Unnamed link',
64+
role: role,
65+
spaceName: space
66+
})
67+
}

0 commit comments

Comments
 (0)