@open-xchange/appsuite-codeceptjs 0.6.2 → 0.6.4

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/README.md CHANGED
@@ -1,3 +1,72 @@
1
1
  # Open-Xchange App Suite: CodeceptJS
2
2
 
3
- TBD
3
+ App Suite specific CodeceptJS tooling.
4
+
5
+ ## Custom Helpers
6
+
7
+ The file `src/helpers.js` contains App Suite specific CodeceptJS helpers. It is possible to overwrite any of these helpers or add new ones in projects that use this package. This might be useful for maintenance work on existing helpers or when developing new ones and can be achieved with the following changes:
8
+
9
+ ```js
10
+ // CodeceptJS configuration of a local package
11
+ // file: e2e/codecept.conf.js
12
+
13
+ const { config } = require('@open-xchange/appsuite-codeceptjs')
14
+
15
+ // import local helpers
16
+ config.helpers.AppSuite = {
17
+ require: './helper'
18
+ }
19
+
20
+ module.exports.config = config
21
+ ```
22
+
23
+ ```js
24
+ // Local helpers
25
+ // file: e2e/helper.js
26
+
27
+ const Helper = require('@open-xchange/appsuite-codeceptjs/src/helper')
28
+
29
+ class CustomHelper extends Helper {
30
+ // This overwrites the existing `selectFolder` helper
31
+ async selectFolder (locator) {
32
+ locator = '.folder-tree ' + locator
33
+ await this.helpers.Playwright.page.locator(locator).click()
34
+ }
35
+
36
+ // This creates the new helper `newCostumHelper`
37
+ async newCostumHelper () {
38
+ await this.helpers.Playwright.waitForVisible({ css: 'html.complete' }, 10)
39
+ }
40
+ }
41
+
42
+ module.exports = CustomHelper
43
+ ```
44
+
45
+ ## Local Configuration Overwrite
46
+
47
+ You can use the config object for local customization of the default CodeceptJS configuration provided by this package. For example you can change the tests directory the following way:
48
+
49
+ ```js
50
+ // CodeceptJS configuration of a local package
51
+ // file: e2e/codecept.conf.js
52
+
53
+ const { config } = require('@open-xchange/appsuite-codeceptjs')
54
+
55
+ config.tests = './costum_directory/*_test.js'
56
+
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
+ ```
@@ -1 +1 @@
1
- FROM registry.gitlab.open-xchange.com/appsuite/web-foundation/base-images/playwright:v1.49.1-jammy
1
+ FROM registry.gitlab.com/openxchange/appsuite/web-foundation/base-images/playwright:v1.53.0-jammy
package/eslint.config.mjs CHANGED
@@ -48,7 +48,7 @@ export default [
48
48
  languageOptions: {
49
49
  globals: {
50
50
  ...codeceptjs[0].languageOptions.globals,
51
- ...mocha.configs.flat.recommended.languageOptions.globals,
51
+ ...mocha.configs.recommended.languageOptions.globals,
52
52
  Feature: true,
53
53
  Scenario: true,
54
54
  Before: true,
package/global.d.ts CHANGED
@@ -1,6 +1,3 @@
1
- /* eslint-disable no-var, camelcase, @typescript-eslint/no-unused-vars */
2
- // IMPORTANT: This solution only works by declaring variables with var (do not use let or const)
3
- var expect: Chai.ExpectStatic
4
- var assert: Chai.AssertStatic
5
- const codecept_dir: string
6
- const output_dir: string
1
+ /* eslint-disable camelcase */
2
+ declare const codecept_dir: string
3
+ declare const output_dir: string
package/package.json CHANGED
@@ -1,44 +1,48 @@
1
1
  {
2
2
  "name": "@open-xchange/appsuite-codeceptjs",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "OX App Suite CodeceptJS Configuration and Helpers",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "e2e-rerun": "./customRerun.js"
8
8
  },
9
- "repository": "https://gitlab.open-xchange.com/appsuite/web-foundation/tools.git",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://gitlab.com/openxchange/appsuite/web-foundation/tools",
12
+ "directory": "packages/appsuite-codeceptjs"
13
+ },
10
14
  "license": "AGPL-3.0-or-later",
11
15
  "private": false,
12
16
  "dependencies": {
13
17
  "@axe-core/playwright": "^4.10.1",
14
18
  "@codeceptjs/helper": "^2.0.4",
15
19
  "@influxdata/influxdb-client": "^1.35.0",
16
- "@open-xchange/codecept-horizontal-scaler": "^0.1.11",
17
- "@playwright/test": "1.49.1",
20
+ "@playwright/test": "1.53.0",
18
21
  "allure-codeceptjs": "2.15.1",
19
- "chai": "^5.1.2",
20
- "chai-subset": "^1.6.0",
22
+ "chai": "^5.2.0",
21
23
  "chalk": "^4.1.2",
22
24
  "chalk-table": "^1.0.2",
23
- "codeceptjs": "3.6.10",
25
+ "codeceptjs": "3.7.3",
24
26
  "dotenv": "^16.4.7",
25
- "mocha": "^11.0.1",
27
+ "mocha": "^11.1.0",
26
28
  "mocha-junit-reporter": "^2.2.1",
27
29
  "mocha-multi": "^1.1.7",
28
30
  "moment": "^2.30.1",
29
- "moment-timezone": "^0.5.46",
31
+ "moment-timezone": "^0.6.0",
30
32
  "p-retry": "^6.2.1",
31
- "playwright-core": "1.49.1",
33
+ "playwright-core": "1.53.0",
32
34
  "short-uuid": "^5.2.0",
33
- "soap": "^1.1.7"
35
+ "@open-xchange/soap-client": "0.0.1",
36
+ "@open-xchange/codecept-horizontal-scaler": "0.1.12"
34
37
  },
35
38
  "devDependencies": {
36
- "@types/node": "^22.10.2",
39
+ "@types/node": "^24.0.0",
37
40
  "ts-node": "^10.9.2",
38
- "typescript": "^5.7.2",
41
+ "typescript": "^5.8.2",
39
42
  "@open-xchange/lint": "0.2.0"
40
43
  },
41
44
  "scripts": {
42
- "lint": "eslint ."
45
+ "lint": "eslint .",
46
+ "test": "mocha --color 'spec/**/*.test.js'"
43
47
  }
44
48
  }
@@ -0,0 +1,4 @@
1
+ packages:
2
+ - '../lint'
3
+ - '../soap-client'
4
+ - '../codecept-horizontal-scaler'
@@ -0,0 +1,123 @@
1
+ const { expect } = require('chai')
2
+ const { getMonday } = require('../../src/pageobjects/util')
3
+ const moment = require('moment')
4
+
5
+ const FORMAT = 'YYYY-MM-DD'
6
+
7
+ describe('Calendar', function () {
8
+ describe('getMonday()', function () {
9
+ describe('Week starts on Monday (locale=de)', function () {
10
+ it('should see the week starting on Monday (1)', function () {
11
+ expect(moment.localeData('de').firstDayOfWeek()).to.equal(1)
12
+ })
13
+ it('should return 2025-06-02 on 2025-06-06 (last Friday)', function () {
14
+ const date = moment('2025-06-06').locale('de')
15
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-02')
16
+ })
17
+ it('should return 2025-06-02 on 2025-06-07 (Saturday)', function () {
18
+ const date = moment('2025-06-07').locale('de')
19
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-02')
20
+ })
21
+ it('should return 2025-06-02 on 2025-06-08 (Sunday)', function () {
22
+ const date = moment('2025-06-08').locale('de')
23
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-02')
24
+ })
25
+ it('should return 2025-06-09 on 2025-06-09 (Monday)', function () {
26
+ const date = moment('2025-06-09').locale('de')
27
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-09')
28
+ })
29
+ it('should return 2025-06-13 on 2025-06-09 (Friday)', function () {
30
+ const date = moment('2025-06-13').locale('de')
31
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-09')
32
+ })
33
+ it('should return 2025-06-02 on 2025-06-14 (next Saturday)', function () {
34
+ const date = moment('2025-06-14').locale('de')
35
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-09')
36
+ })
37
+ it('should return 2025-06-02 on 2025-06-15 (next Sunday)', function () {
38
+ const date = moment('2025-06-15').locale('de')
39
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-09')
40
+ })
41
+ it('should return 2025-06-02 on 2025-06-16 (next Monday)', function () {
42
+ const date = moment('2025-06-16').locale('de')
43
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-16')
44
+ })
45
+ })
46
+
47
+ describe('Week starts on Sunday (locale=en)', function () {
48
+ it('should see the week starting on Sunday (0)', function () {
49
+ expect(moment.localeData('en').firstDayOfWeek()).to.equal(0)
50
+ })
51
+ it('should return 2025-06-02 on 2025-06-06 (last Friday)', function () {
52
+ const date = moment('2025-06-06').locale('en')
53
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-02')
54
+ })
55
+ it('should return 2025-06-02 on 2025-06-07 (Saturday)', function () {
56
+ const date = moment('2025-06-07').locale('en')
57
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-02')
58
+ })
59
+ it('should return 2025-06-09 on 2025-06-08 (Sunday)', function () {
60
+ const date = moment('2025-06-08').locale('en')
61
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-09')
62
+ })
63
+ it('should return 2025-06-09 on 2025-06-09 (Monday)', function () {
64
+ const date = moment('2025-06-09').locale('en')
65
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-09')
66
+ })
67
+ it('should return 2025-06-13 on 2025-06-09 (Friday)', function () {
68
+ const date = moment('2025-06-13').locale('en')
69
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-09')
70
+ })
71
+ it('should return 2025-06-02 on 2025-06-14 (next Saturday)', function () {
72
+ const date = moment('2025-06-14').locale('en')
73
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-09')
74
+ })
75
+ it('should return 2025-06-02 on 2025-06-15 (next Sunday)', function () {
76
+ const date = moment('2025-06-15').locale('en')
77
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-16')
78
+ })
79
+ it('should return 2025-06-02 on 2025-06-16 (next Monday)', function () {
80
+ const date = moment('2025-06-16').locale('en')
81
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-16')
82
+ })
83
+ })
84
+
85
+ describe('Week starts on Saturday (locale=tzm-latn)', function () {
86
+ it('should see the week starting on Saturday (6)', function () {
87
+ expect(moment.localeData('tzm-latn').firstDayOfWeek()).to.equal(6)
88
+ })
89
+ it('should return 2025-06-02 on 2025-06-06 (last Friday)', function () {
90
+ const date = moment('2025-06-06').locale('tzm-latn')
91
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-02')
92
+ })
93
+ it('should return 2025-06-09 on 2025-06-07 (Saturday)', function () {
94
+ const date = moment('2025-06-07').locale('tzm-latn')
95
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-09')
96
+ })
97
+ it('should return 2025-06-09 on 2025-06-08 (Sunday)', function () {
98
+ const date = moment('2025-06-08').locale('tzm-latn')
99
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-09')
100
+ })
101
+ it('should return 2025-06-09 on 2025-06-09 (Monday)', function () {
102
+ const date = moment('2025-06-09').locale('tzm-latn')
103
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-09')
104
+ })
105
+ it('should return 2025-06-13 on 2025-06-09 (Friday)', function () {
106
+ const date = moment('2025-06-13').locale('tzm-latn')
107
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-09')
108
+ })
109
+ it('should return 2025-06-02 on 2025-06-14 (next Saturday)', function () {
110
+ const date = moment('2025-06-14').locale('tzm-latn')
111
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-16')
112
+ })
113
+ it('should return 2025-06-02 on 2025-06-15 (next Sunday)', function () {
114
+ const date = moment('2025-06-15').locale('tzm-latn')
115
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-16')
116
+ })
117
+ it('should return 2025-06-02 on 2025-06-16 (next Monday)', function () {
118
+ const date = moment('2025-06-16').locale('tzm-latn')
119
+ expect(getMonday(date).format(FORMAT)).to.equal('2025-06-16')
120
+ })
121
+ })
122
+ })
123
+ })
package/src/actor.js CHANGED
@@ -107,7 +107,7 @@ module.exports = function () {
107
107
  *
108
108
  * @param {string} locator - The locator of the element. Only accepts css selectors.
109
109
  */
110
- waitForFocus (locator) {
110
+ async waitForFocus (locator) {
111
111
  this.waitForElement(locator)
112
112
  this.waitForVisible(locator)
113
113
  return this.usePlaywrightTo('wait for focus', async ({ page }) => {
package/src/chai.js CHANGED
@@ -19,9 +19,6 @@
19
19
  */
20
20
 
21
21
  import('chai').then(chai => {
22
- const chaiSubset = require('chai-subset')
23
- chai.use(chaiSubset)
24
-
25
22
  chai.util.addProperty(chai.Assertion.prototype, 'accessible', function () {
26
23
  const problems = ['\n', 'Accessibility Violations (' + this._obj.violations.length + ')', '---']
27
24
  const pad = '\n '
@@ -22,7 +22,7 @@ const created = []
22
22
  const users = require('../users/users')()
23
23
  const util = require('../util')
24
24
  const event = require('../event')
25
- const contextService = require('../soap/services/context')
25
+ const { contextService } = require('@open-xchange/soap-client/common')
26
26
  const crypto = require('node:crypto')
27
27
 
28
28
  class Context {
@@ -21,8 +21,7 @@
21
21
  const event = require('../event')
22
22
  const users = require('../users/reseller')()
23
23
  const util = require('../util')
24
- const resellerContextService = require('../soap/services/resellerContext')
25
- const resellerUserService = require('../soap/services/resellerUser')
24
+ const { resellerContextService, resellerUserService } = require('@open-xchange/soap-client/reseller')
26
25
  const contexts = []
27
26
  const created = []
28
27
 
@@ -19,19 +19,21 @@
19
19
  */
20
20
 
21
21
  const { I, contactpicker, autocomplete, dialogs } = inject()
22
- const moment = require('moment')
22
+ const { getMonday } = require('./util')
23
23
 
24
24
  module.exports = {
25
25
 
26
26
  editWindow: '.io-ox-calendar-edit-window',
27
27
  miniCalendar: '.window-sidepanel .date-picker',
28
28
  title: '[data-extension-point="io.ox/calendar/edit/section"] input[name="summary"]',
29
+ location: '[data-extension-point="io.ox/calendar/edit/section"] input[name="location"]',
30
+ description: '[data-extension-point="io.ox/calendar/edit/section"] textarea[name="description"]',
29
31
 
30
32
  async newAppointment () {
31
33
  I.wait(1)
32
34
  I.clickPrimary('New appointment')
33
35
  I.waitForVisible(this.editWindow)
34
- await I.waitForFocus('.io-ox-calendar-edit-window input[type="text"][name="summary"]')
36
+ return I.waitForFocus('.io-ox-calendar-edit-window input[type="text"][name="summary"]')
35
37
  },
36
38
 
37
39
  clickAppointment (title, position = 1) {
@@ -43,9 +45,7 @@ module.exports = {
43
45
  },
44
46
 
45
47
  getNextMonday () {
46
- // isoWeekday is Monday=1 ... Sunday=7
47
- // 8 means next Monday; also over the weekend before
48
- return moment().isoWeekday(8).set('hour', 8)
48
+ return getMonday().add(1, 'week').set('hour', 8)
49
49
  },
50
50
 
51
51
  startNextMonday () {
@@ -106,17 +106,14 @@ module.exports = {
106
106
  }, attr)
107
107
  },
108
108
 
109
- async addParticipant (name, exists, context, addedParticipants) {
109
+ addParticipant (name, exists = true, context) {
110
110
  if (!context) context = '*'
111
- if (!addedParticipants) addedParticipants = 1
112
111
 
113
112
  // does suggestion exists (for contact, user, ...)
114
- exists = typeof exists === 'boolean' ? exists : true
115
- const number = await I.grabNumberOfVisibleElements(locate('.attendee').inside(context).as('Attendee')) + addedParticipants
116
113
  const addParticipantsLocator = locate('.add-participant.tt-input').inside(context).as('Add participant field')
117
114
  // input field
118
115
  I.waitForVisible(addParticipantsLocator)
119
- I.waitForEnabled(addParticipantsLocator)
116
+ // I.waitForEnabled(addParticipantsLocator)
120
117
  I.fillField(addParticipantsLocator, name)
121
118
  I.seeInField(addParticipantsLocator, name)
122
119
  // tokenfield/typeahead
@@ -128,7 +125,6 @@ module.exports = {
128
125
 
129
126
  I.waitForInvisible(autocomplete.suggestions)
130
127
  // note: might be more than one that get's added (group)
131
- I.waitForElement(locate('.attendee').inside(context).at(number).as(`Attendee ${number}`))
132
128
  },
133
129
 
134
130
  async addParticipantByPicker (name) {
@@ -139,11 +135,18 @@ module.exports = {
139
135
  },
140
136
 
141
137
  switchView (view) {
138
+ const viewMap = {
139
+ Day: 'week:day',
140
+ Week: 'week:week',
141
+ Workweek: 'week:workweek',
142
+ Month: 'month',
143
+ List: 'list'
144
+ }
142
145
  I.waitForElement('.page.current .calendar-header > .dropdown button')
143
146
  I.click('.page.current .calendar-header > .dropdown button')
144
147
  I.waitForText(view, undefined, '.open .dropdown-menu')
145
148
  I.click(locate('.dropdown.open a').withText(view).as('Switch to ' + view))
146
- I.wait(2)
149
+ I.waitForVisible(`.io-ox-pagecontroller.page.current[data-page-id="io.ox/calendar/${viewMap[view]}"]`)
147
150
  },
148
151
 
149
152
  getFullname (user) {
@@ -171,8 +174,8 @@ module.exports = {
171
174
 
172
175
  if (startDate) {
173
176
  I.click('~Date (M/D/YYYY)')
174
- I.pressKey(['Control', 'a'])
175
- I.pressKey(startDate)
177
+ I.pressKey(['CommandOrControl', 'a'])
178
+ I.type(startDate)
176
179
  I.pressKey('Enter')
177
180
  }
178
181
 
@@ -183,8 +186,8 @@ module.exports = {
183
186
 
184
187
  if (endDate) {
185
188
  I.click('~Date (M/D/YYYY)', '.dateinput[data-attribute="endDate"]')
186
- I.pressKey(['Control', 'a'])
187
- I.pressKey(startDate)
189
+ I.pressKey(['CommandOrControl', 'a'])
190
+ I.type(endDate)
188
191
  I.pressKey('Enter')
189
192
  }
190
193
 
@@ -23,6 +23,8 @@ const { I, dialogs } = inject()
23
23
  module.exports = {
24
24
 
25
25
  editWindow: '.io-ox-contacts-edit-window',
26
+ title: '.io-ox-contacts-edit-window input[name="title"]',
27
+ note: '.io-ox-contacts-edit-window textarea[name="note"]',
26
28
 
27
29
  selectContact (text) {
28
30
  I.waitForElement(`.vgrid [aria-label="${text}"]`)
@@ -36,7 +36,6 @@ module.exports = {
36
36
  I.wait(1)
37
37
  I.click(item)
38
38
  await I.waitForFocus('.list-view li.list-item.selected')
39
- I.waitForElement('.mail-detail-frame')
40
39
  },
41
40
  async selectMailByIndex (index) {
42
41
  const item = locate('.list-view li.list-item').withAttr({ 'data-index': index.toString() }).as('Mail item')
@@ -26,8 +26,7 @@ module.exports = {
26
26
  I.wait(0.5) // prevent clicking a detached element caused by the bottom toolbar being re-rendered multiple times
27
27
  I.waitForElement('~New contact')
28
28
  I.click({ css: '[data-action="io.ox/contacts/actions/create"]' })
29
- I.waitForElement('.io-ox-contacts-edit-window')
30
- I.waitForVisible('.io-ox-contacts-edit-window.complete')
29
+ I.waitForVisible('.io-ox-contacts-edit-window input[name="first_name"]')
31
30
  I.waitForText('Add personal info')
32
31
  },
33
32
 
@@ -18,19 +18,17 @@
18
18
  * Any use of the work other than as authorized under this license or copyright law is prohibited.
19
19
  */
20
20
 
21
- const { createClientAsync } = require('../soap.js')
22
-
23
- const OXaaSService = createClientAsync('OXaaSService').then(client => client)
24
-
25
- async function setMailQuota (data) {
26
- return await (await OXaaSService).setMailQuotaAsync(data)
27
- }
28
-
29
- async function createSharedDomain (data) {
30
- return await (await OXaaSService).createSharedDomain(data)
31
- }
21
+ const moment = require('moment')
32
22
 
33
23
  module.exports = {
34
- setMailQuota,
35
- createSharedDomain
24
+
25
+ // return the (standard) workweek start on the current week depending on the locale
26
+ getMonday (date = moment()) {
27
+ // robust approach that also works:
28
+ // a) over the weekend (!)
29
+ // b) if firstDayOfWeek is Sunday or Saturday
30
+ const firstDayOfWeek = moment.localeData(date.locale()).firstDayOfWeek()
31
+ const localeWeekday = (8 - firstDayOfWeek) % 7
32
+ return date.startOf('week').weekday(localeWeekday)
33
+ }
36
34
  }
@@ -25,8 +25,7 @@ const usersToRemove = []
25
25
  const preprovisionedUsers = []
26
26
  const util = require('../util')
27
27
  const short = require('short-uuid')
28
- const resellerUserService = require('../soap/services/resellerUser')
29
- const oxaasService = require('../soap/services/oxaas')
28
+ const { resellerUserService, oxaasService } = require('@open-xchange/soap-client/reseller')
30
29
 
31
30
  class User {
32
31
  constructor (opt) {
@@ -24,7 +24,7 @@ const event = require('../event')
24
24
  const users = []
25
25
  const util = require('../util')
26
26
  const short = require('short-uuid')
27
- const userService = require('../soap/services/user')
27
+ const { userService } = require('@open-xchange/soap-client/common')
28
28
 
29
29
  class User {
30
30
  constructor (opt) {
package/src/util.js CHANGED
@@ -20,7 +20,7 @@
20
20
 
21
21
  const codecept = require('codeceptjs')
22
22
  const url = require('node:url')
23
- const { getFilestorageId } = require('./soap/services/util')
23
+ const { getFilestorageId } = require('@open-xchange/soap-client/common')
24
24
 
25
25
  module.exports = {
26
26
 
package/chai.d.ts DELETED
@@ -1,5 +0,0 @@
1
- declare module Chai {
2
- interface Assertion {
3
- accessible: void;
4
- }
5
- }
package/src/chai.d.ts DELETED
@@ -1,6 +0,0 @@
1
- declare module Chai {
2
- interface Assertion {
3
- accessible: void;
4
- }
5
- }
6
- export {}
@@ -1,170 +0,0 @@
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
- const { createClientAsync, logSoapError } = require('../soap.js')
22
-
23
- const OXContextService = createClientAsync('OXContextService').then(client => client)
24
-
25
- /**
26
- * This function retrieves the default context from the OXContextService.
27
- * @returns {Promise<Object>} The first result from the listAsync method call.
28
- */
29
- async function getDefault () {
30
- return (await (await OXContextService).listAsync({ search_pattern: 'defaultcontext' }))[0]
31
- }
32
-
33
- /**
34
- * This function removes the context with the specified ID.
35
- * @param {number} id The ID of the context to remove.
36
- * @returns {Promise<Boolean>} Returns true if it could remove the context and false if it could not
37
- */
38
- async function remove (id) {
39
- return !!await (await OXContextService).deleteAsync({ ctx: { id } }).then(() => true).catch(logSoapError)
40
- }
41
-
42
- /**
43
- * This function creates a new context.
44
- * @param {Object} ctx The context to create.
45
- * @param {Object} adminUser The admin user of the context.
46
- * Defaults to:
47
- * ```JSON
48
- * {
49
- name: 'oxadmin',
50
- password: 'secret',
51
- display_name: 'context admin',
52
- sur_name: 'admin',
53
- given_name: 'context',
54
- email1: `oxadmin@${process.env.MX_DOMAIN}`,
55
- primaryEmail: `oxadmin@${process.env.MX_DOMAIN}`
56
- }
57
- All properties are needed and will be inserted if not provided.
58
- ```
59
- * @returns {Promise<Object>} The created context.
60
- */
61
- async function create (ctx = {}, adminUser = {}) {
62
- return await (await OXContextService)
63
- .createAsync({
64
- ctx,
65
- admin_user: Object.assign({
66
- name: 'oxadmin',
67
- password: 'secret',
68
- display_name: 'context admin',
69
- sur_name: 'admin',
70
- given_name: 'context',
71
- email1: `oxadmin@${process.env.MX_DOMAIN}`,
72
- primaryEmail: `oxadmin@${process.env.MX_DOMAIN}`
73
- }, adminUser)
74
- })
75
- .then(async context => {
76
- await changeModuleAccessByName(context.id, 'all')
77
- return context
78
- })
79
- .catch(e => {
80
- logSoapError(e)
81
- throw e
82
- })
83
- }
84
-
85
- /**
86
- * This function changes the module access of the specified context.
87
- * @param {number} id The ID of the context.
88
- * @param {string} access_combination_name The name of the access combination to set.
89
- * @returns {Promise<void>}
90
- */
91
- // eslint-disable-next-line camelcase
92
- async function changeModuleAccessByName (id, access_combination_name) {
93
- // eslint-disable-next-line camelcase
94
- return await (await OXContextService).changeModuleAccessByNameAsync({ ctx: { id }, access_combination_name })
95
- }
96
-
97
- /**
98
- * This function changes the capabilities of the specified context.
99
- * @param {number} id The ID of the context.
100
- * @param {string} capsToAdd The capabilities to add.
101
- * @param {string} capsToRemove The capabilities to remove.
102
- * @returns {Promise<void>}
103
- */
104
- async function changeCapabilities (id, capsToAdd, capsToRemove) {
105
- const data = {}
106
- if (capsToAdd) data.capsToAdd = capsToAdd
107
- if (capsToRemove) data.capsToRemove = capsToRemove
108
- return await (await OXContextService).changeCapabilitiesAsync({ ctx: { id }, ...data })
109
- }
110
-
111
- /**
112
- * This function retrieves the module access of the specified context.
113
- * @param {number} id The ID of the context.
114
- * @returns {Promise<Object>} The module access of the specified context.
115
- */
116
- async function getModuleAccess (id) {
117
- return await (await OXContextService).getModuleAccessAsync({ ctx: { id } })
118
- }
119
- /**
120
- * This function changes the module access of the specified context.
121
- * @param {number} id The ID of the context.
122
- * @param {Object} moduleAccess The module access to set.
123
- * @returns {Promise<void>}
124
- */
125
- async function changeModuleAccess (id, moduleAccess) {
126
- const currentAccess = await getModuleAccess(id)
127
- return await (await OXContextService).changeModuleAccessAsync({ ctx: { id }, access: { ...currentAccess, ...moduleAccess } })
128
- }
129
-
130
- /**
131
- * Search for contexts.
132
- * @param {String} searchPattern The pattern to search for
133
- * @param {Object} options Additional options
134
- * @param {Boolean} options.excludeDisabled Exclude disabled contexts from the search results (default: true)
135
- * @returns {Promise<Array<Object>>} The list of contexts that match the search pattern.
136
- */
137
- async function list (searchPattern, { excludeDisabled } = { excludeDisabled: true }) {
138
- return await (await OXContextService).listAsync({ search_pattern: searchPattern, exclude_disabled: excludeDisabled })
139
- }
140
-
141
- /**
142
- * This function retrieves the context with the specified ID.
143
- * @param {number} id The ID of the context to retrieve.
144
- * @returns {Promise<Object>} The context with the specified ID.
145
- */
146
- async function get (id) {
147
- return await (await OXContextService).getDataAsync({ ctx: { id } })
148
- }
149
-
150
- /**
151
- * This function changes the context with the specified ID.
152
- * @param {Object} ctx The context to change.
153
- * @returns {Promise<void>}
154
- */
155
- async function change (ctx) {
156
- return await (await OXContextService).changeAsync({ ctx })
157
- }
158
-
159
- module.exports = {
160
- getDefault,
161
- remove,
162
- create,
163
- changeModuleAccessByName,
164
- changeCapabilities,
165
- getModuleAccess,
166
- changeModuleAccess,
167
- get,
168
- list,
169
- change
170
- }
@@ -1,65 +0,0 @@
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
- const { createClientAsync, logSoapError } = require('../soap.js')
22
-
23
- const OXResellerContextService = createClientAsync('OXResellerContextService').then(client => client)
24
-
25
- async function create (data) {
26
- return await (await OXResellerContextService).createAsync(data)
27
- }
28
-
29
- async function remove (contextId) {
30
- return !!await (await OXResellerContextService).deleteAsync({
31
- ctx: { id: contextId }
32
- }).then(() => true).catch(logSoapError)
33
- }
34
-
35
- async function change (ctx) {
36
- return await (await OXResellerContextService).changeAsync({ ctx })
37
- }
38
-
39
- async function get (id) {
40
- return await (await OXResellerContextService).getDataAsync({ ctx: { id } })
41
- }
42
-
43
- async function getModuleAccess (id) {
44
- return await (await OXResellerContextService).getModuleAccessAsync({ ctx: id })
45
- }
46
-
47
- async function changeModuleAccess (id, access) {
48
- const currentAccess = await getModuleAccess(id)
49
-
50
- return await (await OXResellerContextService).changeModuleAccessAsync({ ctx: { id }, access: { ...currentAccess, ...access } })
51
- }
52
-
53
- async function listAll (data) {
54
- return await (await OXResellerContextService).listAllAsync(data)
55
- }
56
-
57
- module.exports = {
58
- create,
59
- remove,
60
- change,
61
- get,
62
- getModuleAccess,
63
- changeModuleAccess,
64
- listAll
65
- }
@@ -1,100 +0,0 @@
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
- const { createClientAsync, logSoapError } = require('../soap.js')
22
-
23
- const OXResellerUserService = createClientAsync('OXResellerUserService').then(client => client)
24
-
25
- async function remove (contextId, userId) {
26
- return !!await (await OXResellerUserService).deleteAsync({
27
- ctx: { id: contextId },
28
- user: { id: userId }
29
- }).then(() => true).catch(logSoapError)
30
- }
31
-
32
- /**
33
- * This function changes the context with the specified ID.
34
- * @param {Object} context The context of the user to be changed.
35
- * @param {Object} usrdata The user to change.
36
- * @returns {Promise<void>}
37
- */
38
- async function change (context, usrdata) {
39
- return await (await OXResellerUserService).changeAsync({
40
- ctx: { id: context.id },
41
- usrdata,
42
- auth: { login: context.admin.name, password: context.admin.password }
43
- })
44
- }
45
-
46
- async function get (data) {
47
- return await (await OXResellerUserService).getDataAsync(data)
48
- }
49
-
50
- async function getModuleAccess (context, userId) {
51
- return await (await OXResellerUserService).getModuleAccessAsync({
52
- ctx: { id: context.id },
53
- user: { id: userId },
54
- auth: { login: context.admin.name, password: context.admin.password }
55
- }).then(
56
- (res) => res
57
- )
58
- }
59
-
60
- async function changeByModuleAccess (context, userId, currentAccess, moduleAccess) {
61
- return await (await OXResellerUserService).changeByModuleAccessAsync({
62
- ctx: { id: context.id },
63
- moduleAccess: Object.assign({}, currentAccess, moduleAccess),
64
- user: { id: userId },
65
- auth: { login: context.admin.name, password: context.admin.password }
66
- })
67
- }
68
-
69
- async function changeByModuleAccessName (context, userId, accessCombinationName) {
70
- return await (await OXResellerUserService).changeByModuleAccessNameAsync({
71
- ctx: { id: context.id },
72
- access_combination_name: accessCombinationName,
73
- user: { id: userId },
74
- auth: { login: context.admin.name, password: context.admin.password }
75
- }).catch(error => console.error('Module access change error: ', error))
76
- }
77
-
78
- async function createByModuleAccessName (context, usrdata) {
79
- return await (await OXResellerUserService).createByModuleAccessNameAsync({
80
- ctx: { id: context.id },
81
- usrdata,
82
- access_combination_name: 'all',
83
- auth: { login: context.admin.name, password: context.admin.password }
84
- })
85
- }
86
-
87
- async function listAll (data) {
88
- return await (await OXResellerUserService).listAllAsync(data)
89
- }
90
-
91
- module.exports = {
92
- remove,
93
- change,
94
- get,
95
- getModuleAccess,
96
- changeByModuleAccess,
97
- changeByModuleAccessName,
98
- createByModuleAccessName,
99
- listAll
100
- }
@@ -1,114 +0,0 @@
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
- const { createClientAsync, logSoapError } = require('../soap.js')
22
-
23
- const OXUserService = createClientAsync('OXUserService').then(client => client)
24
-
25
- /**
26
- * This function removes the user with the specified context and user ID.
27
- * @param {Object} context The context of the user to be removed.
28
- * @param {number} userId The ID of the user to be removed.
29
- * @returns {Promise<Boolean>} Returns true if it could remove the user and false if it could not
30
- */
31
- async function remove (context, userId) {
32
- return !!await (await OXUserService).deleteAsync({
33
- ctx: { id: context.id },
34
- user: { id: userId },
35
- auth: context.admin
36
- }).then(() => true).catch(logSoapError)
37
- }
38
-
39
- /**
40
- * This function creates a new user.
41
- * @param {Object} context The context of the user to be created.
42
- * @param {Object} usrdata The user to create.
43
- * @returns {Promise<Object>} The created user.
44
- */
45
- async function create (context, usrdata) {
46
- return await (await OXUserService).createAsync({
47
- ctx: { id: context.id },
48
- usrdata,
49
- auth: context.admin
50
- })
51
- }
52
-
53
- /**
54
- * This function changes the context with the specified ID.
55
- * @param {Object} context The context of the user to be changed.
56
- * @param {Object} usrdata The user to change.
57
- * @returns {Promise<void>}
58
- */
59
- async function change (context, usrdata) {
60
- return await (await OXUserService).changeAsync({
61
- ctx: { id: context.id },
62
- usrdata,
63
- auth: context.admin
64
- })
65
- }
66
-
67
- async function changeByModuleAccess (context, userId, currentAccess, moduleAccess) {
68
- return await (await OXUserService).changeByModuleAccessAsync({
69
- ctx: { id: context.id },
70
- moduleAccess: Object.assign({}, currentAccess, moduleAccess),
71
- user: { id: userId },
72
- auth: context.admin
73
- })
74
- }
75
-
76
- async function changeByModuleAccessName (context, userId, accessCombinationName) {
77
- return await (await OXUserService).changeByModuleAccessNameAsync({
78
- ctx: { id: context.id },
79
- access_combination_name: accessCombinationName,
80
- user: { id: userId },
81
- auth: context.admin
82
- }).catch(error => console.error('Module access change error:', error))
83
- }
84
-
85
- async function getModuleAccess (context, userId) {
86
- return await (await OXUserService).getModuleAccessAsync({
87
- ctx: { id: context.id },
88
- user: { id: userId },
89
- auth: context.admin
90
- }).then(
91
- (res) => res
92
- )
93
- }
94
-
95
- async function changeCapabilities (context, userId, capsToAdd, capsToRemove) {
96
- const data = {
97
- ctx: { id: context.id },
98
- user: { id: userId },
99
- auth: context.admin
100
- }
101
- if (capsToAdd) data.capsToAdd = capsToAdd
102
- if (capsToRemove) data.capsToRemove = capsToRemove
103
- return await (await OXUserService).changeCapabilitiesAsync(data)
104
- }
105
-
106
- module.exports = {
107
- create,
108
- change,
109
- changeByModuleAccess,
110
- changeByModuleAccessName,
111
- changeCapabilities,
112
- getModuleAccess,
113
- remove
114
- }
@@ -1,39 +0,0 @@
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
- const { createClientAsync } = require('../soap.js')
22
-
23
- /**
24
- * This function retrieves the ID of the first filestorage.
25
- * @returns {Promise<number>} The ID of the first filestorage.
26
- */
27
- let fileStoreId
28
-
29
- async function getFilestorageId () {
30
- const OXUtilService = createClientAsync('OXUtilService').then(client => client)
31
-
32
- if (fileStoreId) return fileStoreId
33
- fileStoreId = (await (await OXUtilService).listFilestoreAsync())[0]?.id
34
- return fileStoreId
35
- }
36
-
37
- module.exports = {
38
- getFilestorageId
39
- }
package/src/soap/soap.js DELETED
@@ -1,176 +0,0 @@
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
- const { performance, PerformanceObserver } = require('node:perf_hooks')
22
- const SOAP = require('soap')
23
- const dotenv = require('dotenv')
24
-
25
- let AbortError
26
- const pRetry = import('p-retry').then(module => {
27
- AbortError = module.AbortError
28
- return module.default
29
- })
30
-
31
- dotenv.config({ path: '.env' })
32
- dotenv.config({ path: '.env.defaults' })
33
-
34
- // This flag enables debug output including timing information.
35
- const debug = process.env.DEBUG_SOAP === 'true'
36
-
37
- // This URL is used to create the SOAP client.
38
- const provisioningUrl = String(process.env.PROVISIONING_URL).replace(/\/$/, '')
39
-
40
- // This user is used to authenticate against the provisioning API.
41
- const provisioningAuth = {
42
- auth: {
43
- login: process.env.E2E_ADMIN_USER,
44
- password: process.env.E2E_ADMIN_PW
45
- }
46
- }
47
-
48
- /**
49
- * This code creates a PerformanceObserver instance which asynchronously observes
50
- * performance measurement events. It logs the name of the event (which is the name
51
- * of the SOAP method in this context) and the time it took to execute in milliseconds.
52
- *
53
- * This is used for performance tracking of the SOAP methods.
54
- * @see https://nodejs.org/api/perf_hooks.html
55
- * @params {PerformanceObserverEntryList} items The list of performance entries.
56
- * @returns {void}
57
- */
58
- const obs = new PerformanceObserver((items) => {
59
- items.getEntries().forEach((entry) => {
60
- if (debug) console.log(`${entry.name} took ${Math.round(entry.duration)}ms`)
61
- })
62
- })
63
- obs.observe({ entryTypes: ['measure'] })
64
-
65
- async function logSoapError (e) {
66
- console.error(e?.originalError?.root?.Envelope?.Body?.Fault?.faultstring || e.message)
67
- }
68
-
69
- /**
70
- * This function checks if the specified error should abort the retry.
71
- * @param {Error} error The error to check.
72
- * @returns {boolean} True if the error should abort the retry, false otherwise.
73
- **/
74
- function shouldAbortRetry (error) {
75
- try {
76
- const fault = error.root.Envelope.Body.Fault
77
- const details = fault.detail
78
- const blockedFaultStrings = [
79
- /Context \d+ already exists/,
80
- /Authentication failed/,
81
- /Context \d+ does not exist/,
82
- /CloudPluginException: username .* already exists/,
83
- /CloudPluginException: context name must begin/,
84
- /The displayname is already used/,
85
- /already exists in this context/,
86
- /Shared Domain already exists/,
87
- /Shared Domain already in use/,
88
- /No such user/,
89
- /Mandatory fields in context not set/,
90
- /A mapping with login info .* already exists/,
91
- /Id must not be set if pre-assembled context should be used/,
92
- /Unmarshalling Error/
93
- ]
94
- const blockedExceptions = [
95
- 'ContextExistsException',
96
- 'InvalidCredentialsException',
97
- 'NoSuchContextException'
98
- ]
99
- // return "details object contains any of the blocked items"
100
- return blockedFaultStrings.some(msg => msg.test(fault.faultstring)) ||
101
- blockedExceptions.some(exception => Object.hasOwnProperty.call(details, exception))
102
- } catch (e) {
103
- // some other error which is never blocked
104
- return false
105
- }
106
- }
107
-
108
- /**
109
- * This function creates a SOAP client for the specified service type.
110
- * @param {string} type The name of the service type.
111
- * @returns {Promise<Object>} The SOAP client.
112
- */
113
- async function createClientAsync (type) {
114
- const startMark = `${type}-start`
115
- const endMark = `${type}-end`
116
- performance.mark(startMark)
117
- const endpoint = `${provisioningUrl}/webservices/${type}`
118
- const url = `${endpoint}/?wsdl`
119
- const client = await SOAP.createClientAsync(url, {
120
- endpoint,
121
- suppressStack: true,
122
- wsdl_options: {
123
- forever: true
124
- },
125
- gzip: true
126
- })
127
-
128
- // https://stackoverflow.com/questions/30740415/namespace-for-array-field-in-node-soap-client-node-js
129
- client.wsdl.definitions.xmlns.ns1 = 'http://dataobjects.soap.admin.openexchange.com/xsd'
130
- client.wsdl.xmlnsInEnvelope = client.wsdl._xmlnsMap()
131
- performance.mark(endMark)
132
- performance.measure(` ⏱ SOAP: ${type} -> createClientAsync`, startMark, endMark)
133
-
134
- // This proxy effectively adds error handling, authentication and performance measurements to all methods of the SOAP client.
135
- return new Proxy(client, {
136
- get (target, prop, receiver) {
137
- const origMethod = Reflect.get(target, prop, receiver)
138
- if (typeof origMethod === 'function') {
139
- return async function (options, clientOptions, ...args) {
140
- const startMark = `${prop}-start`
141
- const endMark = `${prop}-end`
142
- performance.mark(startMark)
143
- const soapOptions = { ...provisioningAuth, ...options }
144
- if (soapOptions.auth) {
145
- // only send login and password instead of complete admin object.
146
- // this can fail because of ambiguous namespacing
147
- soapOptions.auth = { login: soapOptions.auth.login, password: soapOptions.auth.password }
148
- }
149
-
150
- const result = await (await pRetry)(() => origMethod.apply(this, [soapOptions, { timeout: 10000, ...clientOptions }, ...args]), {
151
- retries: 3,
152
- onFailedAttempt: async error => {
153
- if (shouldAbortRetry(error)) throw new (await AbortError)(error)
154
- console.log(`Attempt ${error.attemptNumber} failed. There are ${error.retriesLeft} retries left.`)
155
- }
156
- }).catch(e => {
157
- const soapError = e?.originalError?.root?.Envelope?.Body?.Fault
158
- throw new Error(soapError?.faultstring || e.message)
159
- })
160
- performance.mark(endMark)
161
- performance.measure(` ⏱ SOAP: ${type} -> ${String(prop)}`, startMark, endMark)
162
- // Return only the first result from the SOAP method call, as we don't need the SOAP envelope and other stuff.
163
- if (!result || !result[0]) return
164
- return result[0]?.return
165
- }
166
- } else {
167
- return origMethod
168
- }
169
- }
170
- })
171
- }
172
-
173
- module.exports = {
174
- createClientAsync,
175
- logSoapError
176
- }