expect-webdriverio 4.0.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/LICENSE +21 -0
- package/README.md +65 -0
- package/jasmine.d.ts +6 -0
- package/jest.d.ts +5 -0
- package/lib/addMatchers.js +48 -0
- package/lib/index.js +6 -0
- package/lib/jasmineUtils.js +205 -0
- package/lib/matchers/browser/toHaveTitle.js +26 -0
- package/lib/matchers/browser/toHaveTitleContaining.js +15 -0
- package/lib/matchers/browser/toHaveUrl.js +26 -0
- package/lib/matchers/browser/toHaveUrlContaining.js +15 -0
- package/lib/matchers/element/toBeClickable.js +23 -0
- package/lib/matchers/element/toBeDisabled.js +16 -0
- package/lib/matchers/element/toBeDisplayed.js +23 -0
- package/lib/matchers/element/toBeDisplayedInViewport.js +23 -0
- package/lib/matchers/element/toBeEnabled.js +16 -0
- package/lib/matchers/element/toBeExisting.js +32 -0
- package/lib/matchers/element/toBeFocused.js +16 -0
- package/lib/matchers/element/toBeSelected.js +22 -0
- package/lib/matchers/element/toHaveAttribute.js +72 -0
- package/lib/matchers/element/toHaveAttributeContaining.js +16 -0
- package/lib/matchers/element/toHaveChildren.js +51 -0
- package/lib/matchers/element/toHaveElementClass.js +60 -0
- package/lib/matchers/element/toHaveElementClassContaining.js +20 -0
- package/lib/matchers/element/toHaveElementProperty.js +52 -0
- package/lib/matchers/element/toHaveHref.js +14 -0
- package/lib/matchers/element/toHaveHrefContaining.js +16 -0
- package/lib/matchers/element/toHaveId.js +13 -0
- package/lib/matchers/element/toHaveStyle.js +33 -0
- package/lib/matchers/element/toHaveText.js +37 -0
- package/lib/matchers/element/toHaveTextContaining.js +15 -0
- package/lib/matchers/element/toHaveValue.js +13 -0
- package/lib/matchers/element/toHaveValueContaining.js +15 -0
- package/lib/matchers/elements/toBeElementsArrayOfSize.js +39 -0
- package/lib/matchers/mock/toBeRequested.js +12 -0
- package/lib/matchers/mock/toBeRequestedTimes.js +35 -0
- package/lib/matchers/mock/toBeRequestedWith.js +218 -0
- package/lib/matchers/mock/toBeRequestedWithResponse.js +13 -0
- package/lib/matchers.js +41 -0
- package/lib/options.js +33 -0
- package/lib/util/elementsUtil.js +28 -0
- package/lib/util/executeCommand.js +31 -0
- package/lib/util/expectAdapter.js +41 -0
- package/lib/util/formatMessage.js +93 -0
- package/lib/util/refetchElements.js +15 -0
- package/lib/utils.js +161 -0
- package/package.json +68 -0
- package/types/expect-webdriverio.d.ts +327 -0
- package/types/jest-global.d.ts +9 -0
- package/types/standalone-global.d.ts +9 -0
- package/types/standalone.d.ts +24 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toBeRequestedWith = exports.toBeRequestedWithFn = void 0;
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
const expectAdapter_1 = require("../../util/expectAdapter");
|
|
6
|
+
const jasmineUtils_1 = require("../../jasmineUtils");
|
|
7
|
+
const STR_LIMIT = 80;
|
|
8
|
+
const KEY_LIMIT = 12;
|
|
9
|
+
function toBeRequestedWithFn(received, requestedWith = {}, options = {}) {
|
|
10
|
+
const isNot = this.isNot || false;
|
|
11
|
+
const { expectation = 'called with', verb = 'be' } = this;
|
|
12
|
+
return browser.call(async () => {
|
|
13
|
+
let actual;
|
|
14
|
+
const pass = await utils_1.waitUntil(async () => {
|
|
15
|
+
for (const call of received.calls) {
|
|
16
|
+
actual = call;
|
|
17
|
+
if (methodMatcher(call.method, requestedWith.method) &&
|
|
18
|
+
statusCodeMatcher(call.statusCode, requestedWith.statusCode) &&
|
|
19
|
+
urlMatcher(call.url, requestedWith.url) &&
|
|
20
|
+
headersMatcher(call.headers, requestedWith.requestHeaders) &&
|
|
21
|
+
headersMatcher(call.responseHeaders, requestedWith.responseHeaders) &&
|
|
22
|
+
bodyMatcher(call.postData, requestedWith.postData) &&
|
|
23
|
+
bodyMatcher(call.body, requestedWith.response)) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}, isNot, { ...options, wait: isNot ? 0 : options.wait });
|
|
29
|
+
const message = utils_1.enhanceError('mock', minifyRequestedWith(requestedWith), minifyRequestMock(actual, requestedWith) || 'was not called', this, verb, expectation, '', options);
|
|
30
|
+
return {
|
|
31
|
+
pass,
|
|
32
|
+
message: () => message,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
exports.toBeRequestedWithFn = toBeRequestedWithFn;
|
|
37
|
+
const methodMatcher = (method, expected) => {
|
|
38
|
+
if (typeof expected === 'undefined') {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
if (!Array.isArray(expected)) {
|
|
42
|
+
expected = [expected];
|
|
43
|
+
}
|
|
44
|
+
return expected
|
|
45
|
+
.map((m) => {
|
|
46
|
+
if (typeof m !== 'string') {
|
|
47
|
+
return console.error('expect.toBeRequestedWith: unsupported value passed to method ' + m);
|
|
48
|
+
}
|
|
49
|
+
return m.toUpperCase();
|
|
50
|
+
})
|
|
51
|
+
.includes(method);
|
|
52
|
+
};
|
|
53
|
+
const statusCodeMatcher = (statusCode, expected) => {
|
|
54
|
+
if (typeof expected === 'undefined') {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
if (!Array.isArray(expected)) {
|
|
58
|
+
expected = [expected];
|
|
59
|
+
}
|
|
60
|
+
return expected.includes(statusCode);
|
|
61
|
+
};
|
|
62
|
+
const urlMatcher = (url, expected) => {
|
|
63
|
+
if (typeof expected === 'undefined') {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
if (typeof expected === 'function') {
|
|
67
|
+
return expected(url);
|
|
68
|
+
}
|
|
69
|
+
return jasmineUtils_1.equals(url, expected);
|
|
70
|
+
};
|
|
71
|
+
const headersMatcher = (headers, expected) => {
|
|
72
|
+
if (typeof expected === 'undefined') {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
if (typeof expected === 'function') {
|
|
76
|
+
return expected(headers);
|
|
77
|
+
}
|
|
78
|
+
return jasmineUtils_1.equals(headers, expected);
|
|
79
|
+
};
|
|
80
|
+
const bodyMatcher = (body, expected) => {
|
|
81
|
+
if (typeof expected === 'undefined') {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
if (typeof expected === 'function') {
|
|
85
|
+
return expected(body);
|
|
86
|
+
}
|
|
87
|
+
if (typeof body === 'undefined') {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
let parsedBody = body;
|
|
91
|
+
if (body instanceof Buffer) {
|
|
92
|
+
parsedBody = body.toString();
|
|
93
|
+
}
|
|
94
|
+
if (typeof (body) === 'string' && isExpectedJsonLike(expected)) {
|
|
95
|
+
parsedBody = tryParseBody(body);
|
|
96
|
+
if (parsedBody === null) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return jasmineUtils_1.equals(parsedBody, expected);
|
|
101
|
+
};
|
|
102
|
+
const isExpectedJsonLike = (expected) => {
|
|
103
|
+
if (typeof expected === 'undefined') {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const actualSample = isMatcher(expected)
|
|
107
|
+
? expected.sample
|
|
108
|
+
: expected;
|
|
109
|
+
return (Array.isArray(actualSample) ||
|
|
110
|
+
(typeof actualSample === 'object' &&
|
|
111
|
+
actualSample !== null &&
|
|
112
|
+
actualSample instanceof RegExp === false));
|
|
113
|
+
};
|
|
114
|
+
const isMatcher = (filter) => {
|
|
115
|
+
var _a;
|
|
116
|
+
return typeof ((_a = filter.__proto__) === null || _a === void 0 ? void 0 : _a.asymmetricMatch) === 'function';
|
|
117
|
+
};
|
|
118
|
+
const tryParseBody = (jsonString, fallback = null) => {
|
|
119
|
+
try {
|
|
120
|
+
return typeof jsonString === 'undefined' ? fallback : JSON.parse(jsonString);
|
|
121
|
+
}
|
|
122
|
+
catch (_a) {
|
|
123
|
+
return fallback;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const minifyRequestMock = (requestMock, requestedWith) => {
|
|
127
|
+
if (typeof requestMock === 'undefined') {
|
|
128
|
+
return requestMock;
|
|
129
|
+
}
|
|
130
|
+
const r = {
|
|
131
|
+
url: requestMock.url,
|
|
132
|
+
method: requestMock.method,
|
|
133
|
+
requestHeaders: requestMock.headers,
|
|
134
|
+
responseHeaders: requestMock.responseHeaders,
|
|
135
|
+
postData: typeof requestMock.postData === 'string' && isExpectedJsonLike(requestedWith.postData)
|
|
136
|
+
? tryParseBody(requestMock.postData, requestMock.postData)
|
|
137
|
+
: requestMock.postData,
|
|
138
|
+
response: typeof requestMock.body === 'string' && isExpectedJsonLike(requestedWith.response)
|
|
139
|
+
? tryParseBody(requestMock.body, requestMock.body)
|
|
140
|
+
: requestMock.body,
|
|
141
|
+
};
|
|
142
|
+
deleteUndefinedValues(r, requestedWith);
|
|
143
|
+
return minifyRequestedWith(r);
|
|
144
|
+
};
|
|
145
|
+
const minifyRequestedWith = (r) => {
|
|
146
|
+
const result = {
|
|
147
|
+
url: requestedWithParamToString(r.url),
|
|
148
|
+
method: r.method,
|
|
149
|
+
requestHeaders: requestedWithParamToString(r.requestHeaders, shortenJson),
|
|
150
|
+
responseHeaders: requestedWithParamToString(r.responseHeaders, shortenJson),
|
|
151
|
+
postData: requestedWithParamToString(r.postData, shortenJson),
|
|
152
|
+
response: requestedWithParamToString(r.response, shortenJson),
|
|
153
|
+
};
|
|
154
|
+
deleteUndefinedValues(result);
|
|
155
|
+
return result;
|
|
156
|
+
};
|
|
157
|
+
const requestedWithParamToString = (param, transformFn) => {
|
|
158
|
+
if (typeof param === 'undefined') {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (typeof param === 'function') {
|
|
162
|
+
param = param.toString();
|
|
163
|
+
}
|
|
164
|
+
else if (isMatcher(param)) {
|
|
165
|
+
return (param.constructor.name +
|
|
166
|
+
' ' +
|
|
167
|
+
(JSON.stringify(param.sample) || ''));
|
|
168
|
+
}
|
|
169
|
+
else if (transformFn && typeof param === 'object' && param !== null) {
|
|
170
|
+
param = transformFn(param);
|
|
171
|
+
}
|
|
172
|
+
if (typeof param === 'string') {
|
|
173
|
+
param = shortenString(param);
|
|
174
|
+
}
|
|
175
|
+
return param;
|
|
176
|
+
};
|
|
177
|
+
const shortenJson = (obj, lengthLimit = STR_LIMIT * 2, keyLimit = KEY_LIMIT) => {
|
|
178
|
+
if (JSON.stringify(obj).length < lengthLimit) {
|
|
179
|
+
return obj;
|
|
180
|
+
}
|
|
181
|
+
if (Array.isArray(obj)) {
|
|
182
|
+
const firstItem = typeof obj[0] === 'object' && obj[0] !== null
|
|
183
|
+
? shortenJson(obj[0], lengthLimit / 2, keyLimit / 4)
|
|
184
|
+
: shortenString(JSON.stringify(obj[0]));
|
|
185
|
+
return [firstItem, `... ${obj.length - 1} more items`];
|
|
186
|
+
}
|
|
187
|
+
const minifiedObject = {};
|
|
188
|
+
const entries = Object.entries(obj);
|
|
189
|
+
if (keyLimit >= 4) {
|
|
190
|
+
entries.slice(0, keyLimit).forEach(([k, v]) => {
|
|
191
|
+
if (typeof v === 'object' && v !== null) {
|
|
192
|
+
v = shortenJson(v, lengthLimit / 2, keyLimit / 4);
|
|
193
|
+
}
|
|
194
|
+
else if (typeof v === 'string') {
|
|
195
|
+
v = shortenString(v, 16);
|
|
196
|
+
}
|
|
197
|
+
minifiedObject[shortenString(k, 24)] = v;
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
if (entries.length > keyLimit) {
|
|
201
|
+
minifiedObject['...'] = `${entries.length} items in total`;
|
|
202
|
+
}
|
|
203
|
+
return minifiedObject;
|
|
204
|
+
};
|
|
205
|
+
const shortenString = (str, limit = STR_LIMIT) => {
|
|
206
|
+
return str.length > limit ? str.substring(0, limit / 2 - 1) + '..' + str.substr(1 - limit / 2) : str;
|
|
207
|
+
};
|
|
208
|
+
const deleteUndefinedValues = (obj, baseline = obj) => {
|
|
209
|
+
Object.keys(obj).forEach((k) => {
|
|
210
|
+
if (typeof baseline[k] === 'undefined') {
|
|
211
|
+
delete obj[k];
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
function toBeRequestedWith(...args) {
|
|
216
|
+
return expectAdapter_1.runExpect.call(this, toBeRequestedWithFn, args);
|
|
217
|
+
}
|
|
218
|
+
exports.toBeRequestedWith = toBeRequestedWith;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toBeRequestedWithResponse = void 0;
|
|
4
|
+
const toBeRequestedWith_1 = require("./toBeRequestedWith");
|
|
5
|
+
const expectAdapter_1 = require("../../util/expectAdapter");
|
|
6
|
+
function toBeRequestedWithResponseFn(received, response, options = {}) {
|
|
7
|
+
return toBeRequestedWith_1.toBeRequestedWithFn.call(this, received, { response }, options);
|
|
8
|
+
}
|
|
9
|
+
function toBeRequestedWithResponse(...args) {
|
|
10
|
+
console.warn('expect(...).toBeRequestedWithResponse is deprecated and will be removed in next release. Use toBeRequestedWith instead.');
|
|
11
|
+
return expectAdapter_1.runExpect.call(this, toBeRequestedWithResponseFn, args);
|
|
12
|
+
}
|
|
13
|
+
exports.toBeRequestedWithResponse = toBeRequestedWithResponse;
|
package/lib/matchers.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const matchers = {
|
|
4
|
+
...require('./matchers/browser/toHaveTitle'),
|
|
5
|
+
...require('./matchers/browser/toHaveTitleContaining'),
|
|
6
|
+
...require('./matchers/browser/toHaveUrl'),
|
|
7
|
+
...require('./matchers/browser/toHaveUrlContaining'),
|
|
8
|
+
...require('./matchers/elements/toBeElementsArrayOfSize'),
|
|
9
|
+
...require('./matchers/element/toBeClickable'),
|
|
10
|
+
...require('./matchers/element/toBeDisabled'),
|
|
11
|
+
...require('./matchers/element/toBeDisplayed'),
|
|
12
|
+
...require('./matchers/element/toBeDisplayedInViewport'),
|
|
13
|
+
...require('./matchers/element/toBeEnabled'),
|
|
14
|
+
...require('./matchers/element/toBeExisting'),
|
|
15
|
+
...require('./matchers/element/toBeFocused'),
|
|
16
|
+
...require('./matchers/element/toBeSelected'),
|
|
17
|
+
...require('./matchers/element/toHaveAttribute'),
|
|
18
|
+
...require('./matchers/element/toHaveAttributeContaining'),
|
|
19
|
+
...require('./matchers/element/toHaveChildren'),
|
|
20
|
+
...require('./matchers/element/toHaveElementClass'),
|
|
21
|
+
...require('./matchers/element/toHaveElementClassContaining'),
|
|
22
|
+
...require('./matchers/element/toHaveHref'),
|
|
23
|
+
...require('./matchers/element/toHaveHrefContaining'),
|
|
24
|
+
...require('./matchers/element/toHaveId'),
|
|
25
|
+
...require('./matchers/element/toHaveElementProperty'),
|
|
26
|
+
...require('./matchers/element/toHaveText'),
|
|
27
|
+
...require('./matchers/element/toHaveTextContaining'),
|
|
28
|
+
...require('./matchers/element/toHaveValue'),
|
|
29
|
+
...require('./matchers/element/toHaveValueContaining'),
|
|
30
|
+
...require('./matchers/element/toHaveStyle'),
|
|
31
|
+
...require('./matchers/mock/toBeRequested'),
|
|
32
|
+
...require('./matchers/mock/toBeRequestedTimes'),
|
|
33
|
+
...require('./matchers/mock/toBeRequestedWith'),
|
|
34
|
+
...require('./matchers/mock/toBeRequestedWithResponse'),
|
|
35
|
+
};
|
|
36
|
+
Object.keys(matchers).forEach(key => {
|
|
37
|
+
if (key.endsWith('Fn')) {
|
|
38
|
+
delete matchers[key];
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
exports.default = matchers;
|
package/lib/options.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.setDefaultOptions = exports.getConfig = void 0;
|
|
5
|
+
const DEFAULT_OPTIONS = {
|
|
6
|
+
wait: 2000,
|
|
7
|
+
interval: 100,
|
|
8
|
+
};
|
|
9
|
+
let mode = 'jest';
|
|
10
|
+
let expectLib;
|
|
11
|
+
if (global.expectWdio) {
|
|
12
|
+
expectLib = global.expectWdio;
|
|
13
|
+
}
|
|
14
|
+
else if (global.jasmine && !((_a = global.expect) === null || _a === void 0 ? void 0 : _a.extend)) {
|
|
15
|
+
expectLib = global.jasmine;
|
|
16
|
+
mode = 'jasmine';
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
expectLib = global.expect;
|
|
20
|
+
}
|
|
21
|
+
if (!expectLib._expectWebdriverio) {
|
|
22
|
+
expectLib._expectWebdriverio = { options: { ...DEFAULT_OPTIONS }, mode };
|
|
23
|
+
}
|
|
24
|
+
const getConfig = () => expectLib._expectWebdriverio;
|
|
25
|
+
exports.getConfig = getConfig;
|
|
26
|
+
const setDefaultOptions = (options = {}) => {
|
|
27
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
28
|
+
if (key in DEFAULT_OPTIONS) {
|
|
29
|
+
expectLib._expectWebdriverio.options[key] = value;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
exports.setDefaultOptions = setDefaultOptions;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.updateElementsArray = exports.wrapExpectedWithArray = void 0;
|
|
4
|
+
const wrapExpectedWithArray = (el, actual, expected) => {
|
|
5
|
+
if (Array.isArray(el) && el.length > 1 && Array.isArray(actual)) {
|
|
6
|
+
expected = [expected];
|
|
7
|
+
}
|
|
8
|
+
return expected;
|
|
9
|
+
};
|
|
10
|
+
exports.wrapExpectedWithArray = wrapExpectedWithArray;
|
|
11
|
+
const updateElementsArray = (success, received, refetched, full = false) => {
|
|
12
|
+
if (!success) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (Array.isArray(received) && Array.isArray(refetched)) {
|
|
16
|
+
if (full === true) {
|
|
17
|
+
while (received.length > 0) {
|
|
18
|
+
received.pop();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (received.length === 0) {
|
|
22
|
+
for (let i = 0; i < refetched.length; i++) {
|
|
23
|
+
received.push(refetched[i]);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
exports.updateElementsArray = updateElementsArray;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeCommand = void 0;
|
|
4
|
+
const refetchElements_1 = require("./refetchElements");
|
|
5
|
+
async function executeCommand(el, condition, options = {}, params = [], fullRefetch = false) {
|
|
6
|
+
const { isNot = false } = this;
|
|
7
|
+
let elements;
|
|
8
|
+
if (Array.isArray(el)) {
|
|
9
|
+
elements = await refetchElements_1.refetchElements(el, options.wait, fullRefetch);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
elements = [el];
|
|
13
|
+
}
|
|
14
|
+
if (elements.length === 0) {
|
|
15
|
+
return {
|
|
16
|
+
el: elements,
|
|
17
|
+
success: false,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const results = [];
|
|
21
|
+
for (const element of elements) {
|
|
22
|
+
results.push(await condition(element, ...params, options));
|
|
23
|
+
}
|
|
24
|
+
const values = [...new Set(results.filter(result => result.result === isNot).map(result => result.value))];
|
|
25
|
+
return {
|
|
26
|
+
el: Array.isArray(el) ? elements : el,
|
|
27
|
+
success: results.every(result => result.result === true),
|
|
28
|
+
values: values.length > 1 ? values : values[0]
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
exports.executeCommand = executeCommand;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runExpect = exports.runJasmineExpect = exports.jestResultToJasmine = exports.buildJasmineFromJestResult = exports.runJestExpect = exports.getContext = void 0;
|
|
4
|
+
const options_1 = require("../options");
|
|
5
|
+
const config = options_1.getConfig();
|
|
6
|
+
const { mode: MODE } = config;
|
|
7
|
+
const getContext = (context) => global === context ? {} : context || {};
|
|
8
|
+
exports.getContext = getContext;
|
|
9
|
+
function runJestExpect(fn, args) {
|
|
10
|
+
return fn.apply(this, args);
|
|
11
|
+
}
|
|
12
|
+
exports.runJestExpect = runJestExpect;
|
|
13
|
+
const buildJasmineFromJestResult = (result, isNot) => {
|
|
14
|
+
return {
|
|
15
|
+
pass: result.pass !== isNot,
|
|
16
|
+
message: result.message()
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
exports.buildJasmineFromJestResult = buildJasmineFromJestResult;
|
|
20
|
+
const jestResultToJasmine = (result, isNot) => {
|
|
21
|
+
if (result instanceof Promise) {
|
|
22
|
+
return result.then(jestStyleResult => exports.buildJasmineFromJestResult(jestStyleResult, isNot));
|
|
23
|
+
}
|
|
24
|
+
return exports.buildJasmineFromJestResult(result, isNot);
|
|
25
|
+
};
|
|
26
|
+
exports.jestResultToJasmine = jestResultToJasmine;
|
|
27
|
+
function runJasmineExpect(fn) {
|
|
28
|
+
const context = exports.getContext(this);
|
|
29
|
+
return {
|
|
30
|
+
compare(...args) {
|
|
31
|
+
const result = fn.apply({ ...context, isNot: false }, args);
|
|
32
|
+
return exports.jestResultToJasmine(result, false);
|
|
33
|
+
},
|
|
34
|
+
negativeCompare(...args) {
|
|
35
|
+
const result = fn.apply({ ...context, isNot: true }, args);
|
|
36
|
+
return exports.jestResultToJasmine(result, true);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
exports.runJasmineExpect = runJasmineExpect;
|
|
41
|
+
exports.runExpect = MODE === 'jasmine' ? runJasmineExpect : runJestExpect;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.numberError = exports.enhanceErrorBe = exports.enhanceError = exports.not = exports.getSelectors = exports.getSelector = void 0;
|
|
4
|
+
const jest_matcher_utils_1 = require("jest-matcher-utils");
|
|
5
|
+
const jasmineUtils_1 = require("../jasmineUtils");
|
|
6
|
+
const EXPECTED_LABEL = 'Expected';
|
|
7
|
+
const RECEIVED_LABEL = 'Received';
|
|
8
|
+
const NOT_SUFFIX = ' [not]';
|
|
9
|
+
const NOT_EXPECTED_LABEL = EXPECTED_LABEL + NOT_SUFFIX;
|
|
10
|
+
const getSelector = (el) => {
|
|
11
|
+
let result = typeof el.selector === 'string' ? el.selector : '<fn>';
|
|
12
|
+
if (Array.isArray(el) && el.props.length > 0) {
|
|
13
|
+
result += ', <props>';
|
|
14
|
+
}
|
|
15
|
+
return result;
|
|
16
|
+
};
|
|
17
|
+
exports.getSelector = getSelector;
|
|
18
|
+
const getSelectors = (el) => {
|
|
19
|
+
const selectors = [];
|
|
20
|
+
let parent;
|
|
21
|
+
if (Array.isArray(el)) {
|
|
22
|
+
selectors.push(`${el.foundWith}(\`${exports.getSelector(el)}\`)`);
|
|
23
|
+
parent = el.parent;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
parent = el;
|
|
27
|
+
}
|
|
28
|
+
while (parent && 'selector' in parent) {
|
|
29
|
+
const selector = exports.getSelector(parent);
|
|
30
|
+
const index = parent.index ? `[${parent.index}]` : '';
|
|
31
|
+
selectors.push(`${parent.index ? '$' : ''}$(\`${selector}\`)${index}`);
|
|
32
|
+
parent = parent.parent;
|
|
33
|
+
}
|
|
34
|
+
return selectors.reverse().join('.');
|
|
35
|
+
};
|
|
36
|
+
exports.getSelectors = getSelectors;
|
|
37
|
+
const not = (isNot) => {
|
|
38
|
+
return `${isNot ? 'not ' : ''}`;
|
|
39
|
+
};
|
|
40
|
+
exports.not = not;
|
|
41
|
+
const enhanceError = (subject, expected, actual, context, verb, expectation, arg2 = '', { message = '', containing = false }) => {
|
|
42
|
+
const { isNot = false } = context;
|
|
43
|
+
subject = typeof subject === 'string' ? subject : exports.getSelectors(subject);
|
|
44
|
+
let contain = '';
|
|
45
|
+
if (containing) {
|
|
46
|
+
contain = ' containing';
|
|
47
|
+
}
|
|
48
|
+
if (verb) {
|
|
49
|
+
verb += ' ';
|
|
50
|
+
}
|
|
51
|
+
let diffString;
|
|
52
|
+
if (isNot && jasmineUtils_1.equals(actual, expected)) {
|
|
53
|
+
diffString = `${EXPECTED_LABEL}: ${jest_matcher_utils_1.printExpected(expected)}\n` +
|
|
54
|
+
`${RECEIVED_LABEL}: ${jest_matcher_utils_1.printReceived(actual)}`;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
diffString = jest_matcher_utils_1.printDiffOrStringify(expected, actual, EXPECTED_LABEL, RECEIVED_LABEL, true);
|
|
58
|
+
}
|
|
59
|
+
if (isNot) {
|
|
60
|
+
diffString = diffString
|
|
61
|
+
.replace(EXPECTED_LABEL, NOT_EXPECTED_LABEL)
|
|
62
|
+
.replace(RECEIVED_LABEL, RECEIVED_LABEL + ' '.repeat(NOT_SUFFIX.length));
|
|
63
|
+
}
|
|
64
|
+
if (message) {
|
|
65
|
+
message += '\n';
|
|
66
|
+
}
|
|
67
|
+
if (arg2) {
|
|
68
|
+
arg2 = ` ${arg2}`;
|
|
69
|
+
}
|
|
70
|
+
const msg = `${message}Expect ${subject} ${exports.not(isNot)}to ${verb}${expectation}${arg2}${contain}\n\n${diffString}`;
|
|
71
|
+
return msg;
|
|
72
|
+
};
|
|
73
|
+
exports.enhanceError = enhanceError;
|
|
74
|
+
const enhanceErrorBe = (subject, pass, context, verb, expectation, options) => {
|
|
75
|
+
return exports.enhanceError(subject, exports.not(context.isNot) + expectation, exports.not(!pass) + expectation, context, verb, expectation, '', options);
|
|
76
|
+
};
|
|
77
|
+
exports.enhanceErrorBe = enhanceErrorBe;
|
|
78
|
+
const numberError = (options = {}) => {
|
|
79
|
+
if (options.eq) {
|
|
80
|
+
return options.eq;
|
|
81
|
+
}
|
|
82
|
+
if (options.gte && options.lte) {
|
|
83
|
+
return `>= ${options.gte} && <= ${options.lte}`;
|
|
84
|
+
}
|
|
85
|
+
if (options.gte) {
|
|
86
|
+
return `>= ${options.gte}`;
|
|
87
|
+
}
|
|
88
|
+
if (options.lte) {
|
|
89
|
+
return ` <= ${options.lte}`;
|
|
90
|
+
}
|
|
91
|
+
return "no params";
|
|
92
|
+
};
|
|
93
|
+
exports.numberError = numberError;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.refetchElements = void 0;
|
|
4
|
+
const options_1 = require("../options");
|
|
5
|
+
const config = options_1.getConfig();
|
|
6
|
+
const { options: DEFAULT_OPTIONS } = config;
|
|
7
|
+
const refetchElements = async (elements, wait = DEFAULT_OPTIONS.wait, full = false) => {
|
|
8
|
+
if (elements) {
|
|
9
|
+
if (wait > 0 && (elements.length === 0 || full)) {
|
|
10
|
+
elements = await elements.parent[elements.foundWith](elements.selector, ...elements.props);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return elements;
|
|
14
|
+
};
|
|
15
|
+
exports.refetchElements = refetchElements;
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.aliasFn = exports.compareNumbers = exports.waitUntil = exports.executeCommandBe = exports.executeCommand = exports.numberError = exports.enhanceError = exports.wrapExpectedWithArray = exports.updateElementsArray = exports.compareStyle = exports.compareTextWithArray = exports.compareText = void 0;
|
|
4
|
+
const options_1 = require("./options");
|
|
5
|
+
const executeCommand_1 = require("./util/executeCommand");
|
|
6
|
+
Object.defineProperty(exports, "executeCommand", { enumerable: true, get: function () { return executeCommand_1.executeCommand; } });
|
|
7
|
+
const elementsUtil_1 = require("./util/elementsUtil");
|
|
8
|
+
Object.defineProperty(exports, "wrapExpectedWithArray", { enumerable: true, get: function () { return elementsUtil_1.wrapExpectedWithArray; } });
|
|
9
|
+
Object.defineProperty(exports, "updateElementsArray", { enumerable: true, get: function () { return elementsUtil_1.updateElementsArray; } });
|
|
10
|
+
const formatMessage_1 = require("./util/formatMessage");
|
|
11
|
+
Object.defineProperty(exports, "enhanceError", { enumerable: true, get: function () { return formatMessage_1.enhanceError; } });
|
|
12
|
+
Object.defineProperty(exports, "numberError", { enumerable: true, get: function () { return formatMessage_1.numberError; } });
|
|
13
|
+
const expectAdapter_1 = require("./util/expectAdapter");
|
|
14
|
+
const config = options_1.getConfig();
|
|
15
|
+
const { options: DEFAULT_OPTIONS } = config;
|
|
16
|
+
const waitUntil = async (condition, isNot = false, { wait = DEFAULT_OPTIONS.wait, interval = DEFAULT_OPTIONS.interval } = {}) => {
|
|
17
|
+
if (wait === 0) {
|
|
18
|
+
return await condition();
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
let error;
|
|
22
|
+
await browser.waitUntil(async () => {
|
|
23
|
+
error = undefined;
|
|
24
|
+
try {
|
|
25
|
+
return isNot !== await condition();
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
error = err;
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}, {
|
|
32
|
+
timeout: wait,
|
|
33
|
+
interval
|
|
34
|
+
});
|
|
35
|
+
if (error) {
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
return !isNot;
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
return isNot;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
exports.waitUntil = waitUntil;
|
|
45
|
+
async function executeCommandBe(received, command, options) {
|
|
46
|
+
const { isNot, expectation, verb = 'be' } = this;
|
|
47
|
+
received = await received;
|
|
48
|
+
let el = received;
|
|
49
|
+
const pass = await waitUntil(async () => {
|
|
50
|
+
const result = await executeCommand_1.executeCommand.call(this, el, async (element) => ({ result: await command(element) }), options);
|
|
51
|
+
el = result.el;
|
|
52
|
+
return result.success;
|
|
53
|
+
}, isNot, options);
|
|
54
|
+
elementsUtil_1.updateElementsArray(pass, received, el);
|
|
55
|
+
const message = formatMessage_1.enhanceErrorBe(el, pass, this, verb, expectation, options);
|
|
56
|
+
return {
|
|
57
|
+
pass,
|
|
58
|
+
message: () => message
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
exports.executeCommandBe = executeCommandBe;
|
|
62
|
+
const compareNumbers = (actual, options = {}) => {
|
|
63
|
+
if (typeof options.eq === 'number') {
|
|
64
|
+
return actual === options.eq;
|
|
65
|
+
}
|
|
66
|
+
if (typeof options.gte === 'number' && typeof options.lte === 'number') {
|
|
67
|
+
return actual >= options.gte && actual <= options.lte;
|
|
68
|
+
}
|
|
69
|
+
if (typeof options.gte === 'number') {
|
|
70
|
+
return actual >= options.gte;
|
|
71
|
+
}
|
|
72
|
+
if (typeof options.lte === 'number') {
|
|
73
|
+
return actual <= options.lte;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
};
|
|
77
|
+
exports.compareNumbers = compareNumbers;
|
|
78
|
+
const compareText = (actual, expected, { ignoreCase = false, trim = true, containing = false }) => {
|
|
79
|
+
if (typeof actual !== 'string') {
|
|
80
|
+
return {
|
|
81
|
+
value: actual,
|
|
82
|
+
result: false
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (trim) {
|
|
86
|
+
actual = actual.trim();
|
|
87
|
+
}
|
|
88
|
+
if (ignoreCase) {
|
|
89
|
+
actual = actual.toLowerCase();
|
|
90
|
+
expected = expected.toLowerCase();
|
|
91
|
+
}
|
|
92
|
+
if (containing) {
|
|
93
|
+
return {
|
|
94
|
+
value: actual,
|
|
95
|
+
result: actual.includes(expected)
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
value: actual,
|
|
100
|
+
result: actual === expected
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
exports.compareText = compareText;
|
|
104
|
+
const compareTextWithArray = (actual, expectedArray, { ignoreCase = false, trim = false, containing = false }) => {
|
|
105
|
+
if (typeof actual !== 'string') {
|
|
106
|
+
return {
|
|
107
|
+
value: actual,
|
|
108
|
+
result: false
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (trim) {
|
|
112
|
+
actual = actual.trim();
|
|
113
|
+
}
|
|
114
|
+
if (ignoreCase) {
|
|
115
|
+
actual = actual.toLowerCase();
|
|
116
|
+
expectedArray = expectedArray.map(item => item.toLowerCase());
|
|
117
|
+
}
|
|
118
|
+
if (containing) {
|
|
119
|
+
const textInArray = expectedArray.some((t) => actual.includes(t));
|
|
120
|
+
return {
|
|
121
|
+
value: actual,
|
|
122
|
+
result: textInArray
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
value: actual,
|
|
127
|
+
result: expectedArray.includes(actual)
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
exports.compareTextWithArray = compareTextWithArray;
|
|
131
|
+
const compareStyle = async (actualEl, style, { ignoreCase = true, trim = false }) => {
|
|
132
|
+
let result = true;
|
|
133
|
+
const actual = {};
|
|
134
|
+
for (const key in style) {
|
|
135
|
+
const css = await actualEl.getCSSProperty(key);
|
|
136
|
+
let actualVal = css.value;
|
|
137
|
+
let expectedVal = style[key];
|
|
138
|
+
if (trim) {
|
|
139
|
+
actualVal = actualVal.trim();
|
|
140
|
+
expectedVal = expectedVal.trim();
|
|
141
|
+
}
|
|
142
|
+
if (ignoreCase) {
|
|
143
|
+
actualVal = actualVal.toLowerCase();
|
|
144
|
+
expectedVal = expectedVal.toLowerCase();
|
|
145
|
+
}
|
|
146
|
+
result = result && actualVal === expectedVal;
|
|
147
|
+
actual[key] = css.value;
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
value: actual,
|
|
151
|
+
result
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
exports.compareStyle = compareStyle;
|
|
155
|
+
function aliasFn(fn, { verb, expectation } = {}, ...args) {
|
|
156
|
+
const context = expectAdapter_1.getContext(this);
|
|
157
|
+
context.verb = verb;
|
|
158
|
+
context.expectation = expectation;
|
|
159
|
+
return fn.apply(context, args);
|
|
160
|
+
}
|
|
161
|
+
exports.aliasFn = aliasFn;
|