From 52ca8ed8399c5ef467efbee7a2d00fe0863e7f36 Mon Sep 17 00:00:00 2001 From: Ben Kucera <14625260+Bkucera@users.noreply.github.com> Date: Tue, 9 Jul 2019 09:30:15 -0500 Subject: [PATCH] support partial matching text,html,value (#3259) * add "be.focused" to chai_jquery * add comment explaining the mess * add type definitions * refactor assertion to use jquery assertion * remove trailing whitespace * add test for multiple elements, update typedefs * fix failing tests: not.be.visible -> not.exist * allow should(not.be.visible) for failed selectors * remove unrelated visibility changes * support partial matching text,html,value,id * add partials for html,text,value ONLY, add typedefs, fix tests * address changes --- cli/types/index.d.ts | 48 ++++++++++++++++++ cli/types/tests/chainer-examples.ts | 7 +++ .../driver/src/cypress/chai_jquery.coffee | 50 ++++++++++++++----- .../commands/assertions_spec.coffee | 26 ++++++++++ 4 files changed, 119 insertions(+), 12 deletions(-) diff --git a/cli/types/index.d.ts b/cli/types/index.d.ts index 0311659be5..a372ab5c9e 100644 --- a/cli/types/index.d.ts +++ b/cli/types/index.d.ts @@ -3694,6 +3694,14 @@ declare namespace Cypress { * @see https://on.cypress.io/assertions */ (chainer: 'have.html', value: string): Chainable + /** + * Assert that the html of the first element of the selection partially contains the given html, using `.html()`. + * @example + * cy.get('#result').should('contain.html', 'John Doe') + * @see http://chaijs.com/plugins/chai-jquery/#htmlhtml + * @see https://on.cypress.io/assertions + */ + (chainer: 'contain.html', value: string): Chainable /** * Assert that the first element of the selection has the given id, using `.attr('id')`. * @example @@ -3719,6 +3727,14 @@ declare namespace Cypress { * @see https://on.cypress.io/assertions */ (chainer: 'have.text', value: string): Chainable + /** + * Assert that the text of the first element of the selection partially contains the given text, using `.text()`. + * @example + * cy.get('#result').should('contain.text', 'John Doe') + * @see http://chaijs.com/plugins/chai-jquery/#texttext + * @see https://on.cypress.io/assertions + */ + (chainer: 'contain.text', value: string): Chainable /** * Assert that the first element of the selection has the given value, using `.val()`. * @example @@ -3727,6 +3743,14 @@ declare namespace Cypress { * @see https://on.cypress.io/assertions */ (chainer: 'have.value', value: string): Chainable + /** + * Assert that the first element of the selection partially contains the given value, using `.val()`. + * @example + * cy.get('textarea').should('contain.value', 'foo bar baz') + * @see http://chaijs.com/plugins/chai-jquery/#valuevalue + * @see https://on.cypress.io/assertions + */ + (chainer: 'contain.value', value: string): Chainable /** * Assert that the selection matches a given selector, using `.is()`. Note that this overrides the built-in chai assertion. If the object asserted against is not a jQuery object, the original implementation will be called. * @example @@ -3874,6 +3898,14 @@ declare namespace Cypress { * @see https://on.cypress.io/assertions */ (chainer: 'not.have.html', value: string): Chainable + /** + * Assert that the html of the first element of the selection does not contain the given html, using `.html()`. + * @example + * cy.get('#result').should('not.contain.html', 'John Doe') + * @see http://chaijs.com/plugins/chai-jquery/#htmlhtml + * @see https://on.cypress.io/assertions + */ + (chainer: 'not.contain.html', value: string): Chainable /** * Assert that the first element of the selection does not have the given id, using `.attr('id')`. * @example @@ -3899,6 +3931,14 @@ declare namespace Cypress { * @see https://on.cypress.io/assertions */ (chainer: 'not.have.text', value: string): Chainable + /** + * Assert that the text of the first element of the selection does not contain the given text, using `.text()`. + * @example + * cy.get('#result').should('not.contain.text', 'John Doe') + * @see http://chaijs.com/plugins/chai-jquery/#texttext + * @see https://on.cypress.io/assertions + */ + (chainer: 'not.contain.text', value: string): Chainable /** * Assert that the first element of the selection does not have the given value, using `.val()`. * @example @@ -3907,6 +3947,14 @@ declare namespace Cypress { * @see https://on.cypress.io/assertions */ (chainer: 'not.have.value', value: string): Chainable + /** + * Assert that the first element of the selection does not contain the given value, using `.val()`. + * @example + * cy.get('textarea').should('not.contain.value', 'foo bar baz') + * @see http://chaijs.com/plugins/chai-jquery/#valuevalue + * @see https://on.cypress.io/assertions + */ + (chainer: 'not.contain.value', value: string): Chainable /** * Assert that the selection does not match a given selector, using `.is()`. Note that this overrides the built-in chai assertion. If the object asserted against is not a jQuery object, the original implementation will be called. * @example diff --git a/cli/types/tests/chainer-examples.ts b/cli/types/tests/chainer-examples.ts index 3e22b71a03..48cf5beef8 100644 --- a/cli/types/tests/chainer-examples.ts +++ b/cli/types/tests/chainer-examples.ts @@ -124,6 +124,13 @@ cy.wrap('foobar').should('have.string', 'bar') cy.wrap('foobar').should('include', 'foo') +cy.wrap('foo').should('contain.value') +cy.wrap('foo').should('contain.text') +cy.wrap('foo').should('contain.html') +cy.wrap('foo').should('not.contain.value') +cy.wrap('foo').should('not.contain.text') +cy.wrap('foo').should('not.contain.html') + cy.wrap([1, 2, 3]).should('include.members', [1, 2]) ; () => { diff --git a/packages/driver/src/cypress/chai_jquery.coffee b/packages/driver/src/cypress/chai_jquery.coffee index 171f8c0cf8..dccf123d51 100644 --- a/packages/driver/src/cypress/chai_jquery.coffee +++ b/packages/driver/src/cypress/chai_jquery.coffee @@ -43,14 +43,37 @@ $chaiJquery = (chai, chaiUtils, callbacks = {}) -> try # ## reset obj to wrapped + orig = ctx._obj ctx._obj = wrap(ctx) + if ctx._obj.length is 0 + ctx._obj = ctx._obj.selector + ## apply the assertion ctx.assert(bool, args...) + ctx._obj = orig catch err ## send it up with the obj and whether it was negated callbacks.onError(err, method, ctx._obj, flag(ctx, "negate")) + assertPartial = (ctx, method, actual, expected, message, notMessage, args...) -> + if ctx.__flags.contains + return assert( + ctx + method + _.includes(actual, expected), + 'expected #{this}'+ ' to contain ' + message + 'expected #{this}'+ ' not to contain ' + notMessage + args... + ) + return assert( + ctx + method + actual is expected + 'expected #{this}'+ ' to have ' + message + 'expected #{this}'+ ' not to have ' + notMessage + args... + ) chai.Assertion.addMethod "data", -> assertDom(@, "data") @@ -92,12 +115,13 @@ $chaiJquery = (chai, chaiUtils, callbacks = {}) -> actual = wrap(@).html() - assert( + assertPartial( @, "html", - actual is html, - 'expected #{this} to have HTML #{exp}, but the HTML was #{act}', - 'expected #{this} not to have HTML #{exp}', + actual + html + 'HTML #{exp}, but the HTML was #{act}', + 'HTML #{exp}', html, actual ) @@ -113,12 +137,13 @@ $chaiJquery = (chai, chaiUtils, callbacks = {}) -> actual = wrap(@).text() - assert( + assertPartial( @, "text", - actual is text, - 'expected #{this} to have text #{exp}, but the text was #{act}', - 'expected #{this} not to have text #{exp}', + actual + text + 'text #{exp}, but the text was #{act}', + 'text #{exp}', text, actual ) @@ -134,12 +159,13 @@ $chaiJquery = (chai, chaiUtils, callbacks = {}) -> actual = wrap(@).val() - assert( + assertPartial( @, "value", - actual is value, - 'expected #{this} to have value #{exp}, but the value was #{act}', - 'expected #{this} not to have value #{exp}', + actual + value + 'value #{exp}, but the value was #{act}', + 'value #{exp}', value, actual ) diff --git a/packages/driver/test/cypress/integration/commands/assertions_spec.coffee b/packages/driver/test/cypress/integration/commands/assertions_spec.coffee index 0c56ac1d3c..2f1a92d017 100644 --- a/packages/driver/test/cypress/integration/commands/assertions_spec.coffee +++ b/packages/driver/test/cypress/integration/commands/assertions_spec.coffee @@ -1019,6 +1019,11 @@ describe "src/cy/commands/assertions", -> expect(null).to.have.html("foo") + it "partial match", -> + expect(@$div).to.contain.html('button') + expect(@$div).to.not.contain.html('span') + cy.get('button').should('contain.html', 'button') + context "text", -> beforeEach -> @$div = $("
foo
") @@ -1050,6 +1055,12 @@ describe "src/cy/commands/assertions", -> "expected **
** to have text **bar**, but the text was **foo**" ) + it "partial match", -> + expect(@$div).to.have.text('foo') + expect(@$div).to.contain.text('o') + cy.get('div').should('contain.text', 'iv').should('contain.text', 'd') + cy.get('div').should('not.contain.text', 'fizzbuzz').should('contain.text', 'Nest') + it "throws when obj is not DOM", (done) -> cy.on "fail", (err) => expect(@logs.length).to.eq(1) @@ -1107,6 +1118,21 @@ describe "src/cy/commands/assertions", -> expect({}).to.have.value("foo") + it "partial match", -> + expect(@$input).to.contain.value('oo') + expect(@$input).to.not.contain.value('oof') + cy.get('input') + .invoke('val','foobar') + .should('contain.value', 'bar') + .should('contain.value', 'foo') + cy.wrap(null).then -> + cy.$$('').prependTo(cy.$$('body')) + cy.$$('').prependTo(cy.$$('body')) + cy.get('input').should ($els) -> + expect($els).to.have.value('foo2') + expect($els).to.contain.value('foo') + .should('contain.value', 'oo2') + context "descendants", -> beforeEach -> @$div = $("
")