# Releases

# 3.6.10

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ› Bug Fixes fix(cli): missing failure counts when there is failedHooks (#4633 (opens new window)) - by kobenguyent (opens new window)

# 3.6.9

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ› Hot Fixes fix: could not run tests due to missing invisi-data lib - by kobenguyent (opens new window)

# 3.6.8

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ›©οΈ Features

export const config: CodeceptJS.MainConfig = {
  tests:  '**/*.e2e.test.ts',
  retry: 4,
  output: './output',
  maskSensitiveData: true,
  emptyOutputFolder: true,
...

    I login {"username":"[email protected]","password": "****"}
      I send post request "https://localhost:8000/login", {"username":"[email protected]","password": "****"}
      β€Ί **[Request]** {"baseURL":"https://localhost:8000/login","method":"POST","data":{"username":"[email protected]","password": "****"},"headers":{}}
      β€Ί **[Response]** {"access-token": "****"}
I.sendDeleteRequestWithPayload('/api/users/1', { author: 'john' });

πŸ› Bug Fixes

> codeceptjs dry-run --steps --grep "(?=.*Checkout process)"
Add hint to "I.seeEmailAttachment" that under the hood parameter is treated as RegExp. 
When you don't know it, it can cause a lot of pain, wondering why your test fails with I.seeEmailAttachment('Attachment(1).pdf') although it looks just fine, but actually I.seeEmailAttachment('Attachment\\(1\\).pdf is required to make the test green, in case the attachment is called "Attachment(1).pdf" with special character in it.

πŸ“– Documentation

# 3.6.6

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ›©οΈ Features

Zero-configuration when paired with other helpers like REST, Playwright:

// inside codecept.conf.js
{
  helpers: {
    Playwright: {...},
    SoftExpectHelper: {},
  }
}
// in scenario
I.softExpectEqual('a', 'b')
I.flushSoftAssertions() // Throws an error if any soft assertions have failed. The error message contains all the accumulated failures.

πŸ› Bug Fixes

// fix the validation of httpAgent config. we could now pass ca, instead of key/cert.
{
  helpers: {
    REST: {
      endpoint: 'http://site.com/api',
      prettyPrintJson: true,
      httpAgent: {
         ca: fs.readFileSync(__dirname + '/path/to/ca.pem'),
         rejectUnauthorized: false,
         keepAlive: true
      }
    }
  }
}

πŸ“– Documentation

# 3.6.5

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ›©οΈ Features

it('should wait for input text field to be disabled', () =>
      I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled('#text', 1)))

    it('should wait for input text field to be enabled by xpath', () =>
      I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled("//*[@name = 'test']", 1)))

    it('should wait for a button to be disabled', () =>
      I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled('#text', 1)))

Waits for element to become disabled (by default waits for 1sec).
Element can be located by CSS or XPath.
 **[param](https://github.com/param)** {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator. **[param](https://github.com/param)** {number} [sec=1] (optional) time in seconds to wait, 1 by default. **[returns](https://github.com/returns)** {void} automatically synchronized promise through #recorder

πŸ› Bug Fixes

πŸ“– Documentation

# 3.6.4

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ›©οΈ Features

Config:

...
REST: {
 ...
 printCurl: true,
 ...
}
... 

β€Ί [CURL Request] curl --location --request POST https://httpbin.org/post -H ...

Screenshot from 2024-06-17 02-47-37

πŸ› Bug Fixes

πŸ“– Documentation

# 3.6.3

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ›©οΈ Features

πŸ› Bug Fixes

πŸ“– Documentation

# 3.6.2

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ›©οΈ Features

Support the httpAgent conf to create the TSL connection via REST helper

{
  helpers: {
    REST: {
      endpoint: 'http://site.com/api',
      prettyPrintJson: true,
      httpAgent: {
         key: fs.readFileSync(__dirname + '/path/to/keyfile.key'),
         cert: fs.readFileSync(__dirname + '/path/to/certfile.cert'),
         rejectUnauthorized: false,
         keepAlive: true
      }
    }
  }
}

Currently only screenshot of the active session is saved, this PR aims to save the screenshot of every session for easy debugging

Scenario('should save screenshot for sessions **[WebDriverIO](https://github.com/WebDriverIO)** **[Puppeteer](https://github.com/Puppeteer)** **[Playwright](https://github.com/Playwright)**', async ({ I }) => {
  await I.amOnPage('/form/bug1467');
  await I.saveScreenshot('original.png');
  await I.amOnPage('/');
  await I.saveScreenshot('main_session.png');
  session('john', async () => {
    await I.amOnPage('/form/bug1467');
    event.dispatcher.emit(event.test.failed, this);
  });

  const fileName = clearString('should save screenshot for active session **[WebDriverIO](https://github.com/WebDriverIO)** **[Puppeteer](https://github.com/Puppeteer)** **[Playwright](https://github.com/Playwright)**');
  const [original, failed] = await I.getSHA256Digests([
    `${output_dir}/original.png`,
    `${output_dir}/john_${fileName}.failed.png`,
  ]);

  // Assert that screenshots of same page in same session are equal
  await I.expectEqual(original, failed);

  // Assert that screenshots of sessions are created
  const [main_original, session_failed] = await I.getSHA256Digests([
    `${output_dir}/main_session.png`,
    `${output_dir}/john_${fileName}.failed.png`,
  ]);
  await I.expectNotEqual(main_original, session_failed);
});

Screenshot 2024-04-29 at 11 07 47

Find an element with class attribute

// find div with class contains 'form'
locate('div').withClassAttr('text');
  url: siteUrl,
  windowSize: '300x500',
  show: false,
  restart: true,
  browser: 'chromium',
  trace: true,
  video: true,
  recordVideo: {
    size: {
      width: 400,
      height: 600,
    },
  },

πŸ› Bug Fixes

πŸ“– Documentation

# 3.6.1

  • Fixed regression in interactive pause.

# 3.6.0

πŸ›©οΈ Features

  • Introduced healers to improve stability of failed tests. Write functions that can perform actions to fix a failing test:
heal.addRecipe('reloadPageIfModalIsNotVisisble', {
  steps: [
    'click',
  ],
  fn: async ({ error, step }) => {
    // this function will be executed only if test failed with
    // "model is not visible" message
    if (error.message.include('modal is not visible')) return;

    // we return a function that will refresh a page
    // and tries to perform last step again
    return async ({ I }) => {
      I.reloadPage();
      I.wait(1);
      await step.run();
    };
    // if a function succeeds, test continues without an error
  },
});
  • Breaking Change AI features refactored. Read updated AI guide:

    • removed dependency on openai
    • added support for Azure OpenAI, Claude, Mistal, or any AI via custom request function
    • --ai option added to explicitly enable AI features
    • heal plugin decoupled from AI to run custom heal recipes
    • improved healing for async/await scenarios
    • token limits added
    • token calculation introduced
    • OpenAI helper renamed to AI
  • feat(puppeteer): network traffic manipulation. See #4263 (opens new window) by KobeNguyenT (opens new window)

    • startRecordingTraffic
    • grabRecordedNetworkTraffics
    • flushNetworkTraffics
    • stopRecordingTraffic
    • seeTraffic
    • dontSeeTraffic
  • feat(Puppeteer): recording WS messages. See #4264 (opens new window) by KobeNguyenT (opens new window)

Recording WS messages:

      I.startRecordingWebSocketMessages();
      I.amOnPage('https://websocketstest.com/');
      I.waitForText('Work for You!');
      const wsMessages = I.grabWebSocketMessages();
      expect(wsMessages.length).to.greaterThan(0);

flushing WS messages:

      I.startRecordingWebSocketMessages();
      I.amOnPage('https://websocketstest.com/');
      I.waitForText('Work for You!');
      I.flushWebSocketMessages();
      const wsMessages = I.grabWebSocketMessages();
      expect(wsMessages.length).to.equal(0);

Examples:

// recording traffics and verify the traffic
  I.startRecordingTraffic();
  I.amOnPage('https://codecept.io/');
  I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' });
// check the traffic with advanced params
  I.amOnPage('https://openai.com/blog/chatgpt');
  I.startRecordingTraffic();
  I.seeTraffic({
    name: 'sentry event',
    url: 'https://images.openai.com/blob/cf717bdb-0c8c-428a-b82b-3c3add87a600',
    parameters: {
      width: '1919',
      height: '1138',
    },
  });
Scenario('using playwright locator **[Playwright](https://github.com/Playwright)**', () => {
  I.amOnPage('https://codecept.io/test-react-calculator/');
  I.click('7');
  I.click({ pw: '_react=t[name = "="]' });
  I.seeElement({ pw: '_react=t[value = "7"]' });
  I.click({ pw: '_react=t[name = "+"]' });
  I.click({ pw: '_react=t[name = "3"]' });
  I.click({ pw: '_react=t[name = "="]' });
  I.seeElement({ pw: '_react=t[value = "10"]' });
});
Scenario('using playwright data-testid attribute **[Playwright](https://github.com/Playwright)**', () => {
    I.amOnPage('/');
    const webElements = await I.grabWebElements({ pw: '[data-testid="welcome"]' });
    assert.equal(webElements[0]._selector, '[data-testid="welcome"] >> nth=0');
    assert.equal(webElements.length, 1);
});

Network requests & responses can be mocked and modified. Use mockRoute which strictly follows Puppeteer's setRequestInterception API (opens new window).

I.mockRoute('https://reqres.in/api/comments/1', request => {
  request.respond({
    status: 200,
    headers: { 'Access-Control-Allow-Origin': '*' },
    contentType: 'application/json',
    body: '{"name": "this was mocked" }',
  });
})
I.mockRoute('**/*.{png,jpg,jpeg}', route => route.abort());

// To disable mocking for a route call `stopMockingRoute`
// for previously mocked URL
I.stopMockingRoute('**/*.{png,jpg,jpeg}');

To master request intercepting use HTTPRequest object (opens new window) passed into mock request handler.

πŸ› Bug Fixes

# 3.5.15

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ›©οΈ Features

Once all the tests are completed, codecept will create and store coverage in output/coverage folder, as shown below.

Open index.html in your browser to view the full interactive coverage report.

πŸ› Bug Fixes

dry-run command now supports test level grep.

Tests from /Users/t/Desktop/projects/codeceptjs-rest-demo:@jaja

GET tests -- /Users/t/Desktop/projects/codeceptjs-rest-demo/src/GET_test.ts -- 4 tests
  ☐ Verify getting a single user **[jaja](https://github.com/jaja)**
  ☐ Verify getting list of users **[jaja](https://github.com/jaja)**
PUT tests -- /Users/t/Desktop/projects/codeceptjs-rest-demo/src/PUT_test.ts -- 4 tests
  ☐ Verify creating new user **[Jaja](https://github.com/Jaja)**


  Total: 2 suites | 3 tests  

--- DRY MODE: No tests were executed ---
➜  codeceptjs-rest-demo git:(master) βœ— npx codeceptjs dry-run             
Tests from /Users/t/Desktop/projects/codeceptjs-rest-demo:

DELETE tests -- /Users/t/Desktop/projects/codeceptjs-rest-demo/src/DELETE_test.ts -- 4 tests
  ☐ Verify deleting a user
GET tests -- /Users/t/Desktop/projects/codeceptjs-rest-demo/src/GET_test.ts -- 4 tests
  ☐ Verify a successful call
  ☐ Verify a not found call
  ☐ Verify getting a single user **[jaja](https://github.com/jaja)**
  ☐ Verify getting list of users **[jaja](https://github.com/jaja)**
POST tests -- /Users/tDesktop/projects/codeceptjs-rest-demo/src/POST_test.ts -- 4 tests
  ☐ Verify creating new user
  ☐ Verify uploading a file
PUT tests -- /Users/tDesktop/projects/codeceptjs-rest-demo/src/PUT_test.ts -- 4 tests
  ☐ Verify creating new user **[Jaja](https://github.com/Jaja)**


  Total: 4 suites | 8 tests  

--- DRY MODE: No tests were executed ---
  • Several internal fixes and improvements for github workflows

# 3.5.14

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ› Bug Fixes

# 3.5.13

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ›©οΈ Features

Examples:

// recording traffics and verify the traffic
  I.startRecordingTraffic();
  I.amOnPage('https://codecept.io/');
  I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' });
// check the traffic with advanced params
  I.amOnPage('https://openai.com/blog/chatgpt');
  I.startRecordingTraffic();
  I.seeTraffic({
    name: 'sentry event',
    url: 'https://images.openai.com/blob/cf717bdb-0c8c-428a-b82b-3c3add87a600',
    parameters: {
      width: '1919',
      height: '1138',
    },
  });
I.waitForCookie("token");

πŸ› Bug Fixes

const limitation = [':nth-of-type', ':first-of-type', ':last-of-type', ':nth-last-child', ':nth-last-of-type', ':checked', ':disabled', ':enabled', ':required', ':lang']; fixes the issue. Then an old conversion way over css-to-xpath is used.

πŸ“– Documentation

πŸ›©οΈ Several bugfixes and improvements for Codecept-UI

  • Several internal improvements
  • fix: title is not showing when visiting a test
  • fix: handle erros nicely

# 3.5.12

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ›©οΈ Features

  • feat: upgrade wdio (#4123 (opens new window)) - by KobeNguyenT (opens new window)

    πŸ›©οΈ With the release of WebdriverIO version v8.14.0, and onwards, all driver management hassles are now a thing of the past πŸ™Œ. Read more here (opens new window). One of the significant advantages of this update is that you can now get rid of any driver services you previously had to manage, such as wdio-chromedriver-service, wdio-geckodriver-service, wdio-edgedriver-service, wdio-safaridriver-service, and even @wdio/selenium-standalone-service.

For those who require custom driver options, fear not; WebDriver Helper allows you to pass in driver options through custom WebDriver configuration. If you have a custom grid, use a cloud service, or prefer to run your own driver, there's no need to worry since WebDriver Helper will only start a driver when there are no other connection information settings like hostname or port specified.

Example:

{
   helpers: {
     WebDriver : {
       smartWait: 5000,
       browser: "chrome",
       restart: false,
       windowSize: "maximize",
       timeouts: {
         "script": 60000,
         "page load": 10000
       }
     }
   }
}

Testing Chrome locally is now more convenient than ever. You can define a browser channel, and WebDriver Helper will take care of downloading the specified browser version for you. For example:

{
   helpers: {
     WebDriver : {
       smartWait: 5000,
       browser: "chrome",
       browserVersion: '116.0.5793.0', // or 'stable', 'beta', 'dev' or 'canary'
       restart: false,
       windowSize: "maximize",
       timeouts: {
         "script": 60000,
         "page load": 10000
       }
     }
   }
}

Running with devtools protocol

{
   helpers: {
     WebDriver : {
       url: "http://localhost",
       browser: "chrome",
       devtoolsProtocol: true,
       desiredCapabilities: {
         chromeOptions: {
           args: [ "--headless", "--disable-gpu", "--no-sandbox" ]
         }
       }
     }
   }
}

Find an element with exact text

locate('button').withTextEquals('Add');

Waits for number of tabs.

I.waitForNumberOfTabs(2);

Currently I.say is not added into the Test.steps array. This PR aims to add this to steps array so that we could use it to print steps in ReportPortal for instance.

Screenshot 2024-01-19 at 15 41 34

πŸ› Bug Fixes

Improve the error message for seeElement, dontSeeElement, seeElementInDOM, dontSeeElementInDOM

The current error message doesn't really help when debugging issue also causes some problem described in #4140 (opens new window)

Actual

      expected visible elements '[ELEMENT]' to be empty
      + expected - actual

      -[
      -  "ELEMENT"
      -]
      +[]

Updated

     Error: Element "h1" is still visible
      at seeElementError (lib/helper/errors/ElementAssertion.js:9:9)
      at Playwright.dontSeeElement (lib/helper/Playwright.js:1472:7)
Scenario('Verify getting list of users', async () => {
let res = await I.getUserPerPage(2);
res.data = []; // this line causes the issue
await I.expectEqual(res.data.data[0].id, 7);
});

at this time, res.data.data[0].id would throw undefined error and somehow the test is missing all its steps.

process.env.profile is the string "undefined" instead of type undefined when no --profile is specified in the mode "run-multiple"

Helpers: Playwright
Plugins: screenshotOnFail, tryTo, retryFailedStep, retryTo, eachElement

Repro -- **[1]**  Starting recording promises
Timeouts:
β€Ί **[Session]** Starting singleton browser session
Reproduce issue
I am on page "https://example.com"
β€Ί [Browser:Error] Failed to load resource: the server responded with a status of 404 ()
β€Ί [New Context] {}
user1: I am on page "https://example.com"
user1: I execute script () => {
return { width: window.screen.width, height: window.screen.height };
}
sessionScreen is {"width":375,"height":667}
βœ” OK in 1890ms


OK  | 1 passed   // 4s

deprecate some JSON Wire Protocol commands: grabGeoLocation, setGeoLocation

Locator issue due to the lib changes

The locator locate(".ps-menu-button").withText("Authoring").inside(".ps-submenu-root:nth-child(3)") is translated to
3.5.8: //*[contains(concat(' ', normalize-space(./@class), ' '), ' ps-menu-button ')][contains(., 'Authoring')][ancestor::*[(contains(concat(' ', normalize-space(./@class), ' '), ' ps-submenu-root ') and count(preceding-sibling::*) = 2)]] and works well
3.5.11: //*[contains(@class, "ps-menu-button")][contains(., 'Authoring')][ancestor::*[3][contains(@class, "ps-submenu-root")]] and doesn't work (no clickable element found). Even if you test it in browser inspector, it doesn't work.

# 3.5.11

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ›©οΈ Features

  • feat: other locators from playwright (#4090 (opens new window)) - by KobeNguyenT (opens new window)
    • CodeceptJS - Playwright now supports other locators like
      • React (https://playwright.dev/docs/other-locators#react-locator),
      • Vue (https://playwright.dev/docs/other-locators#vue-locator) Vue Locators Example

πŸ› Bug Fixes

πŸ“– Documentation

# 3.5.10

❀️ Thanks all to those who contributed to make this release! ❀️

πŸ›©οΈ Features

Now we expose the WebElements that are returned by the WebHelper and you could make the subsequence actions on them.

// Playwright helper would return the Locator

I.amOnPage('/form/focus_blur_elements');
const webElements = await I.grabWebElements('#button');
webElements[0].click();
Replaying from HAR

 // Replay API requests from HAR.
 // Either use a matching response from the HAR,
 // or abort the request if nothing matches.
   I.replayFromHar('./output/har/something.har', { url: "*/**/api/v1/fruits" });
   I.amOnPage('https://demo.playwright.dev/api-mocking');
   I.see('CodeceptJS'); **[Parameters]** harFilePath [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) Path to recorded HAR file
opts [object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)? [Options for replaying from HAR](https://playwright.dev/docs/api/class-page#page-route-from-har)
A HAR file is an HTTP Archive file that contains a record of all the network requests that are made when a page is loaded. 
It contains information about the request and response headers, cookies, content, timings, and more. 
You can use HAR files to mock network requests in your tests. HAR will be saved to output/har. 
More info could be found here https://playwright.dev/docs/api/class-browser#browser-new-context-option-record-har.

...
recordHar: {
    mode: 'minimal', // possible values: 'minimal'|'full'.
    content: 'embed' // possible values:  "omit"|"embed"|"attach".
}
...
await I.amOnPage('/form/select');
await I.selectOption('Select your age', '21-');

πŸ› Bug Fixes

Emit the new event: event.workers.result.

CodeceptJS also exposes the env var `process.env.RUNS_WITH_WORKERS` when running tests with run-workers command so that you could handle the events better in your plugins/helpers.

const { event } = require('codeceptjs');

module.exports = function() {
    // this event would trigger the  `_publishResultsToTestrail` when running `run-workers` command
  event.dispatcher.on(event.workers.result, async () => {
    await _publishResultsToTestrail();
  });
  
  // this event would not trigger the  `_publishResultsToTestrail` multiple times when running `run-workers` command
  event.dispatcher.on(event.all.result, async () => {
      // when running `run` command, this env var is undefined
    if (!process.env.RUNS_WITH_WORKERS) await _publishResultsToTestrail();
  });
}
replaced minify library with a modern and more secure fork. Fixes [email protected] Regular Expression Denial of Service vulnerability [#3829](https://github.com/codeceptjs/CodeceptJS/issues/3829)
AI class is implemented as singleton
refactored heal.js plugin to work on edge cases
add configuration params on number of fixes performed by ay heal
improved recorder class to add more verbose log
improved recorder class to ignore some of errors
Fixed this error:

locator.isVisible: Unexpected token "s" while parsing selector ":has-text('Were you able to resolve the resident's issue?') >> nth=0"
      at Playwright.waitForText (node_modules\codeceptjs\lib\helper\Playwright.js:2584:79)
Currently inside the _before() of helpers for example Playwright, the retries is set there, however, when retryFailedStep plugin is enabled, the retries of recorder is still using the value from _before() not the value from retryFailedStep plugin.

Fix:

- introduce the process.env.FAILED_STEP_RETIRES which could be access everywhere as the helper won't know anything about the plugin.
- set default retries of Playwright to 3 to be on the same page with Puppeteer.
When test title doesn't have the data in examples:

Feature: Faker examples

  Scenario Outline: Below are the users
    Examples:
      | user   | role |
      | John  | admin |
      | Tim   | client  |

Faker examples --
    **[1]**  Starting recording promises
    Timeouts: 
  Below are the users {"user":"John","role":"admin"}
  βœ” OK in 4ms

  Below are the users {"user":"Tim","role":"client"}
  βœ” OK in 1ms

When test title includes the data in examples:


Feature: Faker examples

  Scenario Outline: Below are the users - <user> - <role>
    Examples:
      | user   | role |
      | John  | admin |
      | Tim   | client  |


Faker examples --
    **[1]**  Starting recording promises
    Timeouts: 
  Below are the users - John - admin 
  βœ” OK in 4ms

  Below are the users - Tim - client 
  βœ” OK in 1ms

πŸ“– Documentation

# 3.5.8

Thanks all to those who contributed to make this release!

πŸ› Bug Fixes fix(appium): type of setNetworkConnection() (#3994 (opens new window)) - by mirao (opens new window) fix: improve the way to show deprecated appium v1 message (#3992 (opens new window)) - by KobeNguyenT (opens new window) fix: missing exit condition of some wait functions - by KobeNguyenT (opens new window)

# 3.5.7

Thanks all to those who contributed to make this release!

πŸ› Bug Fixes

#language: de
FunktionalitΓ€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
  • Screenshot 2023-11-04 at 10 49 56
  • Screenshot 2023-11-03 at 15 56 38
- 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](https://github.com/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 !== [email protected]) {
              throw new Error ('Wrong user signed in');
        }
      },
    }
  }
}
Scenario('login', async ( {I, login} ) => {
  await login('admin') // you should use `await`
})

# 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.

# 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]', '[email protected]');
  I.fillField('user[password]', '[email protected]');
  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

  • Mask the secret value in UI
  • Improve UX/UI
  • PageObjects are now showing in UI

# 3.5.4

πŸ› Bug Fixes:

  helpers: {
    Playwright: {
      url: 'https://github.com',
      show: false,
      browser: 'chromium',
      waitForNavigation: 'load',
      waitForTimeout: 30_000,
      trace: true,
      keepTraceForPassedTests: true
    },
  },
  multiple: {
    profile1: {
      browsers: [
        {
          browser: "chromium",
        }
      ]
    },
  },
// HTML code uses &nbsp; instead of space
<div class="dJHe_" style="color: rgb(255, 255, 255);">My&nbsp;Text!</div>

I.see("My Text!") // this test would work with both &nbsp; 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

# [Playwright] new features and improvements

      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 }
]
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);

# 3.5.3

πŸ›©οΈ Features

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

  • Nightmare and Protractor helpers have been deprecated

# 3.5.2

πŸ› Bug Fixes

# 3.5.1

πŸ›©οΈ Features

πŸ› Bug Fixes

πŸ“– Documentation

# 3.5.0

πŸ›©οΈ Features

Multiple browsers configured as profiles:

exports.config = {
  helpers: {
    WebDriver: {
      url: 'http://localhost:3000',
    }
  },
  multiple: {
    profile1: {
      browsers: [
        {
          browser: "firefox",
        },
        {
          browser: "chrome",
        }
      ]
    }, 

And executed via run-workers with all argument

npx codeceptjs run-workers 2 all

πŸ› Bug Fixes

# 3.4.1

# 3.4.0

Feature('flaky Before & BeforeSuite', { retryBefore: 2, retryBeforeSuite: 3 })
retry: [
  {
    // enable this config only for flaky tests
    grep: '@flaky', 
    Before: 3 // retry Before 3 times
    Scenario: 3 // retry Scenario 3 times
  }, 
  {
    // retry less when running slow tests
    grep: '@slow' 
    Scenario: 1
    Before: 1
  }, {
    // retry all BeforeSuite 3 times
    BeforeSuite: 3
  }
]
timeout: [
  10, // default timeout is 10secs  
  {   // but increase timeout for slow tests
    grep: '@slow',
    Feature: 50
  },
]

# 3.3.7

πŸ›©οΈ Features

πŸ› Bugfixes

πŸ“– Documentation

# 3.3.6

const secretData = secret('name=john&password=123456');
const response = await I.sendPostRequest('/user', secretData);

# 3.3.5

πŸ›©οΈ Features

  • Added TypeScript types for CodeceptJS config.

Update codecept.conf.js to get intellisense when writing config file:

/**@type {CodeceptJS.MainConfig}**/
exports.config = {
  //...
}

πŸ› Bugfixes

πŸ“– Documentation

# 3.3.4

  • Added support for masking fields in objects via secret function:
I.sendPostRequest('/auth', secret({ name: 'jon', password: '123456' }, 'password'));
plugins: {
 customLocator: {
   enabled: true,
   prefix: '$',
   attribute: ['data-qa', 'data-test'],
 }
}
// response.data == [
//   { user: { name: 'jon', email: '[email protected]' } },
//   { user: { name: 'matt', email: '[email protected]' } },
//]

I.seeResponseContainsKeys(['user']);
I.seeResponseContainsJson({ user: { email: '[email protected]' } });
I.seeResponseContainsJson({ user: { email: '[email protected]' } });
I.dontSeeResponseContainsJson({ user: 2 });

# 3.3.3

  • Fixed DataCloneError: () => could not be cloned when running data tests in run-workers
  • πŸ‡ΊπŸ‡¦ Added #StandWithUkraine notice to CLI

# 3.3.2

# 3.3.1

πŸ›©οΈ Features:

npx codeceptjs run test-dir/*"
  • [Playwright] Possible breaking change. By default timeout is changed to 5000ms. The value set in 3.3.0 was too low. Please set timeout explicitly to not depend on release values.
  • [Playwright] Added for color scheme option by PeterNgTr (opens new window)
 helpers: {
  Playwright : {
    url: "http://localhost",
    colorScheme: "dark",
  }
 }

πŸ› Bugfixes:

πŸ“– Documentation

# 3.3.0

πŸ›©οΈ Features:

  • API Testing introduced
    • Introduced JSONResponse helper which connects to REST, GraphQL or Playwright helper
    • [REST] Added amBearerAuthenticated method
    • [REST] Added haveRequestHeaders method
    • Added dependency on joi and chai
  • [Playwright] Added timeout option to set timeout (opens new window) for all Playwright actions. If an action fails, Playwright keeps retrying it for a time set by timeout.
  • [Playwright] Possible breaking change. By default timeout is set to 1000ms. Previous default was set by Playwright internally to 30s. This was causing contradiction to CodeceptJS retries, so triggered up to 3 retries for 30s of time. This timeout option was lowered so retryFailedStep plugin would not cause long delays.
  • [Playwright] Updated restart config option to include 3 restart strategies:
    • 'context' or false - restarts browser context (opens new window) but keeps running browser. Recommended by Playwright team to keep tests isolated.
    • 'browser' or true - closes browser and opens it again between tests.
    • 'session' or 'keep' - keeps browser context and session, but cleans up cookies and localStorage between tests. The fastest option when running tests in windowed mode. Works with keepCookies and keepBrowserState options. This behavior was default prior CodeceptJS 3.1
  • [Playwright] Extended methods to provide more options from engine. These methods were updated so additional options can be be passed as the last argument:
// use Playwright click options as 3rd argument
I.click('canvas', '.model', { position: { x: 20, y: 40 } })
// check option also has options
I.checkOption('Agree', '.signup', { position: { x: 5, y: 5 } })
  • eachElement plugin introduced. It allows you to iterate over elements and perform some action on them using direct engines API
await eachElement('click all links in .list', '.list a', (el) => {
  await el.click();
})

πŸ› Bugfixes:

πŸ“– Documentation

# 3.2.3

# 3.2.2

# 3.2.1

♻️ This release fixes hanging of tests by reducing timeouts for automatic retries on failures.

  • [retryFailedStep plugin] New Defaults: retries steps up to 3 times with factor of 1.5 (previously 5 with factor 2)
  • [Playwright] - disabled retry on failed context actions (not needed anymore)
  • [Puppeteer] - reduced retries on context failures to 3 times.
  • [Playwright] Handling crash event to automatically close crashed pages.

# 3.2.0

πŸ›©οΈ Features:

Timeouts (opens new window) implemented

  • global timeouts (via timeout config option).
    • Breaking change: timeout option expects timeout in seconds, not in milliseconds as it was previously.
  • test timeouts (via Scenario and Feature options)
    • Breaking change: Feature().timeout() and Scenario().timeout() calls has no effect and are deprecated
// set timeout for every test in suite to 10 secs
Feature('tests with timeout', { timeout: 10 });

// set timeout for this test to 20 secs
Scenario('a test with timeout', { timeout: 20 }, ({ I }) => {});
// set step timeout to 5 secs
I.limitTime(5).click('Link');

retryTo plugin introduced to rerun a set of steps on failure:

// editing in text in iframe
// if iframe was not loaded - retry 5 times
await retryTo(() => {
  I.switchTo('#editor frame');
  I.fillField('textarea', 'value');
}, 5);
  • [Playwright] added locale configuration
  • [WebDriver] upgraded to webdriverio v7

πŸ› Bugfixes:

# 3.1.3

πŸ›©οΈ Features:

  • BDD Improvement. Added DataTableArgument class to work with table data structures.
const { DataTableArgument } = require('codeceptjs');
//...
Given('I have an employee card', (table) => {
  const dataTableArgument = new DataTableArgument(table);
  const hashes = dataTableArgument.hashes(); 
  // hashes = [{ name: 'Harry', surname: 'Potter', position: 'Seeker' }];
  const rows = dataTableArgument.rows();
  // rows = [['Harry', 'Potter', Seeker]];
  }

See updated BDD section (opens new window) for more API options. Thanks to EgorBodnar (opens new window)

πŸ› Bugfixes:

πŸ“– Documentation:

# 3.1.2

πŸ›©οΈ Features:

exports.config = {
  tests: ['./*_test.js','./sampleTest.js'],
  // ... 
}

πŸ› Bugfixes:

🎱 Other:

  • Deprecated puppeteerCoverage plugin in favor of coverage plugin.

# 3.1.1

  • [Appium] Fixed #2759 (opens new window) grabNumberOfVisibleElements, grabAttributeFrom, grabAttributeFromAll to allow id locators.

# 3.1.0

  • [Plawyright] Updated to Playwright 1.13
  • [Playwright] Possible breaking change: BrowserContext is initialized before each test and closed after. This behavior matches recommendation from Playwright team to use different contexts for tests.
  • [Puppeteer] Updated to Puppeteer 10.2.
  • [Protractor] Helper deprecated

πŸ›©οΈ Features:

πŸ› Bugfixes:

# 3.0.7

πŸ“– Documentation fixes:

πŸ›©οΈ Features:

npx codeceptjs shell -c foo.conf.js

Bug fixes:

# 3.0.6

"features": [
  "./features/*.feature",
  "./features/api_features/*.feature"
],
Scenario Outline: ...
  Given ...
  When ...
  Then ...

  Examples:
  | productName          | customer              | email              | anythingMore |
  | {{commerce.product}} | Dr. {{name.findName}} | {{internet.email}} | staticData   |

# 3.0.5

Features:

I.sendPatchRequest('/api/users.json', secret({ "email": "[email protected]" }));

See #2786 (opens new window) by PeterNgTr (opens new window)

Bug fixes:

Documentation fixes:

Library updates:

# 3.0.4

# 3.0.3

# 3.0.2

Bug Fixes:

# 3.0.1

♨️ Hot fix:

πŸ› Bug Fix:

  • Fixed error handling in Scenario.js. See #2607 (opens new window) by haveac1gar

  • Changing type definition in order to allow the use of functions with any number of any arguments. See #2616 (opens new window) by akoltun

  • Some updates/changes on documentations

# 3.0.0

πŸ‘Œ LEARN HOW TO UPGRADE TO CODECEPTJS 3 ➑ (opens new window)

  • Playwright set to be a default engine.
  • NodeJS 12+ required
  • BREAKING CHANGE: Syntax for tests has changed.
// Previous
Scenario('title', (I, loginPage) => {});

// Current
Scenario('title', ({ I, loginPage }) => {});
npx create-codeceptjs .

Read changelog to learn more about version πŸ‘‡

# 3.0.0-rc

# 3.0.0-beta.4

πŸ› Bug Fix:

  • PageObject was broken when using "this" inside a simple object.
  • The typings for all WebDriver methods work correctly.
  • The typings for "this.helper" and helper constructor work correctly, too.

🧀 Internal:

  • Our TS Typings will be tested now! We strarted using dtslint (opens new window) to check all typings and all rules for linter. Example:
const psp = wd.grabPageScrollPosition() // $ExpectType Promise<PageScrollPosition>
psp.then(
  result => {
    result.x // $ExpectType number
    result.y // $ExpectType number
  }
)
  • And last: Reducing package size from 3.3Mb to 2.0Mb

# 3.0.0-beta-3

  • BREAKING Replaced bootstrap/teardown scripts to accept only functions or async functions. Async function with callback (with done parameter) should be replaced with async/await. See our upgrde guide (opens new window).
  • Test artifacts introduced. Each test object has artifacts property, to keep attachment files. For instance, a screenshot of a failed test is attached to a test as artifact.
  • Improved output for test execution
    • Changed colors for steps output, simplified
    • Added stack trace for test failures
    • Removed Event emitted from log in --verbose mode
    • List artifacts of a failed tests

// TEST:
MyPage.hasFiles('first arg', 'second arg');

// OUTPUT:
MyPage: hasFile "First arg", "Second arg"
  I see file "codecept.js"
  I see file "codecept.po.json"

# 3.0.0-beta

  • NodeJS 12+ required
  • BREAKING CHANGE: Syntax for tests has changed.
// Previous
Scenario('title', (I, loginPage) => {});

// Current
Scenario('title', ({ I, loginPage }) => {});
  • BREAKING CHANGE: [WebDriver][Protractor][Puppeteer][Playwright][Nightmare] grab* functions unified:

    • grab*From => returns single value from element or throws error when no matchng elements found
    • grab*FromAll => returns array of values, or empty array when no matching elements
  • Public API for workers introduced by koushikmohan1996 (opens new window). Customize parallel execution (opens new window) with workers by building custom scripts.

  • [Playwright] Added usePlaywrightTo method to access Playwright API in tests directly:

I.usePlaywrightTo('do something special', async ({ page }) => {
  // use page or browser objects here
});
  • [Puppeteer] Introduced usePuppeteerTo method to access Puppeteer API:
I.usePuppeteerTo('do something special', async ({ page, browser }) => {
  // use page or browser objects here
});
  • [WebDriver] Introduced useWebDriverTo method to access webdriverio API:
I.useWebDriverTo('do something special', async ({ browser }) => {
  // use browser object here
});
  • [Protractor] Introduced useProtractorTo method to access protractor API
  • tryTo plugin introduced. Allows conditional action execution:
const isSeen = await tryTo(() => {
  I.see('Some text');
});
// we are not sure if cookie bar is displayed, but if so - accept cookies
tryTo(() => I.click('Accept', '.cookies'));
  • Possible breaking change In semantic locators [ char indicates CSS selector.

# 2.6.11

# 2.6.10

# 2.6.9

# 2.6.8

# 2.6.7

# 2.6.6

# 2.6.5

# 2.6.4

# 2.6.3

# 2.6.2

# 2.6.1

  • [screenshotOnFail plugin] Fixed saving screenshot of active session.
  • [screenshotOnFail plugin] Fix issue #2301 (opens new window) when having the flag uniqueScreenshotNames=true results in undefined in screenshot file name by PeterNgTr (opens new window)
  • [WebDriver] Fixed waitForElement not applying the optional second argument to override the default timeout in webdriverio 6. Fix by Mooksc (opens new window)
  • [WebDriver] Updated waitUntil method which is used by all of the wait* functions. This updates the waitForElement by the same convention used to update waitForVisible and waitInUrl to be compatible with both WebDriverIO v5 & v6. See #2313 (opens new window) by Mooksc (opens new window)

# 2.6.0

Upgrade playwright to ^0.12:

npm i playwright@^0.12 --save

Notable changes (opens new window):

  • Fixed opening two browsers on start
  • executeScript - passed function now accepts only one argument. Pass in objects or arrays if you need multtple arguments:
// Old style, does not work anymore:
I.executeScript((x, y) => x + y, x, y);
// New style, passing an object:
I.executeScript(({x, y}) => x + y, {x, y});
  • click - automatically waits for element to become clickable (visible, not animated) and waits for navigation.
  • clickLink - deprecated
  • waitForClickable - deprecated
  • forceClick - added
  • Added support for custom locators. See #2277 (opens new window)
  • Introduced device emulation:
    • globally via emulate config option
    • per session

[WebDriver] Updated to webdriverio v6 by PeterNgTr (opens new window).

Read release notes (opens new window), then upgrade webdriverio to ^6.0:

npm i webdriverio@^6.0 --save

(webdriverio v5 support is deprecated and will be removed in CodeceptJS 3.0) [WebDriver] Introduced Shadow DOM support by gkushang (opens new window)

I.click({ shadow: ['my-app', 'recipe-hello', 'button'] });
npx codecept run-workers 2 --profile firefox

Value is available at process.env.profile (previously process.profile). See #2302 (opens new window). Fixes #1968 (opens new window) #1315 (opens new window)

__`Given`;
I.amOnPage('/profile')

__`When`;
I.click('Logout');

__`Then`;
I.see('You are logged out');

# 2.5.0

Playwright (opens new window) is an alternative to Puppeteer which works very similarly to it but adds cross-browser support with Firefox and Webkit. Until v1.0 Playwright API is not stable but we introduce it to CodeceptJS so you could try it.

# 2.4.3

  • Hotfix for interactive pause

# 2.4.2

# 2.4.1

  • [Hotfix] - Add missing lib that prevents codeceptjs from initializing.

# 2.4.0

# 2.3.6

// Example:
exports.config = {
  tests: '{./workers/base_test.workers.js,./workers/test_grep.workers.js}',
}

# 2.3.5

  • Set "parse-function" dependency to "5.2.11" to avoid further installation errors.

# 2.3.4

# 2.3.3

// when data-test-id is a special test attribute
// enable and configure plugin to replace this
I.click({ css: '[data-test-id=register_button]');
// with this
I.click('$register_button');
  • [Puppeteer][WebDriver] pressKey improvements by martomo (opens new window): Changed pressKey method to resolve issues and extend functionality.
    • Did not properly recognize 'Meta' (or 'Command') as modifier key.
    • Right modifier keys did not work in WebDriver using JsonWireProtocol.
    • 'Shift' + 'key' combination would not reflect actual keyboard behavior.
    • Respect sequence with multiple modifier keys passed to pressKey.
    • Added support to automatic change operation modifier key based on operating system.
  • [Puppeteer][WebDriver] Added pressKeyUp and pressKeyDown to press and release modifier keys like Control or Shift. By martomo (opens new window).
  • [Puppeteer][WebDriver] Added grabElementBoundingRect by PeterNgTr (opens new window).
  • [Puppeteer] Fixed speed degradation introduced in #1306 (opens new window) with accessibility locators support. See #1953 (opens new window).
  • Added Config.addHook to add a function that will update configuration on load.
  • Started @codeceptjs/configure (opens new window) package with a collection of common configuration patterns.
  • [TestCafe] port's management removed (left on TestCafe itself) by orihomie (opens new window). Fixes #1934 (opens new window).
  • [REST] Headers are no more declared as singleton variable. Fixes #1959 (opens new window)
  • Updated Docker image to include run tests in workers with NUMBER_OF_WORKERS env variable. By PeterNgTr (opens new window).

# 2.3.2

# 2.3.1

# 2.3.0

# run all tests in parallel using 3 workers
npx codeceptjs run-workers 3
npx codeceptjs dry-run

# 2.2.1

# 2.2.0

// use Polly & Puppeteer helpers
I.mockRequest('GET', '/api/users', 200);
I.mockRequest('POST', '/users', { user: { name: 'fake' }});

# 2.1.5

# 2.1.4

# 2.1.3

# 2.1.2

  • Fixed inject to load objects recursively.
  • Fixed TypeScript definitions for locators by LukoyanovE (opens new window)
  • EXPERIMENTAL [WebDriver] ReactJS locators support with webdriverio v5.8+:
// locating React element by name, prop, state
I.click({ react: 'component-name', props: {}, state: {} });
I.seeElement({ react: 'component-name', props: {}, state: {} });

# 2.1.1

# 2.1.0

  • Added global inject() function to require actor and page objects using dependency injection. Recommended to use in page objects, step definition files, support objects:
// old way
const I = actor();
const myPage = require('../page/myPage');

// new way
const { I, myPage } = inject();
I.fillField('password', secret('123456'));

This release was partly sponsored by GSasu (opens new window). Thanks for the support! Do you want to improve this project? [Learn more about sponsorin CodeceptJS

# 2.0.8

Use it with FileSystem helper to test availability of a file:

  const fileName = await I.downloadFile('a.file-link');
  I.amInPath('output');
  I.seeFile(fileName);

Actions amInPath and seeFile are taken from FileSystem (opens new window) helper

# 2.0.7

# 2.0.6

# 2.0.5

[Broken Release]

# 2.0.4

# 2.0.3

  • autoLogin plugin (opens new window) added. Allows to log in once and reuse browser session. When session expires - automatically logs in again. Can persist session between runs by saving cookies to file.
  • Fixed Maximum stack trace issue in retryFailedStep plugin.
  • Added locate() function into the interactive shell.
  • [WebDriver] Disabled smartWait for interactive shell.
  • [Appium] Updated methods to use for mobile locators
    • waitForElement
    • waitForVisible
    • waitForInvisible
  • Helper and page object generators no longer update config automatically. Please add your page objects and helpers manually.

# 2.0.2

  • [Puppeteer] Improved handling of connection with remote browser using Puppeteer by martomo (opens new window)
  • [WebDriver] Updated to webdriverio 5.2.2 by martomo (opens new window)
  • Interactive pause improvements by davertmik (opens new window)
    • Disable retryFailedStep plugin in in interactive mode
    • Removes Interface: parseInput while in interactive pause
  • [ApiDataFactory] Improvements
    • added fetchId config option to override id retrieval from payload
    • added onRequest config option to update request in realtime
    • added returnId config option to return ids of created items instead of items themvelves
    • added headers config option to override default headers.
    • added a new chapter into DataManagement (opens new window)
  • [REST] Added onRequest config option

# 2.0.1

  • Fixed creating project with codecept init.
  • Fixed error while installing webdriverio@5.
  • Added code beautifier for generated configs.
  • [WebDriver] Updated to webdriverio 5.1.0

# 2.0.0

  • [WebDriver] Breaking Change. Updated to webdriverio v5. New helper WebDriver helper introduced.

    • Upgrade plan:

      1. Install latest webdriverio
      npm install webdriverio@5 --save
      
      1. Replace WebDriverIO => WebDriver helper name in config.
      2. Read webdriverio changelog (opens new window). If you were using webdriver API in your helpers, upgrade accordingly.
      3. We made WebDriver helper to be compatible with old API so no additional changes required.

      If you face issues using webdriverio v5 you can still use webdriverio 4.x and WebDriverIO helper. Make sure you have webdriverio: ^4.0 installed.

    • Known issues: attachFile doesn't work with proxy server.

  • [Appium] Breaking Change. Updated to use webdriverio v5 as well. See upgrade plan ↑

  • [REST] Breaking Change. Replaced unirest library with axios.

    • Upgrade plan:

      1. Refer to axios API (opens new window).
      2. If you were using unirest requests/responses in your tests change them to axios format.
  • Breaking Change. Generators support in tests removed. Use async/await in your tests

  • Using codecept.conf.js as default configuration format

  • Fixed "enametoolong" error when saving screenshots for data driven tests by PeterNgTr (opens new window)

  • Updated NodeJS to 10 in Docker image

  • [Pupeteer] Add support to use WSEndpoint. Allows to execute tests remotely. [See #1350 (opens new window)] by gabrielcaires (opens new window) (https://github.com/codeceptjs/CodeceptJS/pull/1350)

  • In interactive shell [Enter] goes to next step. Improvement by PeterNgTr (opens new window).

  • I.say accepts second parameter as color to print colorful comments. Improvement by PeterNgTr (opens new window).

I.say('This is red', 'red'); //red is used
I.say('This is blue', 'blue'); //blue is used
I.say('This is by default'); //cyan is used

# 1.4.6

# 1.4.5

  • Add require param to main config. Allows to require Node modules before executing tests. By LukoyanovE (opens new window). For example:
    • Use ts-node/register to register TypeScript parser
    • Use should to register should-style assertions
"require": ["ts-node/register", "should"]

# 1.4.4

# 1.4.3

  • Groups renamed to Tags for compatibility with BDD layer
  • Test and suite objects to contain tags property which can be accessed from internal API
  • Fixed adding tags for Scenario Outline in BDD
  • Added tag() method to ScenarioConfig and FeatureConfig:
Scenario('update user profile', () => {
  // test goes here
}).tag('@slow');

# 1.4.2

# 1.4.1

# 1.4.0

# 1.3.3

# 1.3.2

  • Interactve Shell improvements for pause()
    • Added next command for step-by-step debug when using pause().
    • Use After(pause); in a to start interactive console after last step.
  • [Puppeteer] Updated to Puppeteer 1.6.0
    • Added waitForRequest to wait for network request.
    • Added waitForResponse to wait for network response.
  • Improved TypeScript definitions to support custom steps and page objects. By xt1 (opens new window)
  • Fixed XPath detection to accept XPath which starts with ./ by BenoitZugmeyer (opens new window)

# 1.3.1

  • BDD-Gherkin: Fixed running async steps.
  • [Puppeteer] Fixed process hanging for 30 seconds. Page loading timeout default via getPageTimeout set 0 seconds.
  • [Puppeteer] Improved displaying client-side console messages in debug mode.
  • [Puppeteer] Fixed closing sessions in restart:false mode for multi-session mode.
  • [Protractor] Fixed grabPopupText to not throw error popup is not opened.
  • [Protractor] Added info on using 'direct' Protractor driver to helper documentation by xt1 (opens new window).
  • [WebDriverIO] Added a list of all special keys to WebDriverIO helper by davertmik (opens new window) and xt1 (opens new window).
  • Improved TypeScript definitions generator by xt1 (opens new window)

# 1.3.0

Basic feature file:

Feature: Business rules
  In order to achieve my goals
  As a persona
  I want to be able to interact with a system

  Scenario: do anything in my life
    Given I need to open Google

Step definition:

const I = actor();

Given('I need to open Google', () => {
  I.amOnPage('https://google.com');
});

Run it with --features --steps flag:

codeceptjs run --steps --features

  • Brekaing Chnage run command now uses relative path + test name to run exactly one test file.

Previous behavior (removed):

codeceptjs run basic_test.js

Current behavior (relative path to config + a test name)

codeceptjs run tests/basic_test.js

This change allows using auto-completion when running a specific test.


  • Nested steps output enabled for page objects.
    • to see high-level steps only run tests with --steps flag.
    • to see PageObjects implementation run tests with --debug.
  • PageObjects simplified to remove _init() extra method. Try updated generators and see updated guide (opens new window).
  • [Puppeteer] Multiple sessions (opens new window) enabled. Requires Puppeteer >= 1.5
  • [Puppeteer] Stability improvement. Waits for for load event on page load. This strategy can be changed in config:
    • waitForNavigation config option introduced. Possible options: load, domcontentloaded, networkidle0, networkidle2. See Puppeteer API (opens new window)
    • getPageTimeout config option to set maximum navigation time in milliseconds. Default is 30 seconds.
    • waitForNavigation method added. Explicitly waits for navigation to be finished.
  • [WebDriverIO][Protractor][Puppeteer][Nightmare] Possible BC grabTextFrom unified. Return a text for single matched element and an array of texts for multiple elements.
  • [Puppeteer]Fixed resizeWindow by sergejkaravajnij (opens new window)
  • [WebDriverIO][Protractor][Puppeteer][Nightmare] waitForFunction added. Waits for client-side JavaScript function to return true by GREENpoint (opens new window).
  • [Puppeteer] waitUntil deprecated in favor of waitForFunction.
  • Added filter function to DataTable.
  • Send non-nested array of files to custom parallel execution chunking by mikecbrant (opens new window).
  • Fixed invalid output directory path for run-multiple by mikecbrant (opens new window).
  • [WebDriverIO] waitUntil timeout accepts time in seconds (as all other wait* functions). Fix by truesrc (opens new window).
  • [Nightmare] Fixed grabNumberOfVisibleElements to work similarly to seeElement. Thx to stefanschenk (opens new window) and Jinbo Jinboson.
  • [Protractor] Fixed alert handling error with message 'no such alert' by truesrc (opens new window).

# 1.2.1

  • Fixed running I.retry() on multiple steps.
  • Fixed parallel execution wih chunks.
  • [Puppeteer] Fixed grabNumberOfVisibleElements to return 0 instead of throwing error if no elements are found.

# 1.2.0

  • [WebDriverIO][Protractor]Multiple Sessions (opens new window). Run several browser sessions in one test. Introduced session command, which opens additional browser window and closes it after a test.
Scenario('run in different browsers', (I) => {
  I.amOnPage('/hello');
  I.see('Hello!');
  session('john', () => {
    I.amOnPage('/bye');
    I.dontSee(