Skip to content

Commit 7030c7f

Browse files
authored
fix: glob backward compatibility (#4775)
1 parent 236dc72 commit 7030c7f

File tree

5 files changed

+132
-127
lines changed

5 files changed

+132
-127
lines changed

lib/codecept.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const { existsSync, readFileSync } = require('fs')
2-
const glob = require('glob')
2+
const { globSync } = require('glob')
33
const fsPath = require('path')
44
const { resolve } = require('path')
55

@@ -168,15 +168,17 @@ class Codecept {
168168
}
169169

170170
for (pattern of patterns) {
171-
glob.sync(pattern, options).forEach(file => {
172-
if (file.includes('node_modules')) return
173-
if (!fsPath.isAbsolute(file)) {
174-
file = fsPath.join(global.codecept_dir, file)
175-
}
176-
if (!this.testFiles.includes(fsPath.resolve(file))) {
177-
this.testFiles.push(fsPath.resolve(file))
178-
}
179-
})
171+
if (pattern) {
172+
globSync(pattern, options).forEach(file => {
173+
if (file.includes('node_modules')) return
174+
if (!fsPath.isAbsolute(file)) {
175+
file = fsPath.join(global.codecept_dir, file)
176+
}
177+
if (!this.testFiles.includes(fsPath.resolve(file))) {
178+
this.testFiles.push(fsPath.resolve(file))
179+
}
180+
})
181+
}
180182
}
181183
}
182184

lib/command/gherkin/snippets.js

Lines changed: 69 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,113 @@
1-
const escapeStringRegexp = require('escape-string-regexp');
2-
const fs = require('fs');
3-
const Gherkin = require('@cucumber/gherkin');
4-
const Messages = require('@cucumber/messages');
5-
const glob = require('glob');
6-
const fsPath = require('path');
1+
const escapeStringRegexp = require('escape-string-regexp')
2+
const fs = require('fs')
3+
const Gherkin = require('@cucumber/gherkin')
4+
const Messages = require('@cucumber/messages')
5+
const { globSync } = require('glob')
6+
const fsPath = require('path')
77

8-
const { getConfig, getTestRoot } = require('../utils');
9-
const Codecept = require('../../codecept');
10-
const output = require('../../output');
11-
const { matchStep } = require('../../mocha/bdd');
8+
const { getConfig, getTestRoot } = require('../utils')
9+
const Codecept = require('../../codecept')
10+
const output = require('../../output')
11+
const { matchStep } = require('../../mocha/bdd')
1212

13-
const uuidFn = Messages.IdGenerator.uuid();
14-
const builder = new Gherkin.AstBuilder(uuidFn);
15-
const matcher = new Gherkin.GherkinClassicTokenMatcher();
16-
const parser = new Gherkin.Parser(builder, matcher);
17-
parser.stopAtFirstError = false;
13+
const uuidFn = Messages.IdGenerator.uuid()
14+
const builder = new Gherkin.AstBuilder(uuidFn)
15+
const matcher = new Gherkin.GherkinClassicTokenMatcher()
16+
const parser = new Gherkin.Parser(builder, matcher)
17+
parser.stopAtFirstError = false
1818

1919
module.exports = function (genPath, options) {
20-
const configFile = options.config || genPath;
21-
const testsPath = getTestRoot(configFile);
22-
const config = getConfig(configFile);
23-
if (!config) return;
20+
const configFile = options.config || genPath
21+
const testsPath = getTestRoot(configFile)
22+
const config = getConfig(configFile)
23+
if (!config) return
2424

25-
const codecept = new Codecept(config, {});
26-
codecept.init(testsPath);
25+
const codecept = new Codecept(config, {})
26+
codecept.init(testsPath)
2727

2828
if (!config.gherkin) {
29-
output.error('Gherkin is not enabled in config. Run `codecept gherkin:init` to enable it');
30-
process.exit(1);
29+
output.error('Gherkin is not enabled in config. Run `codecept gherkin:init` to enable it')
30+
process.exit(1)
3131
}
3232
if (!config.gherkin.steps || !config.gherkin.steps[0]) {
33-
output.error('No gherkin steps defined in config. Exiting');
34-
process.exit(1);
33+
output.error('No gherkin steps defined in config. Exiting')
34+
process.exit(1)
3535
}
3636
if (!options.feature && !config.gherkin.features) {
37-
output.error('No gherkin features defined in config. Exiting');
38-
process.exit(1);
37+
output.error('No gherkin features defined in config. Exiting')
38+
process.exit(1)
3939
}
4040
if (options.path && !config.gherkin.steps.includes(options.path)) {
41-
output.error(`You must include ${options.path} to the gherkin steps in your config file`);
42-
process.exit(1);
41+
output.error(`You must include ${options.path} to the gherkin steps in your config file`)
42+
process.exit(1)
4343
}
4444

45-
const files = [];
46-
glob.sync(options.feature || config.gherkin.features, { cwd: options.feature ? '.' : global.codecept_dir }).forEach(file => {
45+
const files = []
46+
globSync(options.feature || config.gherkin.features, { cwd: options.feature ? '.' : global.codecept_dir }).forEach(file => {
4747
if (!fsPath.isAbsolute(file)) {
48-
file = fsPath.join(global.codecept_dir, file);
48+
file = fsPath.join(global.codecept_dir, file)
4949
}
50-
files.push(fsPath.resolve(file));
51-
});
52-
output.print(`Loaded ${files.length} files`);
50+
files.push(fsPath.resolve(file))
51+
})
52+
output.print(`Loaded ${files.length} files`)
5353

54-
const newSteps = new Map();
54+
const newSteps = new Map()
5555

5656
const parseSteps = steps => {
57-
const newSteps = [];
58-
let currentKeyword = '';
57+
const newSteps = []
58+
let currentKeyword = ''
5959
for (const step of steps) {
6060
if (step.keyword.trim() === 'And') {
61-
if (!currentKeyword) throw new Error(`There is no active keyword for step '${step.text}'`);
62-
step.keyword = currentKeyword;
61+
if (!currentKeyword) throw new Error(`There is no active keyword for step '${step.text}'`)
62+
step.keyword = currentKeyword
6363
}
64-
currentKeyword = step.keyword;
64+
currentKeyword = step.keyword
6565
try {
66-
matchStep(step.text);
66+
matchStep(step.text)
6767
} catch (err) {
68-
let stepLine;
68+
let stepLine
6969
if (/[{}()/]/.test(step.text)) {
7070
stepLine = escapeStringRegexp(step.text)
7171
.replace(/\//g, '\\/')
7272
.replace(/\"(.*?)\"/g, '"(.*?)"')
7373
.replace(/(\d+\\\.\d+)/, '(\\d+\\.\\d+)')
74-
.replace(/ (\d+) /, ' (\\d+) ');
75-
stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: true });
74+
.replace(/ (\d+) /, ' (\\d+) ')
75+
stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: true })
7676
} else {
7777
stepLine = step.text
7878
.replace(/\"(.*?)\"/g, '{string}')
7979
.replace(/(\d+\.\d+)/, '{float}')
80-
.replace(/ (\d+) /, ' {int} ');
81-
stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: false });
80+
.replace(/ (\d+) /, ' {int} ')
81+
stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: false })
8282
}
83-
newSteps.push(stepLine);
83+
newSteps.push(stepLine)
8484
}
8585
}
86-
return newSteps;
87-
};
86+
return newSteps
87+
}
8888

8989
const parseFile = file => {
90-
const ast = parser.parse(fs.readFileSync(file).toString());
90+
const ast = parser.parse(fs.readFileSync(file).toString())
9191
for (const child of ast.feature.children) {
92-
if (child.scenario.keyword === 'Scenario Outline') continue; // skip scenario outline
92+
if (child.scenario.keyword === 'Scenario Outline') continue // skip scenario outline
9393
parseSteps(child.scenario.steps)
9494
.map(step => {
95-
return Object.assign(step, { file: file.replace(global.codecept_dir, '').slice(1) });
95+
return Object.assign(step, { file: file.replace(global.codecept_dir, '').slice(1) })
9696
})
97-
.map(step => newSteps.set(`${step.type}(${step})`, step));
97+
.map(step => newSteps.set(`${step.type}(${step})`, step))
9898
}
99-
};
99+
}
100100

101-
files.forEach(file => parseFile(file));
101+
files.forEach(file => parseFile(file))
102102

103-
let stepFile = options.path || config.gherkin.steps[0];
103+
let stepFile = options.path || config.gherkin.steps[0]
104104
if (!fs.existsSync(stepFile)) {
105-
output.error(`Please enter a valid step file path ${stepFile}`);
106-
process.exit(1);
105+
output.error(`Please enter a valid step file path ${stepFile}`)
106+
process.exit(1)
107107
}
108108

109109
if (!fsPath.isAbsolute(stepFile)) {
110-
stepFile = fsPath.join(global.codecept_dir, stepFile);
110+
stepFile = fsPath.join(global.codecept_dir, stepFile)
111111
}
112112

113113
const snippets = [...newSteps.values()]
@@ -117,18 +117,18 @@ module.exports = function (genPath, options) {
117117
${step.type}(${step.regexp ? '/^' : "'"}${step}${step.regexp ? '$/' : "'"}, () => {
118118
// From "${step.file}" ${JSON.stringify(step.location)}
119119
throw new Error('Not implemented yet');
120-
});`;
121-
});
120+
});`
121+
})
122122

123123
if (!snippets.length) {
124-
output.print('No new snippets found');
125-
return;
124+
output.print('No new snippets found')
125+
return
126126
}
127-
output.success(`Snippets generated: ${snippets.length}`);
128-
output.print(snippets.join('\n'));
127+
output.success(`Snippets generated: ${snippets.length}`)
128+
output.print(snippets.join('\n'))
129129

130130
if (!options.dryRun) {
131-
output.success(`Snippets added to ${output.colors.bold(stepFile)}`);
132-
fs.writeFileSync(stepFile, fs.readFileSync(stepFile).toString() + snippets.join('\n') + '\n');
131+
output.success(`Snippets added to ${output.colors.bold(stepFile)}`)
132+
fs.writeFileSync(stepFile, fs.readFileSync(stepFile).toString() + snippets.join('\n') + '\n')
133133
}
134-
};
134+
}

lib/command/run-multiple/chunk.js

Lines changed: 48 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,94 @@
1-
const glob = require('glob');
2-
const path = require('path');
3-
const fs = require('fs');
1+
const { globSync } = require('glob')
2+
const path = require('path')
3+
const fs = require('fs')
44

55
/**
66
* Splits a list to (n) parts, defined via the size argument.
77
*/
88
const splitFiles = (list, size) => {
9-
const sets = [];
10-
const chunks = list.length / size;
11-
let i = 0;
9+
const sets = []
10+
const chunks = list.length / size
11+
let i = 0
1212

1313
while (i < chunks) {
14-
sets[i] = list.splice(0, size);
15-
i++;
14+
sets[i] = list.splice(0, size)
15+
i++
1616
}
1717

18-
return sets;
19-
};
18+
return sets
19+
}
2020

2121
/**
2222
* Executes a glob pattern and pushes the results to a list.
2323
*/
24-
const findFiles = (pattern) => {
25-
const files = [];
24+
const findFiles = pattern => {
25+
const files = []
2626

27-
glob.sync(pattern).forEach((file) => {
28-
files.push(path.resolve(file));
29-
});
27+
globSync(pattern).forEach(file => {
28+
files.push(path.resolve(file))
29+
})
3030

31-
return files;
32-
};
31+
return files
32+
}
3333

3434
/**
3535
* Joins a list of files to a valid glob pattern
3636
*/
37-
const flattenFiles = (list) => {
38-
const pattern = list.join(',');
39-
return pattern.indexOf(',') > -1 ? `{${pattern}}` : pattern;
40-
};
37+
const flattenFiles = list => {
38+
const pattern = list.join(',')
39+
return pattern.indexOf(',') > -1 ? `{${pattern}}` : pattern
40+
}
4141

4242
/**
4343
* Greps a file by its content, checks if Scenario or Feature text'
4444
* matches the grep text.
4545
*/
4646
const grepFile = (file, grep) => {
47-
const contents = fs.readFileSync(file, 'utf8');
48-
const pattern = new RegExp(`((Scenario|Feature)\(.*${grep}.*\))`, 'g'); // <- How future proof/solid is this?
49-
return !!pattern.exec(contents);
50-
};
47+
const contents = fs.readFileSync(file, 'utf8')
48+
const pattern = new RegExp(`((Scenario|Feature)\(.*${grep}.*\))`, 'g') // <- How future proof/solid is this?
49+
return !!pattern.exec(contents)
50+
}
5151

52-
const mapFileFormats = (files) => {
52+
const mapFileFormats = files => {
5353
return {
5454
gherkin: files.filter(file => file.match(/\.feature$/)),
5555
js: files.filter(file => file.match(/\.t|js$/)),
56-
};
57-
};
56+
}
57+
}
5858

5959
/**
6060
* Creates a list of chunks incl. configuration by either dividing a list of scenario
6161
* files by the passed number or executing a usder deifned function to perform
6262
* the splitting.
6363
*/
6464
const createChunks = (config, patterns = []) => {
65-
const files = patterns.filter(pattern => !!pattern).map((pattern) => {
66-
return findFiles(pattern).filter((file) => {
67-
return config.grep ? grepFile(file, config.grep) : true;
68-
});
69-
}).reduce((acc, val) => acc.concat(val), []);
65+
const files = patterns
66+
.filter(pattern => !!pattern)
67+
.map(pattern => {
68+
return findFiles(pattern).filter(file => {
69+
return config.grep ? grepFile(file, config.grep) : true
70+
})
71+
})
72+
.reduce((acc, val) => acc.concat(val), [])
7073

71-
let chunks = [];
74+
let chunks = []
7275
if (typeof config.chunks === 'function') {
73-
chunks = config.chunks.call(this, files);
76+
chunks = config.chunks.call(this, files)
7477
} else if (typeof config.chunks === 'number' || typeof config.chunks === 'string') {
75-
chunks = splitFiles(files, Math.ceil(files.length / config.chunks));
78+
chunks = splitFiles(files, Math.ceil(files.length / config.chunks))
7679
} else {
77-
throw new Error('chunks is neither a finite number or a valid function');
80+
throw new Error('chunks is neither a finite number or a valid function')
7881
}
7982

80-
const chunkConfig = { ...config };
81-
delete chunkConfig.chunks;
83+
const chunkConfig = { ...config }
84+
delete chunkConfig.chunks
8285

83-
return chunks.map((chunkFiles) => {
84-
const { js, gherkin } = mapFileFormats(chunkFiles);
85-
return { ...chunkConfig, tests: flattenFiles(js), gherkin: { features: flattenFiles(gherkin) } };
86-
});
87-
};
86+
return chunks.map(chunkFiles => {
87+
const { js, gherkin } = mapFileFormats(chunkFiles)
88+
return { ...chunkConfig, tests: flattenFiles(js), gherkin: { features: flattenFiles(gherkin) } }
89+
})
90+
}
8891

8992
module.exports = {
9093
createChunks,
91-
};
94+
}

lib/container.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const glob = require('glob')
1+
const { globSync } = require('glob')
22
const path = require('path')
33
const debug = require('debug')('codeceptjs:container')
44
const { MetaStep } = require('./step')
@@ -464,7 +464,7 @@ function loadGherkinSteps(paths) {
464464
} else {
465465
const folderPath = paths.startsWith('.') ? path.join(global.codecept_dir, paths) : ''
466466
if (folderPath !== '') {
467-
glob.sync(folderPath).forEach(file => {
467+
globSync(folderPath).forEach(file => {
468468
loadSupportObject(file, `Step Definition from ${file}`)
469469
})
470470
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
"figures": "3.2.0",
9595
"fn-args": "4.0.0",
9696
"fs-extra": "11.3.0",
97-
"glob": "^11.0.1",
97+
"glob": ">=9.0.0 <12",
9898
"fuse.js": "^7.0.0",
9999
"html-minifier-terser": "7.2.0",
100100
"inquirer": "6.5.2",

0 commit comments

Comments
 (0)