codeceptjs
Advanced tools
Changelog
3.5.8
Thanks all to those who contributed to make this release!
🐛 Bug Fixes fix(appium): type of setNetworkConnection() (#3994) - by @mirao fix: improve the way to show deprecated appium v1 message (#3992) - by @KobeNguyenT fix: missing exit condition of some wait functions - by @KobeNguyenT
Changelog
3.5.7
Thanks all to those who contributed to make this release!
🐛 Bug Fixes
npx playwright install
to install the browsers as starting from 1.39.0 browsers are not installed automatically (#3924) - by @KobeNguyenTFunktionalität: Faker examples
Szenariogrundriss: Atualizar senha do usuário
Angenommen que estou logado via REST com o usuário "<customer>"
| protocol | https: |
| hostname | https://cucumber.io/docs/gherkin/languages/ |
Faker examples --
Atualizar senha do usuário {"product":"{{vehicle.vehicle}}","customer":"Dr. {{name.findName}}","price":"{{commerce.price}}","cashier":"cashier 2"}
On Angenommen: que estou logado via rest com o usuário "dr. {{name.find name}}"
protocol | https:
hostname | https://cucumber.io/docs/gherkin/languages/
Dr. {{name.findName}}
✔ OK in 13ms
Renamed haveRequestHeaders of Puppeteer, Playwright helper so that it would not confuse the REST helper.
Puppeteer: setPuppeteerRequestHeaders
Playwright: setPlaywrightRequestHeaders
With this fix, we could now use the following syntax:
export = new Factory()
.attr('name', () => faker.name.findName())
.attr('job', () => 'leader');
export default new Factory()
.attr('name', () => faker.name.findName())
.attr('job', () => 'leader');
modules.export = new Factory()
.attr('name', () => faker.name.findName())
.attr('job', () => 'leader');
📖 Documentation
🛩️ Features
[Trace Recording Customization]
Trace recording provides complete information on test execution and includes screenshots, and network requests logged during run. Traces will be saved to output/trace
trace: enables trace recording for failed tests; trace are saved into output/trace folder
keepTraceForPassedTests: - save trace for passed tests
* This helper allows performing assertions based on Chai.
*
* ### Examples
*
* Zero-configuration when paired with other helpers like REST, Playwright:
*
* ```js
* // inside codecept.conf.js
*{
* helpers: {
* Playwright: {...},
* ExpectHelper: {},
* }
Expect Helper
#expectEqual
#expectNotEqual
#expectContain
#expectNotContain
#expectStartsWith
#expectNotStartsWith
#expectEndsWith
#expectNotEndsWith
#expectJsonSchema
#expectHasProperty
#expectHasAProperty
#expectToBeA
#expectToBeAn
#expectMatchRegex
#expectLengthOf
#expectTrue
#expectEmpty
#expectFalse
#expectAbove
#expectBelow
#expectLengthAboveThan
#expectLengthBelowThan
#expectLengthBelowThan
#expectDeepMembers
#expectDeepIncludeMembers
#expectDeepEqualExcluding
#expectLengthBelowThan
- grabCheckedElementStatus
- grabDisabledElementStatus
#language: de
Funktionalität: Checkout-Prozess
Um Produkte zu kaufen
Als Kunde
Möchte ich in der Lage sein, mehrere Produkte zu kaufen
@i18n
Szenariogrundriss: Bestellrabatt
Angenommen ich habe ein Produkt mit einem Preis von <price>$ in meinem Warenkorb
Und der Rabatt für Bestellungen über $20 beträgt 10 %
Wenn ich zur Kasse gehe
Dann sollte ich den Gesamtpreis von "<total>" $ sehen
Beispiele:
| price | total |
| 10 | 10.0 |
Instead of asserting on page elements for the current user in check, you can use the session you saved in fetch
autoLogin: {
enabled: true,
saveToFile: true,
inject: 'login',
users: {
admin: {
login: async (I) => { // If you use async function in the autoLogin plugin
const phrase = await I.grabTextFrom('#phrase')
I.fillField('username', 'admin'),
I.fillField('password', 'password')
I.fillField('phrase', phrase)
},
check: (I, session) => {
// Throwing an error in `check` will make CodeceptJS perform the login step for the user
if (session.profile.email !== the.email.you.expect@some-mail.com) {
throw new Error ('Wrong user signed in');
}
},
}
}
}
Scenario('login', async ( {I, login} ) => {
await login('admin') // you should use `await`
})
Changelog
3.5.6
Thanks all to those who contributed to make this release!
🐛 Bug Fixes
verbose/ highlight TRUE TRUE -> highlight element
verbose/ highlight TRUE FALSE -> no highlight element
verbose/ highlight FALSE TRUE -> no highlight element
verbose/ highlight FALSE FALSE -> no highlight element
const accounts = new DataTable(['role', 'username', 'password']);
accounts.add([
'ROLE_A',
process.env['FIRST_USERNAME'],
secret(process.env['FIRST_PASSWORD']),
]);
accounts.add([
'ROLE_B',
process.env['SECOND_USERNAME'],
secret(process.env['SECOND_PASSWORD']),
]);
Data(accounts)
.Scenario(
'ScenarioTitle',
({ I, pageObject, current }) => {
I.say("Given I'am logged in");
I.amOnPage('/');
loginPage.**sendForm**(current.username, current.password);
)
// output
The test feature --
The scenario | {"username":"Username","password": ***}
'The real password: theLoggedPasswordInCleartext'
I.fillField('somePasswordLocator', '****')
✔ OK in 7ms
The scenario | {"username":"theSecondUsername","password": ***}
'The real password: theLoggedPasswordInCleartext'
I.fillField('somePasswordLocator', '****')
✔ OK in 1ms
📖 Documentation
🛩️ Features
- Add some french keywords for translation
- I.waitForClickable has the same "attends" than I.wait. Using "attends" leads to use the deprecated waitForClickable. Fix it by using different words.
Changelog
3.5.5
🐛 Bug Fixes
export const caps = {
androidCaps: {
appiumV2: true,
host: "hub-cloud.browserstack.com",
port: 4444,
user: process.env.BROWSERSTACK_USER,
key: process.env.BROWSERSTACK_KEY,
'app': `bs://c700ce60cf13ae8ed97705a55b8e022f1hjhkjh3c5827c`,
browser: '',
desiredCapabilities: {
'appPackage': data.packageName,
'deviceName': process.env.DEVICE || 'Google Pixel 3',
'platformName': process.env.PLATFORM || 'android',
'platformVersion': process.env.OS_VERSION || '10.0',
'automationName': process.env.ENGINE || 'UIAutomator2',
'newCommandTimeout': 300000,
'androidDeviceReadyTimeout': 300000,
'androidInstallTimeout': 90000,
'appWaitDuration': 300000,
'autoGrantPermissions': true,
'gpsEnabled': true,
'isHeadless': false,
'noReset': false,
'noSign': true,
'bstack:options' : {
"appiumVersion" : "2.0.1",
},
}
},
}
I.switchTo({ css: 'iframe[id^=number-frame]' }) // support the strict locator
I.amOnPage('/iframe');
within({
frame: { css: '#number-frame-1234' }, // support the strict locator
}, () => {
I.fillField('user[login]', 'User');
I.fillField('user[email]', 'user@user.com');
I.fillField('user[password]', 'user@user.com');
I.click('button');
});
include: {
Je: './steps_file.js'
}
helpers: {
Playwright: {
bypassCSP: true
}
🛩️ Features and Improvements
Environment information:-
codeceptVersion: "3.5.4"
nodeInfo: 18.16.0
osInfo: macOS 13.5
cpuInfo: (8) arm64 Apple M1 Pro
chromeInfo: 116.0.5845.179
edgeInfo: 116.0.1938.69
firefoxInfo: Not Found
safariInfo: 16.6
helpers: {
"Playwright": {
"url": "https://github.com",
"show": false,
"browser": "chromium",
"waitForNavigation": "load",
"waitForTimeout": 30000,
"trace": false,
"keepTraceForPassedTests": true
},
"CDPHelper": {
"require": "./helpers/CDPHelper.ts"
},
"OpenAI": {
"chunkSize": 8000
},
"ExpectHelper": {
"require": "codeceptjs-expect"
},
"REST": {
"endpoint": "https://reqres.in",
"timeout": 20000
},
"AllureHelper": {
"require": "./helpers/AllureHelper.ts"
}
}
plugins: {
"screenshotOnFail": {
"enabled": true
},
"tryTo": {
"enabled": true
},
"retryFailedStep": {
"enabled": true
},
"retryTo": {
"enabled": true
},
"eachElement": {
"enabled": true
},
"pauseOnFail": {}
}
***************************************
If you have questions ask them in our Slack: http://bit.ly/chat-codeceptjs
Or ask them on our discussion board: https://codecept.discourse.group/
Please copy environment info when you report issues on GitHub: https://github.com/Codeception/CodeceptJS/issues
***************************************
CodeceptJS v3.5.4 #StandWithUkraine
await I.amOnPage('/form/field_values');
await I.dontSeeInField('checkbox[]', secret('not seen one'));
await I.seeInField('checkbox[]', secret('see test one'));
await I.dontSeeInField('checkbox[]', secret('not seen two'));
await I.seeInField('checkbox[]', secret('see test two'));
await I.dontSeeInField('checkbox[]', secret('not seen three'));
await I.seeInField('checkbox[]', secret('see test three'));
🛩️ Several bugfixes and improvements for Codecept-UI
Changelog
3.5.4
🐛 Bug Fixes:
userDataDir
, it throws error after test execution (#3814) - by @KobeNguyenTall
with run-workers
(#3805) - by @KobeNguyenT helpers: {
Playwright: {
url: 'https://github.com',
show: false,
browser: 'chromium',
waitForNavigation: 'load',
waitForTimeout: 30_000,
trace: true,
keepTraceForPassedTests: true
},
},
multiple: {
profile1: {
browsers: [
{
browser: "chromium",
}
]
},
},
 
symbol in I.see
method (#3815) - by @KobeNguyenT// HTML code uses instead of space
<div class="dJHe_" style="color: rgb(255, 255, 255);">My Text!</div>
I.see("My Text!") // this test would work with both and space
📖 Documentation
const path = require("path");
exports.config = {
helpers: {
Playwright: {
browser: "electron",
electron: {
executablePath: require("electron"),
args: [path.join(__dirname, ".webpack/main/index.js")],
},
},
},
// rest of config
}
🛩️ Features
const traffics = await I.grabRecordedNetworkTraffics();
expect(traffics[0].url).to.equal('https://reqres.in/api/comments/1');
expect(traffics[0].response.status).to.equal(200);
expect(traffics[0].response.body).to.contain({ name: 'this was mocked' });
expect(traffics[1].url).to.equal('https://reqres.in/api/comments/1');
expect(traffics[1].response.status).to.equal(200);
expect(traffics[1].response.body).to.contain({ name: 'this was another mocked' });
const metrics = await I.grabMetrics();
// returned metrics
[
{ name: 'Timestamp', value: 1584904.203473 },
{ name: 'AudioHandlers', value: 0 },
{ name: 'AudioWorkletProcessors', value: 0 },
{ name: 'Documents', value: 22 },
{ name: 'Frames', value: 10 },
{ name: 'JSEventListeners', value: 366 },
{ name: 'LayoutObjects', value: 1240 },
{ name: 'MediaKeySessions', value: 0 },
{ name: 'MediaKeys', value: 0 },
{ name: 'Nodes', value: 4505 },
{ name: 'Resources', value: 141 },
{ name: 'ContextLifecycleStateObservers', value: 34 },
{ name: 'V8PerContextDatas', value: 4 },
{ name: 'WorkerGlobalScopes', value: 0 },
{ name: 'UACSSResources', value: 0 },
{ name: 'RTCPeerConnections', value: 0 },
{ name: 'ResourceFetchers', value: 22 },
{ name: 'AdSubframes', value: 0 },
{ name: 'DetachedScriptStates', value: 2 },
{ name: 'ArrayBufferContents', value: 1 },
{ name: 'LayoutCount', value: 0 },
{ name: 'RecalcStyleCount', value: 0 },
{ name: 'LayoutDuration', value: 0 },
{ name: 'RecalcStyleDuration', value: 0 },
{ name: 'DevToolsCommandDuration', value: 0.000013 },
{ name: 'ScriptDuration', value: 0 },
{ name: 'V8CompileDuration', value: 0 },
{ name: 'TaskDuration', value: 0.000014 },
{ name: 'TaskOtherDuration', value: 0.000001 },
{ name: 'ThreadTime', value: 0.000046 },
{ name: 'ProcessTime', value: 0.616852 },
{ name: 'JSHeapUsedSize', value: 19004908 },
{ name: 'JSHeapTotalSize', value: 26820608 },
{ name: 'FirstMeaningfulPaint', value: 0 },
{ name: 'DomContentLoaded', value: 1584903.690491 },
{ name: 'NavigationStart', value: 1584902.841845 }
]
flushWebSocketMessages
grabWebSocketMessages
startRecordingWebSocketMessages
stopRecordingWebSocketMessages
await I.startRecordingWebSocketMessages();
I.amOnPage('https://websocketstest.com/');
I.waitForText('Work for You!');
I.flushNetworkTraffics();
const wsMessages = I.grabWebSocketMessages();
expect(wsMessages.length).to.equal(0);
await I.startRecordingWebSocketMessages();
await I.amOnPage('https://websocketstest.com/');
I.waitForText('Work for You!');
const wsMessages = I.grabWebSocketMessages();
expect(wsMessages.length).to.greaterThan(0);
await I.startRecordingWebSocketMessages();
await I.amOnPage('https://websocketstest.com/');
I.waitForText('Work for You!');
const wsMessages = I.grabWebSocketMessages();
await I.stopRecordingWebSocketMessages();
await I.amOnPage('https://websocketstest.com/');
I.waitForText('Work for You!');
const afterWsMessages = I.grabWebSocketMessages();
expect(wsMessages.length).to.equal(afterWsMessages.length);
ElementHandle
to Locator
. This change is quite major, but it happened under hood, so should not affect your code. (#3738) - by @KobeNguyenTChangelog
3.5.3
🛩️ Features
startRecordingTraffic
grabRecordedNetworkTraffics
blockTraffic
mockTraffic
flushNetworkTraffics
stopRecordingTraffic
seeTraffic
grabTrafficUrl
dontSeeTraffic
Examples:
// recording traffics and verify the traffic
await I.startRecordingTraffic();
I.amOnPage('https://codecept.io/');
await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' });
// block the traffic
I.blockTraffic('https://reqres.in/api/comments/*');
await I.amOnPage('/form/fetch_call');
await I.startRecordingTraffic();
await I.click('GET COMMENTS');
await I.see('Can not load data!');
// check the traffic with advanced params
I.amOnPage('https://openai.com/blog/chatgpt');
await I.startRecordingTraffic();
await I.seeTraffic({
name: 'sentry event',
url: 'https://images.openai.com/blob/cf717bdb-0c8c-428a-b82b-3c3add87a600',
parameters: {
width: '1919',
height: '1138',
},
});
🐛 Bugfix
🗑 Deprecated