Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about config name here?


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
Loading