@open-xchange/appsuite-codeceptjs 0.6.11 → 0.6.13

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/index.js CHANGED
@@ -20,6 +20,7 @@
20
20
 
21
21
  require('./src/chai')
22
22
  const { recorder, event: codeceptEvents } = require('codeceptjs')
23
+ const pageobjects = require('@open-xchange/appsuite-codeceptjs-pageobjects')
23
24
 
24
25
  const dotenv = require('dotenv')
25
26
  dotenv.config({ path: ['.env', '.env.defaults'], quiet: true })
@@ -87,25 +88,7 @@ module.exports = {
87
88
  I: '@open-xchange/appsuite-codeceptjs/src/actor',
88
89
  users: '@open-xchange/appsuite-codeceptjs/src/users',
89
90
  contexts: '@open-xchange/appsuite-codeceptjs/src/contexts',
90
- // pageobjects
91
- contacts: '@open-xchange/appsuite-codeceptjs/src/pageobjects/contacts',
92
- calendar: '@open-xchange/appsuite-codeceptjs/src/pageobjects/calendar',
93
- mail: '@open-xchange/appsuite-codeceptjs/src/pageobjects/mail',
94
- drive: '@open-xchange/appsuite-codeceptjs/src/pageobjects/drive',
95
- tasks: '@open-xchange/appsuite-codeceptjs/src/pageobjects/tasks',
96
- // fragments
97
- dialogs: '@open-xchange/appsuite-codeceptjs/src/pageobjects/fragments/dialogs',
98
- autocomplete: '@open-xchange/appsuite-codeceptjs/src/pageobjects/fragments/contact-autocomplete',
99
- contactpicker: '@open-xchange/appsuite-codeceptjs/src/pageobjects/fragments/contact-picker',
100
- mailfilter: '@open-xchange/appsuite-codeceptjs/src/pageobjects/fragments/settings-mailfilter',
101
- search: '@open-xchange/appsuite-codeceptjs/src/pageobjects/fragments/search',
102
- tinymce: '@open-xchange/appsuite-codeceptjs/src/pageobjects/fragments/tinymce',
103
- topbar: '@open-xchange/appsuite-codeceptjs/src/pageobjects/fragments/topbar',
104
- settings: '@open-xchange/appsuite-codeceptjs/src/pageobjects/fragments/settings',
105
- viewer: '@open-xchange/appsuite-codeceptjs/src/pageobjects/fragments/viewer',
106
- mobileCalendar: '@open-xchange/appsuite-codeceptjs/src/pageobjects/mobile/mobileCalendar',
107
- mobileMail: '@open-xchange/appsuite-codeceptjs/src/pageobjects/mobile/mobileMail',
108
- mobileContacts: '@open-xchange/appsuite-codeceptjs/src/pageobjects/mobile/mobileContacts'
91
+ ...pageobjects
109
92
  },
110
93
  async bootstrap () {
111
94
  // set moment defaults
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-xchange/appsuite-codeceptjs",
3
- "version": "0.6.11",
3
+ "version": "0.6.13",
4
4
  "description": "OX App Suite CodeceptJS Configuration and Helpers",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -17,6 +17,7 @@
17
17
  "@axe-core/playwright": "^4.10.2",
18
18
  "@codeceptjs/helper": "^2.0.4",
19
19
  "@influxdata/influxdb-client": "^1.35.0",
20
+ "@open-xchange/appsuite-codeceptjs-pageobjects": "^1.0.0",
20
21
  "@playwright/test": "1.55.1",
21
22
  "allure-codeceptjs": "2.15.1",
22
23
  "chai": "^6.0.0",
@@ -32,8 +33,8 @@
32
33
  "p-retry": "^7.0.0",
33
34
  "playwright-core": "1.55.1",
34
35
  "short-uuid": "^5.2.0",
35
- "@open-xchange/codecept-horizontal-scaler": "0.1.13",
36
- "@open-xchange/soap-client": "0.0.7"
36
+ "@open-xchange/soap-client": "0.0.8",
37
+ "@open-xchange/codecept-horizontal-scaler": "0.1.13"
37
38
  },
38
39
  "devDependencies": {
39
40
  "@types/node": "^24.3.0",
@@ -45,7 +46,6 @@
45
46
  "axios": ">1.12.0"
46
47
  },
47
48
  "scripts": {
48
- "lint": "eslint .",
49
- "test": "mocha --color 'spec/**/*.test.js'"
49
+ "lint": "eslint ."
50
50
  }
51
51
  }
@@ -26,6 +26,12 @@ const { contextService, getFilestorageId } = require('@open-xchange/soap-client/
26
26
  const crypto = require('node:crypto')
27
27
  const codecept = require('codeceptjs')
28
28
 
29
+ let defaultContext
30
+ ;(async () => {
31
+ console.log('Fetching default context')
32
+ defaultContext = await contextService.getDefault()
33
+ })()
34
+
29
35
  class Context {
30
36
  constructor ({ ctxdata, admin, auth }) {
31
37
  this.id = ctxdata.id
@@ -41,7 +47,6 @@ class Context {
41
47
  }
42
48
 
43
49
  async remove () {
44
- const defaultContext = await contextService.getDefault()
45
50
  // do not remove default context
46
51
  if (defaultContext !== undefined && this.ctxdata.id === defaultContext.id) throw new Error('Cannot remove default context')
47
52
  try {
@@ -1,123 +0,0 @@
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
- })
@@ -1,229 +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 { I, contactpicker, autocomplete, dialogs } = inject()
22
- const { getMonday } = require('./util')
23
-
24
- module.exports = {
25
-
26
- editWindow: '.io-ox-calendar-edit-window',
27
- miniCalendar: '.window-sidepanel .date-picker',
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"]',
31
-
32
- async newAppointment () {
33
- I.wait(1)
34
- I.clickPrimary('New appointment')
35
- I.waitForVisible(this.editWindow)
36
- return I.waitForFocus('.io-ox-calendar-edit-window input[type="text"][name="summary"]')
37
- },
38
-
39
- clickAppointment (title, position = 1) {
40
- I.wait(0.5) // wait for rendering
41
- const appointment = locate('.page.current .appointment .title').withText(title).at(position).as('Appointment')
42
- I.waitForElement(appointment)
43
- I.scrollTo(appointment)
44
- I.click(appointment)
45
- },
46
-
47
- getNextMonday () {
48
- return getMonday().add(1, 'week').set('hour', 8)
49
- },
50
-
51
- startNextMonday () {
52
- // use next monday to avoid problems when tests run over the weekend
53
- const date = this.getNextMonday()
54
- I.fillField('Starts on', date.format('L'))
55
- I.clearField('~Start time')
56
- I.fillField('~Start time', '8:00')
57
- return date
58
- },
59
-
60
- moveCalendarViewToNextWeek () {
61
- I.waitForText('Today', undefined, '.calendar-header')
62
- I.click('Today')
63
- I.waitForElement('~Next week')
64
- I.click('~Next week')
65
- // look for proper aria-label
66
- I.waitForElement('~' + this.getNextMonday().format('ddd D') + ', create all-day appointment')
67
- },
68
-
69
- openScheduling () {
70
- I.waitForElement(locate('button').withText('New appointment').as('New appointment'))
71
- I.click('.primary-action button[aria-label="More actions"]')
72
- I.waitForElement('.primary-action .dropdown-menu')
73
- I.click('Scheduling', '.primary-action .dropdown-menu')
74
- },
75
-
76
- recurAppointment (date) {
77
- I.checkOption('Repeat')
78
- if (date) I.see(`Every ${date.format('dddd')}.`)
79
- I.click('.recurrence-view button.summary')
80
- I.waitForElement('.recurrence-view-dialog')
81
- },
82
-
83
- deleteAppointment () {
84
- I.waitForElement('~Delete')
85
- I.click('~Delete', '.detail-popup')
86
- dialogs.waitForVisible()
87
- dialogs.clickButton('Delete')
88
- I.waitForDetached('.modal-dialog')
89
- },
90
-
91
- // attr: [startDate, endDate, until]
92
- setDate (attr, value) {
93
- I.click('~Date (M/D/YYYY)', locate(`[data-attribute="${attr}"]`).as('Date input'))
94
- I.waitForElement('.date-picker.open')
95
- I.click(`.dateinput[data-attribute="${attr}"] .datepicker-day-field`)
96
- I.fillField(`.dateinput[data-attribute="${attr}"] .datepicker-day-field`, value.format('L'))
97
- I.pressKey('Enter')
98
- I.waitForDetached('.date-picker.open')
99
- },
100
-
101
- getDate (attr) {
102
- return I.executeScript(function (attr) {
103
- // fillfield works only for puppeteer, pressKey(11/10....) only for webdriver
104
- // @ts-ignore
105
- return document.querySelector(`.dateinput[data-attribute="${attr}"] .datepicker-day-field`).value
106
- }, attr)
107
- },
108
-
109
- addParticipant (name, exists = true, context) {
110
- if (!context) context = '*'
111
-
112
- // does suggestion exists (for contact, user, ...)
113
- const addParticipantsLocator = locate('.add-participant.tt-input').inside(context).as('Add participant field')
114
- // input field
115
- I.waitForVisible(addParticipantsLocator)
116
- // I.waitForEnabled(addParticipantsLocator)
117
- I.fillField(addParticipantsLocator, name)
118
- I.seeInField(addParticipantsLocator, name)
119
- // tokenfield/typeahead
120
- if (exists) {
121
- autocomplete.select(name, context.replace('.', ''))
122
- } else {
123
- I.pressKey('Enter')
124
- }
125
-
126
- I.waitForInvisible(autocomplete.suggestions)
127
- // note: might be more than one that get's added (group)
128
- },
129
-
130
- async addParticipantByPicker (name) {
131
- I.click('~Select contacts')
132
- await contactpicker.add(name)
133
- contactpicker.close()
134
- I.waitForText(name, undefined, '.attendee-container')
135
- },
136
-
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
- }
145
- I.waitForElement('.page.current .calendar-header > .dropdown button')
146
- I.click('.page.current .calendar-header > .dropdown button')
147
- I.waitForText(view, undefined, '.open .dropdown-menu')
148
- I.click(locate('.dropdown.open a').withText(view).as('Switch to ' + view))
149
- I.waitForVisible(`.io-ox-pagecontroller.page.current[data-page-id="io.ox/calendar/${viewMap[view]}"]`)
150
- },
151
-
152
- getFullname (user) {
153
- return `${user.get('sur_name')}, ${user.get('given_name')}`
154
- },
155
-
156
- async createAppointment ({ subject, location, folder, startDate, startTime, endDate, endTime }) {
157
- // select calendar
158
- if (folder) {
159
- I.selectFolder(folder)
160
- I.waitForElement('li.selected[aria-label^="' + folder + '"] .color-label')
161
- }
162
-
163
- I.clickPrimary('New appointment')
164
- I.waitForVisible(locate('.io-ox-calendar-edit-window').as('Edit Dialog'))
165
- await I.waitForFocus('.io-ox-calendar-edit-window input[type="text"][name="summary"]')
166
-
167
- if (folder) {
168
- I.see(folder, '.io-ox-calendar-edit-window .folder-selection')
169
- }
170
- await within('.io-ox-calendar-edit-window', async () => {
171
- I.fillField('Title', subject)
172
-
173
- if (location) I.fillField('Location', location)
174
-
175
- if (startDate) {
176
- I.click('~Date (M/D/YYYY)')
177
- I.pressKey(['CommandOrControl', 'a'])
178
- I.type(startDate)
179
- I.pressKey('Enter')
180
- }
181
-
182
- if (startTime) {
183
- I.click('~Start time')
184
- I.click(startTime)
185
- }
186
-
187
- if (endDate) {
188
- I.click('~Date (M/D/YYYY)', '.dateinput[data-attribute="endDate"]')
189
- I.pressKey(['CommandOrControl', 'a'])
190
- I.type(endDate)
191
- I.pressKey('Enter')
192
- }
193
-
194
- if (endTime) {
195
- I.click('~End time')
196
- I.click(endTime)
197
- }
198
-
199
- // save
200
- I.click('Create')
201
- })
202
- I.waitForDetached('.io-ox-calendar-edit-window')
203
- },
204
-
205
- // remove previously created appointments by appointment title
206
- async removeAllAppointments (title) {
207
- const { skipRefresh } = await I.executeScript(async function (title) {
208
- const appointments = [...document.querySelectorAll('.appointment')]
209
- .map(el => {
210
- const folder = el.getAttribute('data-folder')
211
- return { folder, id: el.getAttribute('data-cid').replace(folder + '.', '') }
212
- })
213
- if (appointments.length === 0) return { skipRefresh: true }
214
- const { default: api } = await import(String(new URL('io.ox/calendar/api.js', location.href)))
215
- return await api.remove(appointments, {})
216
- }, title)
217
- if (skipRefresh === true) return
218
- I.click('#io-ox-refresh-icon')
219
- I.waitForDetached('#io-ox-refresh-icon .animate-spin')
220
- },
221
-
222
- async setDateTo (dateString) {
223
- await I.executeScript(async function (dateStr) {
224
- const { default: apps } = await import(String(new URL('io.ox/core/api/apps.js', location.href)))
225
- const { moment } = await import(String(new URL('e2e.js', location.href)))
226
- apps.get('io.ox/calendar').setDate(moment(dateStr))
227
- }, dateString)
228
- }
229
- }
@@ -1,149 +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 { I, dialogs } = inject()
22
-
23
- module.exports = {
24
-
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"]',
28
-
29
- selectContact (text) {
30
- I.waitForElement(`.vgrid [aria-label="${text}"]`)
31
- I.click(`.vgrid [aria-label="${text}"]`)
32
- I.waitForElement('.contact-header')
33
- I.waitForText(text, undefined, '.contact-header .fullname')
34
- },
35
-
36
- selectListItem (text, selector = '.last_name') {
37
- I.waitForElement(locate(`.vgrid-cell ${selector}`).withText(text).as(text))
38
- I.click(locate(`.vgrid-cell ${selector}`).withText(text).as(text))
39
- I.waitForElement(locate(`.contact-detail h2 ${selector}`).withText(text).as(text))
40
- I.wait(0.5)
41
- },
42
-
43
- newAddressbook (name) {
44
- I.click('button.contextmenu-control', '~My address books')
45
- I.clickDropdown('Add new address book')
46
- dialogs.waitForVisible()
47
- I.fillField('[placeholder="New address book"][type="text"]', name)
48
- dialogs.clickButton('Add')
49
- I.waitForDetached('.modal-dialog')
50
- },
51
-
52
- newContact () {
53
- I.waitForDetached('.dropdown-toggle.disabled')
54
- I.clickPrimary('New contact')
55
- I.waitForText('Add personal info')
56
- },
57
-
58
- newDistributionlist () {
59
- I.waitForDetached('.dropdown-toggle.disabled')
60
- const button = locate('.primary-action .btn-group').withText('New contact').as('Primary Dropdown Button: New contact')
61
- I.waitForVisible(button)
62
- I.click(locate('.dropdown-toggle').inside(button).as('Dropdown Toggle'))
63
- I.click('New distribution list', '.primary-action .btn-group > .dropdown-menu')
64
- I.waitForText('Participants')
65
- },
66
-
67
- addField (fieldType, field) {
68
- I.click(`.dropdown[data-add="${fieldType}"] button`, '.contact-edit')
69
- I.waitForVisible('.dropdown.open .dropdown-menu')
70
- I.click(field)
71
- I.waitForText(field, 30, '.contact-edit')
72
- },
73
-
74
- editMyAccount () {
75
- I.waitForVisible('.dropdown-toggle[aria-label="My account"]')
76
- I.waitForVisible('.contact-picture')
77
- I.click('.contact-picture')
78
- I.waitForText('Edit personal data', 30, '.dropdown.open .dropdown-menu')
79
- I.click('Edit personal data', '.dropdown.open .dropdown-menu')
80
- I.waitForVisible(this.editWindow)
81
- },
82
-
83
- deleteSelected () {
84
- I.clickToolbar('Delete')
85
- dialogs.waitForVisible()
86
- dialogs.clickButton('Delete')
87
- I.waitForDetached('.modal-dialog')
88
- },
89
-
90
- async hasImage () {
91
- const rule = await I.grabCssPropertyFrom('.contact-header .contact-photo', 'background-image')
92
- expect(rule).to.match(/^url\(/)
93
- },
94
-
95
- importCSV (file, path = 'media/imports/contacts', folder = 'Contacts') {
96
- I.rightClick(`~${folder}`)
97
- I.clickDropdown('Import')
98
- dialogs.waitForVisible()
99
- I.selectOption('Format', 'CSV')
100
- I.attachFile('.file-input', `${path}/${file}.csv`)
101
- dialogs.clickButton('Import')
102
- I.waitForDetached('.modal-dialog')
103
- I.waitForText('Data imported successfully')
104
- },
105
-
106
- importVCF (file, path = 'media/imports/contacts', folder = 'Contacts') {
107
- I.rightClick(`~${folder}`)
108
- I.clickDropdown('Import')
109
- dialogs.waitForVisible()
110
- I.selectOption('Format', 'VCARD')
111
- I.attachFile('.file-input', `${path}/${file}.vcf`)
112
- dialogs.clickButton('Import')
113
- I.waitForDetached('.modal-dialog')
114
- I.waitForText('Data imported successfully')
115
- },
116
-
117
- async exportCSV (file) {
118
- I.clickToolbar('More actions')
119
- I.clickDropdown('Export')
120
- dialogs.waitForVisible()
121
- I.checkOption('CSV')
122
- I.waitForDownload('.modal-dialog button:has-text("Export")', `${file}.csv`)
123
- I.waitForDetached('.modal-dialog')
124
- },
125
- async exportVCF (file) {
126
- I.clickToolbar('More actions')
127
- I.clickDropdown('Export')
128
- dialogs.waitForVisible()
129
- I.checkOption('vCard')
130
- I.waitForDownload('.modal-dialog button:has-text("Export")', `${file}.vcf`)
131
- I.waitForDetached('.modal-dialog')
132
- },
133
- async exportAddressBookCSV (file) {
134
- I.rightClick('~Contacts')
135
- I.clickDropdown('Export')
136
- dialogs.waitForVisible()
137
- I.checkOption('CSV')
138
- I.waitForDownload('.modal-dialog button:has-text("Export")', `${file}.csv`)
139
- I.waitForDetached('.modal-dialog')
140
- },
141
- async exportAddressBookVCF (file) {
142
- I.rightClick('~Contacts')
143
- I.clickDropdown('Export')
144
- dialogs.waitForVisible()
145
- I.checkOption('vCard')
146
- I.waitForDownload('.modal-dialog button:has-text("Export")', `${file}.vcf`)
147
- I.waitForDetached('.modal-dialog')
148
- }
149
- }