-
Notifications
You must be signed in to change notification settings - Fork 42
/
Copy pathindex.js
129 lines (111 loc) · 3.47 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
const utils = require('@percy/sdk-utils');
// Collect client and environment information
const sdkPkg = require('./package.json');
const CLIENT_INFO = `${sdkPkg.name}/${sdkPkg.version}`;
const ENV_INFO = `cypress/${Cypress.version}`;
// asset discovery should timeout before this
// 1.5 times the 30 second nav timeout
const CY_TIMEOUT = 30 * 1000 * 1.5;
// Maybe set the CLI API address from the environment
utils.percy.address = Cypress.env('PERCY_SERVER_ADDRESS');
// Use Cypress's http:request backend task
utils.request.fetch = async function fetch(url, options) {
options = { url, retryOnNetworkFailure: false, ...options };
return Cypress.backend('http:request', options);
};
// Create Cypress log messages
function cylog(message, meta) {
Cypress.log({
name: 'percySnapshot',
displayName: 'percy',
consoleProps: () => meta,
message
});
}
// Take a DOM snapshot and post it to the snapshot endpoint
Cypress.Commands.add('percySnapshot', (name, options = {}) => {
let log = utils.logger('cypress');
// if name is not passed
if (typeof name === 'object') {
options = name;
name = undefined;
}
// Default name to test title
name ||= cy.state('runnable').fullTitle();
const meta = {
snapshot: {
name: name,
testCase: options.testCase
}
};
const withLog = async (func, context, _throw = true) => {
try {
return await func();
} catch (error) {
log.error(`Got error while ${context}`, meta);
log.error(error, meta);
log.error(error.stack, meta);
if (_throw) throw error;
return error;
}
};
const withRetry = async (func) => {
let num = 1;
const maxNum = 3;
const sleepTime = 1000;
let error;
while (num <= maxNum) {
try {
return await func();
} catch (e) {
error = e;
log.error(`Retrying... (${num}/${maxNum})`);
await new Promise((res) => setTimeout(res, sleepTime));
}
num += 1;
}
throw error;
};
return cy.then({ timeout: CY_TIMEOUT }, async () => {
if (Cypress.config('isInteractive') &&
!Cypress.config('enablePercyInteractiveMode')) {
return cylog('Disabled in interactive mode', {
details: 'use "cypress run" instead of "cypress open"',
name
});
}
// Check if Percy is enabled
if (!await utils.isPercyEnabled()) {
return cylog('Not running', { name });
}
await withLog(async () => {
// Inject @percy/dom
if (!window.PercyDOM) {
// eslint-disable-next-line no-eval
eval(await utils.fetchPercyDOM());
}
}, 'injecting @percy/dom');
// Serialize and capture the DOM
return cy.document({ log: false }).then({ timeout: CY_TIMEOUT }, async (dom) => {
let domSnapshot = await withLog(() => {
return window.PercyDOM.serialize({ ...options, dom });
}, 'taking dom snapshot');
const throwConfig = Cypress.config('percyThrowErrorOnFailure');
const _throw = throwConfig === undefined ? false : throwConfig;
// Post the DOM snapshot to Percy
let response = await withRetry(async () => await withLog(async () => {
return await utils.postSnapshot({
...options,
environmentInfo: ENV_INFO,
clientInfo: CLIENT_INFO,
domSnapshot,
url: dom.URL,
name
});
}, 'posting dom snapshot', _throw));
// Log the snapshot name on success
cylog(name, meta);
return response;
});
});
});