@applitools/eyes-cypress 3.30.2 → 3.31.1

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,263 @@
1
+ type MaybeArray<T> = T | T[]
2
+ import type {
3
+ CypressCheckSettings,
4
+ Element,
5
+ Selector,
6
+ LegacyRegion,
7
+ ElementWithOptions,
8
+ EyesSelector,
9
+ SelectorWithOptions,
10
+ FloatingRegion,
11
+ accessibilityRegion,
12
+ } from '../expose'
13
+ import type {CheckSettings, SpecType} from '@applitools/core'
14
+ import * as utils from '@applitools/utils'
15
+ import {transformBrowsers} from './utils'
16
+ type CodedRegion = MaybeArray<Element | Selector | ElementWithOptions | SelectorWithOptions | LegacyRegion | EyesSelector>
17
+ type Ref = {'applitools-ref-id': string}
18
+ type RefRegionWIthOptions = {region: Ref} & {padding?: number | LegacyRegion; regionId?: string}
19
+
20
+ export function transformCypressCheckSettings(settings: CypressCheckSettings, refer: any): CheckSettings<SpecType, 'ufg'> {
21
+ if (utils.types.isString(settings)) {
22
+ return {name: settings}
23
+ }
24
+ const target = settings.target === 'region' ? transformTargetRegion(settings) : undefined
25
+ return {
26
+ renderers: transformBrowsers(settings.browser),
27
+ hooks: settings.scriptHooks,
28
+ disableBrowserFetching: settings.disableBrowserFetching,
29
+ layoutBreakpoints: settings.layoutBreakpoints,
30
+ ufgOptions: settings.visualGridOptions,
31
+ name: settings.tag,
32
+ ignoreRegions: transformRegionsWithOptions(settings.ignore),
33
+ floatingRegions: convertFloatingRegion(settings.floating),
34
+ strictRegions: transformRegionsWithOptions(settings.strict),
35
+ contentRegions: transformRegionsWithOptions(settings.content),
36
+ layoutRegions: transformRegionsWithOptions(settings.layout),
37
+ accessibilityRegions: convertAccessabilityRegions(settings.accessibility),
38
+ userCommandId: settings.variationGroupId,
39
+ region: utils.types.has(target, 'region') ? target.region : undefined,
40
+ ignoreCaret: settings.ignoreCaret,
41
+ ignoreDisplacements: settings.ignoreDisplacements,
42
+ fully: settings.fully,
43
+ waitBeforeCapture: settings.waitBeforeCapture,
44
+ lazyLoad: settings.lazyLoad,
45
+ matchLevel: settings.matchLevel,
46
+ useDom: settings.useDom,
47
+ sendDom: settings.sendDom,
48
+ enablePatterns: settings.enablePatterns,
49
+ pageId: settings.pageId,
50
+ }
51
+
52
+ function transformTargetRegion(checkSettings: CypressCheckSettings): CheckSettings<SpecType, 'ufg'>['region'] {
53
+ const shadowDomSettings: any = {}
54
+ let regionSettings: any = {}
55
+ if (!Array.isArray(checkSettings.selector)) {
56
+ if (utils.types.has(checkSettings, 'element')) {
57
+ if (isHTMLElement(checkSettings.element)) {
58
+ regionSettings = {
59
+ region: Object.assign(refer.ref(checkSettings.element), {type: 'element'}),
60
+ }
61
+ } else if (utils.types.has(checkSettings.element, [0])) {
62
+ // JQuery element
63
+ regionSettings = {
64
+ region: Object.assign(refer.ref(checkSettings.element[0]), {type: 'element'}),
65
+ }
66
+ }
67
+ } else if (
68
+ utils.types.has(checkSettings, 'region') &&
69
+ utils.types.has(checkSettings.region, 'top') &&
70
+ utils.types.has(checkSettings.region, 'left') &&
71
+ utils.types.has(checkSettings.region, 'width') &&
72
+ utils.types.has(checkSettings.region, 'height')
73
+ ) {
74
+ regionSettings = {
75
+ region: {
76
+ y: checkSettings.region.top,
77
+ x: checkSettings.region.left,
78
+ width: checkSettings.region.width,
79
+ height: checkSettings.region.height,
80
+ },
81
+ }
82
+ } else if (!utils.types.has(checkSettings, 'selector')) {
83
+ regionSettings = {
84
+ region: checkSettings.region,
85
+ }
86
+ } else {
87
+ regionSettings = {
88
+ region: checkSettings.selector,
89
+ }
90
+ }
91
+ } else {
92
+ const selectors = checkSettings.selector
93
+ for (let i = selectors.length - 1; i > -1; i--) {
94
+ if (i === selectors.length - 1) {
95
+ shadowDomSettings['shadow'] = selectors[i].selector
96
+ } else {
97
+ const prevSettings = Object.assign({}, shadowDomSettings)
98
+ shadowDomSettings['selector'] = selectors[i].selector
99
+ if (!prevSettings.hasOwnProperty('selector')) {
100
+ shadowDomSettings['shadow'] = prevSettings.shadow
101
+ } else {
102
+ shadowDomSettings['shadow'] = prevSettings
103
+ }
104
+ }
105
+ }
106
+ regionSettings = {region: shadowDomSettings}
107
+ }
108
+ return regionSettings
109
+ }
110
+
111
+ function convertAccessabilityRegions(
112
+ accessibilityRegions: accessibilityRegion,
113
+ ): CheckSettings<SpecType, 'ufg'>['accessibilityRegions'] {
114
+ if (!accessibilityRegions) return
115
+ if (!Array.isArray(accessibilityRegions)) {
116
+ accessibilityRegions = [accessibilityRegions]
117
+ }
118
+ const accessibility: any = []
119
+ for (const region of accessibilityRegions) {
120
+ const accessabilityRegion = {
121
+ type: utils.types.has(region, 'accessibilityType') ? region.accessibilityType : undefined,
122
+ }
123
+
124
+ if (utils.types.has(region, 'selector')) {
125
+ const currRegion = {...accessabilityRegion, region: region.selector}
126
+ delete region.selector
127
+ accessibility.push(currRegion)
128
+ } else if (utils.types.has(region, 'element')) {
129
+ const elements = refElements(region.element)
130
+ delete region['element']
131
+ for (const element of elements) {
132
+ accessibility.push(Object.assign({}, region, accessabilityRegion, {region: element}))
133
+ }
134
+ } else if (utils.types.has(region, 'region')) {
135
+ const currRegion = {...region, type: region.region.accessibilityType}
136
+ delete currRegion.region.accessibilityType
137
+ accessibility.push(currRegion)
138
+ } else if (utils.types.has(region, 'top')) {
139
+ accessibility.push({
140
+ ...accessabilityRegion,
141
+ region: {y: region.top, x: region.left, width: region.width, height: region.height},
142
+ })
143
+ } else {
144
+ accessibility.push(region)
145
+ }
146
+ }
147
+ return accessibility
148
+ }
149
+
150
+ function convertFloatingRegion(floatingRegions: FloatingRegion): CheckSettings<SpecType, 'ufg'>['floatingRegions'] {
151
+ if (!floatingRegions) return
152
+ if (!Array.isArray(floatingRegions)) {
153
+ floatingRegions = [floatingRegions]
154
+ }
155
+ const floating = []
156
+
157
+ for (const region of floatingRegions) {
158
+ const floatingRegion = {
159
+ offset: {
160
+ bottom: region.maxDownOffset || 0,
161
+ left: region.maxLeftOffset || 0,
162
+ top: region.maxUpOffset || 0,
163
+ right: region.maxRightOffset || 0,
164
+ },
165
+ }
166
+ delete region.maxDownOffset
167
+ delete region.maxLeftOffset
168
+ delete region.maxUpOffset
169
+ delete region.maxRightOffset
170
+ if (utils.types.has(region, 'selector')) {
171
+ const currRegion = {region: region.selector, ...region, ...floatingRegion}
172
+ delete currRegion.selector
173
+ floating.push(currRegion)
174
+ } else if (utils.types.has(region, 'element')) {
175
+ const elements = refElements(region.element)
176
+ delete region.element
177
+ for (const element of elements) {
178
+ floating.push({...region, ...floatingRegion, region: element})
179
+ }
180
+ } else if (utils.types.has(region, 'region')) {
181
+ const currRegion = {offset: floatingRegion.offset, ...region}
182
+ floating.push(currRegion)
183
+ } else if (utils.types.has(region, 'top')) {
184
+ floating.push({
185
+ ...floatingRegion,
186
+ region: {
187
+ y: region.top,
188
+ x: region.left,
189
+ width: region.width,
190
+ height: region.height,
191
+ },
192
+ })
193
+ } else {
194
+ floating.push(region)
195
+ }
196
+ }
197
+ return floating
198
+ }
199
+
200
+ function transformRegionsWithOptions(regions: CodedRegion): CheckSettings<SpecType, 'ufg'>['ignoreRegions'] {
201
+ if (!regions) return
202
+ if (!Array.isArray(regions)) regions = [regions]
203
+ let resRegions: any = []
204
+ for (const region of regions) {
205
+ if (utils.types.has(region, 'element')) {
206
+ if (utils.types.has(region, 'padding') || utils.types.has(region, 'regionId')) {
207
+ const currRefElements = refElements(region.element)
208
+ for (const refElement of currRefElements) {
209
+ const curr: RefRegionWIthOptions = {region: refElement}
210
+ if (region.padding) {
211
+ curr.padding = region.padding
212
+ }
213
+ if (region.regionId) {
214
+ curr.regionId = region.regionId
215
+ }
216
+ resRegions.push(curr)
217
+ }
218
+ } else {
219
+ resRegions = [...resRegions, ...refElements(region.element)]
220
+ }
221
+ } else if (isHTMLElement(region) || utils.types.has(region, 'jquery')) {
222
+ // @ts-ignore
223
+ //for some reason TS doesn't recognize that region is an HTMLElement,
224
+ //but if I paste the conditions from the method here, it does recornize it
225
+ resRegions = [...resRegions, ...refElements(region)]
226
+ } else {
227
+ if (utils.types.has(region, 'selector') && !utils.types.has(region, 'type')) {
228
+ const currRegion = {region: region.selector, ...region}
229
+ delete currRegion.selector
230
+ resRegions.push(currRegion)
231
+ } else {
232
+ resRegions.push(region)
233
+ }
234
+ }
235
+ }
236
+ return resRegions
237
+ }
238
+
239
+ function refElements(regions: Element | Element[]): Ref[] {
240
+ if (!regions) return
241
+ if (!Array.isArray(regions)) regions = [regions]
242
+ const elements = []
243
+ for (const region of regions) {
244
+ if (isHTMLElement(region)) {
245
+ elements.push(Object.assign(refer.ref(region), {type: 'element'}))
246
+ } else if (utils.types.has(region, 'jquery')) {
247
+ region.each(function () {
248
+ // there's a small chance that `this` is not an HTML element. So we just verify it.
249
+ elements.push(isHTMLElement(this) ? Object.assign(refer.ref(this), {type: 'element'}) : this)
250
+ })
251
+ } else {
252
+ elements.push(region)
253
+ }
254
+ }
255
+ return elements
256
+ }
257
+
258
+ function isHTMLElement(element: CodedRegion): boolean {
259
+ // Avoiding instanceof here since the element might come from an iframe, and `instanceof HTMLElement` would fail.
260
+ // This check looks naive, but if anyone passes something like {nodeType: 1} as a region, then I'm fine with them crashing :)
261
+ return utils.types.has(element, 'nodeType') && element.nodeType === Node.ELEMENT_NODE
262
+ }
263
+ }
@@ -0,0 +1,56 @@
1
+ import type {CypressEyesConfig} from '../expose'
2
+ import type {SpecType, Config} from '@applitools/core'
3
+ import {transformBrowsers, transformAccessibilityValidation} from './utils'
4
+
5
+ export function transformCypressConfig(config: CypressEyesConfig): Config<SpecType, 'ufg'> {
6
+ return {
7
+ open: {
8
+ apiKey: config.apiKey,
9
+ serverUrl: config.serverUrl,
10
+ proxy: config.proxy,
11
+ appName: config.appName,
12
+ testName: config.testName,
13
+ displayName: config.displayName,
14
+ batch: {
15
+ ...config.batch,
16
+ id: config.batchId ?? config.batch?.id,
17
+ name: config.batchName ?? config.batch?.name,
18
+ sequenceName: config.batchSequenceName ?? config.batch?.sequenceName,
19
+ notifyOnCompletion: config.notifyOnCompletion ?? config.batch?.notifyOnCompletion,
20
+ },
21
+ keepBatchOpen: !config.shouldUseBrowserHooks,
22
+ environmentName: config.envName,
23
+ baselineBranchName: config.baselineBranchName,
24
+ branchName: config.branchName,
25
+ parentBranchName: config.parentBranchName,
26
+ compareWithParentBranch: config.compareWithParentBranch,
27
+ ignoreBaseline: config.ignoreBaseline,
28
+ ignoreGitBranching: config.ignoreGitMergeBase,
29
+ saveDiffs: config.saveDiffs,
30
+ properties: config.properties,
31
+ environment: {
32
+ viewportSize: config.viewportSize,
33
+ },
34
+ },
35
+ check: {
36
+ renderers: transformBrowsers(config.browser),
37
+ matchLevel: config.matchLevel,
38
+ ignoreCaret: config.ignoreCaret,
39
+ ignoreDisplacements: config.ignoreDisplacements,
40
+ accessibilitySettings: transformAccessibilityValidation(config.accessibilityValidation),
41
+ layoutBreakpoints: config.layoutBreakpoints,
42
+ sendDom: config.sendDom,
43
+ useDom: config.useDom,
44
+ enablePatterns: config.enablePatterns,
45
+ ufgOptions: config.visualGridOptions,
46
+ disableBrowserFetching: config.disableBrowserFetching,
47
+ hooks: config.scriptHooks,
48
+ },
49
+ screenshot: {
50
+ waitBeforeCapture: config.waitBeforeCapture,
51
+ },
52
+ close: {
53
+ updateBaselineIfNew: config.saveNewTests,
54
+ },
55
+ }
56
+ }
@@ -0,0 +1,33 @@
1
+ import * as utils from '@applitools/utils'
2
+
3
+ import type {CypressEyesConfig, MaybeArray, DeviceName, ScreenOrientationPlain} from '../expose'
4
+ import type {SpecType, Config} from '@applitools/core'
5
+ import type {Renderer} from '@applitools/core'
6
+
7
+ type CypressBrowser = MaybeArray<Renderer | {deviceName: DeviceName; screenOrientation?: ScreenOrientationPlain; name?: string}>
8
+
9
+ export function transformBrowsers(browsers: CypressBrowser): Renderer[] {
10
+ if (!browsers) return
11
+ if (!Array.isArray(browsers)) browsers = [browsers]
12
+
13
+ return browsers.map(browser => {
14
+ if (utils.types.has(browser, 'width') && utils.types.has(browser, 'height') && !utils.types.has(browser, 'name')) {
15
+ browser.name = 'chrome'
16
+ return browser
17
+ } else if (utils.types.has(browser, 'deviceName')) {
18
+ return {chromeEmulationInfo: browser}
19
+ } else {
20
+ return browser
21
+ }
22
+ })
23
+ }
24
+
25
+ export function transformAccessibilityValidation(
26
+ accessibilityValidation: NonNullable<CypressEyesConfig['defaultMatchSettings']>['accessibilitySettings'],
27
+ ): Config<SpecType, 'ufg'>['check']['accessibilitySettings'] {
28
+ if (!accessibilityValidation) return
29
+ return {
30
+ level: accessibilityValidation.level,
31
+ version: accessibilityValidation.guidelinesVersion,
32
+ }
33
+ }
package/src/expose.ts CHANGED
@@ -9,60 +9,89 @@
9
9
  /// <reference types="cypress" />
10
10
  import type * as api from '@applitools/eyes-api'
11
11
  import type * as core from '@applitools/core'
12
- import {type EyesSelector, type TestResultsStatus} from '@applitools/eyes-api'
12
+ import {
13
+ type EyesSelector,
14
+ type TestResultsStatus,
15
+ type DeviceName,
16
+ type ScreenOrientationPlain,
17
+ type AccessibilityRegionTypePlain,
18
+ } from '@applitools/eyes-api'
13
19
 
14
- export type {EyesSelector, TestResultsStatus}
15
-
16
- type MaybeArray<T> = T | T[]
17
-
18
- type LegacyRegion = {left: number; top: number; width: number; height: number}
19
- type Selector = {selector: string; type?: 'css' | 'xpath'; nodeType?: 'element' | 'shadow-root'} | string
20
- type Element = HTMLElement | JQuery<HTMLElement>
21
- type ElementWithOptions = {element: Element; regionId?: string; padding?: any}
20
+ export type MaybeArray<T> = T | T[]
21
+ export type {EyesSelector, TestResultsStatus, DeviceName, ScreenOrientationPlain}
22
+ export type LegacyRegion = {left: number; top: number; width: number; height: number}
23
+ export type Selector = {selector: string; type?: 'css' | 'xpath'; nodeType?: 'element' | 'shadow-root'} | string
24
+ export type Element = HTMLElement | JQuery<HTMLElement>
25
+ export type ElementWithOptions = {element: Element; regionId?: string; padding?: any}
26
+ export type SelectorWithOptions = {region: Selector; regionId?: string; padding?: number | LegacyRegion}
22
27
  type SpecType = core.SpecType<unknown, unknown, Element, Selector>
28
+ type CodedRegion = NonNullable<Element | ElementWithOptions | LegacyRegion | Selector | SelectorWithOptions>
29
+ export type AccessibilityValidation = NonNullable<CypressEyesConfig['defaultMatchSettings']>['accessibilitySettings']
30
+ export type FloatingRegion = MaybeArray<
31
+ (ElementWithOptions | SelectorWithOptions | Selector | LegacyRegion) & {
32
+ maxUpOffset?: number
33
+ maxDownOffset?: number
34
+ maxLeftOffset?: number
35
+ maxRightOffset?: number
36
+ }
37
+ >
38
+ export type accessibilityRegion = MaybeArray<
39
+ | ((ElementWithOptions | Selector | LegacyRegion) & {
40
+ accessibilityType?: AccessibilityRegionTypePlain
41
+ })
42
+ | {
43
+ region: {selector: Selector; accessibilityType: AccessibilityRegionTypePlain}
44
+ regionId?: string
45
+ padding?: number | LegacyRegion
46
+ }
47
+ >
23
48
 
24
49
  export type CypressCheckSettings = api.CheckSettingsAutomationPlain<SpecType> & {
25
- tag?: CypressCheckSettings['name']
26
-
50
+ tag?: string
27
51
  target?: 'window' | 'region'
28
52
  selector?: Selector
29
53
  element?: Element
30
-
31
- ignore?: MaybeArray<NonNullable<CypressCheckSettings['ignoreRegions']>[number] | LegacyRegion | ElementWithOptions>
32
- layout?: MaybeArray<NonNullable<CypressCheckSettings['layoutRegions']>[number] | LegacyRegion | ElementWithOptions>
33
- content?: MaybeArray<NonNullable<CypressCheckSettings['contentRegions']>[number] | LegacyRegion | ElementWithOptions>
34
- strict?: MaybeArray<NonNullable<CypressCheckSettings['strictRegions']>[number] | LegacyRegion | ElementWithOptions>
35
- floating?: MaybeArray<
36
- | NonNullable<CypressCheckSettings['floatingRegions']>[number]
37
- | ((ElementWithOptions | Selector | LegacyRegion) & {
38
- maxUpOffset?: number
39
- maxDownOffset?: number
40
- maxLeftOffset?: number
41
- maxRightOffset?: number
42
- })
43
- >
44
- accessibility?: MaybeArray<
45
- | NonNullable<CypressCheckSettings['accessibilityRegions']>[number]
46
- | ((ElementWithOptions | Selector | LegacyRegion) & {accessibilityType?: api.AccessibilityRegionTypePlain})
47
- >
54
+ region?: LegacyRegion
55
+ ignore?: MaybeArray<CodedRegion>
56
+ layout?: MaybeArray<CodedRegion>
57
+ content?: MaybeArray<CodedRegion>
58
+ strict?: MaybeArray<CodedRegion>
59
+ floating?: FloatingRegion
60
+ accessibility?: accessibilityRegion
48
61
  scriptHooks?: CypressCheckSettings['hooks']
49
62
  ignoreCaret?: boolean
50
63
  ignoreDisplacements?: boolean
64
+ browser?: MaybeArray<
65
+ | NonNullable<CypressEyesConfig['browsersInfo']>[number]
66
+ | {deviceName: DeviceName; screenOrientation?: ScreenOrientationPlain; name?: string}
67
+ >
51
68
  }
52
69
  export type CypressEyesConfig = api.ConfigurationPlain<SpecType> & {
53
70
  browser?: MaybeArray<
54
71
  | NonNullable<CypressEyesConfig['browsersInfo']>[number]
55
- | {deviceName: string; screenOrientation?: api.ScreenOrientationPlain; name?: string}
72
+ | {deviceName: DeviceName; screenOrientation?: ScreenOrientationPlain; name?: string}
56
73
  >
57
74
 
58
75
  batchId?: NonNullable<CypressEyesConfig['batch']>['id']
59
76
  batchName?: NonNullable<CypressEyesConfig['batch']>['name']
60
77
  batchSequence?: NonNullable<CypressEyesConfig['batch']>['sequenceName']
61
78
  notifyOnCompletion?: NonNullable<CypressEyesConfig['batch']>['notifyOnCompletion']
79
+ batchSequenceName?: NonNullable<CypressEyesConfig['batch']>['sequenceName']
62
80
 
63
81
  envName?: CypressEyesConfig['environmentName']
64
82
 
65
- accessibilitySettings?: NonNullable<CypressEyesConfig['defaultMatchSettings']>['accessibilitySettings']
83
+ accessibilityValidation?: AccessibilityValidation
84
+ matchLevel?: NonNullable<CypressEyesConfig['defaultMatchSettings']>['matchLevel']
85
+ ignoreCaret?: NonNullable<boolean>
86
+ ignoreDisplacements?: NonNullable<boolean>
87
+ useDom?: NonNullable<boolean>
88
+ enablePatterns?: NonNullable<boolean>
89
+ scriptHooks?: {
90
+ beforeCaptureScreenshot: string
91
+ }
92
+ saveNewTests?: boolean
93
+ /** @internal */
94
+ shouldUseBrowserHooks?: boolean
66
95
  }
67
96
 
68
97
  export type CypressTestResultsSummary = api.TestResultsSummary
@@ -6,7 +6,15 @@ import {type EyesPluginConfig} from './'
6
6
 
7
7
  export default function makeConfig(): {config: any; eyesConfig: EyesPluginConfig} {
8
8
  const config = utils.config.getConfig({
9
- params: [...configParams, 'failCypressOnDiff', 'tapDirPath', 'tapFileName', 'disableBrowserFetching', 'testConcurrency'],
9
+ params: [
10
+ ...configParams,
11
+ 'failCypressOnDiff',
12
+ 'tapDirPath',
13
+ 'tapFileName',
14
+ 'disableBrowserFetching',
15
+ 'testConcurrency',
16
+ 'removeDuplicateTests',
17
+ ],
10
18
  })
11
19
 
12
20
  if ((!config.batch || !config.batch.id) && !config.batchId) {
@@ -40,6 +48,7 @@ export default function makeConfig(): {config: any; eyesConfig: EyesPluginConfig
40
48
  eyesDisableBrowserFetching: !!config.disableBrowserFetching,
41
49
  eyesTestConcurrency: config.testConcurrency || DEFAULT_TEST_CONCURRENCY,
42
50
  eyesWaitBeforeCapture: config.waitBeforeCapture,
51
+ eyesRemoveDuplicateTests: !!config.removeDuplicateTests,
43
52
  }
44
53
 
45
54
  return {config, eyesConfig}
@@ -41,6 +41,7 @@ const configParams = [
41
41
  'notifyOnCompletion',
42
42
  'batchNotify',
43
43
  'dontCloseBatches',
44
+ 'removeDuplicateTests',
44
45
  ]
45
46
 
46
47
  export default configParams
@@ -23,12 +23,13 @@ export type EyesPluginConfig = {
23
23
  eyesWaitBeforeCapture: number
24
24
  eyesPort?: number
25
25
  eyesIsGlobalHooksSupported?: boolean
26
+ eyesRemoveDuplicateTests?: boolean
26
27
  }
27
28
 
28
29
  const {config, eyesConfig} = makeConfig()
29
30
  const logger = makeLogger({level: config.showLogs ? 'info' : 'silent', label: 'eyes'})
30
31
 
31
- const startServer = makeStartServer({logger})
32
+ const startServer = makeStartServer({logger, eyesConfig})
32
33
 
33
34
  const pluginExport = makePluginExport({
34
35
  startServer,
@@ -10,6 +10,7 @@ import which from 'which'
10
10
  import {type Logger} from '@applitools/logger'
11
11
  import {AddressInfo} from 'net'
12
12
  import {promisify} from 'util'
13
+ import {EyesPluginConfig} from './index'
13
14
  export type StartServerReturn = {
14
15
  server: Omit<SocketWithUniversal, 'disconnect' | 'ref' | 'unref' | 'send' | 'request' | 'setPassthroughListener'>
15
16
  port: number
@@ -18,7 +19,7 @@ export type StartServerReturn = {
18
19
  closeUniversalServer: () => void
19
20
  }
20
21
 
21
- export default function makeStartServer({logger}: {logger: Logger}) {
22
+ export default function makeStartServer({logger, eyesConfig}: {logger: Logger; eyesConfig: EyesPluginConfig}) {
22
23
  return async function startServer(options?: Cypress.PluginConfigOptions): Promise<StartServerReturn> {
23
24
  const key = fs.readFileSync(path.resolve(__dirname, '../../src/pem/server.key'))
24
25
  const cert = fs.readFileSync(path.resolve(__dirname, '../../src/pem/server.cert'))
@@ -142,7 +143,10 @@ export default function makeStartServer({logger}: {logger: Logger}) {
142
143
  function closeManager() {
143
144
  return Promise.all(
144
145
  managers.map(({manager, socketWithUniversal}) =>
145
- socketWithUniversal.request('EyesManager.getResults', {manager, settings: {throwErr: false}}),
146
+ socketWithUniversal.request('EyesManager.getResults', {
147
+ manager,
148
+ settings: {throwErr: false, removeDuplicateTests: eyesConfig.eyesRemoveDuplicateTests},
149
+ }),
146
150
  ),
147
151
  )
148
152
  }