Git Product home page Git Product logo

expect-webdriverio's Introduction

expect-webdriverio Test

WebdriverIO Assertion library inspired by expect

Key Features

  • waits for expectation to succeed
  • detailed error messages
  • works in Mocha, Cucumber, Jest, Jasmine
  • builtin types for TypeScript and JS autocompletion

Installation

  1. npm install expect (Jasmine and Jest users should skip this step)
  2. npm install expect-webdriverio

NOTE: WebdriverIO v8.0.0 or higher is required!

Usage

Using WebdriverIO Testrunner

If you run your tests through the WDIO testrunner no additional setup is needed. WebdriverIO initialises expect-webdriverio and makes expect available in the global scope. So you can use it directly in your tests:

const $button = await $('button')
await expect($button).toBeDisplayed()

See more Examples

Using in a standalone script

If you embed WebdriverIO in a standalone script, make sure you import expect-webdriverio before you use it anywhere.

import { remote } from 'webdriverio'
import { expect } from 'expect-webdriverio'

;(async () => {
    const browser = await remote({
        capabilities: {
            browserName: 'chrome'
        }
    })

    await browser.url('https://webdriver.io')

    const $button = await browser.$('button')
    await expect($button).toBeDisplayed()
    
    await browser.deleteSession()
})().catch(console.error)

API

Please see API doc

Error messages

Error messages are informative out of the box and contain:

  • full element selector, like $('form').$('input')
  • actual and expected values
  • highlight the difference (texts assertions)

toHaveText toHaveElementClass

What's next?

First of all, feel free to raise an issue with your suggestions or help with PR!

Planned

  • css matcher
  • size matcher
  • cookie / localStorage matchers?
  • text regex matchers
  • multiremote support (if requested)

expect-webdriverio's People

Contributors

anthonyquy avatar christian-bromann avatar danielkroon avatar dependabot-preview[bot] avatar dependabot[bot] avatar erickzhao avatar erwinheitzman avatar harry-liversedge avatar kent-hervey avatar kyrylodolynskyi avatar lacell75 avatar lukasheimann avatar maikeru avatar mathew-jithin avatar mdsauce avatar mgrybyk avatar naruaway avatar paymand avatar praveendvd avatar sangcnguyen avatar seanpoulter avatar strmer15 avatar thorn0 avatar tuxedofish avatar wdio-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

expect-webdriverio's Issues

way to do number comparison

Is there a way to do number comparison ?

ex.
expect(page.getCount()).to.be.gt(2000)

I would like to replace chai to use expect-webdriverio just need to map those as well

Allow text options for `toHaveText` or `toHaveTextContaining`

I just ran into the following error message:

Expect $(`.todo`) to have text

Expected: "ToDo #3"
Received: " ToDo #3  "

I suggest to allow options for toHaveText and toHaveTextContaining to strip text from the result. These options should be default true as I believe there are more scenarios where you want to strip it rather than keep it.

expect matchers return type is not a Promise in async mode

Environment

expect-webdriverio version: 1.2.3
WebdriverIO version: 6.4.1
Test Framework: mocha (jest/jasmine/mocha/cucumber/etc)
async/sync: async (is @wdio/sync used? - No)

Description

expect matchers return type is not a Promise

image

Additional Information

Jasmine users should not be affected as far as expectAsync is used in async mode.

expect should not be a required dependency

  • expect is only required for expect-webdriverio to work with Mocha / CucumberJS test frameworks out of the box in webdriverio.
  • expect is not a required dependency for expect-webdriverio used in the Jasmine framework.

Ideally, expect-webdriverio should install expect depending on if Jasmine/Jest installation however it's not currently possible.

toBeRequested mocks wait for calls to decrease

const mock = browser.mock('**')
// some calls happened ...
// let's say mock.calls.length is more than 1
expect(mock).not.toBeRequested()

it doesn't make sense to wait for mock.calls length to decrease.

Actual Result
waiting mock.calls length to decrease which makes no sense

Expected Result
should not wait

toHaveProperty conflicts with original Expect assertion

toHaveProperty exists in both this library and the core ExpectJS package:
https://webdriver.io/docs/api/expect.html#tohaveproperty
https://jestjs.io/docs/en/expect#tohavepropertykeypath-value

This means you can't use the core ExpectJS assertion, because the WDIO one in this package overwrites it.

Not really sure on a good solution. Maybe add a check in the custom matcher to see if it's an Object, and if so, use the Expect version. I'm not crazy about have two functions of the same name serve different purposes though... Maybe change the name of this matcher to toHaveHtmlProperty or toHaveElementProperty?

Matchers types are missing with .not

Environment

expect-webdriverio version: 1.3.0
WebdriverIO version: 6.4.1
Test Framework: mocha (jest/jasmine/mocha/cucumber/etc)
async/sync: sync (is @wdio/sync used? - Yes)

Description

  1. expect(section).not.toHaveClass('page2')

Property 'toHaveClass' does not exist on type 'Matchers<Element>'

Additional Information

Looks like a regression since #122

expect(elem).toBeElementsArrayOfSize gte behaves as strict equals instead of greater than or equal

   expect(sessionCountListBeforeCleanUp).toBeElementsArrayOfSize({ gte: 3 })

The above line, when checking that the array is greater or equal than 3, fails if it gets a number greater than 3. In this example, our sessionCountListBeforeCleanUp variable is of size 4.

The below output seems to contradict itself, since a value of 4 is indeed greater than or equal to 4.

Expect $$(`//div[@class="span6 class-timings-list"]/ul/li[@class="hasHoverStyles"]`) to be elements array of size

Expected: ">= 3"
Received: 4
[chrome 83.0.4103.61 linux #0-0] Error: Expect $$(`//div[@class="span6 class-timings-list"]/ul/li[@class="hasHoverStyles"]`) to be elements array of size
[chrome 83.0.4103.61 linux #0-0]
[chrome 83.0.4103.61 linux #0-0] Expected: ">= 3"
[chrome 83.0.4103.61 linux #0-0] Received: 4
[chrome 83.0.4103.61 linux #0-0]     at Context.<anonymous>

While we would love to have a strict equals version of this, the gte behavior does not seem correct.

Platform: Mac OS
WebdriverIO: v7.0.7

Report assertions

In order to better understand what has been asserted it would be super helpful if the library could report every assertion so that the consumer (WebdriverIO) can use this to enrich its reporting capabilities.

toHaveAttribute type checking

Inside of toHaveAttribute the condition is:

async function condition(el: WebdriverIO.Element, attribute: string, value: string, options: ExpectWebdriverIO.StringOptions): Promise<any> {
    const attr = await el.getAttribute(attribute)
    if (typeof attr !== 'string') {
        return { result: false, value: attr }
    }

    if (typeof value !== 'string') {
        return { result: true, value: attr }
    }

    return compareText(attr, value, options)
}

Which means that a test like this would pass

test('success with non-string attribute value as expected', async () => {
        el.getAttribute = jest.fn().mockImplementation((attribute: string) => {
            return "Correct Value"
        })
        const result = await toHaveAttribute(el, "attribute_name", 123, { ignoreCase: true });
        expect(result.pass).toBe(true)
    })

Is this the expected behaviour because surely this implies that passing in any non-string value as the expected would result in a success which seems like confusing behaviour to me?

toBeRequestedWithResponse partial match support

toBeRequestedWithResponse should support { containing: true } and/or a function comparator

toBeRequestedWithResponse({ foo: 'bar' }, { containing: true })
toBeRequestedWithResponse((data: string | Array<...> | Record<string, unknown>) => data === '{"filter":"year"}')

Error with $ tsc

When I run tsc 5 errors are found

$ tsc
node_modules/@types/jasmine/ts3.1/index.d.ts:112:18 - error TS2451: Cannot redeclare block-scoped variable 'expect'.

112 declare function expect<T extends jasmine.Func>(spy: T | jasmine.Spy<T>): jasmine.FunctionMatchers<T>;
                     ~~~~~~

  node_modules/expect-webdriverio/types/jest-global.d.ts:3:15
    3 declare const expect: jest.Expect
                    ~~~~~~
    'expect' was also declared here.

node_modules/@types/jasmine/ts3.1/index.d.ts:119:18 - error TS2451: Cannot redeclare block-scoped variable 'expect'.

119 declare function expect<T>(actual: ArrayLike<T>): jasmine.ArrayLikeMatchers<T>;
                     ~~~~~~

  node_modules/expect-webdriverio/types/jest-global.d.ts:3:15
    3 declare const expect: jest.Expect
                    ~~~~~~
    'expect' was also declared here.

node_modules/@types/jasmine/ts3.1/index.d.ts:126:18 - error TS2451: Cannot redeclare block-scoped variable 'expect'.

126 declare function expect<T>(actual: T): jasmine.Matchers<T>;
                     ~~~~~~

  node_modules/expect-webdriverio/types/jest-global.d.ts:3:15
    3 declare const expect: jest.Expect
                    ~~~~~~
    'expect' was also declared here.

node_modules/@types/jasmine/ts3.1/index.d.ts:131:18 - error TS2451: Cannot redeclare block-scoped variable 'expect'.

131 declare function expect(): jasmine.NothingMatcher;
                     ~~~~~~

  node_modules/expect-webdriverio/types/jest-global.d.ts:3:15
    3 declare const expect: jest.Expect
                    ~~~~~~
    'expect' was also declared here.

node_modules/expect-webdriverio/types/jest-global.d.ts:3:15 - error TS2451: Cannot redeclare block-scoped variable 'expect'.

3 declare const expect: jest.Expect
                ~~~~~~

  node_modules/@types/jasmine/ts3.1/index.d.ts:112:18
    112 declare function expect<T extends jasmine.Func>(spy: T | jasmine.Spy<T>): jasmine.FunctionMatchers<T>;
                         ~~~~~~
    'expect' was also declared here.
  node_modules/@types/jasmine/ts3.1/index.d.ts:119:18
    119 declare function expect<T>(actual: ArrayLike<T>): jasmine.ArrayLikeMatchers<T>;
                         ~~~~~~
    and here.
  node_modules/@types/jasmine/ts3.1/index.d.ts:126:18
    126 declare function expect<T>(actual: T): jasmine.Matchers<T>;
                         ~~~~~~
    and here.
  node_modules/@types/jasmine/ts3.1/index.d.ts:131:18
    131 declare function expect(): jasmine.NothingMatcher;
                         ~~~~~~
    and here.


Found 5 errors.

Dependencies

$ npm ls --depth=0                                       
├── @types/[email protected]
├── @typescript-eslint/[email protected]
├── @wdio/[email protected]
├── @wdio/[email protected]
├── @wdio/[email protected]
├── @wdio/[email protected]
├── @wdio/[email protected]
├── @wdio/[email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]

tsconfig.json

{
    "compilerOptions": {
        "target": "es6",
        "outDir": "./dist/",
        "baseUrl": ".",
        "allowJs": true,
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "paths": {
            "@tests/*": ["./tests/*"],
            "@be-pages/*":["./src/pages/*"],
            "@be-selectors/*":["./src/selectors/*"]
          },
        "types": ["node", "@wdio/sync", "@wdio/jasmine-framework", "expect-webdriverio"]
    },
    "include": ["./src/**/*.ts", "./tests/**/*.ts", "./config/**/*.ts"],
    "exclude": ["node_modules"]
}

Error message fails to show full element selector when using shadow$ command

Description
When an expectation fails, error message does not provide accurate element selector info when using shadow$ command.

Expected Behaviour
When an expectation fails, it provides full element selector info when using shadow$ command.
$('form').$('input')

Actual Behaviour
When an expectation fails, error message has the following structure when using shadow$ command:
Expect $().$().$().$() to have property value

Additional Info
Testing framework: Mocha
Tech stack: LitElement

Dependencies
"@wdio/cli": "^5.18.6"
"@wdio/mocha-framework": "^5.18.6"
"expect": "^25.1.0"
"expect-webdriverio": "^0.2.0"

Not working with wdio/allure-reporter

Using wdio 5.18.4 and allure-reporter 5.16.6. In case of a failed assertion the allure reporter can not parse the failure message to XML which causes the process to hang indefinitely.
This is the failure message that can not be handled by allure-js-commons 1.3.2.

�[32m- Ditt spel på Bomben �[7m(är betal|kostade)�[27m�[39m
�[31m+ Ditt spel på Bomben �[7mkostade 16kr�[27m�[39m
�[31m+ �[7mDu hittar ditt spel under Mina spel.�[27m�[39m
�[31m+ �[7mDu vet väl att du kan stötta din favoritförening varje gång du spelar.�[27m�[39m
�[31m+ �[7mVälj föreningar här.�[27m�[39m

I guess the failure-message ends up formatted in the test object which then is used in all reporters.
While this works for console output, the hidden ESC character makes the xml parsing fail. The colorcoding will also look bad in any other reports.

I'm sorry I don't have any suggestions on how to solve this, but my personal view is that the colorcoding does not add much to the understanding of the failure. Having the expected and actual criterias would give enough information.

Negating tests with .not doesn't work

Tests with .not negation don't work correctly, the end result is the testrunner always receiving undefined and then failing the test. This seems to happen with all methods. The result is the same in both sync and async modes.

Test case:

describe('webdriver.io page footer', () => {
    it('should have the right class', () => {
        browser.url('https://webdriver.io');
        const footer = $('#footer');
        footer.waitForExist();

        // ok, passes
        expect(footer).toHaveClass('nav-footer');  

        // doesn't pass
        expect(footer).not.toHaveClass('asdf');

        // from the documentation, doesn't pass
        expect(footer).not.toHaveProperty('height', 42);
    });
});

Output:

[chrome 85.0.4183.83 mac os x #0-0] 1 failing (10.9s)
[chrome 85.0.4183.83 mac os x #0-0]
[chrome 85.0.4183.83 mac os x #0-0] 1) webdriver.io page footer should have the right class
[chrome 85.0.4183.83 mac os x #0-0] Expect $(`#footer`) not to have class

Expected [not]: "asdf"
Received      : undefined

String option 'ignoreCase' not working for 'toHaveValue()'

Hi

It seems like the option ignoreCase is not working for the toHaveValue() assertion method.

Given this assertion:

expect(browser.$('#searchField')).toHaveValue('iPhone', {ignoreCase: true, asString: true});

I'm getting this error when running the test:

[chrome  mac os x #0-0] Error: Expect $(`#searchField`) to have property value
[chrome  mac os x #0-0]
[chrome  mac os x #0-0] Expected: "iPhone"
[chrome  mac os x #0-0] Received: "iphone"

Is that a bug or do the 'stringOptions' just don't work for toHaveValue?

Best regards,
Annika

By the way:
Great project! I'm using 'chai-webdriverio' right now and just started to look into this - it looks very promising :)! I like the syntax and the fact that you can pass in WebdriverIO elements and not only selectors like in 'chai-webdriverio'.

Tests for the waitUntil function (discussion wanted)

I was thinking about adding some test cases for the waitUntil function. A couple of conditions here failed, for example:

"waitUntil › positive condition › should fail if isNot is true".

In this case:

  • The condition is returning true
  • isNot is set to true

In my mind it makes sense that you are waiting for the condition to be failing in this test case. So therefore you should expect the result to fail.

I have written in my head the starter unit tests that I would expect the function to obey (pre adding in wait times) and I wondered if anyone had any thoughts on if this is what they also expect?

describe('waitUntil', () => {
        let condition: any
        const positiveCondition = () => { return {result: true, message: "test" }}
        const negativeCondition = () => { return {result: false, message: "test" }}

        describe('positive condition', () => {
                beforeEach(() => { 
                    condition = async () => { 
                        return positiveCondition().result
                    } 
                })
          
                test('should fail if isNot is true', async () => {
                    const pass = await waitUntil(condition, true, {})
                    expect(pass).toBe(false)
                })
          
                test('should pass if isNot is false', async () => {
                    const pass = await waitUntil(condition, false, {})
                    expect(pass).toBe(true)
                })
                
                test('should fail if isNot is true and wait is 0', async () => {
                    const pass = await waitUntil(condition, true, {wait: 0})
                    expect(pass).toBe(false)
                })
          
                test('should pass if isNot is false and wait is 0', async () => {
                    const pass = await waitUntil(condition, false, {wait: 0})
                    expect(pass).toBe(true)
                })
            })
          
            describe('negative condition', () => {
                beforeEach(() => { 
                    condition = async () => { 
                        return negativeCondition().result
                    } 
                })
          
                test('should pass if isNot is true', async () => {
                    const pass = await waitUntil(condition, true, {})
                    expect(pass).toBe(true)
                })
          
                test('should fail if isNot is false', async () => {
                    const pass = await waitUntil(condition, false, {})
                    expect(pass).toBe(false)
                })
          
                test('should pass if isNot is true and wait is 0', async () => {
                    const pass = await waitUntil(condition, true, {wait: 0})
                    expect(pass).toBe(true)
                })
          
                test('should fail if isNot is false and wait is 0', async () => {
                    const pass = await waitUntil(condition, false, {wait: 0})
                    expect(pass).toBe(false)
                })
        })
})

Unable to compile project in Windows

I have taken the latest pull from the master branch. I am getting Complication error when i run "npm run build" command.
Could anyone please help me resolve this issue?, i want to start doing contribution to this project.
Below is the screenshot of the issue:

image

toHaveTextContaining not working on async mode

toHaveText and toHaveTextContaining do not get the element text correctly

it('go to google', async () => {
    await browser.url('http://www.google.com');

    const elem = await $('#SIvCob');

    expect(await elem.getText()).toContain('Google offered in');
    expect(elem).toHaveTextContaining('Google offered in');
  })

The assertions should be equivalent, but actually, the second resolves to false.

[0-0] {
  passed: true,
  assertion: {
    matcherName: 'toContain',
    passed: true,
    message: '',
    error: undefined,
    errorForStack: undefined,
    actual: 'Google offered in: Français',
    expected: 'Google offered in'
  }
}
[0-0] {
  passed: undefined,
  assertion: {
    matcherName: 'toHaveTextContaining',
    passed: undefined,
    message: "Expected Element({ sessionId: '276a5be58236ede817a24f4e00b3ef3c', elementId: '283acefc-74ce-4fea-9699-ffb41e49b0ba', element-6066-11e4-a52e-4f735466cecf: '283acefc-74ce-4fea-9699-ffb41e49b0ba', selector: '#SIvCob', parent: Browser({ sessionId: '276a5be58236ede817a24f4e00b3ef3c', capabilities: Object({ acceptInsecureCerts: true, browserName: 'chrome', browserVersion: '90.0.4430.85', chrome: Object({ chromedriverVersion: '90.0.4430.24 (4c6d850f087da467d926e8eddb76550aed655991-refs/branch-heads/4430@{#429})', userDataDir: '/var/folders/x8/c58l8cz10x7gkpf7wy1hxcv00000gn/T/.com.google.Chrome.CscXpN' }), goog:chromeOptions: Object({ debuggerAddress: 'localhost:52180' }), networkConnectionEnabled: false, pageLoadStrategy: 'normal', platformName: 'mac os x', proxy: Object({  }), setWindowRect: true, strictFileInteractability: false, timeouts: Object({ implicit: 0, pageLoad: 300000, script: 30000 }), unhandledPromptBehavior: 'dismiss and notify', webauthn:extension:largeBlob: true, webauthn:virtualA ... to have text containing 'Google offered in'.",
    error: undefined,
    errorForStack: undefined,
    actual: Element {
      sessionId: '276a5be58236ede817a24f4e00b3ef3c',
      elementId: '283acefc-74ce-4fea-9699-ffb41e49b0ba',
      'element-6066-11e4-a52e-4f735466cecf': '283acefc-74ce-4fea-9699-ffb41e49b0ba',
      selector: '#SIvCob',
      parent: [Browser],
      emit: [Function: bound ],
      isReactElement: false,
      addCommand: [Function (anonymous)],
      overwriteCommand: [Function (anonymous)]
    },
    expected: 'Google offered in'
  }
}
[0-0] {
  passed: false,
  assertion: {
    matcherName: '',
    passed: false,
    expected: '',
    actual: '',
    error: {
      matcherName: 'toHaveTextContaining',
      message: "Expected Element({ sessionId: '276a5be58236ede817a24f4e00b3ef3c', elementId: '283acefc-74ce-4fea-9699-ffb41e49b0ba', element-6066-11e4-a52e-4f735466cecf: '283acefc-74ce-4fea-9699-ffb41e49b0ba', selector: '#SIvCob', parent: Browser({ sessionId: '276a5be58236ede817a24f4e00b3ef3c', capabilities: Object({ acceptInsecureCerts: true, browserName: 'chrome', browserVersion: '90.0.4430.85', chrome: Object({ chromedriverVersion: '90.0.4430.24 (4c6d850f087da467d926e8eddb76550aed655991-refs/branch-heads/4430@{#429})', userDataDir: '/var/folders/x8/c58l8cz10x7gkpf7wy1hxcv00000gn/T/.com.google.Chrome.CscXpN' }), goog:chromeOptions: Object({ debuggerAddress: 'localhost:52180' }), networkConnectionEnabled: false, pageLoadStrategy: 'normal', platformName: 'mac os x', proxy: Object({  }), setWindowRect: true, strictFileInteractability: false, timeouts: Object({ implicit: 0, pageLoad: 300000, script: 30000 }), unhandledPromptBehavior: 'dismiss and notify', webauthn:extension:largeBlob: true, webauthn:virtualA ... to have text containing 'Google offered in'.",
      stack: "Error: Expected Element({ sessionId: '276a5be58236ede817a24f4e00b3ef3c', elementId: '283acefc-74ce-4fea-9699-ffb41e49b0ba', element-6066-11e4-a52e-4f735466cecf: '283acefc-74ce-4fea-9699-ffb41e49b0ba', selector: '#SIvCob', parent: Browser({ sessionId: '276a5be58236ede817a24f4e00b3ef3c', capabilities: Object({ acceptInsecureCerts: true, browserName: 'chrome', browserVersion: '90.0.4430.85', chrome: Object({ chromedriverVersion: '90.0.4430.24 (4c6d850f087da467d926e8eddb76550aed655991-refs/branch-heads/4430@{#429})', userDataDir: '/var/folders/x8/c58l8cz10x7gkpf7wy1hxcv00000gn/T/.com.google.Chrome.CscXpN' }), goog:chromeOptions: Object({ debuggerAddress: 'localhost:52180' }), networkConnectionEnabled: false, pageLoadStrategy: 'normal', platformName: 'mac os x', proxy: Object({  }), setWindowRect: true, strictFileInteractability: false, timeouts: Object({ implicit: 0, pageLoad: 300000, script: 30000 }), unhandledPromptBehavior: 'dismiss and notify', webauthn:extension:largeBlob: true, webauthn:virtualA ... to have text containing 'Google offered in'.\n" +
        '    at <Jasmine>\n' +
        '    at Spec.addExpectationResult (/Users/thiagolima/Documents/neo/member-portal/node_modules/@wdio/jasmine-framework/build/index.js:296:32)\n' +
        '    at <Jasmine>\n' +
        '    at UserContext.<anonymous> (/Users/thiagolima/Documents/neo/member-portal/test/wdio/tests/login.test.ts:32:18)\n' +
        '    at processTicksAndRejections (internal/process/task_queues.js:93:5)',
      passed: undefined,
      expected: 'Google offered in',
      actual: [Element]
    }
  }
}

Add unit tests

Add unit tests to reach 99% coverage. Any help is appreciated!

Assertions are thrown twice

In jasmine framework this throws two assertions :

it('Sorts the inventory in asc order of price and adds element to cart', async () => {
    expect(1).toBe(2)
});

This can be validated by :

Adding below to config file:

    jasmineOpts: {
        // Jasmine default timeout
        defaultTimeoutInterval: 60000,
        //
        // The Jasmine framework allows interception of each assertion in order to log the state of the application
        // or website depending on the result. For example, it is pretty handy to take a screenshot every time
        // an assertion fails.
        expectationResultHandler: function (passed, assertion) {

            console.log("Pass:      ",passed,"Assertion:          ", assertion)
            // do something
        }
    },

This gives below outputs:


[0-0] Pass:       false Assertion:           {
[0-0]   matcherName: 'toBe',
[0-0]   passed: false,
[0-0]   message: 'Expected 1 to be 2.',
[0-0]   error: undefined,
[0-0]   errorForStack: undefined,
[0-0]   actual: 1,
[0-0]   expected: 2
[0-0] }
[0-0] Pass:       false Assertion:           {
[0-0]   matcherName: '',
[0-0]   passed: false,
[0-0]   expected: '',
[0-0]   actual: '',
[0-0]   error: {
[0-0]     matcherName: 'toBe',
[0-0]     message: 'Expected 1 to be 2.',
[0-0]     stack: 'Error: Expected 1 to be 2.\n' +
[0-0]       '    at <Jasmine>\n' +
[0-0]       '    at Spec.addExpectationResult (D:\\prject\\node_modules\\@wdio\\jasmine-framework\\build\\index.js:296:32)\n' +
[0-0]       '    at <Jasmine>\n' +
[0-0]       '    at UserContext.<anonymous> (D:\\prject\\test\\specs\\cartFeature.js:12:25)\n' +
[0-0]       '    at UserContext.executeAsync (D:\\prject\\node_modules\\@wdio\\utils\\build\\shim.js:136:25)',
[0-0]     passed: false,
[0-0]     expected: 2,
[0-0]     actual: 1
[0-0]   }
[0-0] }

And the allure report looks like:

image

Do anyone knows how to avoid this ?

Reproducible example:

webdriverio-Jasmine - Copy.zip

Just run:

npm install
npx wdio
./openAllureRport.bat

observe console log and allure report as mentioned above

expect-webdriverio and webdriverio with typescript = > Unexpected return from a matcher function.

Good day.

I have no idea where things are failing, but I'm unable to use expect assertions.

My packages:

"@types/chromedriver": "^81.0.0",
"@types/jest": "23.3.13",
"@types/node": "^10.17.21",
"chromedriver": "^81.0.0",
"expect-webdriverio": "^1.1.0",
"jest": "22.4.3",
"ts-jest": "^22.4.6",
"webdriverio": "5.22.4"

I'm using jest and typescript. In my tsconfig:

"compilerOptions": {
    "module": "commonjs",
    "types": [
      "node",
      "jest", 
      "webdriverio",
      "expect-webdriverio"
    ],
}

And in my jestconfig:

  testEnvironment: 'node',
  setupTestFrameworkScriptFile: 'expect-webdriverio',
  transform: {
    "^.+\\.tsx?$": "ts-jest",
  },

My test code contains:

 const el = await browser.$('input');
 await el.click();
 expect(el).toBeFocused();

And this fails!

Error:

    Unexpected return from a matcher function.
    Matcher functions should return an object in the following format:
      {message?: string | function, pass: boolean}
    '{}' was returned

      83 |   await el.click();
    > 84 |    expect(el).toBeFocused();

     
      at _validateResult (node_modules/expect/build/index.js:196:11)
      at Object.throwingMatcher [as toBeFocused] (node_modules/expect/build/index.js:158:5)
      at src/my/test/file.ts

What's happening here and how do I fix it?

toHaveValue in appium

When using appium for testing ios safari

       appiumVersion: '1.17.1',
        browserName: 'Safari',
        deviceName: 'iPhone XS Simulator',
        deviceOrientation: 'portrait',
        platformName: 'iOS',
        platformVersion: '13.0',

The following check fails

expect($('#search')).toHaveValue('');

with error

Method has not yet been implemented"

and from appium log

Calling AppiumDriver.getProperty() with args: ["value","5011","9ee8f32f-9e8e-46c4-b488-e2c6dda4cf96"]
2020-12-29 21:34:01:303 - [debug] [XCUITest] Executing command 'getProperty'

However the same test passes when

expect($('#search')).toHaveAttribute('value', '');

It seems to be related to the issue brought up here
webdriverio/webdriverio#3606

Support of custom error messages

While updating the Cucumber boilerplate I recognise that the expect-webdriverio lib doesn't allow for customer error messages like

        expect(nrOfElements).toHaveLength(
            0,
            `Element with selector "${selector}" should not exist on the page`
        );

The definition of the expect dependency (node_modules/expect/build/types.d.ts) is as follows:

    /**
     * Used to check that an object has a `.length` property
     * and it is set to a certain numeric value.
     */
    toHaveLength(expected: number): R;

Add `toHaveUrlContaining` and `toHaveTitleContaining` matcher

Since we already have toHaveTextContaining it would be nice to also have such a matcher for urls. Given that we have toHaveText and toHaveTextContaining we should follow this pattern for toHaveTitle and toHaveUrl as aliases to e.g. toHaveTitle("foobar", { containing: true }).

toBeRequested matcher wrong error message

Environment
expect-webdriverio version: 1.3.1
WebdriverIO version: 6.4.4
Test Framework: mocha (jest/jasmine/mocha/cucumber/etc)
async/sync: sync (is @wdio/sync used? - Yes)

Steps to reproduce

const searchMock = browser.mock('FOOBAR') // 0 requests
expect(searchMock).toBeRequested() // should fail

Actual Result

Expect mock to be called

Expected: 0
Received: serializes to the same string

Expected Result
similar to how toHaveChildren matcher works

Expect $(`input`) to have children

Expected: ">= 1"
Received: 0

Expose utility methods to enable external contribution of additional custom matchers.

I have a couple of matchers that I've already created for the Chai version of webdriver.io expects that I'd like to move over to the Jest-style matchers as I port to this framework. The problem is that some of them might not make sense to be part of this core library and over time a monolithic package probably isn't the best idea anyways.

Would it be possible to expose a some of the existing custom methods and / or a new method to enable some extensibility? Specifically, I'd be looking to at least get the core src/utils methods (e.g. executeCommandBe and its dependencies).

The first method I'd like to swap in looks like this:

// check the style (supports type validation of keys in Typescript)
expect(label).toHaveStyle({
    "font-family": "Faktum",
    "font-size": "26px",
    color: "#000" // handles "black", "#000000", "rgb(0, 0, 0)", and "rgba(0, 0, 0, 1)"
});

Implement toBeRequestedWith matcher

Let's implement a new matcher that works this:

const searchMock = browser.mock('**/search?*', { method: 'POST' })
$('search').click()
// POST http://localhost:8080/tst/invoices/search?size=20&page=0&sort=createdDateTime,desc'
// body { foo: 'bar', released: true }
expect(searchMock).toBeRequestedWith({
  method: 'POST',
  url: (url) => url.includes('invoices') && url.includes('localhost'),
  request: { released: true },
  query: { size: 20 },
  headers: (headers) => headers.Authorization.startsWith('Bearer '),
}, { containing: true })
// types.d.ts
toBeRequestedWith({
  method: string
  url: string | (url: string) => boolean
  request: string | Record<string: unknown> | Array<Record<string: unknown>> | (payload: unknown) => boolean
  query: string | Record<string: string>| (query: Record<string: string>) => boolean
  headers: Record<string: string> | (headers: Record<string: string>) => boolean
}): R

Async matchers have incorrect typings

Environment (please complete the following information):

  • WebdriverIO version: 7.7.4
  • Mode: WDIO Testrunner
  • If WDIO Testrunner, running sync/async: async
  • Node.js version: 14.17.1
  • NPM version: 6.14.13
  • Browser name and version: Chrome 91
  • Platform name and version: e.g. Windows 10
  • Additional wdio packages used (if applicable): "@wdio/mocha-framework": "^7.7.4"

Config of WebdriverIO
By Default

Describe the bug
Looks like there is a bug in typings in expects
toHaveText(text: string | string[], options?: ExpectWebdriverIO.StringOptions): R
Shouldn't it be like this
toHaveText(text: string | string[], options?: ExpectWebdriverIO.StringOptions): Promise<R>

To Reproduce
Steps to reproduce the behavior:

describe('sample spec', () => {
    it('should be logo', async () => {
        browser.url('https://webdriver.io/')
        expect(await $('p.hero__subtitle')).toHaveText('bla bla') //expect is definetely wrong, but the test passes 
    });
});

Expected behavior
Test above should failed.

NOTE: I know that there is a workaround
await expect($('p.hero__subtitle')).toHaveText('bla bla') //it should fail and it fails
but I still think that there is a bug in typings

Move into WebdiverIO

I think this module is must-have for writing nice web tests with WebdriverIO.
I stumbled upon this module when I read the release notes for WebdriverIO 6, and otherwise wouldn't have known about it.

Is there a specific reason why this was made as a separate module, instead of being bundled directly in WebdriverIO? Are you planning on bundling it with WebdriverIO in the future?

I believe that bundling this module directly into WebdriverIO would be one of the improvements that would help making with making it easier to write non-flaky tests with WebdriverIO, out-of-the-box.

Slightly related, my isssue on WebdriverIO

toHaveChildren throws error 'serializes to the same string'

Hi all!
I am checking out webdriverio 6 and I got an error using toHaveChildren

Expect $$(`div.card`) to have children
Expected: 9
Received: serializes to the same string

However when using toBeElementsArrayOfSize instead it works fine, according to the docs it is Same as toHaveChildren.
expect(StoreHomePage.productCards).toBeElementsArrayOfSize({ eq: 9 }); works fine
expect(StoreHomePage.productCards).toHaveChildren({ eq: 9 }); fails
StoreHomePage.productCards is $$('div.card')

Context:
"@wdio/cli": "^6.1.5"

node --version
v12.16.1

Bug in expect.toHaveChildren - It is returning 4 when we expect 31

[//]: # NOTE: This repository only maintains packages that are listed in the Readme. Please make sure that your issue is directly caused by one of these packages and if not file an issue in the correct 3rd party package repository.

Environment (please complete the following information):

  • WebdriverIO version: 6.5.2
  • Mode: WDIO Testrunner
  • If WDIO Testrunner, running sync/async: sync
  • Node.js version: 14.3.0
  • NPM version: 6.14.5
  • Browser name and version: Chrome 83.0.4103
  • Platform name and version: [e.g. Windows 10 and Ubuntu 18]
  • Additional wdio packages used (if applicable):

Config of WebdriverIO
I don't think any of this matters in this case.

Describe the bug

expect.toHaveChildren, according to the docs, is the same as expect.toBeElementsArrayOfSize; however, after hours of trying to figure out why toHaveChildren gave us 4, we realized that toBeElementsArrayOfSize was giving the value we expected.

Since the WebdriverIO Expect docs state that toHaveChildren and toBeElementsArrayOfSize are the same, we just happen to try it out and the alternative method worked.

It seems toHaveChildren may have a bug in it since it doesn't behave the same way and returns a value that doesn't make sense.

To Reproduce

we expected 33 but instead it showed 4 in the logs.

console.debug('size of $$(#settingsClassesList > li).length = ' + $$('#settingsClassesList > li').length);  // printed 32
expect($$('#settingsClassesList > li')).toHaveChildren({ gte: 31 });    // threw AssertionError with Expected 31 Received 4

Expected behavior

Expected 31 not 4, but with the alternative command, it worked.

Log

[0-0] size of $$(#settingsClassesList > li).length = 32
[0-0] Error in "Class Creation & Deletion  Should create class and delete the class"
Expect $$(`#settingsClassesList > li`) to have children

Expected: ">= 31"
Received: 4

Implement toHaveStyle matcher

Example

expect(label).toHaveStyle({
    "font-family": "Faktum",
    "font-size": "26px",
    color: "#000" // handles "black", "#000000", "rgb(0, 0, 0)", and "rgba(0, 0, 0, 1)"
});

according to #105

Please also add:

  • types
  • docs
  • unit tests

Do not output `Warning! Unsupported expect lib is used` to console

I've upgraded webdriverio & all used @wdio/* package dependencies to v6 on a projects which also uses chai for expect(...) matchers. Now, when I run tests, I see the following in STDOUT for each spec file that is executed:

[0-0] Warning! Unsupported expect lib is used.
  | Only Jasmine >= 3.3.0 and Jest's expect are supported.
  | expect-webdriverio is assigned to global.expectWdio

I was first confused to see this, as I don't have expect-webdriverio defined as a dependency in package.json. But then I noticed it is enabled by default now if you use @wdio/mocha-framework (webdriverio/webdriverio#5335).

So, is there any way to suppress the warning?

Failed tests does not exit

Description:
When a tests fail, it doesn't exit automatically

Expected Behaviour:
When tests fail, it'll continue running and exit properly

Actual Behaviour:
When tests fail, it gets stuck to the point where it describes the discrepancy between the expected and actual results

Additional Info:
I'm using mocha as my framework

Support for Multiremote

Allow users to use this assertion library with multiremote. Using the isMultiremote flag of the browser object should help to determine the current mode and allows to then iterate over the multiremote instances to do separate assertions.

[BUG] The matchers aren't working with jasmine framework

Environment:

WebdriverIO version: 7.10.1
Mode: WDIO Testrunner
If WDIO Testrunner, running sync/async: async
Node.js version: v15.12.0
NPM version: v7.6.3
Browser name and version: Chrome 92
Platform name and version: e.g. MacOs Big Sur
Additional wdio packages used (if applicable): "@wdio/jasmine-framework": "^7.11.0"

Config of WebdriverIO

exports.config = {
  baseUrl: 'https://todomvc.com/',
  capabilities: [{
    browserName: 'chrome',
    'goog:chromeOptions': {
      args: ['--headless']
    }
  }],
  headless: true,
  framework: 'jasmine',
  specs: ['*.test.js'],
  services: ['chromedriver'],
  jasmineOpts: {
    defaultTimeoutInterval: 90000,
  }
};

Describe the bug

The matchers aren't working with jasmine framework. If I change to the mocha, then it'll work as expected.

Steps to reproduce the behavior:

describe('TodoMVC', () => {
  it('verify title', async () => {
    await browser.url('#');

    await expect(browser).toHaveTitle('TodoMVC');
  });
});

Expected behavior:

The test above should be passed.

Error:

Error in "TodoMVC verify title"
Error: Expected Browser({ sessionId: 'c76db59575408052600827adc6476a2f', capabilities: Object({ acceptInsecureCerts: false, browserName: 'chrome', browserVersion: '93.0.4577.63', chrome: Object({ chromedriverVersion: '92.0.4515.107 (87a818b10553a07434ea9e2b6dccf3cbe7895134-refs/branch-heads/4515@{#1634})', userDataDir: '/var/folders/fv/1gs2zg7n6hq1m3zy_pxkh54m0000gp/T/.com.google.Chrome.AycbGv' }), goog:chromeOptions: Object({ debuggerAddress: 'localhost:61336' }), networkConnectionEnabled: false, pageLoadStrategy: 'normal', platformName: 'mac os x', proxy: Object({ }), setWindowRect: true, strictFileInteractability: false, timeouts: Object({ implicit: 0, pageLoad: 300000, script: 30000 }), unhandledPromptBehavior: 'dismiss and notify', webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true }), addCommand: Function, overwriteCommand: Function, addLocatorStrategy: Function, config: Object({ specs: [ './webdriverio/e2e/*.test.js' ], suites: Object({ ... to have title 'React'.
at

Logs:

0-0] 2021-09-06T19:13:11.845Z INFO webdriver: Initiate new session using the WebDriver protocol
[0-0] 2021-09-06T19:13:11.908Z INFO webdriver: [POST] http://localhost:9515/session
[0-0] 2021-09-06T19:13:11.908Z INFO webdriver: DATA {
[0-0]   capabilities: {
[0-0]     alwaysMatch: { browserName: 'chrome', 'goog:chromeOptions': [Object] },
[0-0]     firstMatch: [ {} ]
[0-0]   },
[0-0]   desiredCapabilities: { browserName: 'chrome', 'goog:chromeOptions': { args: [Array] } }
[0-0] }
2021-09-06T19:13:12.274Z WARN chromedriver: [1630955592.274][WARNING]: This version of ChromeDriver has not been tested with Chrome version 93.
[0-0] 2021-09-06T19:13:12.699Z INFO webdriver: COMMAND navigateTo("https://todomvc.com/")
[0-0] 2021-09-06T19:13:12.699Z INFO webdriver: [POST] http://localhost:9515/session/c76db59575408052600827adc6476a2f/url
[0-0] 2021-09-06T19:13:12.699Z INFO webdriver: DATA { url: 'https://todomvc.com/' }
[0-0] 2021-09-06T19:13:14.155Z INFO webdriver: COMMAND getTitle()
[0-0] 2021-09-06T19:13:14.155Z INFO webdriver: [GET] http://localhost:9515/session/c76db59575408052600827adc6476a2f/title
[0-0] Error in "TodoMVC verify title"
Error: Expected Browser({ sessionId: 'c76db59575408052600827adc6476a2f', capabilities: Object({ acceptInsecureCerts: false, browserName: 'chrome', browserVersion: '93.0.4577.63', chrome: Object({ chromedriverVersion: '92.0.4515.107 (87a818b10553a07434ea9e2b6dccf3cbe7895134-refs/branch-heads/4515@{#1634})', userDataDir: '/var/folders/fv/1gs2zg7n6hq1m3zy_pxkh54m0000gp/T/.com.google.Chrome.AycbGv' }), goog:chromeOptions: Object({ debuggerAddress: 'localhost:61336' }), networkConnectionEnabled: false, pageLoadStrategy: 'normal', platformName: 'mac os x', proxy: Object({  }), setWindowRect: true, strictFileInteractability: false, timeouts: Object({ implicit: 0, pageLoad: 300000, script: 30000 }), unhandledPromptBehavior: 'dismiss and notify', webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true }), addCommand: Function, overwriteCommand: Function, addLocatorStrategy: Function, config: Object({ specs: [ './webdriverio/e2e/*.test.js' ], suites: Object({  ... to have title 'React'.
    at <Jasmine>
    at UserContext.<anonymous> (/Users/ylaichenkov/Desktop/practice/protractor-endgame/webdriverio/e2e/simple.test.js:14:27)
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
[0-0] 2021-09-06T19:13:14.158Z INFO webdriver: COMMAND deleteSession()
[0-0] 2021-09-06T19:13:14.159Z INFO webdriver: [DELETE] http://localhost:9515/session/c76db59575408052600827adc6476a2f
[0-0] 2021-09-06T19:13:14.160Z INFO webdriver: RESULT TodoMVC
[0-0] FAILED in chrome - /webdriverio/e2e/simple.test.js
2021-09-06T19:13:14.332Z INFO @wdio/cli:launcher: Run onComplete hook

Spec Files:      0 passed, 1 failed, 1 total (100% completed) in 00:00:03 

2021-09-06T19:13:14.334Z INFO @wdio/local-runner: Shutting down spawned worker
2021-09-06T19:13:14.585Z INFO @wdio/local-runner: Waiting for 0 to shut down gracefully
2021-09-06T19:13:14.585Z INFO @wdio/local-runner: shutting down

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.