@applitools/eyes-cypress 3.25.7 → 3.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@
7
7
 
8
8
 
9
9
 
10
+
11
+ ## 3.26.0 - 2022/5/19
12
+
13
+ ### Features
14
+ - `cy.eyesCheckWindow` now supports passing DOM elements and jQuery object for target and regions.
15
+ ### Bug fixes
16
+ - Support `cy.eyesGetAllTestResults` in TypeScript
17
+
10
18
  ## 3.25.7 - 2022/5/6
11
19
 
12
20
  ### Features
package/README.md CHANGED
@@ -255,7 +255,7 @@ cy.eyesCheckWindow({ tag: 'Login screen', target: 'your target' })
255
255
  <br/> 1. `window`
256
256
  This is the default value. If set then the captured image is of the entire page or the viewport, use [`fully`](#fully) for specifying what `window` mode to use.
257
257
  <br/>2. `region`
258
- If set then the captured image is of the parts of the page, use this parameter with [`region`](#region) or [`selector`](#selector) for specifying the areas to captured.
258
+ If set then the captured image is of the parts of the page, use this parameter with [`region`](#region), [`selector`](#selector), or [`element`](#element) for specifying the areas to captured.
259
259
 
260
260
  ##### `fully`
261
261
 
@@ -310,18 +310,72 @@ cy.eyesCheckWindow({ tag: 'Login screen', target: 'your target' })
310
310
  });
311
311
  ```
312
312
 
313
+ ##### `element`
314
+
315
+ (optional): In case [`target`](#target) is `region`, this should be an instance of either an HTML element or a jQuery object. For example:
316
+
317
+ ```js
318
+ // passing a jQuery object
319
+ cy.get('body > div > h1')
320
+ .then($el => {
321
+ cy.eyesCheckWindow({
322
+ target: 'region',
323
+ element: $el
324
+ })
325
+ })
326
+
327
+ // passing an HTML element
328
+ cy.document()
329
+ .then(doc => {
330
+ const el = document.querySelector('div')
331
+ cy.eyesCheckWindow({
332
+ target: 'region',
333
+ element: el
334
+ })
335
+ })
336
+ ```
337
+
313
338
  ##### `ignore`
314
339
 
315
340
  (optional): A single or an array of regions to ignore when checking for visual differences. For example:
316
341
 
317
- ```js
342
+ ```js
343
+ // ignore region by coordinates
344
+ cy.eyesCheckWindow({
345
+ ignore: {top: 100, left: 0, width: 1000, height: 100},
346
+ });
347
+
348
+ // ignore regions by selector
349
+ cy.eyesCheckWindow({
350
+ ignore: {selector: '.some-div-to-ignore'} // all elements matching this selector would become ignore regions
351
+ });
352
+
353
+ // ignore regions by jQuery or DOM elements
354
+ cy.get('.some-div-to-ignore').then($el => {
355
+ cy.eyesCheckWindow({
356
+ ignore: $el
357
+ });
358
+ })
359
+
360
+ // mix multiple ignore regions with different methods
361
+ cy.eyesCheckWindow({
362
+ ignore: [
363
+ {top: 100, left: 0, width: 1000, height: 100},
364
+ {selector: '.some-div-to-ignore'}
365
+ ]
366
+ });
367
+
368
+ // mix multiple ignore regions with different methods including element
369
+ cy.get('.some-div-to-ignore').then($el => {
318
370
  cy.eyesCheckWindow({
319
371
  ignore: [
320
372
  {top: 100, left: 0, width: 1000, height: 100},
321
373
  {selector: '.some-div-to-ignore'}
374
+ $el
322
375
  ]
323
376
  });
324
- ```
377
+ })
378
+ ```
325
379
 
326
380
  ##### `floating`
327
381
 
@@ -334,6 +388,15 @@ cy.eyesCheckWindow({
334
388
  {selector: '.some-div-to-float', maxUpOffset: 20, maxDownOffset: 20, maxLeftOffset: 20, maxRightOffset: 20}
335
389
  ]
336
390
  });
391
+
392
+ // use jQuery or DOM elements
393
+ cy.get('.some-div-to-float').then($el => {
394
+ cy.eyesCheckWindow({
395
+ floating: [
396
+ {element: $el, maxUpOffset: 20, maxDownOffset: 20, maxLeftOffset: 20, maxRightOffset: 20},
397
+ ]
398
+ })
399
+ })
337
400
  ```
338
401
 
339
402
  ##### `layout`
@@ -347,6 +410,13 @@ cy.eyesCheckWindow({
347
410
  {selector: '.some-div-to-test-as-layout'}
348
411
  ]
349
412
  });
413
+
414
+ // use jQuery or DOM elements
415
+ cy.get('.some-div-to-test-as-layout').then($el => {
416
+ cy.eyesCheckWindow({
417
+ layout: $el
418
+ });
419
+ })
350
420
  ```
351
421
 
352
422
  ##### `strict`
@@ -360,6 +430,13 @@ cy.eyesCheckWindow({
360
430
  {selector: '.some-div-to-test-as-strict'}
361
431
  ]
362
432
  });
433
+
434
+ // use jQuery or DOM elements
435
+ cy.get('.some-div-to-test-as-strict').then($el => {
436
+ cy.eyesCheckWindow({
437
+ strict: $el
438
+ });
439
+ })
363
440
  ```
364
441
 
365
442
  ##### `content`
@@ -373,6 +450,13 @@ cy.eyesCheckWindow({
373
450
  {selector: '.some-div-to-test-as-content'}
374
451
  ]
375
452
  });
453
+
454
+ // use jQuery or DOM elements
455
+ cy.get('.some-div-to-test-as-content').then($el => {
456
+ cy.eyesCheckWindow({
457
+ content: $el
458
+ });
459
+ })
376
460
  ```
377
461
 
378
462
  ##### `accessibility`
@@ -387,6 +471,16 @@ cy.eyesCheckWindow({
387
471
  {accessibilityType: 'BoldText', top: 100, left: 0, width: 1000, height: 100},
388
472
  ]
389
473
  });
474
+
475
+ // use jQuery or DOM elements
476
+ cy.get('.some-div').then($el => {
477
+ cy.eyesCheckWindow({
478
+ accessibility: [
479
+ {accessibilityType: 'RegularText', element: $el},
480
+ ]
481
+ });
482
+ })
483
+
390
484
  ```
391
485
 
392
486
  Possible accessibilityType values are: `IgnoreContrast`,`RegularText`,`LargeText`,`BoldText` and `GraphicalObject`.
@@ -43,7 +43,7 @@ async function makeHandler({ port = 31077, singleton = true, lazy = false } = {}
43
43
  exports.makeHandler = makeHandler;
44
44
  async function isHandshakable(port) {
45
45
  return new Promise(resolve => {
46
- const handshake = http_1.request(`http://localhost:${port}/handshake`, {
46
+ const handshake = (0, http_1.request)(`http://localhost:${port}/handshake`, {
47
47
  headers: { [TOKEN_HEADER]: TOKEN },
48
48
  });
49
49
  handshake.on('response', ({ statusCode, headers }) => {
package/eyes-index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  /// <reference types="Cypress" />
2
2
  /// <reference types="@applitools/visual-grid-client" />
3
+ import {TestResultsSummary} from '@applitools/eyes-api';
3
4
 
4
- declare namespace Cypress {
5
+ declare global {
6
+ namespace Cypress {
5
7
  interface Chainable {
6
8
  /**
7
9
  * Create an Applitools test.
@@ -30,5 +32,17 @@ declare namespace Cypress {
30
32
  * @example cy.eyesClose()
31
33
  */
32
34
  eyesClose(): null
35
+
36
+ /**
37
+ * Returns an object with the applitools test results from a given test / test file. This should be called after close.
38
+ * @example
39
+ * after(() => {
40
+ * cy.eyesGetAllTestResults().then(summary => {
41
+ * console.log(summary)
42
+ * })
43
+ * })
44
+ */
45
+ eyesGetAllTestResults(): Chainable<TestResultsSummary>
33
46
  }
34
47
  }
48
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/eyes-cypress",
3
- "version": "3.25.7",
3
+ "version": "3.26.0",
4
4
  "main": "index.js",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "bin": {
@@ -12,8 +12,11 @@
12
12
  "test:unit": "mocha --no-timeouts 'test/unit/**/*.test.js'",
13
13
  "test:it": "mocha --no-timeouts 'test/it/**/*.test.js'",
14
14
  "test:e2e": "mkdir -p test/fixtures/testAppCopies && mocha --no-timeouts 'test/e2e/**/*.test.js'",
15
+ "test:ts:compile": "tsc --project test/e2e/ts/cypress",
16
+ "test:ts:run": "cypress run --config-file test/e2e/ts/cypress-ts.json",
17
+ "test:ts": "yarn test:ts:compile && yarn test:ts:run",
15
18
  "lint": "eslint \"**/*.js\"",
16
- "test": "yarn test:unit && yarn test:it && yarn test:e2e && yarn test:coverage",
19
+ "test": "yarn test:unit && yarn test:it && yarn test:e2e && yarn test:ts && yarn test:coverage",
17
20
  "cypress": "cypress open --config-file test/fixtures/cypress-play.json",
18
21
  "cypress:new": "node_modules/cypress-new/bin/cypress open --config-file test/fixtures/cypress-play.json",
19
22
  "cypress:run": "cypress run --config-file test/fixtures/cypress-play.json --spec=test/fixtures/testApp/cypress/integration-play/play.js",
@@ -46,11 +49,11 @@
46
49
  },
47
50
  "dependencies": {
48
51
  "@applitools/dom-snapshot": "4.5.12",
49
- "@applitools/eyes-api": "1.3.1",
50
- "@applitools/eyes-universal": "2.5.1",
52
+ "@applitools/eyes-api": "1.4.1",
53
+ "@applitools/eyes-universal": "2.5.15",
51
54
  "@applitools/functional-commons": "1.6.0",
52
- "@applitools/logger": "1.1.2",
53
- "@applitools/visual-grid-client": "15.12.13",
55
+ "@applitools/logger": "1.1.5",
56
+ "@applitools/visual-grid-client": "15.12.28",
54
57
  "body-parser": "1.19.0",
55
58
  "chalk": "3.0.0",
56
59
  "cors": "2.8.5",
@@ -60,14 +63,14 @@
60
63
  "ws": "8.5.0"
61
64
  },
62
65
  "devDependencies": {
63
- "@applitools/bongo": "^2.0.3",
66
+ "@applitools/bongo": "^2.1.0",
64
67
  "@applitools/scripts": "1.1.0",
65
68
  "@applitools/sdk-coverage-tests": "^2.3.18",
66
69
  "@applitools/snaptdout": "1.0.1",
67
70
  "@applitools/test-server": "1.0.8",
68
71
  "@applitools/test-utils": "1.3.2",
69
- "@applitools/types": "^1.4.2",
70
- "@applitools/utils": "1.2.14",
72
+ "@applitools/types": "^1.4.3",
73
+ "@applitools/utils": "1.3.0",
71
74
  "@types/node": "17.0.13",
72
75
  "@types/ws": "^8.2.2",
73
76
  "@typescript-eslint/eslint-plugin": "^5.10.2",
@@ -88,7 +91,7 @@
88
91
  "ncp": "2.0.0",
89
92
  "node-fetch": "2.6.0",
90
93
  "prettier": "1.19.1",
91
- "typescript": "3.9.2"
94
+ "typescript": "4.6.4"
92
95
  },
93
96
  "husky": {
94
97
  "hooks": {
@@ -7,7 +7,6 @@ const {socketCommands} = require('./socketCommands');
7
7
  const {eyesOpenMapValues} = require('./eyesOpenMapping');
8
8
  const {eyesCheckMapValues} = require('./eyesCheckMapping');
9
9
  const {TestResultsSummary} = require('@applitools/eyes-api');
10
-
11
10
  const refer = new Refer(value => {
12
11
  if (!value || !value.constructor || !value.constructor.name) return false;
13
12
  const name = value.constructor.name;
@@ -148,7 +147,7 @@ Cypress.Commands.add('eyesOpen', function(args = {}) {
148
147
  });
149
148
  });
150
149
 
151
- Cypress.Commands.add('eyesCheckWindow', args =>
150
+ Cypress.Commands.add('eyesCheckWindow', (args = {}) =>
152
151
  cy.then({timeout: 86400000}, () => {
153
152
  if (isCurrentTestDisabled) return;
154
153
 
@@ -156,7 +155,7 @@ Cypress.Commands.add('eyesCheckWindow', args =>
156
155
 
157
156
  Cypress.log({name: 'Eyes: check window'});
158
157
 
159
- const checkSettings = eyesCheckMapValues({args});
158
+ const checkSettings = eyesCheckMapValues({args, refer});
160
159
 
161
160
  return socket.request('Eyes.check', {
162
161
  eyes,
@@ -1,8 +1,6 @@
1
- function eyesCheckMapValues({args}) {
2
- return toCheckWindowConfiguration(args);
3
- }
4
-
5
- function toCheckWindowConfiguration(config = {}) {
1
+ /* global Node */
2
+ function eyesCheckMapValues({args, refer}) {
3
+ const config = args; // just did it for having less git changes at this moment
6
4
  const mappedValues = [
7
5
  'tag',
8
6
  'scriptHooks',
@@ -21,17 +19,28 @@ function toCheckWindowConfiguration(config = {}) {
21
19
  const checkSettings = {
22
20
  name: config.tag,
23
21
  hooks: config.scriptHooks,
24
- ignoreRegions: config.ignore,
22
+ ignoreRegions: refElements(config.ignore),
25
23
  floatingRegions: convertFloatingRegion(config.floating),
26
- strictRegions: config.strict,
27
- layoutRegions: config.layout,
28
- contentRegions: config.content,
24
+ strictRegions: refElements(config.strict),
25
+ layoutRegions: refElements(config.layout),
26
+ contentRegions: refElements(config.content),
29
27
  accessibilityRegions: convertAccessabilityRegions(config.accessibility),
30
28
  };
31
29
 
32
30
  if (config.target === 'region') {
33
31
  if (!Array.isArray(config.selector)) {
34
- if (!config.hasOwnProperty('selector')) {
32
+ if (config.element) {
33
+ if (isHTMLElement(config.element)) {
34
+ regionSettings = {
35
+ region: refer.ref(config.element),
36
+ };
37
+ } else {
38
+ // JQuery element
39
+ regionSettings = {
40
+ region: refer.ref(config.element[0]),
41
+ };
42
+ }
43
+ } else if (!config.hasOwnProperty('selector')) {
35
44
  regionSettings = {
36
45
  region: config.region,
37
46
  };
@@ -66,39 +75,97 @@ function toCheckWindowConfiguration(config = {}) {
66
75
  }
67
76
 
68
77
  return Object.assign({}, checkSettings, regionSettings, config);
69
- }
70
78
 
71
- function convertAccessabilityRegions(accessibilityRegions) {
72
- if (!accessibilityRegions) return accessibilityRegions;
79
+ // #region helper functions
73
80
 
74
- return accessibilityRegions.map(region => ({
75
- region: region.selector,
76
- type: region.accessibilityType,
77
- }));
78
- }
81
+ function convertAccessabilityRegions(accessibilityRegions) {
82
+ if (!accessibilityRegions) return accessibilityRegions;
83
+ const accessibility = [];
84
+
85
+ accessibilityRegions.map(region => {
86
+ const accessabilityRegion = {
87
+ type: region.accessibilityType,
88
+ };
89
+ if (region.hasOwnProperty('selector')) {
90
+ accessabilityRegion.region = region.selector;
91
+ accessibility.push(accessabilityRegion);
92
+ } else if (region.hasOwnProperty('element')) {
93
+ const elements = refElements(region.element);
94
+ for (const element of elements) {
95
+ accessibility.push(Object.assign({}, accessabilityRegion, {region: element}));
96
+ }
97
+ } else {
98
+ accessabilityRegion.region = {
99
+ top: region.top,
100
+ left: region.left,
101
+ width: region.width,
102
+ height: region.height,
103
+ };
104
+ accessibility.push(accessabilityRegion);
105
+ }
106
+ });
79
107
 
80
- function convertFloatingRegion(floatingRegions) {
81
- if (!floatingRegions) return floatingRegions;
108
+ return accessibility;
109
+ }
82
110
 
83
- return floatingRegions.map(region => {
84
- const floatingRegion = {
85
- maxDownOffset: region.maxDownOffset || 0,
86
- maxLeftOffset: region.maxLeftOffset || 0,
87
- maxUpOffset: region.maxUpOffset || 0,
88
- maxRightOffset: region.maxRightOffset || 0,
89
- };
90
- if (region.hasOwnProperty('selector')) {
91
- floatingRegion.region = region.selector;
92
- } else {
93
- floatingRegion.region = {
94
- top: region.top,
95
- left: region.left,
96
- width: region.width,
97
- height: region.height,
111
+ function convertFloatingRegion(floatingRegions) {
112
+ if (!floatingRegions) return floatingRegions;
113
+ const floating = [];
114
+
115
+ for (const region of floatingRegions) {
116
+ const floatingRegion = {
117
+ maxDownOffset: region.maxDownOffset || 0,
118
+ maxLeftOffset: region.maxLeftOffset || 0,
119
+ maxUpOffset: region.maxUpOffset || 0,
120
+ maxRightOffset: region.maxRightOffset || 0,
98
121
  };
122
+ if (region.hasOwnProperty('selector')) {
123
+ floatingRegion.region = region.selector;
124
+ floating.push(floatingRegion);
125
+ } else if (region.hasOwnProperty('element')) {
126
+ const elements = refElements(region.element);
127
+ for (const element of elements) {
128
+ floating.push(Object.assign({}, floatingRegion, {region: element}));
129
+ }
130
+ } else {
131
+ floatingRegion.region = {
132
+ top: region.top,
133
+ left: region.left,
134
+ width: region.width,
135
+ height: region.height,
136
+ };
137
+ floating.push(floatingRegion);
138
+ }
139
+ }
140
+ return floating;
141
+ }
142
+
143
+ function refElements(regions) {
144
+ if (!regions) return regions;
145
+ if (!Array.isArray(regions)) regions = [regions];
146
+ const elements = [];
147
+ for (const region of regions) {
148
+ if (isHTMLElement(region)) {
149
+ elements.push(refer.ref(region));
150
+ } else if (region.jquery) {
151
+ region.each(function() {
152
+ // there's a small chance that `this` is not an HTML element. So we just verify it.
153
+ elements.push(isHTMLElement(this) ? refer.ref(this) : this);
154
+ });
155
+ } else {
156
+ elements.push(region);
157
+ }
99
158
  }
100
- return floatingRegion;
101
- });
159
+ return elements;
160
+ }
161
+
162
+ // #endregion
163
+ }
164
+
165
+ function isHTMLElement(element) {
166
+ // Avoiding instanceof here since the element might come from an iframe, and `instanceof HTMLElement` would fail.
167
+ // This check looks naive, but if anyone passes something like {nodeType: 1} as a region, then I'm fine with them crashing :)
168
+ return element.nodeType && element.nodeType === Node.ELEMENT_NODE;
102
169
  }
103
170
 
104
171
  module.exports = {eyesCheckMapValues};