@onehat/ui 0.3.283 → 0.3.284

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.
@@ -0,0 +1,269 @@
1
+ import {
2
+ fixInflector,
3
+ getLastPartOfPath,
4
+ } from './utilities';
5
+ import {
6
+ getDomNode,
7
+ getDomNodes,
8
+ } from './dom_functions';
9
+ import Inflector from 'inflector-js';
10
+ import _ from 'lodash';
11
+ const $ = Cypress.$;
12
+
13
+
14
+
15
+ // Get rows
16
+ export function hasRowWithFieldValue(gridSelector, field, value) {
17
+ return getDomNodes([gridSelector, 'row', 'cell-' + field]).contains(value);
18
+ }
19
+ export function getRowWithFieldValue(gridSelector, field, value) {
20
+ return getDomNodes([gridSelector, 'row', 'cell-' + field]).contains(value).then((cells) => {
21
+ if (!cells.length) {
22
+ return null;
23
+ }
24
+
25
+ const cell = cells[0];
26
+ return $(cell).closest('[data-testid="row"]')[0];
27
+ });
28
+ }
29
+ // export function getRowWithText(grid, text) {
30
+ // return getRows(grid).contains(text);
31
+ // }
32
+ // export function getRowWithId(grid, id) {
33
+ // return getRows(grid, '[data-cy-recordid=' + id + ']');
34
+ // }
35
+ // export function getRowWithIx(grid, ix) {
36
+ // return getRows(grid, '[data-recordindex=' + ix + ']');
37
+ // }
38
+
39
+
40
+ // Select rows
41
+ export function selectGridRowById(gridSelector, id) {
42
+ cy.then(() => {
43
+ Cypress.log({ name: 'selectGridRowById ' + gridSelector + ' ' + id});
44
+ });
45
+ const rowSelector = getGridRowSelectorById(gridSelector, id);
46
+ getDomNode([gridSelector, rowSelector])
47
+ .click();
48
+ }
49
+ export function selectGridRowIfNotAlreadySelectedById(gridSelector, id) {
50
+ cy.then(() => {
51
+ Cypress.log({ name: 'selectGridRowIfNotAlreadySelectedById ' + gridSelector + ' ' + id});
52
+ });
53
+ const rowSelector = getGridRowSelectorById(gridSelector, id);
54
+ getDomNode([gridSelector, rowSelector]).then((row) => {
55
+ const found = row.find('[data-testid="row-selected"]')
56
+ if (!found.length) {
57
+ selectGridRowById(gridSelector, id);
58
+ }
59
+ })
60
+ }
61
+ // export function selectRowWithText(grid, text) {
62
+ // getRowWithText(grid, text).click(5, 5);
63
+ // }
64
+ // export function selectRowWithIx(grid, ix) {
65
+ // getRowWithIx(grid, ix).click(5, 5);
66
+ // }
67
+ // export function cmdClickRowWithId(grid, id) {
68
+ // getRowWithId(grid, id).click('left', { metaKey: true });
69
+ // }
70
+
71
+
72
+ // // Double-click rows
73
+ // export function doubleClickRowWithText(grid, text) {
74
+ // getRowWithText(grid, text).dblclick();
75
+ // }
76
+ // export function doubleClickRowWithId(grid, id) {
77
+ // getRowWithId(grid, id).dblclick();
78
+ // }
79
+ // export function doubleClickRowWithIx(grid, ix) {
80
+ // getRowWithIx(grid, ix).dblclick();
81
+ // }
82
+
83
+
84
+ export function verifyGridRecordDoesNotExistByValue(gridSelector, fieldValues, schema) {
85
+ const
86
+ field = schema.model.displayProperty,
87
+ value = fieldValues[field];
88
+
89
+ getDomNodes([gridSelector, 'row', 'cell-' + field])
90
+ .contains(value, { timeout: 500 })
91
+ .should('not.exist');
92
+ }
93
+ export function verifyGridRecordExistsByValue(gridSelector, fieldValues, schema) {
94
+ const
95
+ field = schema.model.displayProperty,
96
+ value = fieldValues[field];
97
+
98
+ getDomNodes([gridSelector, 'row', 'cell-' + field])
99
+ .contains(value, { timeout: 500 })
100
+ .should('exist');
101
+ }
102
+ export function verifyGridRecordExistsById(gridSelector, id) {
103
+ cy.then(() => {
104
+ Cypress.log({ name: 'verifyGridRecordExistsById ' + gridSelector + ' ' + id });
105
+ });
106
+
107
+ const rowSelector = getGridRowSelectorById(gridSelector, id);
108
+ getDomNodes([gridSelector, rowSelector])
109
+ .should('exist');
110
+ }
111
+ export function verifyGridRecordDoesNotExistById(gridSelector, id) {
112
+ cy.then(() => {
113
+ Cypress.log({ name: 'verifyGridRecordDoesNotExistById ' + gridSelector + ' ' + id });
114
+ });
115
+ const rowSelector = getGridRowSelectorById(gridSelector, id);
116
+ getDomNodes([gridSelector, rowSelector])
117
+ .should('not.exist');
118
+ }
119
+ export function verifyGridRowIsSelectedById(gridSelector, id) {
120
+ cy.then(() => {
121
+ Cypress.log({ name: 'verifyGridRowIsSelectedById ' + gridSelector + ' ' + id});
122
+ });
123
+ const rowSelector = getGridRowSelectorById(gridSelector, id);
124
+ getDomNodes([gridSelector, rowSelector, 'row-selected'])
125
+ .should('exist');
126
+ }
127
+
128
+
129
+
130
+
131
+
132
+ // export function addRecordWithInlineEditor(grid, fieldValues, schema) {
133
+ // clickGridAddButton(grid, true);
134
+ // fillInlineForm(grid, fieldValues, schema);
135
+ // cy.route('POST', '**/extAdd**').as('addWaiter');
136
+ // submitInlineForm(grid);
137
+ // cy.wait('@addWaiter');
138
+ // verifyNoErrorBox();
139
+ // getSelectedRowId(grid); // Adds @id alias
140
+ // cy.wait(1000);
141
+ // }
142
+ // export function addRecordWithWindowedEditor(grid, editorCls, fieldValues, schema) {
143
+ // clickGridAddButton(grid, true);
144
+ // fillWindowedForm(editorCls, fieldValues, schema);
145
+ // cy.route('POST', '**/extAdd**').as('addWaiter');
146
+ // submitWindowedForm(editorCls);
147
+ // cy.wait('@addWaiter');
148
+ // verifyNoErrorBox();
149
+ // getSelectedRowId(grid); // Adds @id alias
150
+ // cy.wait(1000);
151
+ // }
152
+ // export function editRecordWithInlineEditor(grid, fieldValues, schema) {
153
+ // cy.get("@id").then((id) => {
154
+ // doubleClickRowWithId(grid, id);
155
+ // fillInlineForm(grid, fieldValues, schema);
156
+ // cy.route('POST', '**/extEdit**').as('editWaiter');
157
+ // submitInlineForm(grid);
158
+ // cy.wait('@editWaiter');
159
+ // verifyNoErrorBox();
160
+ // cy.wait(500);
161
+ // });
162
+ // }
163
+ // export function editRecordWithWindowedEditor(grid, editorCls, fieldValues, schema) {
164
+ // cy.get("@id").then((id) => {
165
+ // doubleClickRowWithId(grid, id);
166
+ // fillWindowedForm(editorCls, fieldValues, schema);
167
+ // cy.route('POST', '**/extEdit**').as('editWaiter');
168
+ // submitWindowedForm(editorCls);
169
+ // cy.wait('@editWaiter');
170
+ // verifyNoErrorBox();
171
+ // });
172
+ // }
173
+ // export function removeRecord(grid) {
174
+ // cy.get("@id").then((id) => {
175
+ // cy.wait(500);
176
+ // clickGridRemoveButton(grid);
177
+ // cy.route('POST', '**/extDelete**').as('removeWaiter');
178
+ // clickMessageBoxDefaultButton();
179
+ // cy.wait('@removeWaiter');
180
+ // verifyNoErrorBox();
181
+ // });
182
+ // }
183
+
184
+
185
+ // Grid Utilities
186
+ export function getModelFromGridName(gridName) {
187
+ // try to match with something like 'EquipmentFilteredGridEditor'
188
+ const
189
+ pattern = '^' + // start
190
+ '([\\w]+?)' + // model name
191
+ '(?=Filtered|Inline|Side|Grid)' + // positive lookahead to guarantee one of these is the next word
192
+ '(Filtered)?' + // optional
193
+ '(Inline)?' + // optional
194
+ '(Side)?' + // optional
195
+ 'Grid' + // required
196
+ '(Editor)?' + // optional
197
+ '(Side[AB])?' + // optional
198
+ '$', // end
199
+ regex = new RegExp(pattern),
200
+ match = gridName.match(regex);
201
+ return match?.length ? match[1] : null;
202
+ }
203
+ export function getModelFromGridPath(gridPath) {
204
+ // try to match with something like '...__eq_manufacturer_id/grid'
205
+ let
206
+ pattern = '^' + // start
207
+ '.*' + // previous selector path (ignore)
208
+ '(?=__)' + // positive lookahead to guarantee '__' is the next word
209
+ '__' + // required
210
+ '([A-Za-z_]+)' + // field name (model name underscored, singularized)
211
+ '([\\d]+)?' + // optional (digit, e.g. eq_engine_model1_id)
212
+ '_id/(combo/)?grid' + // required
213
+ '$', // end
214
+ regex = new RegExp(pattern),
215
+ match = gridPath.match(regex);
216
+ if (!match) {
217
+ // try to match with something like '.../work_orders__equipment/combo/grid"'
218
+ pattern = '^' + // start
219
+ '.*' + // previous selector path (ignore)
220
+ '(?=__)' + // positive lookahead to guarantee '__' is the next word
221
+ '__' + // required
222
+ '([A-Za-z_]+)' + // field name (model name underscored, pluralized)
223
+ '/(combo/)?grid' + // required
224
+ '$', // end
225
+ regex = new RegExp(pattern);
226
+ match = gridPath.match(regex);
227
+ }
228
+ return match?.length ? match[1] : null;
229
+ }
230
+ export function getModelFromGridSelector(gridSelector) {
231
+ const gridName = getLastPartOfPath(gridSelector);
232
+ let model = getModelFromGridName(gridName);
233
+ if (!model) {
234
+ model = getModelFromGridPath(gridSelector);
235
+ if (model) {
236
+ model = fixInflector(Inflector.camelize(Inflector.pluralize(model)));
237
+ }
238
+ }
239
+ return model;
240
+ }
241
+ export function getGridRowSelectorById(gridSelector, id) {
242
+ const
243
+ model = getModelFromGridSelector(gridSelector);
244
+
245
+ if (!model) {
246
+ debugger;
247
+ }
248
+ const inflected = fixInflector(Inflector.camelize(Inflector.pluralize(model)));
249
+ return inflected + '-' + id;
250
+ }
251
+
252
+
253
+
254
+ // function fillInlineForm(grid, fieldValues, schema) {
255
+ // getInlineEditor(grid)
256
+ // .then((editor) => {
257
+ // fillForm(editor, fieldValues, schema);
258
+ // });
259
+ // }
260
+ // function submitInlineForm(grid) {
261
+ // cy.wait(1000);
262
+ // getInlineEditorButtons(grid)
263
+ // .filter('.x-row-editor-update-button')
264
+ // // .then((el) => {
265
+ // // cy.get(el[0]).click();
266
+ // // // el[0].click();
267
+ // // });
268
+ // .click({ force: true });
269
+ // }
@@ -0,0 +1,19 @@
1
+ import * as ButtonFunctions from './button_functions.js';
2
+ import * as CommonFunctions from './common_functions.js';
3
+ import * as CrudFunctions from './crud_functions.js';
4
+ import * as DomFunctions from './dom_functions.js';
5
+ import * as FormFunctions from './form_functions.js';
6
+ import * as GridFunctions from './grid_functions.js';
7
+ import * as NavigationFunctions from './navigation_functions.js';
8
+ import * as Utilities from './utilities.js';
9
+
10
+ export default {
11
+ ...ButtonFunctions,
12
+ ...CommonFunctions,
13
+ ...CrudFunctions,
14
+ ...DomFunctions,
15
+ ...FormFunctions,
16
+ ...GridFunctions,
17
+ ...NavigationFunctions,
18
+ ...Utilities,
19
+ };
@@ -0,0 +1,77 @@
1
+ import {
2
+ DOMAIN,
3
+ LOGIN_ID_FIELD,
4
+ SUPER_USER,
5
+ SUPER_EMAIL,
6
+ SUPER_PASSWORD,
7
+ } from './constants';
8
+ import {
9
+ getDomNode,
10
+ getDomNodes,
11
+ } from './dom_functions';
12
+
13
+
14
+ // __ _
15
+ // / / ____ ____ _(_)___
16
+ // / / / __ \/ __ `/ / __ \
17
+ // / /___/ /_/ / /_/ / / / / /
18
+ // /_____/\____/\__, /_/_/ /_/
19
+ // /____/
20
+
21
+ export function login(user, password) {
22
+ cy.visit(Cypress.env('baseUrl') + 'login')
23
+ .then(() => {
24
+ getDomNode(LOGIN_ID_FIELD).clear();
25
+ getDomNode(LOGIN_ID_FIELD).type(user);
26
+
27
+ getDomNode('password').clear();
28
+ getDomNode('password').type(password);
29
+
30
+ getDomNode('loginBtn').click();
31
+ cy.url().should('include', 'home');
32
+ });
33
+ }
34
+ export function loginAsSuper() {
35
+ return login(LOGIN_ID_FIELD === 'username' ? SUPER_USER : SUPER_EMAIL, SUPER_PASSWORD);
36
+ }
37
+ export function logout() {
38
+ getDomNode('/logout').click({ force: true });
39
+ }
40
+
41
+
42
+ // _ __ _ __ _
43
+ // / | / /___ __ __(_)___ _____ _/ /_(_)___ ____
44
+ // / |/ / __ `/ | / / / __ `/ __ `/ __/ / __ \/ __ \
45
+ // / /| / /_/ /| |/ / / /_/ / /_/ / /_/ / /_/ / / / /
46
+ // /_/ |_/\__,_/ |___/_/\__, /\__,_/\__/_/\____/_/ /_/
47
+ // /____/
48
+
49
+ export function navigateViaTabOrHomeButtonTo(url) {
50
+ // i.e. If we're on home screen, press the button.
51
+ // If we have a tab navigation, press the tab's button
52
+ getDomNode(url).click(); // i.e. the DomNode's data-testid is the url
53
+ cy.url().should('include', url);
54
+ }
55
+ export function navigateToHome() {
56
+ navigateToScreen('/home');
57
+ }
58
+ export function navigateToScreen(path) {
59
+ cy.visit(DOMAIN + path)
60
+ .then(() => {
61
+ cy.url().should('include', path);
62
+ });
63
+ }
64
+ // export function selectMainTab(name) {
65
+ // cy.get('.mainTabPanel .x-tab')
66
+ // .contains(name)
67
+ // .first()
68
+ // .click();
69
+ // cy.wait(1000); // Time to render new tab
70
+ // }
71
+ // export function selectSecondaryTab(name) {
72
+ // cy.get('.mainTabPanel > .x-panel-bodyWrap > .x-panel-body .x-tab')
73
+ // .contains(name)
74
+ // .first()
75
+ // .click();
76
+ // cy.wait(1000); // Time to render new tab
77
+ // }
@@ -0,0 +1,109 @@
1
+ import moment from 'moment';
2
+
3
+ // __ ____ _ ___ __ _
4
+ // / / / / /_(_) (_) /_(_)__ _____
5
+ // / / / / __/ / / / __/ / _ \/ ___/
6
+ // / /_/ / /_/ / / / /_/ / __(__ )
7
+ // \____/\__/_/_/_/\__/_/\___/____/
8
+
9
+
10
+ export function fixInflector(str) {
11
+ // inflector-js doesn't handle pluralization of 'equipment' correctly
12
+ str = str.replace(/quipments/, 'quipment');
13
+ return str;
14
+ }
15
+ export function getPropertyDefinitionFromSchema(fieldName, schema) {
16
+ return _.find(schema.model.properties, { name: fieldName });
17
+ }
18
+ export function getLastPartOfPath(path) {
19
+ return path.split('/').pop();
20
+ }
21
+ export function unescapeHtml(html) {
22
+ const el = document.createElement('div');
23
+ return html.replace(/\&[#0-9a-z]+;/gi, function (enc) {
24
+ el.innerHTML = enc;
25
+ return el.innerText
26
+ });
27
+ }
28
+
29
+ /**
30
+ * Given a URL query string,
31
+ * return an object with keyed properties
32
+ * @param {string} urlString
33
+ * @return {object} keyed properties
34
+ */
35
+ export function extractKeysValuesFromQueryString(urlString) {
36
+ var entries = (new URLSearchParams(urlString)).entries(),
37
+ fv = {},
38
+ entry;
39
+ while(!(entry = entries.next()).done) {
40
+ let [key, val] = entry.value;
41
+ // if (/\[\]$/.test(key)) {
42
+ // key = key.slice(0, -2);
43
+ // }
44
+ if (fv.hasOwnProperty(key)) {
45
+ if (!_.isArray(fv[key])) {
46
+ var tmp = fv[key];
47
+ fv[key] = [];
48
+ fv[key].push(tmp);
49
+ }
50
+ fv[key].push(val);
51
+ } else {
52
+ fv[key] = val;
53
+ }
54
+ }
55
+ return fv;
56
+ }
57
+
58
+ /**
59
+ * JS equivalent of PHP's urlencode
60
+ * https://www.php.net/manual/en/function.urlencode.php
61
+ * Author: http://kevin.vanzonneveld.net
62
+ * @param {string} string to encode
63
+ */
64
+ export function urlencode(str) {
65
+ // Note: Tilde should be allowed unescaped in future versions of PHP (as reflected below), but if you want to reflect current PHP behavior, you would need to add ".replace(/~/g, '%7E');" to the following.
66
+ return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
67
+ }
68
+
69
+ /**
70
+ * Deep diff between two objects - i.e. an object with the new value of new & changed fields.
71
+ * Removed fields will be set as undefined on the result.
72
+ * Only plain objects will be deeply compared (@see _.isPlainObject)
73
+ *
74
+ * Inspired by: https://gist.github.com/Yimiprod/7ee176597fef230d1451#gistcomment-2565071
75
+ * This fork: https://gist.github.com/TeNNoX/5125ab5770ba287012316dd62231b764/
76
+ *
77
+ * @param {Object} base Object to compare with (if falsy we return object)
78
+ * @param {Object} object Object compared
79
+ * @return {Object} Return a new object who represent the changed & new values
80
+ */
81
+ export function deepDiffObj(base, object) {
82
+ if (!object) throw new Error(`The object compared should be an object: ${object}`);
83
+ if (!base) return object;
84
+ const result = _.transform(object, (result, value, key) => {
85
+ if (!_.has(base, key)) result[key] = value; // fix edge case: not defined to explicitly defined as undefined
86
+ if (!_.isEqual(value, base[key])) {
87
+ result[key] = _.isPlainObject(value) && _.isPlainObject(base[key]) ? deepDiffObj(base[key], value) : value;
88
+ }
89
+ });
90
+ // map removed fields to undefined
91
+ _.forOwn(base, (value, key) => {
92
+ if (!_.has(object, key)) result[key] = undefined;
93
+ });
94
+ return result;
95
+ }
96
+
97
+ export const dates = {
98
+ today: moment().format('YYYY-MM-DD'),
99
+ todayDatetime: moment().format('YYYY-MM-DD HH:mm:ss'),
100
+ yesterday: moment().subtract(1, 'days').format('YYYY-MM-DD'),
101
+ tomorrow: moment().add(1, 'days').format('YYYY-MM-DD'),
102
+ oneMonthAgo: moment().subtract(1, 'months').format('YYYY-MM-DD'),
103
+ oneYearAgo: moment().subtract(1, 'years').format('YYYY-MM-DD'),
104
+ startOfThisMonth: moment().startOf('months').format('YYYY-MM-DD'),
105
+ endOfLastMonth: moment().subtract(1, 'months').endOf('month').format('YYYY-MM-DD'),
106
+ twoMonthsAgo: moment().subtract(2, 'months').format('YYYY-MM-DD'),
107
+ sixMonthsAgo: moment().subtract(6, 'months').format('YYYY-MM-DD'),
108
+ oneMonthFromNow: moment().add(1, 'months').format('YYYY-MM-DD'),
109
+ };