Skip to content

Commit

Permalink
Merge branch '3.x' into task-4806-bump-cucumber/messages-to-27.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
kobenguyent committed Jan 31, 2025
2 parents 95800a3 + 6865d84 commit 425226c
Show file tree
Hide file tree
Showing 21 changed files with 235 additions and 148 deletions.
26 changes: 14 additions & 12 deletions lib/codecept.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { existsSync, readFileSync } = require('fs')
const glob = require('glob')
const { globSync } = require('glob')
const fsPath = require('path')
const { resolve } = require('path')

Expand Down Expand Up @@ -168,15 +168,17 @@ class Codecept {
}

for (pattern of patterns) {
glob.sync(pattern, options).forEach(file => {
if (file.includes('node_modules')) return
if (!fsPath.isAbsolute(file)) {
file = fsPath.join(global.codecept_dir, file)
}
if (!this.testFiles.includes(fsPath.resolve(file))) {
this.testFiles.push(fsPath.resolve(file))
}
})
if (pattern) {
globSync(pattern, options).forEach(file => {
if (file.includes('node_modules')) return
if (!fsPath.isAbsolute(file)) {
file = fsPath.join(global.codecept_dir, file)
}
if (!this.testFiles.includes(fsPath.resolve(file))) {
this.testFiles.push(fsPath.resolve(file))
}
})
}
}
}

Expand All @@ -200,12 +202,12 @@ class Codecept {
}
const done = () => {
event.emit(event.all.result, container.result())
event.emit(event.all.after)
event.emit(event.all.after, this)
resolve()
}

try {
event.emit(event.all.before)
event.emit(event.all.before, this)
mocha.run(() => done())
} catch (e) {
output.error(e.stack)
Expand Down
13 changes: 11 additions & 2 deletions lib/command/check.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const { getConfig, getTestRoot } = require('./utils')
const Codecept = require('../codecept')
const output = require('../output')
const standardActingHelpers = require('../plugin/standardActingHelpers')
const store = require('../store')
const container = require('../container')
const figures = require('figures')
Expand All @@ -23,6 +22,7 @@ module.exports = async function (options) {
container: false,
pageObjects: false,
plugins: false,
ai: true, // we don't need to check AI
helpers: false,
setup: false,
tests: false,
Expand Down Expand Up @@ -51,6 +51,8 @@ module.exports = async function (options) {
checks.container = err
}

const standardActingHelpers = container.STANDARD_ACTING_HELPERS

printCheck('container', checks['container'])

if (codecept) {
Expand Down Expand Up @@ -83,6 +85,13 @@ module.exports = async function (options) {
}
}

if (config?.ai?.request) {
checks.ai = true
printCheck('ai', checks['ai'], 'AI configuration is enabled, request function is set')
} else {
printCheck('ai', checks['ai'], 'AI is disabled')
}

printCheck('tests', checks['tests'], `Total: ${numTests} tests`)

store.dryRun = true
Expand Down Expand Up @@ -170,7 +179,7 @@ function printCheck(name, value, comment = '') {
}

if (value instanceof Error) {
comment = `${comment} ${chalk.red.italic(value.message)}`.trim()
comment = `${comment} ${chalk.red(value.message)}`.trim()
}

output.print(status, name.toUpperCase(), chalk.dim(comment))
Expand Down
2 changes: 1 addition & 1 deletion lib/command/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const { getConfig, getTestRoot } = require('./utils')
const Codecept = require('../codecept')
const container = require('../container')
const output = require('../output')
const actingHelpers = [...require('../plugin/standardActingHelpers'), 'REST']
const actingHelpers = [...container.STANDARD_ACTING_HELPERS, 'REST']

/**
* Prepare data and generate content of definitions file
Expand Down
138 changes: 69 additions & 69 deletions lib/command/gherkin/snippets.js
Original file line number Diff line number Diff line change
@@ -1,113 +1,113 @@
const escapeStringRegexp = require('escape-string-regexp');
const fs = require('fs');
const Gherkin = require('@cucumber/gherkin');
const Messages = require('@cucumber/messages');
const glob = require('glob');
const fsPath = require('path');
const escapeStringRegexp = require('escape-string-regexp')
const fs = require('fs')
const Gherkin = require('@cucumber/gherkin')
const Messages = require('@cucumber/messages')
const { globSync } = require('glob')
const fsPath = require('path')

const { getConfig, getTestRoot } = require('../utils');
const Codecept = require('../../codecept');
const output = require('../../output');
const { matchStep } = require('../../mocha/bdd');
const { getConfig, getTestRoot } = require('../utils')
const Codecept = require('../../codecept')
const output = require('../../output')
const { matchStep } = require('../../mocha/bdd')

const uuidFn = Messages.IdGenerator.uuid();
const builder = new Gherkin.AstBuilder(uuidFn);
const matcher = new Gherkin.GherkinClassicTokenMatcher();
const parser = new Gherkin.Parser(builder, matcher);
parser.stopAtFirstError = false;
const uuidFn = Messages.IdGenerator.uuid()
const builder = new Gherkin.AstBuilder(uuidFn)
const matcher = new Gherkin.GherkinClassicTokenMatcher()
const parser = new Gherkin.Parser(builder, matcher)
parser.stopAtFirstError = false

module.exports = function (genPath, options) {
const configFile = options.config || genPath;
const testsPath = getTestRoot(configFile);
const config = getConfig(configFile);
if (!config) return;
const configFile = options.config || genPath
const testsPath = getTestRoot(configFile)
const config = getConfig(configFile)
if (!config) return

const codecept = new Codecept(config, {});
codecept.init(testsPath);
const codecept = new Codecept(config, {})
codecept.init(testsPath)

if (!config.gherkin) {
output.error('Gherkin is not enabled in config. Run `codecept gherkin:init` to enable it');
process.exit(1);
output.error('Gherkin is not enabled in config. Run `codecept gherkin:init` to enable it')
process.exit(1)
}
if (!config.gherkin.steps || !config.gherkin.steps[0]) {
output.error('No gherkin steps defined in config. Exiting');
process.exit(1);
output.error('No gherkin steps defined in config. Exiting')
process.exit(1)
}
if (!options.feature && !config.gherkin.features) {
output.error('No gherkin features defined in config. Exiting');
process.exit(1);
output.error('No gherkin features defined in config. Exiting')
process.exit(1)
}
if (options.path && !config.gherkin.steps.includes(options.path)) {
output.error(`You must include ${options.path} to the gherkin steps in your config file`);
process.exit(1);
output.error(`You must include ${options.path} to the gherkin steps in your config file`)
process.exit(1)
}

const files = [];
glob.sync(options.feature || config.gherkin.features, { cwd: options.feature ? '.' : global.codecept_dir }).forEach(file => {
const files = []
globSync(options.feature || config.gherkin.features, { cwd: options.feature ? '.' : global.codecept_dir }).forEach(file => {
if (!fsPath.isAbsolute(file)) {
file = fsPath.join(global.codecept_dir, file);
file = fsPath.join(global.codecept_dir, file)
}
files.push(fsPath.resolve(file));
});
output.print(`Loaded ${files.length} files`);
files.push(fsPath.resolve(file))
})
output.print(`Loaded ${files.length} files`)

const newSteps = new Map();
const newSteps = new Map()

const parseSteps = steps => {
const newSteps = [];
let currentKeyword = '';
const newSteps = []
let currentKeyword = ''
for (const step of steps) {
if (step.keyword.trim() === 'And') {
if (!currentKeyword) throw new Error(`There is no active keyword for step '${step.text}'`);
step.keyword = currentKeyword;
if (!currentKeyword) throw new Error(`There is no active keyword for step '${step.text}'`)
step.keyword = currentKeyword
}
currentKeyword = step.keyword;
currentKeyword = step.keyword
try {
matchStep(step.text);
matchStep(step.text)
} catch (err) {
let stepLine;
let stepLine
if (/[{}()/]/.test(step.text)) {
stepLine = escapeStringRegexp(step.text)
.replace(/\//g, '\\/')
.replace(/\"(.*?)\"/g, '"(.*?)"')
.replace(/(\d+\\\.\d+)/, '(\\d+\\.\\d+)')
.replace(/ (\d+) /, ' (\\d+) ');
stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: true });
.replace(/ (\d+) /, ' (\\d+) ')
stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: true })
} else {
stepLine = step.text
.replace(/\"(.*?)\"/g, '{string}')
.replace(/(\d+\.\d+)/, '{float}')
.replace(/ (\d+) /, ' {int} ');
stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: false });
.replace(/ (\d+) /, ' {int} ')
stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: false })
}
newSteps.push(stepLine);
newSteps.push(stepLine)
}
}
return newSteps;
};
return newSteps
}

const parseFile = file => {
const ast = parser.parse(fs.readFileSync(file).toString());
const ast = parser.parse(fs.readFileSync(file).toString())
for (const child of ast.feature.children) {
if (child.scenario.keyword === 'Scenario Outline') continue; // skip scenario outline
if (child.scenario.keyword === 'Scenario Outline') continue // skip scenario outline
parseSteps(child.scenario.steps)
.map(step => {
return Object.assign(step, { file: file.replace(global.codecept_dir, '').slice(1) });
return Object.assign(step, { file: file.replace(global.codecept_dir, '').slice(1) })
})
.map(step => newSteps.set(`${step.type}(${step})`, step));
.map(step => newSteps.set(`${step.type}(${step})`, step))
}
};
}

files.forEach(file => parseFile(file));
files.forEach(file => parseFile(file))

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

if (!fsPath.isAbsolute(stepFile)) {
stepFile = fsPath.join(global.codecept_dir, stepFile);
stepFile = fsPath.join(global.codecept_dir, stepFile)
}

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

if (!snippets.length) {
output.print('No new snippets found');
return;
output.print('No new snippets found')
return
}
output.success(`Snippets generated: ${snippets.length}`);
output.print(snippets.join('\n'));
output.success(`Snippets generated: ${snippets.length}`)
output.print(snippets.join('\n'))

if (!options.dryRun) {
output.success(`Snippets added to ${output.colors.bold(stepFile)}`);
fs.writeFileSync(stepFile, fs.readFileSync(stepFile).toString() + snippets.join('\n') + '\n');
output.success(`Snippets added to ${output.colors.bold(stepFile)}`)
fs.writeFileSync(stepFile, fs.readFileSync(stepFile).toString() + snippets.join('\n') + '\n')
}
};
}
2 changes: 1 addition & 1 deletion lib/command/interactive.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const Codecept = require('../codecept')
const Container = require('../container')
const event = require('../event')
const output = require('../output')
const webHelpers = require('../plugin/standardActingHelpers')
const webHelpers = Container.STANDARD_ACTING_HELPERS

module.exports = async function (path, options) {
// Backward compatibility for --profile
Expand Down
Loading

0 comments on commit 425226c

Please sign in to comment.