@open-xchange/appsuite-codeceptjs 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +167 -0
- package/README.md +1 -15
- package/index.d.ts +598 -0
- package/index.js +7 -12
- package/package.json +9 -14
- package/src/plugins/testmetrics/index.js +16 -15
- package/.claude/settings.local.json +0 -9
- package/.env.defaults +0 -48
- package/container/Dockerfile +0 -1
- package/global.d.ts +0 -3
- package/pnpm-workspace.yaml +0 -14
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.8.0] - 2026-03-15
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Replace chalk and dotenv with Node.js built-ins
|
|
12
|
+
- Clean up dependencies, packaging, and config files
|
|
13
|
+
- Clean up Chromium args and add renderer process limit
|
|
14
|
+
|
|
15
|
+
## [0.7.2] - 2026-03-09
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- TypeScript type definitions
|
|
20
|
+
|
|
21
|
+
## [0.7.0] - 2026-02-24
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Switch container base image to wolfi/playwright and make output directory configurable
|
|
26
|
+
|
|
27
|
+
## [0.6.20] - 2026-02-24
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- Fix typo in import statement
|
|
32
|
+
|
|
33
|
+
## [0.6.19] - 2026-02-24
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- Support for shared accounts in e2e tests
|
|
38
|
+
|
|
39
|
+
## [0.6.18] - 2026-02-23
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- Convert various step functions to sync
|
|
44
|
+
|
|
45
|
+
## [0.6.17] - 2026-02-13
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
|
|
49
|
+
- Helpers for manipulating user settings in tests
|
|
50
|
+
- Allow passing more custom steps to actor()
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
|
|
54
|
+
- Internal Node exception when requiring appsuite-codeceptjs and chai (#18)
|
|
55
|
+
|
|
56
|
+
## [0.6.16] - 2026-01-22
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
|
|
60
|
+
- `e2e-context-` prefix check to prevent accidental context deletion
|
|
61
|
+
- Export "actor" from main module
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- Use existing helper instead of creating new instance for every user
|
|
66
|
+
|
|
67
|
+
### Fixed
|
|
68
|
+
|
|
69
|
+
- Location of "reporter" option inside "mocha" object
|
|
70
|
+
- Move `util.getURLRoot` call into actor
|
|
71
|
+
|
|
72
|
+
### Removed
|
|
73
|
+
|
|
74
|
+
- Unnecessary default context fetch on module load
|
|
75
|
+
|
|
76
|
+
## [0.6.14] - 2025-12-12
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
|
|
80
|
+
- Switch Playwright base image from jammy to noble
|
|
81
|
+
|
|
82
|
+
## [0.6.13] - 2025-09-30
|
|
83
|
+
|
|
84
|
+
### Fixed
|
|
85
|
+
|
|
86
|
+
- Unhandled rejection timeout errors in soap-client
|
|
87
|
+
|
|
88
|
+
### Removed
|
|
89
|
+
|
|
90
|
+
- Unit tests (moved elsewhere)
|
|
91
|
+
|
|
92
|
+
## [0.6.12] - 2025-09-25
|
|
93
|
+
|
|
94
|
+
### Changed
|
|
95
|
+
|
|
96
|
+
- Use pageobjects package from core-ui
|
|
97
|
+
|
|
98
|
+
## [0.6.10] - 2025-09-15
|
|
99
|
+
|
|
100
|
+
### Fixed
|
|
101
|
+
|
|
102
|
+
- Use job group name as node-prefix for filter suite
|
|
103
|
+
|
|
104
|
+
## [0.6.7] - 2025-07-18
|
|
105
|
+
|
|
106
|
+
### Fixed
|
|
107
|
+
|
|
108
|
+
- Do not load common contexts when using reseller API
|
|
109
|
+
|
|
110
|
+
## [0.6.4] - 2025-06-13
|
|
111
|
+
|
|
112
|
+
### Changed
|
|
113
|
+
|
|
114
|
+
- Update pageobjects and actor to work with unpatched CodeceptJS
|
|
115
|
+
|
|
116
|
+
## [0.6.3] - 2025-06-11
|
|
117
|
+
|
|
118
|
+
### Added
|
|
119
|
+
|
|
120
|
+
- Documentation for overwriting helpers locally
|
|
121
|
+
|
|
122
|
+
### Changed
|
|
123
|
+
|
|
124
|
+
- Move soap to own library
|
|
125
|
+
- Clean up codeceptjs dependencies
|
|
126
|
+
- Update paths for gitlab.com move
|
|
127
|
+
|
|
128
|
+
### Fixed
|
|
129
|
+
|
|
130
|
+
- Setting startDate and endDate in calendar/createAppointment
|
|
131
|
+
- getNextMonday (pageobjects/calendar) to work on Sunday correctly
|
|
132
|
+
|
|
133
|
+
### Removed
|
|
134
|
+
|
|
135
|
+
- chai-subset (now merged with chai)
|
|
136
|
+
|
|
137
|
+
## [0.6.2] - 2024-12-17
|
|
138
|
+
|
|
139
|
+
### Changed
|
|
140
|
+
|
|
141
|
+
- Replace Jest with Vitest and improve test infrastructure
|
|
142
|
+
- Switch to neostandard library
|
|
143
|
+
|
|
144
|
+
## [0.6.0] - 2024-10-10
|
|
145
|
+
|
|
146
|
+
### Added
|
|
147
|
+
|
|
148
|
+
- allure-js-commons module
|
|
149
|
+
|
|
150
|
+
## [0.5.0] - 2024-09-30
|
|
151
|
+
|
|
152
|
+
### Added
|
|
153
|
+
|
|
154
|
+
- E2E setup and testing for appsuite-codeceptjs
|
|
155
|
+
- Container image
|
|
156
|
+
|
|
157
|
+
## [0.4.4] - 2024-08-27
|
|
158
|
+
|
|
159
|
+
### Fixed
|
|
160
|
+
|
|
161
|
+
- Reseller API support for pre-assembled contexts
|
|
162
|
+
|
|
163
|
+
## [0.4.3] - 2024-08-22
|
|
164
|
+
|
|
165
|
+
### Added
|
|
166
|
+
|
|
167
|
+
- Initial release
|
package/README.md
CHANGED
|
@@ -55,18 +55,4 @@ const { config } = require('@open-xchange/appsuite-codeceptjs')
|
|
|
55
55
|
config.tests = './costum_directory/*_test.js'
|
|
56
56
|
|
|
57
57
|
module.exports.config = config
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Known Issues
|
|
61
|
-
|
|
62
|
-
Add this to your `package.json` to ignore CVE-2025-5889 when installing this package with `pnpm`:
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
"pnpm": {
|
|
66
|
-
"auditConfig": {
|
|
67
|
-
"ignoreCves": [
|
|
68
|
-
"CVE-2025-5889"
|
|
69
|
-
]
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
```
|
|
58
|
+
```
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright (c) Open-Xchange GmbH, Germany <info@open-xchange.com>
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
*
|
|
5
|
+
* This code is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
* (at your option) any later version.
|
|
9
|
+
*
|
|
10
|
+
* This program is distributed in the hope that it will be useful,
|
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
* GNU Affero General Public License for more details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
* along with OX App Suite. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt>.
|
|
17
|
+
*
|
|
18
|
+
* Any use of the work other than as authorized under this license or copyright law is prohibited.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
declare module '@open-xchange/appsuite-codeceptjs' {
|
|
22
|
+
|
|
23
|
+
import Helper from '@codeceptjs/helper'
|
|
24
|
+
import { Page, Browser, BrowserContext, Request, Response } from 'playwright-core'
|
|
25
|
+
import * as OXPO from '@open-xchange/appsuite-codeceptjs-pageobjects'
|
|
26
|
+
|
|
27
|
+
export { recorder, event as codeceptEvents } from 'codeceptjs'
|
|
28
|
+
|
|
29
|
+
// util ---------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Converts the return type `Promise<void>` of all methods in `T` to `void`.
|
|
33
|
+
*
|
|
34
|
+
* @template T
|
|
35
|
+
* The interface with methods to be converted.
|
|
36
|
+
*/
|
|
37
|
+
export type SyncifyVoidMethods<T> = {
|
|
38
|
+
[K in keyof T]: T[K] extends (...args: infer A) => Promise<infer R> ? R extends void ? (...args: A) => void : T[K] : T[K]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class PropagatedError extends Error {
|
|
42
|
+
constructor (error: Error)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type { PropagatedError }
|
|
46
|
+
|
|
47
|
+
export const util: {
|
|
48
|
+
getLoginTimeout (): number
|
|
49
|
+
getURLRoot (): string
|
|
50
|
+
getServerURL (): string
|
|
51
|
+
getJavascriptRoot (): string
|
|
52
|
+
userContextId (): number
|
|
53
|
+
admin (): string
|
|
54
|
+
mxDomain (): string
|
|
55
|
+
smtpServer (): string
|
|
56
|
+
imapServer (): string
|
|
57
|
+
getDefaultUserPassword (): string
|
|
58
|
+
PropagatedError: typeof PropagatedError
|
|
59
|
+
addJitter (id: number): number
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// config -------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
export interface AppSuiteCodeceptConfig extends CodeceptJS.MainConfig {
|
|
65
|
+
helpers: NonNullable<CodeceptJS.MainConfig['helpers']>
|
|
66
|
+
include: NonNullable<CodeceptJS.MainConfig['include']>
|
|
67
|
+
plugins: NonNullable<CodeceptJS.MainConfig['plugins']>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const config: AppSuiteCodeceptConfig
|
|
71
|
+
|
|
72
|
+
// contexts -----------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
export interface UserAttributes {
|
|
75
|
+
entries: Array<{ key: string; value: unknown }>
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface ContextData {
|
|
79
|
+
enabled: boolean
|
|
80
|
+
filestoreId: number
|
|
81
|
+
filestore_name: string
|
|
82
|
+
id: number
|
|
83
|
+
loginMappings: string[]
|
|
84
|
+
maxQuota: number
|
|
85
|
+
name: string
|
|
86
|
+
userAttributes: UserAttributes
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface AuthData {
|
|
90
|
+
login: string
|
|
91
|
+
password: string
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface ContextAdmin extends AuthData {
|
|
95
|
+
display_name: string
|
|
96
|
+
email1: string
|
|
97
|
+
given_name: string
|
|
98
|
+
name: string
|
|
99
|
+
primaryEmail: string
|
|
100
|
+
sur_name: string
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export type ModuleAccess = Record<string, boolean>
|
|
104
|
+
|
|
105
|
+
class Context {
|
|
106
|
+
readonly id: number
|
|
107
|
+
readonly ctxdata: ContextData
|
|
108
|
+
readonly admin: ContextAdmin
|
|
109
|
+
readonly auth: AuthData
|
|
110
|
+
constructor (options: { ctxdata: ContextData; admin: ContextAdmin; auth: AuthData })
|
|
111
|
+
remove (): Promise<void>
|
|
112
|
+
hasConfig (key: string, value: unknown): Promise<void>
|
|
113
|
+
hasCapability (capability: string): Promise<void>
|
|
114
|
+
doesntHaveCapability (capability: string): Promise<void>
|
|
115
|
+
hasAccessCombination (accessCombinationName: string): Promise<void>
|
|
116
|
+
getModuleAccess (): Promise<ModuleAccess>
|
|
117
|
+
hasModuleAccess (moduleAccess: ModuleAccess): Promise<void>
|
|
118
|
+
hasQuota (maxQuota: number): Promise<void>
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export type { Context }
|
|
122
|
+
|
|
123
|
+
export interface Contexts extends ReadonlyArray<Context> {
|
|
124
|
+
create (ctx?: { filestoreId?: number; id?: string; maxQuota?: number }): Promise<Context>
|
|
125
|
+
reuse (ctx: Context, admin?: ContextAdmin, auth?: AuthData): Promise<Context>
|
|
126
|
+
removeAll (auth?: AuthData): Promise<void>
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// users --------------------------------------------------------------------
|
|
130
|
+
|
|
131
|
+
export interface UserData {
|
|
132
|
+
aliases: string[]
|
|
133
|
+
contextadmin: boolean
|
|
134
|
+
defaultSenderAddress: string
|
|
135
|
+
display_name: string
|
|
136
|
+
email1: string
|
|
137
|
+
given_name: string
|
|
138
|
+
id: number
|
|
139
|
+
imapLogin: string
|
|
140
|
+
imapPort: number
|
|
141
|
+
imapSchema: string
|
|
142
|
+
imapServer: string
|
|
143
|
+
imapServerString: string
|
|
144
|
+
language: string
|
|
145
|
+
mailenabled: boolean
|
|
146
|
+
name: string
|
|
147
|
+
password: string
|
|
148
|
+
passwordMech: string
|
|
149
|
+
password_expired: boolean
|
|
150
|
+
primaryEmail: string
|
|
151
|
+
smtpPort: number
|
|
152
|
+
smtpSchema: string
|
|
153
|
+
smtpServer: string
|
|
154
|
+
smtpServerString: string
|
|
155
|
+
sur_name: string
|
|
156
|
+
userAttributes: UserAttributes
|
|
157
|
+
convert_drive_user_folders: boolean
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
class User {
|
|
161
|
+
readonly userdata: UserData
|
|
162
|
+
readonly context: Context
|
|
163
|
+
constructor (options: { user: UserData, context: Context })
|
|
164
|
+
remove (): Promise<void>
|
|
165
|
+
hasConfig (key: string, value: unknown): Promise<void>
|
|
166
|
+
hasAlias (alias: string): Promise<void>
|
|
167
|
+
doesntHaveAlias (alias: string): Promise<void>
|
|
168
|
+
hasAccessCombination (accessCombinationName: string): Promise<void>
|
|
169
|
+
getModuleAccess (): Promise<ModuleAccess>
|
|
170
|
+
hasModuleAccess (moduleAccess: ModuleAccess): Promise<void>
|
|
171
|
+
hasCapability (capability: string): Promise<void>
|
|
172
|
+
doesntHaveCapability (capability: string): Promise<void>
|
|
173
|
+
login (): string
|
|
174
|
+
get <K extends keyof UserData> (param: K): UserData[K]
|
|
175
|
+
toJSON (): UserData & { context: ContextData & { admin: ContextAdmin; auth: AuthData } }
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export type { User }
|
|
179
|
+
|
|
180
|
+
export interface Users extends ReadonlyArray<User> {
|
|
181
|
+
getRandom (user?: Partial<UserData>): Partial<UserData>
|
|
182
|
+
create (user?: Partial<UserData>, context?: Context): Promise<User>
|
|
183
|
+
change (userdata: Partial<UserData>): Promise<void>
|
|
184
|
+
removeAll (): Promise<void>
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// shared accounts ----------------------------------------------------------
|
|
188
|
+
|
|
189
|
+
export interface SharedAccountData {
|
|
190
|
+
imapServer: string
|
|
191
|
+
smtpServer: string
|
|
192
|
+
language: string
|
|
193
|
+
mailenabled: number
|
|
194
|
+
name: string
|
|
195
|
+
display_name: string
|
|
196
|
+
imapLogin: string
|
|
197
|
+
primaryEmail: string
|
|
198
|
+
email1: string
|
|
199
|
+
timezone: string
|
|
200
|
+
password: string
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export type SharedAccountCapability = 'sendAs' | 'sendOnBehalf' | 'snippets' | 'writeSnippets' | 'manageSieve'
|
|
204
|
+
|
|
205
|
+
export interface SharedAccountModuleConfig {
|
|
206
|
+
permissionLevel: 'viewer' | 'editor' | 'author' | 'admin'
|
|
207
|
+
grantedCapability: SharedAccountCapability[]
|
|
208
|
+
deniedCapability: SharedAccountCapability[]
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
class SharedAccount {
|
|
212
|
+
readonly sharedAccountData: SharedAccountData
|
|
213
|
+
readonly context: Context
|
|
214
|
+
constructor (options: { sharedAccountData: SharedAccountData, context: Context })
|
|
215
|
+
createPermissions (options?: { users?: User[], groups?: User[], mail?: SharedAccountModuleConfig, calendar?: SharedAccountModuleConfig }): Promise<void>
|
|
216
|
+
getFullId (): string
|
|
217
|
+
getData (): Promise<SharedAccountData>
|
|
218
|
+
remove (): Promise<void>
|
|
219
|
+
toJSON (): SharedAccountData & { context: ContextData & { admin: ContextAdmin; auth: AuthData } }
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export type { SharedAccount }
|
|
223
|
+
|
|
224
|
+
export interface SharedAccounts extends ReadonlyArray<SharedAccount> {
|
|
225
|
+
getRandom (): SharedAccountData
|
|
226
|
+
create (sharedAccountData?: Partial<SharedAccountData>, ctx?: Context): Promise<SharedAccount>
|
|
227
|
+
getDefaultConfig (): { permissionLevel: string; grantedCapability: string[]; deniedCapability: string[] }
|
|
228
|
+
list (context: Context): Promise<SharedAccountData[]>
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// event --------------------------------------------------------------------
|
|
232
|
+
|
|
233
|
+
export interface AppSuiteCodeceptEventMap {
|
|
234
|
+
'provisioning.user.create': [user: UserData, context: Context]
|
|
235
|
+
'provisioning.user.created': [user: User]
|
|
236
|
+
'provisioning.user.removed': [user: User]
|
|
237
|
+
'provisioning.context.create': [context: ContextData, admin: ContextAdmin, auth: AuthData]
|
|
238
|
+
'provisioning.context.created': [context: Context]
|
|
239
|
+
'provisioning.context.removed': [context: Context]
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export const event: {
|
|
243
|
+
readonly provisioning: {
|
|
244
|
+
readonly user: {
|
|
245
|
+
readonly create: 'provisioning.user.create'
|
|
246
|
+
readonly created: 'provisioning.user.created'
|
|
247
|
+
readonly removed: 'provisioning.user.removed'
|
|
248
|
+
}
|
|
249
|
+
readonly context: {
|
|
250
|
+
readonly create: 'provisioning.context.create'
|
|
251
|
+
readonly created: 'provisioning.context.created'
|
|
252
|
+
readonly removed: 'provisioning.context.removed'
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
dispatcher: NodeJS.EventEmitter<AppSuiteCodeceptEventMap>
|
|
256
|
+
emit <K extends keyof AppSuiteCodeceptEventMap> (event: K, ...params: AppSuiteCodeceptEventMap[K]): void
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// helper -------------------------------------------------------------------
|
|
260
|
+
|
|
261
|
+
export interface UserOptions {
|
|
262
|
+
/**
|
|
263
|
+
* The user account to be used. Default is the first created user.
|
|
264
|
+
* @default users[0]
|
|
265
|
+
*/
|
|
266
|
+
user?: User
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export type MailAddress = [name: string, address: string]
|
|
270
|
+
|
|
271
|
+
export interface MailAttachment {
|
|
272
|
+
id?: string
|
|
273
|
+
content_type: string
|
|
274
|
+
content?: string
|
|
275
|
+
filename?: string
|
|
276
|
+
size?: number
|
|
277
|
+
disp?: 'inline' | 'attachment' | 'alternative'
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export interface MailSecurity {
|
|
281
|
+
encrypt?: boolean
|
|
282
|
+
sign?: boolean
|
|
283
|
+
type?: 'pgp' | 'smime'
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export interface HaveMailData {
|
|
287
|
+
folder?: string
|
|
288
|
+
from: MailAddress[]
|
|
289
|
+
to: MailAddress[]
|
|
290
|
+
subject?: string
|
|
291
|
+
sendtype: number
|
|
292
|
+
attachments?: MailAttachment[]
|
|
293
|
+
security?: MailSecurity
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export interface HaveMailFromFile {
|
|
297
|
+
folder?: string
|
|
298
|
+
path: string
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export interface GrabDefaultFolderOptions extends UserOptions {
|
|
302
|
+
type?: string
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export interface HaveFileData {
|
|
306
|
+
filename: string
|
|
307
|
+
contents: BlobPart
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export interface HaveFileOptions extends UserOptions {
|
|
311
|
+
cryptoAction?: 'encrypt'
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export interface AppSuiteHelper extends Helper {
|
|
315
|
+
waitForDownload (locator: string, filename: string, referenceFilePath?: string): Promise<void>
|
|
316
|
+
grabAxeReport (options?: { disableRules?: string | string[]; exclude?: string | string[]; include?: string | string[] }): Promise<object>
|
|
317
|
+
selectFolder (id: string, context?: string): Promise<void>
|
|
318
|
+
throttleNetwork (networkConfig: 'OFFLINE' | 'GPRS' | '2G' | '3G' | '4G' | 'DSL' | 'ONLINE'): Promise<void>
|
|
319
|
+
haveSetting (settings: Record<string, unknown>, options?: UserOptions): Promise<void>
|
|
320
|
+
haveSetting (key: string, value: unknown, options?: UserOptions): Promise<void>
|
|
321
|
+
/**
|
|
322
|
+
* Changes a configuration item of a user account during a test.
|
|
323
|
+
*
|
|
324
|
+
* Use this method inside test scenarios instead of calling `await
|
|
325
|
+
* user.hasConfig()` directly to make this call part of the recorder queue,
|
|
326
|
+
* instead of executing it immediately during test step registration.
|
|
327
|
+
*
|
|
328
|
+
* @param key
|
|
329
|
+
* The configuration key.
|
|
330
|
+
*
|
|
331
|
+
* @param value
|
|
332
|
+
* The new configuration value.
|
|
333
|
+
*
|
|
334
|
+
* @param options
|
|
335
|
+
* Optional parameters.
|
|
336
|
+
*/
|
|
337
|
+
haveConfig (key: string, value: unknown, options?: UserOptions): Promise<void>
|
|
338
|
+
/**
|
|
339
|
+
* Adds a capability to a user account during a test.
|
|
340
|
+
*
|
|
341
|
+
* Use this method inside test scenarios instead of calling `await
|
|
342
|
+
* user.hasCapability()` directly to make this call part of the recorder
|
|
343
|
+
* queue, instead of executing it immediately during test step registration.
|
|
344
|
+
*
|
|
345
|
+
* @param capability
|
|
346
|
+
* The capability to be added to the user account.
|
|
347
|
+
*
|
|
348
|
+
* @param options
|
|
349
|
+
* Optional parameters.
|
|
350
|
+
*/
|
|
351
|
+
haveCapability (capability: string, options?: UserOptions): Promise<void>
|
|
352
|
+
/**
|
|
353
|
+
* Removes a capability from a user account during a test.
|
|
354
|
+
*
|
|
355
|
+
* Use this method inside test scenarios instead of calling `await
|
|
356
|
+
* user.doesntHaveCapability()` directly to make this call part of the
|
|
357
|
+
* recorder queue, instead of executing it immediately during test step
|
|
358
|
+
* registration.
|
|
359
|
+
*
|
|
360
|
+
* @param capability
|
|
361
|
+
* The capability to be removed from the user account.
|
|
362
|
+
*
|
|
363
|
+
* @param options
|
|
364
|
+
* Optional parameters.
|
|
365
|
+
*/
|
|
366
|
+
dontHaveCapability (capability: string, options?: UserOptions): Promise<void>
|
|
367
|
+
/**
|
|
368
|
+
* Changes the access combination of a user account during a test.
|
|
369
|
+
*
|
|
370
|
+
* Use this method inside test scenarios instead of calling `await
|
|
371
|
+
* user.hasAccessCombination()` directly to make this call part of the
|
|
372
|
+
* recorder queue, instead of executing it immediately during test step
|
|
373
|
+
* registration.
|
|
374
|
+
*
|
|
375
|
+
* @param accessCombination
|
|
376
|
+
* The access combination to be set at the user account.
|
|
377
|
+
*
|
|
378
|
+
* @param options
|
|
379
|
+
* Optional parameters.
|
|
380
|
+
*/
|
|
381
|
+
haveAccessCombination (accessCombination: string, options?: UserOptions): Promise<void>
|
|
382
|
+
/**
|
|
383
|
+
* Changes the module access flags of a user account during a test.
|
|
384
|
+
*
|
|
385
|
+
* Use this method inside test scenarios instead of calling `await
|
|
386
|
+
* user.hasModuleAccess()` directly to make this call part of the recorder
|
|
387
|
+
* queue, instead of executing it immediately during test step
|
|
388
|
+
* registration.
|
|
389
|
+
*
|
|
390
|
+
* @param moduleAccess
|
|
391
|
+
* The module access flags to be set at the user account.
|
|
392
|
+
*
|
|
393
|
+
* @param options
|
|
394
|
+
* Optional parameters.
|
|
395
|
+
*/
|
|
396
|
+
haveModuleAccess (moduleAccess: ModuleAccess, options?: UserOptions): Promise<void>
|
|
397
|
+
haveSnippet (snippet: object /* TODO */, options?: UserOptions): Promise<void>
|
|
398
|
+
haveMail (data: HaveMailData | HaveMailFromFile, options?: UserOptions): Promise<void>
|
|
399
|
+
haveMails (iterable: Iterable<HaveMailData | HaveMailFromFile>, options?: UserOptions): Promise<void>
|
|
400
|
+
/**
|
|
401
|
+
* Adds an alias email address to a user account during a test.
|
|
402
|
+
*
|
|
403
|
+
* Use this method inside test scenarios instead of calling `await
|
|
404
|
+
* user.hasAlias()` directly to make this call part of the recorder queue,
|
|
405
|
+
* instead of executing it immediately during test step registration.
|
|
406
|
+
*
|
|
407
|
+
* @param alias
|
|
408
|
+
* The alias email address to be added to the user account.
|
|
409
|
+
*
|
|
410
|
+
* @param options
|
|
411
|
+
* Optional parameters.
|
|
412
|
+
*/
|
|
413
|
+
haveAnAlias (alias: string, options?: UserOptions): Promise<void>
|
|
414
|
+
/**
|
|
415
|
+
* Removes an alias email address from a user account during a test.
|
|
416
|
+
*
|
|
417
|
+
* Use this method inside test scenarios instead of calling `await
|
|
418
|
+
* user.doesntHaveAlias()` directly to make this call part of the recorder
|
|
419
|
+
* queue, instead of executing it immediately during test step registration.
|
|
420
|
+
*
|
|
421
|
+
* @param alias
|
|
422
|
+
* The alias email address to be removed from the user account.
|
|
423
|
+
*
|
|
424
|
+
* @param options
|
|
425
|
+
* Optional parameters.
|
|
426
|
+
*/
|
|
427
|
+
dontHaveAlias (alias: string, options?: UserOptions): Promise<void>
|
|
428
|
+
haveMailFilterRule (rule: object /* TODO */, options?: UserOptions): Promise<void>
|
|
429
|
+
haveFolder (folder: { title: string; module: string; parent: string; permissions?: string[]; subscribed?: number }, options?: UserOptions): Promise<string>
|
|
430
|
+
haveContact (contact: object /* TODO */, options?: UserOptions): Promise<object> /* TODO */
|
|
431
|
+
grabDefaultFolder (module: string, options?: GrabDefaultFolderOptions): Promise<string>
|
|
432
|
+
/**
|
|
433
|
+
* Uploads a file to a specified folder.
|
|
434
|
+
* @param folderId - The ID of the folder where the file will be uploaded.
|
|
435
|
+
* @param file - The path to the file or an object containing the file information.
|
|
436
|
+
* @param options - Additional options for the file upload.
|
|
437
|
+
* @returns - The uploaded file data.
|
|
438
|
+
*/
|
|
439
|
+
haveFile(folderId: string, file: string | HaveFileData, options?: HaveFileOptions): Promise<{ folder_id: string; id: string }>
|
|
440
|
+
haveTask (task: object /* TODO */, options?: UserOptions): Promise<object> /* TODO */
|
|
441
|
+
/**
|
|
442
|
+
* Uploads an attachment to the specified module and object.
|
|
443
|
+
* @param module - The module to attach the file to.
|
|
444
|
+
* @param obj - The object to attach the file to.
|
|
445
|
+
* @param file - The file to be attached.
|
|
446
|
+
* @param options - The options for creating the HTTP client.
|
|
447
|
+
*/
|
|
448
|
+
haveAttachment (module: 'calendar' | 'chronos' | 'contacts' | 'drive' | 'files' | 'infostore' | 'tasks', obj: object /** TODO */, file: string, options?: UserOptions): Promise<object> /* TODO */
|
|
449
|
+
haveAppointment (appointment: object /* TODO */, options?: UserOptions): Promise<object> /* TODO */
|
|
450
|
+
importAppointment (data: { sourcePath: string; folder?: string }, options?: UserOptions): Promise<object> /* TODO */
|
|
451
|
+
haveResource (data: object /* TODO */, options?: UserOptions): Promise<string>
|
|
452
|
+
dontHaveResource (pattern: object /* TODO */, options?: UserOptions): Promise<Array<{ id: string; pattern: object }>>
|
|
453
|
+
haveGroup (group: object /* TODO */, options?: UserOptions): Promise<object> /* TODO */
|
|
454
|
+
dontHaveGroup (name: string, options?: UserOptions): Promise<Array<{ id: string; name: string }>>
|
|
455
|
+
haveLockedFile (data: object /* TODO */, options?: UserOptions): Promise<object> /* TODO */
|
|
456
|
+
setMailCategories (data: { mailId: string; folder: string; categories: string[] }, options?: UserOptions): Promise<object> /* TODO */
|
|
457
|
+
pressKeys (text: string): Promise<void>
|
|
458
|
+
/**
|
|
459
|
+
* @param options
|
|
460
|
+
* @param [options.user] a user object as returned by provisioning helper, default is the "first" user
|
|
461
|
+
* @param [options.additionalAccount] an additional user that will be provisioned as the external account
|
|
462
|
+
* @param [options.extension] optional extension added to the mail address ("ext" will be translated to: $user.primary+ext@mailDomain)
|
|
463
|
+
* @param [options.name] name of the account
|
|
464
|
+
* @param [options.transport_auth] transport authentication, default: 'none'
|
|
465
|
+
*/
|
|
466
|
+
haveMailAccount (options?: { user?: object, additionalAccount?: object, extension?: string, name?: string, transport_auth?: string }): Promise<object> /* TODO */
|
|
467
|
+
waitForSetting (obj: object, timeout?: number, options?: UserOptions): Promise<void>
|
|
468
|
+
waitForCapability (capability: string, timeout?: number, options?: UserOptions & { shouldBe?: boolean }): Promise<void>
|
|
469
|
+
copyToClipboard (): Promise<void>
|
|
470
|
+
getClipboardContent (): Promise<string>
|
|
471
|
+
createGenericFile (filename: string, size: number): Promise<void>
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export interface AppSuiteHelpers {
|
|
475
|
+
Playwright: CodeceptJS.Playwright
|
|
476
|
+
AppSuite: AppSuiteHelper
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// actor --------------------------------------------------------------------
|
|
480
|
+
|
|
481
|
+
export interface LoginOptions extends UserOptions {
|
|
482
|
+
wait?: boolean
|
|
483
|
+
isDeepLink?: boolean
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
export interface AppSuiteActor {
|
|
487
|
+
amOnLoginPage (): void
|
|
488
|
+
openApp (appName: CodeceptJS.LocatorOrString): void
|
|
489
|
+
waitForApp (): void
|
|
490
|
+
/**
|
|
491
|
+
* This simplifies the input of mail addresses into input fields.
|
|
492
|
+
* There must be an array of users defined in the AppSuite helper configuration.
|
|
493
|
+
* If you want to fill in a mailaddress of such a user you can simply use this function.
|
|
494
|
+
*
|
|
495
|
+
* @param locator - the selector of an editable field
|
|
496
|
+
* @param userIndex - the users position in the users array provided via helper config
|
|
497
|
+
*/
|
|
498
|
+
insertMailaddress (locator: CodeceptJS.LocatorOrString, userIndex: number): void
|
|
499
|
+
/**
|
|
500
|
+
* Logs in the user with the specified URL parameters and options.
|
|
501
|
+
* If the URL parameters are an object, it will be converted to an empty array.
|
|
502
|
+
* The options parameter is an object that can contain a 'user' property.
|
|
503
|
+
* If the 'user' property is not provided, the first user from the 'users' container will be used.
|
|
504
|
+
* The login process includes making an API request to the login endpoint with the user's credentials.
|
|
505
|
+
* After successful login, the page will be navigated to the specified URL with the URL parameters.
|
|
506
|
+
* If the 'isDeepLink' option is true, the URL will be constructed with a '#' prefix.
|
|
507
|
+
* The login process also includes waiting for the page to load and checking for the presence of the app.
|
|
508
|
+
* @param urlParams - The URL parameters as an array or object.
|
|
509
|
+
* @param options - The login options.
|
|
510
|
+
*/
|
|
511
|
+
login(urlParams: string | string[], options?: LoginOptions): void
|
|
512
|
+
login(options?: LoginOptions): void
|
|
513
|
+
logout(): void
|
|
514
|
+
waitForNetworkTraffic (): void
|
|
515
|
+
/**
|
|
516
|
+
* Waits for the specified element to receive focus.
|
|
517
|
+
* @param selector - The locator of the element. Only accepts css selectors.
|
|
518
|
+
*/
|
|
519
|
+
waitForFocus (selector: string): void
|
|
520
|
+
triggerRefresh (): void
|
|
521
|
+
grabBackgroundImageFrom (locator: CodeceptJS.LocatorOrString): Promise<string>
|
|
522
|
+
clickDropdown (text: string): void
|
|
523
|
+
clickToolbar (selector: string, timeout?: number): void
|
|
524
|
+
clickPrimary (text: string): void
|
|
525
|
+
openFolderMenu (folderName: string): void
|
|
526
|
+
changeTheme (options: { theme: string }): void
|
|
527
|
+
/**
|
|
528
|
+
* Selects the text in a text field or contenteditable element from cursor position to beginning of line.
|
|
529
|
+
*/
|
|
530
|
+
selectLine (): void
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
export const actor: CodeceptJS.actor
|
|
534
|
+
|
|
535
|
+
// augment global CodeceptJS interfaces -------------------------------------
|
|
536
|
+
|
|
537
|
+
global {
|
|
538
|
+
namespace CodeceptJS {
|
|
539
|
+
|
|
540
|
+
// Playwright interface fixes
|
|
541
|
+
interface Playwright {
|
|
542
|
+
/** The browser object. */
|
|
543
|
+
readonly browser: Browser
|
|
544
|
+
/** The browser context object. */
|
|
545
|
+
readonly browserContext: BrowserContext
|
|
546
|
+
/** The page object for the current (active) page in the browser. */
|
|
547
|
+
readonly page: Page
|
|
548
|
+
|
|
549
|
+
// fix for non-generic `any` signature
|
|
550
|
+
usePlaywrightTo(description: string, callback: (playwright: Playwright) => void | Promise<void>): void
|
|
551
|
+
usePlaywrightTo<R>(description: string, callback: (playwright: Playwright) => R | Promise<R>): Promise<R>
|
|
552
|
+
|
|
553
|
+
// fix for non-generic `any` signature
|
|
554
|
+
executeScript(callback: (this: void) => void | Promise<void>): void
|
|
555
|
+
executeScript<T>(callback: (this: void, arg: T) => void | Promise<void>, arg: T): void
|
|
556
|
+
executeScript<R>(callback: (this: void) => R | Promise<R>): Promise<R>
|
|
557
|
+
executeScript<T, R>(callback: (this: void, arg: T) => R | Promise<R>, arg: T): Promise<R>
|
|
558
|
+
|
|
559
|
+
// fix for `any` callback signature
|
|
560
|
+
waitForRequest(urlOrPredicate: string | ((request: Request) => boolean), sec?: number): void
|
|
561
|
+
waitForResponse(urlOrPredicate: string | ((response: Response) => boolean), sec?: number): void
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// helpers and actor methods for `I` object added by this plugin
|
|
565
|
+
interface Methods extends
|
|
566
|
+
SyncifyVoidMethods<Playwright>,
|
|
567
|
+
SyncifyVoidMethods<AppSuiteHelper>,
|
|
568
|
+
AppSuiteActor { }
|
|
569
|
+
|
|
570
|
+
// CodeceptJS does not add `Methods` to `I` by itself
|
|
571
|
+
interface I extends Methods { }
|
|
572
|
+
|
|
573
|
+
// additional fragments and page objects
|
|
574
|
+
interface SupportObject {
|
|
575
|
+
autocomplete: OXPO.ContactAutoCompleteFragment
|
|
576
|
+
calendar: OXPO.CalendarPageObject
|
|
577
|
+
contactpicker: OXPO.ContactPickerFragment
|
|
578
|
+
contacts: OXPO.ContactsPageObject
|
|
579
|
+
contexts: Contexts
|
|
580
|
+
dialogs: OXPO.DialogsFragment
|
|
581
|
+
drive: OXPO.DrivePageObject
|
|
582
|
+
mail: OXPO.MailPageObject
|
|
583
|
+
mailfilter: OXPO.SettingsMailFilterFragment
|
|
584
|
+
mobileCalendar: OXPO.MobileCalendarPageObject
|
|
585
|
+
mobileContacts: OXPO.MobileContactsPageObject
|
|
586
|
+
mobileMail: OXPO.MobileMailPageFragment
|
|
587
|
+
search: OXPO.SearchFragment
|
|
588
|
+
settings: OXPO.SettingsFragment
|
|
589
|
+
sharedaccounts: SharedAccounts
|
|
590
|
+
tasks: OXPO.TasksPageObject
|
|
591
|
+
tinymce: OXPO.TinyMceFragment
|
|
592
|
+
topbar: OXPO.TopBarFragment
|
|
593
|
+
users: Users
|
|
594
|
+
viewer: OXPO.ViewerFragment
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
package/index.js
CHANGED
|
@@ -22,8 +22,9 @@ require('./src/chai')
|
|
|
22
22
|
const { recorder, event: codeceptEvents } = require('codeceptjs')
|
|
23
23
|
const pageobjects = require('@open-xchange/appsuite-codeceptjs-pageobjects')
|
|
24
24
|
|
|
25
|
-
const
|
|
26
|
-
|
|
25
|
+
for (const envFile of ['.env', '.env.defaults']) {
|
|
26
|
+
try { process.loadEnvFile(envFile) } catch {}
|
|
27
|
+
}
|
|
27
28
|
|
|
28
29
|
const outputDir = process.env.E2E_OUTPUT_DIR || './output'
|
|
29
30
|
|
|
@@ -52,20 +53,14 @@ module.exports = {
|
|
|
52
53
|
browser: 'chromium',
|
|
53
54
|
chromium: {
|
|
54
55
|
args: [
|
|
55
|
-
'--disable-print-preview',
|
|
56
|
-
'--disable-crash-reporter',
|
|
57
|
-
'--disable-dev-shm-usage',
|
|
58
|
-
'--disable-features=IsolateOrigins',
|
|
59
56
|
'--disable-gpu',
|
|
60
|
-
'--disable-notifications', // to disable native notification window on Mac OS
|
|
57
|
+
'--disable-notifications', // to disable native notification window on Mac OS
|
|
61
58
|
'--disable-print-preview',
|
|
62
59
|
'--disable-setuid-sandbox',
|
|
63
|
-
'--disable-site-isolation-trials',
|
|
64
60
|
'--disable-web-security',
|
|
65
|
-
'--no-
|
|
66
|
-
'--
|
|
67
|
-
|
|
68
|
-
].concat((process.env.CHROME_ARGS || '').split(' '))
|
|
61
|
+
'--no-zygote',
|
|
62
|
+
'--renderer-process-limit=1'
|
|
63
|
+
].concat((process.env.CHROME_ARGS || '').split(' ').filter(Boolean))
|
|
69
64
|
},
|
|
70
65
|
url: process.env.LAUNCH_URL,
|
|
71
66
|
show: process.env.HEADLESS === 'false',
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-xchange/appsuite-codeceptjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "OX App Suite CodeceptJS Configuration and Helpers",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
6
7
|
"bin": {
|
|
7
8
|
"e2e-rerun": "./customRerun.js"
|
|
8
9
|
},
|
|
@@ -14,17 +15,14 @@
|
|
|
14
15
|
"license": "AGPL-3.0-or-later",
|
|
15
16
|
"private": false,
|
|
16
17
|
"dependencies": {
|
|
17
|
-
"@axe-core/playwright": "^4.11.
|
|
18
|
+
"@axe-core/playwright": "^4.11.1",
|
|
18
19
|
"@codeceptjs/helper": "^2.0.4",
|
|
19
20
|
"@influxdata/influxdb-client": "^1.35.0",
|
|
20
|
-
"@open-xchange/appsuite-codeceptjs-pageobjects": "^1.1.
|
|
21
|
+
"@open-xchange/appsuite-codeceptjs-pageobjects": "^1.1.1",
|
|
21
22
|
"@playwright/test": "1.58.2",
|
|
22
23
|
"allure-codeceptjs": "2.15.1",
|
|
23
|
-
"chai": "^6.2.
|
|
24
|
-
"chalk": "^4.1.2",
|
|
25
|
-
"chalk-table": "^1.0.2",
|
|
24
|
+
"chai": "^6.2.2",
|
|
26
25
|
"codeceptjs": "3.7.6",
|
|
27
|
-
"dotenv": "^17.2.3",
|
|
28
26
|
"mocha": "^11.7.5",
|
|
29
27
|
"mocha-junit-reporter": "^2.2.1",
|
|
30
28
|
"mocha-multi": "^1.1.7",
|
|
@@ -33,17 +31,14 @@
|
|
|
33
31
|
"p-retry": "^7.1.1",
|
|
34
32
|
"playwright-core": "1.58.2",
|
|
35
33
|
"short-uuid": "^6.0.3",
|
|
36
|
-
"@open-xchange/
|
|
37
|
-
"@open-xchange/
|
|
34
|
+
"@open-xchange/codecept-horizontal-scaler": "0.1.15",
|
|
35
|
+
"@open-xchange/soap-client": "0.1.0"
|
|
38
36
|
},
|
|
39
37
|
"devDependencies": {
|
|
40
|
-
"@types/node": "^
|
|
38
|
+
"@types/node": "^25.5.0",
|
|
41
39
|
"ts-node": "^10.9.2",
|
|
42
40
|
"typescript": "^5.9.3",
|
|
43
|
-
"@open-xchange/lint": "0.
|
|
44
|
-
},
|
|
45
|
-
"resolutions": {
|
|
46
|
-
"axios": ">1.12.0"
|
|
41
|
+
"@open-xchange/lint": "0.3.0"
|
|
47
42
|
},
|
|
48
43
|
"scripts": {
|
|
49
44
|
"lint": "eslint ."
|
|
@@ -21,8 +21,7 @@
|
|
|
21
21
|
const { InfluxDB, Point } = require('@influxdata/influxdb-client')
|
|
22
22
|
const event = require('codeceptjs/lib/event')
|
|
23
23
|
const recorder = require('codeceptjs/lib/recorder')
|
|
24
|
-
const
|
|
25
|
-
const chalkTable = require('chalk-table')
|
|
24
|
+
const { styleText } = require('node:util')
|
|
26
25
|
|
|
27
26
|
function durationOf (test) {
|
|
28
27
|
return test.steps.reduce((sum, step) => sum + (step.endTime - step.startTime), 0)
|
|
@@ -39,18 +38,16 @@ module.exports = function setupTestMetricsPlugin ({ url, org, token, defaultTags
|
|
|
39
38
|
writePoint (p) { points.push(p) },
|
|
40
39
|
flush () {
|
|
41
40
|
if (!points.length) return
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
console.log(chalkTable(options, points.filter(p => p.name !== 'testrun').map(p => {
|
|
41
|
+
const columns = [
|
|
42
|
+
{ field: 'measurement', name: 'Measurement', color: 'cyan' },
|
|
43
|
+
{ field: 'metric', name: 'Metric', color: 'cyan' },
|
|
44
|
+
{ field: 'duration', name: 'Duration', color: 'green' },
|
|
45
|
+
{ field: 'transferSize', name: 'Transfer size', color: 'green' },
|
|
46
|
+
{ field: 'decodedBodySize', name: 'Dec. body size', color: 'green' },
|
|
47
|
+
{ field: 'cached', name: 'Cached', color: 'yellow' },
|
|
48
|
+
{ field: 'tags', name: 'Tags', color: 'cyan' }
|
|
49
|
+
]
|
|
50
|
+
const rows = points.filter(p => p.name !== 'testrun').map(p => {
|
|
54
51
|
const metric = p.tags.metric
|
|
55
52
|
delete p.tags.metric
|
|
56
53
|
const cached = p.tags.cached
|
|
@@ -65,7 +62,11 @@ module.exports = function setupTestMetricsPlugin ({ url, org, token, defaultTags
|
|
|
65
62
|
row[field] = p.fields[field]
|
|
66
63
|
}
|
|
67
64
|
return row
|
|
68
|
-
})
|
|
65
|
+
})
|
|
66
|
+
const widths = columns.map(col => Math.max(col.name.length, ...rows.map(r => String(r[col.field] ?? '').length)))
|
|
67
|
+
const header = columns.map((col, i) => styleText(col.color, col.name.padEnd(widths[i]))).join(' ')
|
|
68
|
+
const lines = rows.map(row => columns.map((col, i) => String(row[col.field] ?? '').padEnd(widths[i])).join(' '))
|
|
69
|
+
console.log([header, ...lines].join('\n'))
|
|
69
70
|
points.splice(0, points.length)
|
|
70
71
|
},
|
|
71
72
|
dispose () {
|
package/.env.defaults
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# Default environment variables
|
|
2
|
-
#
|
|
3
|
-
# Do not edit this file, instead create a .env file in the root directory!
|
|
4
|
-
|
|
5
|
-
# CONTEXT_ID only needs to be set for local development
|
|
6
|
-
# CONTEXT_ID=
|
|
7
|
-
|
|
8
|
-
# Admin credentials for e2e middleware
|
|
9
|
-
# PROVISIONING_USER=
|
|
10
|
-
# PROVISIONING_PASSWORD=
|
|
11
|
-
|
|
12
|
-
# SMTP and IMAP server for e2e-tests
|
|
13
|
-
SMTP_SERVER=main-asbox-postfix
|
|
14
|
-
IMAP_SERVER=main-asbox-dovecot
|
|
15
|
-
|
|
16
|
-
# Number of maximum retries of e2e-test runs and minimal successful e2e-test runs
|
|
17
|
-
MIN_SUCCESS=1
|
|
18
|
-
MAX_RERUNS=1
|
|
19
|
-
|
|
20
|
-
# URL to the App Suite Middleware for e2e-provisioning via SOAP
|
|
21
|
-
PROVISIONING_URL=https://appsuite-main.dev.oxui.de/
|
|
22
|
-
|
|
23
|
-
# URL to the App Suite UI for e2e-tests
|
|
24
|
-
LAUNCH_URL=https://core-ui-main.dev.oxui.de
|
|
25
|
-
|
|
26
|
-
# MX domain for e2e-tests
|
|
27
|
-
MX_DOMAIN=box.ox.io
|
|
28
|
-
|
|
29
|
-
# API used for e2e user provisioning (common/reseller)
|
|
30
|
-
PROVISIONING_API=common
|
|
31
|
-
|
|
32
|
-
# Default timeout for all wait operations for e2e tests in ms
|
|
33
|
-
WAIT_TIMEOUT=5000
|
|
34
|
-
|
|
35
|
-
# Run test headless or in chrome (Must be true for CI)
|
|
36
|
-
HEADLESS=true
|
|
37
|
-
|
|
38
|
-
# Test metrics plugin configuration
|
|
39
|
-
E2E_TEST_METRICS_CLIENT=
|
|
40
|
-
E2E_TEST_METRICS_TOKEN=
|
|
41
|
-
|
|
42
|
-
# Path to the chrome binary
|
|
43
|
-
CHROME_BIN=/Applications/Google Chrome.app/Contents/MacOS/Google Chrome
|
|
44
|
-
|
|
45
|
-
# See https://peter.sh/experiments/chromium-command-line-switches
|
|
46
|
-
CHROME_ARGS=
|
|
47
|
-
# CHROME_ARGS: '--disable-accelerated-2d-canvas --no-zygote --single-process'
|
|
48
|
-
DOTENV_CONFIG_QUIET=true
|
package/container/Dockerfile
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
FROM registry.gitlab.com/openxchange/base-images/wolfi/playwright:1.58.2
|
package/global.d.ts
DELETED
package/pnpm-workspace.yaml
DELETED