Skip to content

Commit 4a1f385

Browse files
DavertMikDavertMik
andauthored
Check command (#4727)
* 3.7.0-beta.1 * added check command * added file * added debug for container, fixed check command * added support for custom config -c, added checks to workflows * fixed check command * added await for check --------- Co-authored-by: DavertMik <[email protected]>
1 parent 2e067e4 commit 4a1f385

File tree

6 files changed

+224
-30
lines changed

6 files changed

+224
-30
lines changed

.github/workflows/playwright.yml

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,40 +15,41 @@ env:
1515

1616
jobs:
1717
build:
18-
1918
runs-on: ubuntu-latest
2019

2120
strategy:
2221
matrix:
2322
node-version: [20.x]
2423

2524
steps:
26-
- uses: actions/checkout@v4
27-
- name: Use Node.js ${{ matrix.node-version }}
28-
uses: actions/setup-node@v4
29-
with:
30-
node-version: ${{ matrix.node-version }}
31-
- uses: shivammathur/setup-php@v2
32-
with:
33-
php-version: 7.4
34-
- name: npm install
35-
run: |
36-
npm i --force
37-
env:
38-
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
39-
- name: Install browsers and deps
40-
run: npx playwright install && npx playwright install-deps
41-
- name: start a server
42-
run: "php -S 127.0.0.1:8000 -t test/data/app &"
43-
- name: run chromium tests
44-
run: "./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug"
45-
- name: run chromium with restart==browser tests
46-
run: "BROWSER_RESTART=browser ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug"
47-
- name: run chromium with restart==session tests
48-
run: "BROWSER_RESTART=session ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug"
49-
- name: run firefox tests
50-
run: "BROWSER=firefox node ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug"
51-
- name: run webkit tests
52-
run: "BROWSER=webkit node ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug"
53-
- name: run chromium unit tests
54-
run: ./node_modules/.bin/mocha test/helper/Playwright_test.js --timeout 5000
25+
- uses: actions/checkout@v4
26+
- name: Use Node.js ${{ matrix.node-version }}
27+
uses: actions/setup-node@v4
28+
with:
29+
node-version: ${{ matrix.node-version }}
30+
- uses: shivammathur/setup-php@v2
31+
with:
32+
php-version: 7.4
33+
- name: npm install
34+
run: |
35+
npm i --force
36+
env:
37+
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
38+
- name: Install browsers and deps
39+
run: npx playwright install && npx playwright install-deps
40+
- name: check
41+
run: './bin/codecept.js check -c test/acceptance/codecept.Playwright.js'
42+
- name: start a server
43+
run: 'php -S 127.0.0.1:8000 -t test/data/app &'
44+
- name: run chromium tests
45+
run: './bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug'
46+
- name: run chromium with restart==browser tests
47+
run: 'BROWSER_RESTART=browser ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug'
48+
- name: run chromium with restart==session tests
49+
run: 'BROWSER_RESTART=session ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug'
50+
- name: run firefox tests
51+
run: 'BROWSER=firefox node ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug'
52+
- name: run webkit tests
53+
run: 'BROWSER=webkit node ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug'
54+
- name: run chromium unit tests
55+
run: ./node_modules/.bin/mocha test/helper/Playwright_test.js --timeout 5000

.github/workflows/webdriver.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ jobs:
3838
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
3939
- name: start a server
4040
run: 'php -S 127.0.0.1:8000 -t test/data/app &'
41+
- name: Check CodeceptJS can be started
42+
run: './bin/codecept.js check -c test/acceptance/codecept.WebDriver.js'
4143
- name: run unit tests
4244
run: ./node_modules/.bin/mocha test/helper/WebDriver_test.js --exit
4345
- name: run tests

bin/codecept.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ program
5858
.description('Creates dummy config in current dir or [path]')
5959
.action(errorHandler(require('../lib/command/init')))
6060

61+
program
62+
.command('check')
63+
.option(commandFlags.config.flag, commandFlags.config.description)
64+
.description('Checks configuration and environment before running tests')
65+
.option('-t, --timeout [ms]', 'timeout for checks in ms, 20000 by default')
66+
.action(errorHandler(require('../lib/command/check')))
67+
6168
program
6269
.command('migrate [path]')
6370
.description('Migrate json config to js config in current dir or [path]')

lib/command/check.js

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
const { getConfig, getTestRoot } = require('./utils')
2+
const Codecept = require('../codecept')
3+
const output = require('../output')
4+
const standardActingHelpers = require('../plugin/standardActingHelpers')
5+
const store = require('../store')
6+
const container = require('../container')
7+
const figures = require('figures')
8+
const chalk = require('chalk')
9+
const { createTest } = require('../mocha/test')
10+
const { getMachineInfo } = require('./info')
11+
const definitions = require('./definitions')
12+
13+
module.exports = async function (options) {
14+
const configFile = options.config
15+
16+
setTimeout(() => {
17+
output.error("Something went wrong. Checks didn't pass and timed out. Please check your config and helpers.")
18+
process.exit(1)
19+
}, options.timeout || 50000)
20+
21+
const checks = {
22+
config: false,
23+
container: false,
24+
pageObjects: false,
25+
helpers: false,
26+
setup: false,
27+
tests: false,
28+
def: false,
29+
}
30+
31+
const testRoot = getTestRoot(configFile)
32+
let config = getConfig(configFile)
33+
34+
try {
35+
config = getConfig(configFile)
36+
checks['config'] = true
37+
} catch (err) {
38+
checks['config'] = err
39+
}
40+
41+
printCheck('config', checks['config'], config.name)
42+
43+
let codecept
44+
try {
45+
codecept = new Codecept(config, options)
46+
codecept.init(testRoot)
47+
await container.started()
48+
checks.container = true
49+
} catch (err) {
50+
checks.container = err
51+
}
52+
53+
printCheck('container', checks['container'])
54+
55+
if (codecept) {
56+
try {
57+
if (options.bootstrap) await codecept.bootstrap()
58+
checks.bootstrap = true
59+
} catch (err) {
60+
checks.bootstrap = err
61+
}
62+
printCheck('bootstrap', checks['bootstrap'], options.bootstrap ? 'Bootstrap was executed' : 'No bootstrap command')
63+
}
64+
65+
let numTests = 0
66+
if (codecept) {
67+
try {
68+
codecept.loadTests()
69+
const mocha = container.mocha()
70+
mocha.files = codecept.testFiles
71+
mocha.loadFiles()
72+
mocha.suite.suites.forEach(suite => {
73+
numTests += suite.tests.length
74+
})
75+
if (numTests > 0) {
76+
checks.tests = true
77+
} else {
78+
throw new Error('No tests found')
79+
}
80+
} catch (err) {
81+
checks.tests = err
82+
}
83+
}
84+
85+
printCheck('tests', checks['tests'], `Total: ${numTests} tests`)
86+
87+
store.dryRun = true
88+
89+
const helpers = container.helpers()
90+
91+
try {
92+
if (!Object.keys(helpers).length) throw new Error('No helpers found')
93+
// load helpers
94+
for (const helper of Object.values(helpers)) {
95+
if (helper._init) helper._init()
96+
}
97+
checks.helpers = true
98+
} catch (err) {
99+
checks.helpers = err
100+
}
101+
102+
printCheck('helpers', checks['helpers'], `${Object.keys(helpers).join(', ')}`)
103+
104+
const pageObjects = container.support()
105+
106+
try {
107+
if (Object.keys(pageObjects).length) {
108+
for (const pageObject of Object.values(pageObjects)) {
109+
pageObject.name
110+
}
111+
}
112+
checks.pageObjects = true
113+
} catch (err) {
114+
checks.pageObjects = err
115+
}
116+
printCheck('page objects', checks['pageObjects'], `Total: ${Object.keys(pageObjects).length} support objects`)
117+
118+
if (Object.keys(helpers).length) {
119+
const suite = container.mocha().suite
120+
const test = createTest('test', () => {})
121+
try {
122+
for (const helper of Object.values(helpers)) {
123+
if (helper._beforeSuite) await helper._beforeSuite(suite)
124+
if (helper._before) await helper._before(test)
125+
if (helper._passed) await helper._passed(test)
126+
if (helper._after) await helper._after(test)
127+
if (helper._finishTest) await helper._finishTest(suite)
128+
if (helper._afterSuite) await helper._afterSuite(suite)
129+
}
130+
checks.setup = true
131+
} catch (err) {
132+
checks.setup = err
133+
}
134+
}
135+
136+
printCheck('Helpers Before/After', checks['setup'], standardActingHelpers.some(h => Object.keys(helpers).includes(h)) ? 'Initializing and closing browser' : '')
137+
138+
try {
139+
definitions(configFile, { dryRun: true })
140+
checks.def = true
141+
} catch (err) {
142+
checks.def = err
143+
}
144+
145+
printCheck('TypeScript Definitions', checks['def'])
146+
147+
output.print('')
148+
149+
if (!Object.values(checks).every(check => check === true)) {
150+
output.error("Something went wrong. Checks didn't pass.")
151+
output.print()
152+
await getMachineInfo()
153+
process.exit(1)
154+
}
155+
156+
output.print(output.styles.success('All checks passed'.toUpperCase()), 'Ready to run your tests 🚀')
157+
process.exit(0)
158+
}
159+
160+
function printCheck(name, value, comment = '') {
161+
let status = ''
162+
if (value == true) {
163+
status += chalk.bold.green(figures.tick)
164+
} else {
165+
status += chalk.bold.red(figures.cross)
166+
}
167+
168+
if (value instanceof Error) {
169+
comment = `${comment} ${chalk.red.italic(value.message)}`.trim()
170+
}
171+
172+
output.print(status, name.toUpperCase(), chalk.dim(comment))
173+
}

lib/command/definitions.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ module.exports = function (genPath, options) {
185185
definitionsFileContent += `\n${translationAliases.join('\n')}`
186186
}
187187

188+
if (options.dryRun) return
189+
188190
fs.writeFileSync(path.join(targetFolderPath, 'steps.d.ts'), definitionsFileContent)
189191
output.print('TypeScript Definitions provide autocompletion in Visual Studio Code and other IDEs')
190192
output.print('Definitions were generated in steps.d.ts')

lib/container.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const glob = require('glob')
22
const path = require('path')
3+
const debug = require('debug')('codeceptjs:container')
34
const { MetaStep } = require('./step')
45
const { methodsOfObject, fileExists, isFunction, isAsyncFunction, installedLocally } = require('./utils')
56
const Translation = require('./translation')
@@ -38,6 +39,7 @@ class Container {
3839
* @param {*} opts
3940
*/
4041
static create(config, opts) {
42+
debug('creating container')
4143
asyncHelperPromise = Promise.resolve()
4244

4345
// dynamically create mocha instance
@@ -134,6 +136,7 @@ class Container {
134136
static append(newContainer) {
135137
const deepMerge = require('./utils').deepMerge
136138
container = deepMerge(container, newContainer)
139+
debug('appended', JSON.stringify(newContainer).slice(0, 300))
137140
}
138141

139142
/**
@@ -150,6 +153,7 @@ class Container {
150153
container.plugins = newPlugins || {}
151154
asyncHelperPromise = Promise.resolve()
152155
store.actor = null
156+
debug('container cleared')
153157
}
154158

155159
/**
@@ -216,6 +220,8 @@ function createHelpers(config) {
216220
throw new Error(`Helper class from module '${helperName}' is not a class. Use CJS async module syntax.`)
217221
}
218222

223+
debug(`helper ${helperName} async initialized`)
224+
219225
helpers[helperName] = new ResolvedHelperClass(config[helperName])
220226
})
221227

@@ -225,6 +231,7 @@ function createHelpers(config) {
225231
checkHelperRequirements(HelperClass)
226232

227233
helpers[helperName] = new HelperClass(config[helperName])
234+
debug(`helper ${helperName} initialized`)
228235
} catch (err) {
229236
throw new Error(`Could not load helper ${helperName} (${err.message})`)
230237
}
@@ -322,6 +329,7 @@ function createSupportObjects(config) {
322329
if (container.support[name]._init) {
323330
container.support[name]._init()
324331
}
332+
debug(`support object ${name} initialized`)
325333
} catch (err) {
326334
throw new Error(`Initialization failed for ${name}: ${container.support[name]}\n${err.message}\n${err.stack}`)
327335
}
@@ -334,6 +342,7 @@ function createSupportObjects(config) {
334342
const ms = new MetaStep(name, prop)
335343
ms.setContext(currentObject)
336344
if (isAsyncFunction(currentValue)) currentValue = asyncWrapper(currentValue)
345+
debug(`metastep is created for ${name}.${prop.toString()}()`)
337346
return ms.run.bind(ms, currentValue)
338347
}
339348

0 commit comments

Comments
 (0)