Skip to content

Commit

Permalink
Check command (#4727)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
DavertMik and DavertMik authored Jan 9, 2025
1 parent 2e067e4 commit 4a1f385
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 30 deletions.
61 changes: 31 additions & 30 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,40 +15,41 @@ env:

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [20.x]

steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- uses: shivammathur/setup-php@v2
with:
php-version: 7.4
- name: npm install
run: |
npm i --force
env:
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
- name: Install browsers and deps
run: npx playwright install && npx playwright install-deps
- name: start a server
run: "php -S 127.0.0.1:8000 -t test/data/app &"
- name: run chromium tests
run: "./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug"
- name: run chromium with restart==browser tests
run: "BROWSER_RESTART=browser ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug"
- name: run chromium with restart==session tests
run: "BROWSER_RESTART=session ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug"
- name: run firefox tests
run: "BROWSER=firefox node ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug"
- name: run webkit tests
run: "BROWSER=webkit node ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug"
- name: run chromium unit tests
run: ./node_modules/.bin/mocha test/helper/Playwright_test.js --timeout 5000
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- uses: shivammathur/setup-php@v2
with:
php-version: 7.4
- name: npm install
run: |
npm i --force
env:
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
- name: Install browsers and deps
run: npx playwright install && npx playwright install-deps
- name: check
run: './bin/codecept.js check -c test/acceptance/codecept.Playwright.js'
- name: start a server
run: 'php -S 127.0.0.1:8000 -t test/data/app &'
- name: run chromium tests
run: './bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug'
- name: run chromium with restart==browser tests
run: 'BROWSER_RESTART=browser ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug'
- name: run chromium with restart==session tests
run: 'BROWSER_RESTART=session ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug'
- name: run firefox tests
run: 'BROWSER=firefox node ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug'
- name: run webkit tests
run: 'BROWSER=webkit node ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug'
- name: run chromium unit tests
run: ./node_modules/.bin/mocha test/helper/Playwright_test.js --timeout 5000
2 changes: 2 additions & 0 deletions .github/workflows/webdriver.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ jobs:
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
- name: start a server
run: 'php -S 127.0.0.1:8000 -t test/data/app &'
- name: Check CodeceptJS can be started
run: './bin/codecept.js check -c test/acceptance/codecept.WebDriver.js'
- name: run unit tests
run: ./node_modules/.bin/mocha test/helper/WebDriver_test.js --exit
- name: run tests
Expand Down
7 changes: 7 additions & 0 deletions bin/codecept.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ program
.description('Creates dummy config in current dir or [path]')
.action(errorHandler(require('../lib/command/init')))

program
.command('check')
.option(commandFlags.config.flag, commandFlags.config.description)
.description('Checks configuration and environment before running tests')
.option('-t, --timeout [ms]', 'timeout for checks in ms, 20000 by default')
.action(errorHandler(require('../lib/command/check')))

program
.command('migrate [path]')
.description('Migrate json config to js config in current dir or [path]')
Expand Down
173 changes: 173 additions & 0 deletions lib/command/check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
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')
const chalk = require('chalk')
const { createTest } = require('../mocha/test')
const { getMachineInfo } = require('./info')
const definitions = require('./definitions')

module.exports = async function (options) {
const configFile = options.config

setTimeout(() => {
output.error("Something went wrong. Checks didn't pass and timed out. Please check your config and helpers.")
process.exit(1)
}, options.timeout || 50000)

const checks = {
config: false,
container: false,
pageObjects: false,
helpers: false,
setup: false,
tests: false,
def: false,
}

const testRoot = getTestRoot(configFile)
let config = getConfig(configFile)

try {
config = getConfig(configFile)
checks['config'] = true
} catch (err) {
checks['config'] = err
}

printCheck('config', checks['config'], config.name)

let codecept
try {
codecept = new Codecept(config, options)
codecept.init(testRoot)
await container.started()
checks.container = true
} catch (err) {
checks.container = err
}

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

if (codecept) {
try {
if (options.bootstrap) await codecept.bootstrap()
checks.bootstrap = true
} catch (err) {
checks.bootstrap = err
}
printCheck('bootstrap', checks['bootstrap'], options.bootstrap ? 'Bootstrap was executed' : 'No bootstrap command')
}

let numTests = 0
if (codecept) {
try {
codecept.loadTests()
const mocha = container.mocha()
mocha.files = codecept.testFiles
mocha.loadFiles()
mocha.suite.suites.forEach(suite => {
numTests += suite.tests.length
})
if (numTests > 0) {
checks.tests = true
} else {
throw new Error('No tests found')
}
} catch (err) {
checks.tests = err
}
}

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

store.dryRun = true

const helpers = container.helpers()

try {
if (!Object.keys(helpers).length) throw new Error('No helpers found')
// load helpers
for (const helper of Object.values(helpers)) {
if (helper._init) helper._init()
}
checks.helpers = true
} catch (err) {
checks.helpers = err
}

printCheck('helpers', checks['helpers'], `${Object.keys(helpers).join(', ')}`)

const pageObjects = container.support()

try {
if (Object.keys(pageObjects).length) {
for (const pageObject of Object.values(pageObjects)) {
pageObject.name
}
}
checks.pageObjects = true
} catch (err) {
checks.pageObjects = err
}
printCheck('page objects', checks['pageObjects'], `Total: ${Object.keys(pageObjects).length} support objects`)

if (Object.keys(helpers).length) {
const suite = container.mocha().suite
const test = createTest('test', () => {})
try {
for (const helper of Object.values(helpers)) {
if (helper._beforeSuite) await helper._beforeSuite(suite)
if (helper._before) await helper._before(test)
if (helper._passed) await helper._passed(test)
if (helper._after) await helper._after(test)
if (helper._finishTest) await helper._finishTest(suite)
if (helper._afterSuite) await helper._afterSuite(suite)
}
checks.setup = true
} catch (err) {
checks.setup = err
}
}

printCheck('Helpers Before/After', checks['setup'], standardActingHelpers.some(h => Object.keys(helpers).includes(h)) ? 'Initializing and closing browser' : '')

try {
definitions(configFile, { dryRun: true })
checks.def = true
} catch (err) {
checks.def = err
}

printCheck('TypeScript Definitions', checks['def'])

output.print('')

if (!Object.values(checks).every(check => check === true)) {
output.error("Something went wrong. Checks didn't pass.")
output.print()
await getMachineInfo()
process.exit(1)
}

output.print(output.styles.success('All checks passed'.toUpperCase()), 'Ready to run your tests 🚀')
process.exit(0)
}

function printCheck(name, value, comment = '') {
let status = ''
if (value == true) {
status += chalk.bold.green(figures.tick)
} else {
status += chalk.bold.red(figures.cross)
}

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

output.print(status, name.toUpperCase(), chalk.dim(comment))
}
2 changes: 2 additions & 0 deletions lib/command/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ module.exports = function (genPath, options) {
definitionsFileContent += `\n${translationAliases.join('\n')}`
}

if (options.dryRun) return

fs.writeFileSync(path.join(targetFolderPath, 'steps.d.ts'), definitionsFileContent)
output.print('TypeScript Definitions provide autocompletion in Visual Studio Code and other IDEs')
output.print('Definitions were generated in steps.d.ts')
Expand Down
9 changes: 9 additions & 0 deletions lib/container.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const glob = require('glob')
const path = require('path')
const debug = require('debug')('codeceptjs:container')
const { MetaStep } = require('./step')
const { methodsOfObject, fileExists, isFunction, isAsyncFunction, installedLocally } = require('./utils')
const Translation = require('./translation')
Expand Down Expand Up @@ -38,6 +39,7 @@ class Container {
* @param {*} opts
*/
static create(config, opts) {
debug('creating container')
asyncHelperPromise = Promise.resolve()

// dynamically create mocha instance
Expand Down Expand Up @@ -134,6 +136,7 @@ class Container {
static append(newContainer) {
const deepMerge = require('./utils').deepMerge
container = deepMerge(container, newContainer)
debug('appended', JSON.stringify(newContainer).slice(0, 300))
}

/**
Expand All @@ -150,6 +153,7 @@ class Container {
container.plugins = newPlugins || {}
asyncHelperPromise = Promise.resolve()
store.actor = null
debug('container cleared')
}

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

debug(`helper ${helperName} async initialized`)

helpers[helperName] = new ResolvedHelperClass(config[helperName])
})

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

helpers[helperName] = new HelperClass(config[helperName])
debug(`helper ${helperName} initialized`)
} catch (err) {
throw new Error(`Could not load helper ${helperName} (${err.message})`)
}
Expand Down Expand Up @@ -322,6 +329,7 @@ function createSupportObjects(config) {
if (container.support[name]._init) {
container.support[name]._init()
}
debug(`support object ${name} initialized`)
} catch (err) {
throw new Error(`Initialization failed for ${name}: ${container.support[name]}\n${err.message}\n${err.stack}`)
}
Expand All @@ -334,6 +342,7 @@ function createSupportObjects(config) {
const ms = new MetaStep(name, prop)
ms.setContext(currentObject)
if (isAsyncFunction(currentValue)) currentValue = asyncWrapper(currentValue)
debug(`metastep is created for ${name}.${prop.toString()}()`)
return ms.run.bind(ms, currentValue)
}

Expand Down

0 comments on commit 4a1f385

Please sign in to comment.