lakitna / cypress-commands Goto Github PK
View Code? Open in Web Editor NEWA collection of Cypress commands to extend and complement the defaults
License: MIT License
A collection of Cypress commands to extend and complement the defaults
License: MIT License
I want to be able to assert the full text of an element instead of relying on contains
.
Because in some cases having extra text is a problem and using the current methods you can't properly assert the full text.
The following example is, in some cases, not specific enough. I would like it to fail if the text does not match /^foo$/
.
cy.get('div').should('contain', 'foo');
.should('equal', 'foo')
does not work here as it would assert agains the element instead of the text.
I want a more specific way to test strings.
cy.get('div')
.text()
.should('equal', 'foo');
This would be really usefull for complex pages where you need to assert data and such.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
I am using Cypress with typescript and would love to use the retry feature of your package
A short description of why you want to accomplish the things mentioned above.
however I am getting errors related to types.
Argument of type '{ retry: boolean; }' is not assignable to parameter of type 'Partial<Timeoutable>'. Object literal may only specify known properties, and 'retry' does not exist in type 'Partial<Timeoutable>'.ts(2345)
A clear and concise description of what you want to happen.
I am not quite sure how, but I think we need to overwrite the default cypress then typings to include this packages options.
Add any other context or screenshots about the request here.
All tests still pass in both GUI and CLI mode, but some things will have to be updated for future compatibility.
Hello 👋 I'm writing on behalf of the Cypress DX team. We wanted to notify you that some changes may need to be made to this plugin to ensure that it works in Cypress 10.
For more information, here is our official plugin update guide.
Dependency to upgrade:
Cypress to 3.6.x
Issue to track all the little things that have to be done before publishing.
Initial context: cypress-io/cypress#630 (comment)
The ability to cast values to different primitives to allow us to write something like
cy.get(...)
.text()
.castSubjectToANumberInThisCommand()
.should('be.above', 1);
To simplify reading your tests. This would replace code like
cy.get(...)
.text()
.then((val) => Number(val))
.should('be.above', 1);
This code isn't bad, but it can be a bit scary for some.
A few possibilities at this point:
cy.wrap('007')
.number()
.should('equal', 7);
cy.wrap(123)
.string()
.should('equal', '123');
cy.wrap('foo')
.array()
.should('equal', ['foo']);
These might be better when named .asNumber()
, .asString()
and .asArray()
. Otherwise you would get confusing chains like cy.get(...).text().number()
.
Example for the .text()
command: Add a new .number()
command that will retrieve the numeric contents of a subject element.
cy.get('.mrBond')
.number()
.should('equal', 7);
On a technical level this would essentially contain .text().then((n) => Number(n))
.
cy.wrap('007')
.cast('number')
.should('equal', 7);
For the .attribute()
command I made a way to gather the upcoming assertions with decent stability. This is very hacky and we probably shouldn't rely on that if we can help it.
cy.get('.mrBond')
.text()
.should('equal', 7);
cy.get('.mrBond')
.text({ cast: 'number' })
.should('equal', 7);
The conversation starting at this comment cypress-io/cypress#630 (comment)
I want an easy way to get the text inside input
and textarea
elements.
Right now it's a pain to get these values even though they can be important to assert.
Ways you can assert this value right now:
// Will pass on whitespace
cy.get('input')
.should('not.have.value', '');
// Will not retry properly
cy.get('input')
.then((elem) => elem.val())
.should('not.be.empty');
// Currently the best implementation imo
cy.get('input')
.should((elem) => {
expect(elem.val()).to.not.be.empty;
});
I was thinking about extending its()
to use jQueries val
function when the subject is a jQuery element and the command is called like .its('value')
.
cy.get('input')
.its('value')
.should('be.empty');
Alternatively, the text()
command could be used for this.
cy.get('input')
.text()
.should('be.empty');
A third option would be to create an attribute()
command that uses jQueries attr
function. This would enable much more than just retrieving the value of form elements, but is not great semantically.
cy.get('input')
.attribute('value')
.should('be.empty');
Ran into this on Gitter.
Only distribute bundled files (.js and .d.ts).
To limit the number of files in the users node_modules we should distribute bundled files.
Use Rollup with lessons learned from another project.
This will not change any functionality.
The .request()
method has been overhauled in Cypress 3.3.x. Update tests and make sure the requestBaseUrl
still works.
Clone repo, run tests
Tests pass
One can't use this.myAlias
inside then()
callbacks.
specify('aliases work', function () {
cy.wrap(1).as('myAlias');
cy.wrap(2).then(function(subj) {
expect(this.myAlias).to.eq(1); // undefined
});
});
The test succeeds.
A way to fix this would be:
--- node_modules/cypress-commands/lib/then.js.orig 2019-09-07 10:32:52.749110507 +0300
+++ node_modules/cypress-commands/lib/then.js 2019-09-07 10:33:18.125849439 +0300
@@ -23,7 +23,8 @@
* @yields {any}
* @since 0.0.0
*/
-Cypress.Commands.overwrite('then', (originalCommand, subject, fn, options = {}) => {
+Cypress.Commands.overwrite('then', function(originalCommand, subject, fn, options = {}) {
+ const ctx = this;
if (_.isFunction(options)) {
// Flip the values of `fn` and `options`
[fn, options] = [options, fn];
@@ -86,7 +87,7 @@
*/
async function executeFn() {
// Execute using the original `then` to not reinvent the wheel
- return await originalCommand(subject, options, fn)
+ return await originalCommand.call(ctx, subject, options, fn)
.then((value) => {
if (options.log) {
consoleProps.Yielded = value;
But for one reason or another originalCommand
doesn't pass down the context either.
Greetings from the @cypress-io team. Cypress 12 is coming out next week, and some changes might affect your plugin. One of the big changes is introducing a new API to register custom commands, which helps fix one of the oldest and most annoying issues with Cypress, the “Detached DOM” error.
For commands that are classified as queries (mainly used to return something like a DOM element), there is a new Cypress.Commands.addQuery method. The addQuery
method greatly simplifies writing custom query commands and has the benefit of not encountering detached DOM errors.
If your plugin currently registers custom command “queries”, we recommend updating your plugin to use the new API for Cypress 12. Note the API is only going to be in Cypress 12 and newer.
To test out a prerelease version of Cypress 12, you can follow the instructions for installing a prerelease binary here, but instead of using the develop
branch use the release/12.0.0
branch.
We recommend all plugin authors test their plugins against the Cypress 12 prerelease to check for compatibility.
If you have any questions, contact us by pinging me on this issue or in our Discord server.
You might find our Retry-ability Guide (updated to cover the latest changes), and Cypress 12 Migration Guide | Cypress Documentation helpful as well.
Thanks
How do I actually use these commands in my test files? I don't understand, the documentation tells me some random steps but actually invoking say .text() function doesn't work.
text()
commands adds spaces if element's content has <wbr>
tags inside
HTML to reproduce:
<a href="/cell_phones/mobile_phone_samsung_a207f_galaxy_a20s_32_duos_red_sm-a207fzrdsek.html" class="product-name">Мобильны<wbr>й телефон Samsung A207F Galaxy A20s/32 Duos Red (SM-A207FZRD<wbr>SEK)</a>
cy.get('.product-name').text()
yields
Мобильны й телефон Samsung A207F Galaxy A20s/32 Duos Red (SM-A207FZRD SEK)
cy.get('.product-name').text()
yields
Мобильный телефон Samsung A207F Galaxy A20s/32 Duos Red (SM-A207FZRDSEK)
The native approach cy.get('.product-name').invoke('text')
gives the expected result of Мобильный телефон Samsung A307F Galaxy A30s/32 Duos White (SM-A307FZWUSEK)
I pulled down the code base and updated Cypress from 5.x to 6.x. I found two failing tests, one relatively simple issue and one I believe may be a test which has been removed from the Cypress suite.
Delete node_modules
and package-lock.json
Change Cypress version in package.json
to ^6.0.0
Reinstall
All tests run green
There are two failing tests.
then.js
Line 320
expect(err.message).to.equal('Timed out retrying: expected 5 to equal 4');
Fails because the message from Cypress has changed to include the number of millseconds. Changing to
expect(err.message).to.contain('expected 5 to equal 4');
Causes the test to pass and verifies the intended result.
copied/request.js
here is a folder under cypress integration, copied
. It contains one spec, request.js
. This variant fails the test
is deprecated but does not fail even on 500 when failOnStatus=false
The full error is:
cy.request() failed on:
http://localhost:1234/foo
The response we received from your web server was:
> 500: undefined
This was considered a failure because the status code was not 2xx or 3xx.
If you do not want status codes to cause failures pass the option: failOnStatusCode: false
Inspired by @thekiiingbob on the Cypress Gitter.
// Visit http://www.domain.com/foo
cy.visit('/foo');
// Request from http://api.domain.com/foo
cy.request('/foo');
@thekiiingbob has an app where he needs to .visit()
to http://www.domain.com
and .request()
to http://api.domain.com
. To keep things clean and concise it would be great if there are separate base urls for .visit()
and .request()
.
Overwrite the .request()
command to look at the config key requestBaseUrl
. If this key is undefined
use the normal baseUrl
instead.
cy.get('img').attribute('src', {whitespace: 'simplify'})
.should('eq', 'http://host/some/path');
Because with cy.wrap($('<img src=" http://host/some/path">'))
or something it fails.
https://github.com/Lakitna/cypress-commands/blob/develop/src/text.js#L53-L57
plus trim()
Just to make sure everything still works as intended :)
I want to be able to select multiple elements by its contents.
The command .contains()
only returns a single element. In most cases this is great, but some specific cases you want to find multiple elements by its contents.
In most of these cases, you can make a workaround using .filter()
, but this requires you to write custom, often untestable code. Adding this to a command makes sure you don't have deal as much with test code bugs.
Add an option to the .contains()
command to allow you to do this. The option could be named multiple
like in the default .click()
.
cy.get('div')
.contains('foo', { multiple: true });
By default .contains()
always selects the deepest element it can find, if there are multiple it will grab the first of those. This behaviour should only change if the multiple
option is set.
Given the following situation:
<p>Lorum <b>ipsum</b> dolor sit amet.</p>
cy.get('p').text({ depth: Infinity })
Will yield:
"Lorum dolor sit amet. ipsum"
That is an unexpected order.
It yields
"Lorum ipsum dolor sit amet."
The following change to the text()
command seems to solve the issue.
/**
* @param {JQuery} element
* @param {number} depth
* @return {string}
*/
function getTextOfElement(element, depth) {
return element
.contents()
.filter((_, content) => {
console.log(content)
// Only keep the text nodes
return content.nodeType === Node.TEXT_NODE
|| (content.nodeType === Node.ELEMENT_NODE && depth > 0);
})
.map((_, content) => {
if (content.nodeType === Node.TEXT_NODE) {
// Get the text from the text node
return content.data.trim();
}
if (content.nodeType === Node.ELEMENT_NODE) {
// Get the text from child element
return getTextOfElement($(content), --depth)
}
})
.toArray()
.join(' ')
.trim();
I want a neat way to access an element's attributes so I can assert them.
The current way of doing so would be something like below. This is unnecessarily verbose and can be confusing.
// Using then
cy.get('div')
.then((elem) => elem.attr('foo'))
.should('equal', 'bar');
// Without then (and thus with retry)
cy.get('div')
.should((elem) => {
const attribute = elem.attr('foo');
expect(attribute).to.equal('bar');
});
A command that basically wraps the jQuery attr()
function
cy.get('div')
.attribute('foo')
.should('equal', 'bar');
It should throw an error if the attribute does not exist on the subject (unless the upcoming assertion demands it not existing).
It should yield a string when applied to a single element. It should yield an array of strings when applied to multiple elements.
When an assertion fails the previous command will be retried until the assertion passes. Only one command will be retried. I want to find a way to make Cypress retry 2 or more commands instead.
This can be very useful for improving tests stability when building custom commands or when added to certain commands like for example text()
.
The only existing thing in Cypress that resembles this behaviour is the should(fn)
. Creating an alias for should is a last resort to get this behaviour. It would be a lot better if we can hook into the underlying logic of should
instead to bypass the default chaining logic.
The first step would be to find out if this is even possible. Next step would be to find out if this behaviour can be added to existing commands with an option.
I can't get text() command working - it doesn't return text as a string.
Why do you think there should be a change?
How can we improve it? You probably don't need to answer this question if you are writing the improvements yourself.
The default then
command accepts a timeout
option. Can you extend your types to mirror (or import) the cypress types? In 4.1.0, this is the Timeoutable
interface.
BTW I love this plugin. Thank you for writing it!
When you try to use the .attribute
command, you get:
queue.filter is not a function
It looks like Cypress removed the .filter
method in version 8.3. I played with this locally and it seems to work if I just switch it to use .find
However, I think I'm missing something with the invoked
Write any test that uses the .attribute
command
The .attribute
command should not throw an error.
The problem line is here:
I cannot seem to find any info on the .filter
method on Cypress docs or in the issues list.
I've seen the problem in Cypress 8.3 and 8.3.1
I can try to do a PR to fix it if that would help.
Thanks!
Ricardo Diaz
I'm trying to obtain a value/text within the via .text(), it always brings back an empty string - but looking at the logs it contains a jQuery and within it, it contains value="MY_VALUE".
I did via <div with .text() and it worked, I just have an issue with <input - is there away to obtain this from the results within the jQuery. I did the following things but didnt work.
I'm not sure if this is a bug or due to my lack of understanding please help :)
const getToken = cy.get('#copiedToken').text()
- empty string
const getToken = cy.get('#copiedToken').text() let bla = getToken[0].value
- this always gives undefined value - but in jQuery it shows my text in the value part
cy.get('#copiedToken').text({ depth: Infinity }).then(($info) => { cy.log($info) })
- this gives empty string
Add any other context about the problem here.
cy.request()
fails with:
TypeError: Cannot read property 'length' of undefined
when no requestBaseUrl
present in cypress.json
.
cypress/integration/1.spec.js
:
describe('cy.request', function() {
it('succeeds', () => {
cy.request('GET', '/some/relative/url');
});
});
It succeeds.
The culprit line is this one.
A basic Travis pipeline to ensure all tests pass and there are no linting errors.
I've been thinking that we should probably solidify the package in major version 1.
Therefore I would like to invite everyone to suggest any changes that should be made before we do this.
I'll leave this open for about a month after which I'll publish 1.0.0, even if there are no changes. This issue will serve as a tracker for 1.0.0.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.