-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathsetup.js
More file actions
executable file
·276 lines (248 loc) · 13.1 KB
/
setup.js
File metadata and controls
executable file
·276 lines (248 loc) · 13.1 KB
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const cwd = process.cwd();
const pluginRequire = `\nrequire('@smartbear/visualtest-cypress')(module)`;
const commandsImport = `\nimport '@smartbear/visualtest-cypress/commands'`;
let vtConfContent = `module.exports = {\n\tprojectToken: 'PROJECT_TOKEN',\n}`;
// const jsonData = `"chromeWebSecurity": false`;
let error = false;
const usersCypressVersion = (() => {
let packageFile, usersCypress;
try {
let file = path.dirname(require.resolve('cypress', {paths: [cwd]}))
if (file.endsWith("dist")) file = path.resolve(file, '..'); // in cypress 15+ resolve paths to dist folder
packageFile = fs.readFileSync(path.resolve(file, 'package.json'));
usersCypress = JSON.parse(packageFile.toString());
} catch (err) {
error = true;
console.log(chalk.bold.yellow('\nCypress not found, please run: '));
console.log(chalk.magenta.underline(`npm install cypress\nnpx cypress open`));
console.log((`Go through the Cypress setup wizard`));
process.stdout.write(chalk.yellow(`Then, run: `));
process.stdout.write(chalk.magenta.underline(`npx visualtest-setup`));
console.log(chalk.yellow(` again.\n`));
}
return usersCypress;
})();
let cypressVersionAbove10; //boolean true if above version 10
let checkCypressVersion = () => {
//checks if the user's version is supported, and if it above or below Cypress version 10 (due to different naming conventions)
if (usersCypressVersion.version.split('.')[0] < 9 || usersCypressVersion.version.split('.')[0] <= 9 && usersCypressVersion.version.split('.')[1] < 4) {
// Note as of now this is not supported because cy.request cannot send blobs in previous versions
console.log(chalk.redBright(`Detected Cypress ${usersCypressVersion.version}`));
console.log(chalk.green(`Only Cypress 9.4.0+ is supported`));
// error = true; //todo not throwing an error for now
}
cypressVersionAbove10 = usersCypressVersion.version.split('.')[0] >= 10;
checkForTypeScript(cypressVersionAbove10);
/**
if we decide to support older versions commenting out for now
else if ((usersCypress.version.split('.')[0] = 7 && usersCypress.version.split('.')[1] < 4)) {
const filePath = path.resolve(process.cwd(), 'cypress.json');
if (fs.existsSync(filePath)) { //file exists
const fileContent = fs.readFileSync(filePath, 'utf-8');
if (fileContent.toString().includes(jsonData)){
console.log(chalk.blue(`Detected Cypress ${usersCypress.version}`))
console.log(chalk.blue(`chromeWebSecurity found in cypress.json`));
} else {
console.log(chalk.yellow(`Detected Cypress ${usersCypress.version}`))
console.log(chalk.yellow(`This is below 7.4.0 - extra parameters are required.\n`))
// console.log()
console.log(chalk.bgRedBright('include the below line in your cypress.json file'))
console.log(chalk.magenta(jsonData))
console.log(chalk.dim(`Read about it here: https://docs.cypress.io/guides/guides/web-security\n`))
}
} else {
console.log(chalk.yellow(`Detected Cypress ${usersCypress.version}`))
console.log(chalk.yellow(`This is below 7.4.0 - extra parameters are required.\n`))
console.log(chalk.bgRedBright('cypress.json not found. This is required for Cypress < 10'))
process.stdout.write('Please run: ');
console.log(chalk.magenta.underline('npx cypress open\n'));
console.log(chalk.bgRedBright('\n Then include the below line in your cypress.json file'))
console.log(chalk.magenta(jsonData))
console.log(chalk.dim(`Read about it here: https://docs.cypress.io/guides/guides/web-security\n`))
}
}
**/
};
let fileExtension; // this for either '.js' or '.ts'
const checkForTypeScript = (version10) => {
try {
try {
fs.readFileSync(version10 ? `${process.cwd()}/cypress/support/e2e.js` : `${process.cwd()}/cypress/support/index.js`, 'utf-8');
fileExtension = ".js";
} catch (error) {
fs.readFileSync(version10 ? `${process.cwd()}/cypress/support/e2e.ts` : `${process.cwd()}/cypress/support/index.ts`, 'utf-8');
fileExtension = ".ts";
console.log(chalk.yellow('TypeScript detected - this currently in beta.'));
}
} catch (error) {
//TODO look into logging later
// logger.debug('Issue with finding file extension, defaulting to ".js".')
// logger.debug('Most likely the Cypress project is not set up yet')
fileExtension = ".js";
// error handled later
}
};
let setupVTConf = () => {
/** logic for grabbing the projectToken**/
let projectTokenArg = null;
if (process.argv[2]) {
projectTokenArg = inputUsersProjectToken();
if (projectTokenArg) vtConfContent = `module.exports = {\n\tprojectToken: '${projectTokenArg}',\n}`;
}
const filePath = `${process.cwd()}/visualTest.config.js`;
if (fs.existsSync(filePath)) { //file exists
console.log(chalk.blue(`visualTest.config.js found.`));
let fileContent = fs.readFileSync(filePath, 'utf-8');
if (projectTokenArg) {
if (fileContent.toString().includes('projectToken') && fileContent.toString().includes('module.exports')) { //vtConf boilerplate looks good, but no project token
if (fileContent.toString().includes(`projectToken: 'PROJECT_TOKEN'`)) { // boiler plate config file setup
fileContent = fileContent.toString().replace(`projectToken: 'PROJECT_TOKEN',`, `projectToken: '${projectTokenArg}',`);
fs.writeFileSync(filePath, fileContent,'utf-8')
console.log(chalk.green(`"PROJECT_TOKEN" has been replaced with "${projectTokenArg}".`));
} else if (fileContent.toString().includes(`projectToken: '${projectTokenArg}'`)){ //everything looks good
console.log(chalk.blue(`Your projectToken was found on visualtest.config.js.`));
} else { //neither 'PROJECT_TOKEN' && projectTokenArg found (most likely a different projectToken saved)
logicToCheckForProjectTokenAndReplace(filePath, fileContent, projectTokenArg);
}
} else { //vtConf boilerplate does NOT look good, shouldn't get here often. It means the file is created, but no 'projectToken' && 'module.exports' hopefully empty file
fs.appendFileSync(filePath, vtConfContent);
console.log(chalk.green('Your projectToken has been written to visualTest.config.js.'));
}
} else {
if (fileContent.toString().includes('projectToken') && fileContent.toString().includes('module.exports')) { //vtConf boilerplate looks good
if (fileContent.toString().includes(`projectToken: 'PROJECT_TOKEN'`)) { //user has not entered their own projectToken
console.log(chalk.underline.yellow('Please enter your projectToken in visualTest.config.js.'));
} else {
console.log(chalk.blue(`projectToken found.`));
}
} else { //vtConf boilerplate does NOT look good
fs.appendFileSync(filePath, vtConfContent);
console.log(chalk.underline.yellow('Please enter your projectToken in visualTest.config.js.'));
}
}
} else { //file does not exist, so create the file and import boilerplate
fs.appendFile('visualTest.config.js', vtConfContent, function (err) {
if (err) throw err;
});
console.log(chalk.green('visualTest.config.js has been created.'));
if (!projectTokenArg){
process.stdout.write(chalk.yellow('Please enter your projectToken'));
console.log(chalk.green(' in visualTest.config.js'));
} else {
console.log(chalk.green('Your projectToken has been written to visualTest.config.js.'));
}
}
};
let setupCommands = () => {
let aboveVersion10 = usersCypressVersion.version.split('.')[0] >= 10;
const supportPath = aboveVersion10 ? `${process.cwd()}/cypress/support/e2e` : `${process.cwd()}/cypress/support/index`;
let fileContent;
try {
fileContent = fs.readFileSync(`${supportPath}${fileExtension}`, 'utf-8');
} catch (err) {
error = true;
console.log(chalk.red(`Cypress e2e.js file not found, this is most likely due to Cypress not being setup yet, please run: `));
console.log("");
console.log("\tnpx cypress open");
console.log("");
console.log(chalk.grey(`${err}`));
return;
}
if (fileContent.toString().includes(commandsImport)) {
console.log(chalk.blue(`Commands already installed.`));
} else {
fs.appendFileSync(`${supportPath}${fileExtension}`, commandsImport);
console.log(chalk.green(`Commands installed.`));
}
};
let setupPlugin = () => {
let aboveVersion10 = usersCypressVersion.version.split('.')[0] >= 10;
const supportPath = aboveVersion10 ? path.resolve(process.cwd(), 'cypress.config') : `${process.cwd()}/cypress/plugins/index`;
let fileContent;
try {
fileContent = fs.readFileSync(`${supportPath}${fileExtension}`, 'utf-8');
} catch (err) {
error = true;
console.log(chalk.red(`Cypress cypress.config.js file not found, this is most likely due to Cypress not being setup yet, please run: `));
console.log("");
console.log("npx cypress open");
console.log("");
console.log(chalk.grey(`${err}`));
return;
}
if (fileContent.toString().includes(pluginRequire)) {
console.log(chalk.blue(`Plugin already installed.`));
} else {
fs.appendFileSync(`${supportPath}${fileExtension}`, pluginRequire);
console.log(chalk.green(`Plugin installed.`));
}
};
const setupTypeScriptIndexFile = () => {
const filePath = path.join(process.cwd(), 'cypress', 'support', 'index.d.ts');
const importStatement = "import '@smartbear/visualtest-cypress';\n";
let fileContent;
try {
fileContent = fs.readFileSync(filePath, 'utf-8');
} catch (err) {
// okay if this file was not found
}
if (fileContent && fileContent.toString().includes(importStatement)) {
console.log(chalk.blue(`TypeScript import statement found.`));
} else {
fs.appendFileSync(filePath, importStatement);
// fs.writeFileSync(`${filePath}`, fileContent.replace(/([\s\S])$/, `$1\n${importStatement}`));
process.stdout.write(chalk.green(`TypeScript import statement added.`));
console.log(chalk.dim(`\t Filepath: cypress/support/index.d.ts`));
}
};
const inputUsersProjectToken = () => {
const npxArgument = process.argv[2];
if (npxArgument.startsWith("projectToken=") && npxArgument.split("projectToken=")[1]) {
return npxArgument.split("projectToken=")[1]; // in case there is another "=" in the projectToken
} else {
// console.error("Argument passed through is not recognized. Please enter your PROJECT_TOKEN manually."); // probably not needed
}
}
const logicToCheckForProjectTokenAndReplace = (filePath, fileContent, projectTokenArg) => {
try {
const projectTokenPattern = /^(?!\/\/)\s*projectToken:/m; // Regular expression pattern to match lines that start with "projectToken:" and isn't commented out
const lines = fileContent.toString().split('\n');
let foundProjectTokenLine = null;
for (const line of lines) {
if (projectTokenPattern.test(line)) {
foundProjectTokenLine = line;
break;
}
}
if (foundProjectTokenLine) {
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question(`Would you like to replace: ${chalk.blue(foundProjectTokenLine.trim())} with: ${chalk.green(`projectToken: '${projectTokenArg}',`)} (y/n): `, (answer) => {
if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
fileContent = fileContent.toString().replace(foundProjectTokenLine, `\tprojectToken: '${projectTokenArg}',`);
fs.writeFileSync(filePath, fileContent, 'utf-8')
console.log(chalk.green('projectToken replaced on visualtest.config.js file.'));
} else {
console.log(chalk.yellow('projectToken will not be replaced.'));
}
rl.close();
});
} else {
console.log('Please set up you visualtest.confis.js file manually'); //shouldn't get here
}
} catch (e) {
console.log('Please set up you visualtest.confis.js file manually. Error: ', e); //shouldn't get here
}
}
if (!error) checkCypressVersion();
if (!error) setupCommands();
if (!error) setupPlugin();
if (!error && fileExtension === '.ts') setupTypeScriptIndexFile();
if (!error) setupVTConf();