Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 74 additions & 1 deletion .drone.star
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,10 @@ def stagePipelines(ctx):
if (determineReleasePackage(ctx) != None):
return unit_test_pipelines

e2e_playwright_pipeline = e2eTestsOnPlaywright(ctx)
e2e_pipelines = e2eTests(ctx)
keycloak_pipelines = e2eTestsOnKeycloak(ctx)
return unit_test_pipelines + pipelinesDependsOn(e2e_pipelines + keycloak_pipelines, unit_test_pipelines)
return unit_test_pipelines + pipelinesDependsOn(e2e_playwright_pipeline + e2e_pipelines + keycloak_pipelines, unit_test_pipelines)

def afterPipelines(ctx):
return build(ctx) + pipelinesDependsOn(notify(ctx), build(ctx))
Expand Down Expand Up @@ -535,6 +536,64 @@ def unitTests(ctx):
},
}]

def e2eTestsOnPlaywright(ctx):
e2e_workspace = {
"base": dir["base"],
"path": config["app"],
}

e2e_trigger = {
"ref": [
"refs/heads/master",
"refs/heads/stable-*",
"refs/tags/**",
"refs/pull/**",
],
}

pipelines = []

# pipeline steps
steps = skipIfUnchanged(ctx, "e2e-tests-playwright")

environment = {
"BASE_URL_OCIS": "ocis:9200",
"PLAYWRIGHT_BROWSERS_PATH": ".playwright",
}

steps += restoreBuildArtifactCache(ctx, "pnpm", ".pnpm-store") + \
installPnpm() + \
restoreBrowsersCache() + \
restoreBuildArtifactCache(ctx, "web-dist", "dist")

if ctx.build.event == "cron":
steps += restoreBuildArtifactCache(ctx, "ocis", "ocis")
else:
steps += restoreOcisCache()

steps += ocisService()

steps += [{
"name": "e2e-tests-playwright",
"image": OC_CI_NODEJS_IMAGE,
"environment": environment,
"commands": [
"pnpm test:e2e:playwright --project=chromium",
],
}]

pipelines.append({
"kind": "pipeline",
"type": "docker",
"name": "e2e-tests-playwright",
"workspace": e2e_workspace,
"steps": steps,
"depends_on": ["cache-ocis"],
"trigger": e2e_trigger,
})

return pipelines

def e2eTests(ctx):
e2e_workspace = {
"base": dir["base"],
Expand Down Expand Up @@ -1365,12 +1424,26 @@ def skipIfUnchanged(ctx, type):
}
return [skip_step]

if type == "e2e-tests-playwright":
e2e_playwright_skip_steps = [
"^__fixtures__/.*",
"^__mocks__/.*",
"^packages/.*/tests/.*",
"^tests/unit/.*",
"^tests/e2e/cucumber/.*",
]
skip_step["settings"] = {
"ALLOW_SKIP_CHANGED": base_skip_steps + e2e_playwright_skip_steps,
}
return [skip_step]

if type == "e2e-tests":
e2e_skip_steps = [
"^__fixtures__/.*",
"^__mocks__/.*",
"^packages/.*/tests/.*",
"^tests/unit/.*",
"^tests/e2e-playwright/.*",
]
skip_step["settings"] = {
"ALLOW_SKIP_CHANGED": base_skip_steps + e2e_skip_steps,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"lint": "eslint vite.config.ts '{packages,tests}/**/*.{js,ts,vue}' --color",
"serve": "SERVER=true pnpm build:w",
"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",
"test:e2e:playwright": "NODE_TLS_REJECT_UNAUTHORIZED=0 npx playwright test --config=tests/e2e-playwright/",
"test:unit": "NODE_OPTIONS=--unhandled-rejections=throw vitest",
"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'",
"licenses:csv": "license-checker-rseidelsohn --relativeLicensePath --csv --out ./third-party-licenses/third-party-licenses.csv",
Expand Down
10 changes: 10 additions & 0 deletions tests/e2e-playwright/helpers/setAccessAndRefreshToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { config } from '../../e2e/config.js'
import { api } from '../../e2e/support'
import { UsersEnvironment } from '../../e2e/support/environment'

export async function setAccessAndRefreshToken(usersEnvironment: UsersEnvironment) {
if (!config.basicAuth && !config.predefinedUsers) {
let user = usersEnvironment.getUser({ key: config.adminUsername })
await api.token.setAccessAndRefreshToken(user)
}
}
46 changes: 46 additions & 0 deletions tests/e2e-playwright/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { defineConfig, devices } from '@playwright/test'

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
// Look for test files in the following directory, relative to this configuration file.
testDir: 'specs',

// Run all tests in parallel.
fullyParallel: false,

// Fail the build on CI if you accidentally left test.only in the source code.
forbidOnly: !!process.env.CI,

// Retry on CI only.
retries: process.env.CI ? 1 : 0,

// Opt out of parallel tests on CI.
workers: process.env.CI ? 1 : undefined,

// Reporter to use
reporter: 'html',

use: {
ignoreHTTPSErrors: true,

// Collect trace when retrying the failed test.
trace: 'on-first-retry'
},
// Configure projects for major browsers.
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] }
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] }
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] }
}
]
})
97 changes: 97 additions & 0 deletions tests/e2e-playwright/specs/internalLink.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { expect, test } from '@playwright/test'
import { config } from '../../e2e/config.js'
import {
ActorsEnvironment,
UsersEnvironment,
LinksEnvironment,
FilesEnvironment
} from '../../e2e/support/environment'
import { setAccessAndRefreshToken } from '../helpers/setAccessAndRefreshToken'
import * as api from '../steps/api/api'
import * as ui from '../steps/ui/index'

test.describe('internal link share', () => {
let actorsEnvironment
const usersEnvironment = new UsersEnvironment()
const linksEnvironment = new LinksEnvironment()
const filesEnvironment = new FilesEnvironment()

test.beforeEach(async ({ browser }) => {
actorsEnvironment = new ActorsEnvironment({
context: {
acceptDownloads: config.acceptDownloads,
reportDir: config.reportDir,
tracingReportDir: config.tracingReportDir,
reportHar: config.reportHar,
reportTracing: config.reportTracing,
reportVideo: config.reportVideo,
failOnUncaughtConsoleError: config.failOnUncaughtConsoleError
},
browser: browser
})

await setAccessAndRefreshToken(usersEnvironment)

await api.userHasBeenCreated({ usersEnvironment, stepUser: 'Admin', userToBeCreated: 'Alice' })
await api.userHasBeenCreated({ usersEnvironment, stepUser: 'Admin', userToBeCreated: 'Brian' })

await ui.logInUser({ usersEnvironment, actorsEnvironment, stepUser: 'Alice' })
await ui.logInUser({ usersEnvironment, actorsEnvironment, stepUser: 'Brian' })

await api.userHasCreatedFolder({ usersEnvironment, stepUser: 'Alice', folderName: 'myfolder' })

await api.userHasSharedResource({
usersEnvironment,
stepUser: 'Alice',
resource: 'myfolder',
recipient: 'Brian',
type: 'user',
role: 'Can edit',
resourceType: 'folder'
})

await api.userHasCreatedPublicLinkOfResource({
usersEnvironment,
stepUser: 'Alice',
resource: 'myfolder',
role: 'Invited people'
})
})

test('opening a link with internal role', async () => {
await ui.openPublicLink({
actorsEnvironment,
linksEnvironment,
stepUser: 'Brian',
name: 'Unnamed link'
})
await ui.navigateToSharedWithMePage({ actorsEnvironment, stepUser: 'Brian' })
await ui.uploadResource({
actorsEnvironment,
filesEnvironment,
stepUser: 'Brian',
resource: 'simple.pdf',
to: 'myfolder'
})
await ui.updateShareeRole({
usersEnvironment,
actorsEnvironment,
stepUser: 'Alice',
resource: 'myfolder',
recipient: 'Brian',
type: 'user',
role: 'Can view',
resourceType: 'folder'
})
await ui.logOutUser({ actorsEnvironment, stepUser: 'Alice' })

expect(
await ui.isAbleToEditFileOrFolder({
actorsEnvironment,
stepUser: 'Brian',
resource: 'myfolder'
})
).toBeFalsy()
await ui.logOutUser({ actorsEnvironment, stepUser: 'Brian' })
})
})
91 changes: 91 additions & 0 deletions tests/e2e-playwright/steps/api/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { config } from '../../../e2e/config.js'
import { UsersEnvironment } from '../../../e2e/support/environment'
import { api } from '../../../e2e/support'
import { ResourceType } from '../../../e2e/support/api/share/share'

export async function userHasBeenCreated({
usersEnvironment,
stepUser,
userToBeCreated
}: {
usersEnvironment: UsersEnvironment
stepUser: string
userToBeCreated: string
}): Promise<void> {
const admin = usersEnvironment.getUser({ key: stepUser })
const user = usersEnvironment.getUser({ key: userToBeCreated })
// do not try to create users when using predefined users
if (!config.predefinedUsers) {
await api.provision.createUser({ user, admin })
}
}

export async function userHasCreatedFolder({
usersEnvironment,
stepUser,
folderName
}: {
usersEnvironment: UsersEnvironment
stepUser: string
folderName: string
}): Promise<void> {
const user = usersEnvironment.getUser({ key: stepUser })
await api.dav.createFolderInsidePersonalSpace({ user, folder: folderName })
}

export async function userHasSharedResource({
usersEnvironment,
stepUser,
resource,
recipient,
type,
role,
resourceType
}: {
usersEnvironment: UsersEnvironment
stepUser: string
resource: string
recipient: string
type: string
role: string
resourceType: ResourceType
}): Promise<void> {
const user = usersEnvironment.getUser({ key: stepUser })
await api.share.createShare({
user,
path: resource,
shareType: type,
shareWith: recipient,
role: role,
resourceType: resourceType as ResourceType
})
}

export async function userHasCreatedPublicLinkOfResource({
usersEnvironment,
stepUser,
resource,
role,
name,
password,
space
}: {
usersEnvironment: UsersEnvironment
stepUser: string
resource: string
role: string
name?: string
password?: undefined
space?: 'Personal'
}) {
const user = usersEnvironment.getUser({ key: stepUser })

await api.share.createLinkShare({
user,
path: resource,
password: password,
name: name ? name : 'Unnamed link',
role: role,
spaceName: space
})
}
4 changes: 4 additions & 0 deletions tests/e2e-playwright/steps/ui/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './public'
export * from './shares'
export * from './resources'
export * from './session'
23 changes: 23 additions & 0 deletions tests/e2e-playwright/steps/ui/public.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { objects } from '../../../e2e/support'
import { ActorsEnvironment, LinksEnvironment } from '../../../e2e/support/environment'

export async function openPublicLink({
actorsEnvironment,
linksEnvironment,
stepUser,
name
}: {
actorsEnvironment: ActorsEnvironment
linksEnvironment: LinksEnvironment
stepUser: string
name: string
}): Promise<void> {
const { page } = await actorsEnvironment.createActor({
key: stepUser,
namespace: actorsEnvironment.generateNamespace(stepUser, stepUser)
})

const { url } = linksEnvironment.getLink({ name })
const pageObject = new objects.applicationFiles.page.Public({ page })
await pageObject.open({ url })
}
Loading