cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
47.03k stars 3.19k forks source link

Allow hiding assertion logs for `.should()` and `.and()` except on failure #7693

Open ncknuna opened 4 years ago

ncknuna commented 4 years ago

Current behavior:

There is no way to hide logs when making assertions, for example, with should.

Desired behavior:

There is a way to hide passing assertions while still reporting failing assertions. Ideally these successful assertions could also be turned back on when running under a different log level.

This came up because I wanted a "safer" version of the get command, which would by default assert that there is only 1 element found (unless an explicit length option was passed) and that the element is visible (unless an explicit noVisibleCheck option was passed), since I've seen tests fail or falsely succeed because of overbroad selectors or when an element was present in the DOM but not visible. Cypress tests run fast enough that doing this shouldn't add significantly to the test run time.

However, when I do this, I end up with a ton of extra logs for each get, which clutters the test output. I'd like a way to disable these logs by default, unless the assertions fail.

Test code to reproduce

https://github.com/ncknuna/cypress-test-tiny/blob/master/cypress/support/commands.js#L45

Versions

Cypress 4.8.0 OSX 10.15.5 Chrome 83.0.4103.61

jennifer-shehane commented 4 years ago

.should() and .and() doesn't currently accept a log option (or any options) as an argument. So turning off these assertions within the Command Log is not currently possible. This would have to be coded in somehow which would likely be a bit more difficult than other commands given the API signature of .should().

ncknuna commented 4 years ago

Got it, that makes sense! Thanks for accepting it as an valid potential enhancement :)

bmitchinson commented 3 years ago

Would like to +1 this, i'm asserting that 3 strings are contained in a file (represented as a string), and the entire contents of the file are printed, 3 times over.

johnnymetz commented 3 years ago

+1

JasonFairchild commented 3 years ago

+1 I want to assert that a local storage token exists before I get it to send as an auth header before any cy.request. Cypress will often look for it quicker than it is set, so an assertion seems like the best way, but then it can lead to many weird assertions in the log.

northkevin commented 3 years ago

+1

I like to check that a cookie exists before each outgoing api request & suppressing this assertion would clean up test logs quite nicely 👍

nickdavis2001 commented 3 years ago

+1. The use case this would solve for us is for example:

  cy.request(myUrl).then((response) => {
                expect(response.headers['content-type']).to.contain('application/pdf');
                expect(response.body).to.have.length.gt(500);
            });

This is checking that the response is a reasonably sized pdf. This currently prints out the whole pdf in the log. :( I'm open to other ideas of how to do this if there's a better way. :)

richardscarrott commented 3 years ago

@ncknuna I found this issue when attempting to define the exact same thing as I found myself constantly checking have.length and is.visible.

I'm now using this:

type VGetOptions = { length: number; visible: boolean } & Parameters<
  typeof cy.get
>[1];

Cypress.Commands.add(
  'vget',
  (
    selector: string,
    { length, visible, ...rest }: VGetOptions = { visible: true, length: 1 }
  ): Cypress.Chainable<JQuery<HTMLElement>> =>
    cy
      .get(selector, rest)
      .should('have.length', length)
      .and(visible ? 'be.visible' : 'not.be.visible')
);

// ...
cy.vget('.foo'); // most common scenario
cy.vget('.foos', { length: 10 });
cy.vget('.bar', { visible: false });
cy.vget('.bars', { visible: false, length: 5 });

But yes, It would be great if passing assertions could optionally be removed from the command log.

Threnos commented 3 years ago

I'm using retry-ability to wait for SSE connection to establish. In this case I have no need for --assert expected true to be true in command log, unless it failed. Thus, having ability to hide assertion will free up space from not critical information.

const eventSource = new FetchEventSource(`http://localhost/sse/subscribe`)
cy.wrap(eventSource, { log: false }).should(eventSource => expect(eventSource.isOpen).to.be.true)

A little background for why it is done like this: for connecting to SSE we use @microsoft/fetch-event-source package. Unfortunately, because of the way it handles connection, chrome cannot properly read events and data. Which makes cy.intercept() helpless in this case.

pcj commented 3 years ago

I would like this feature as well, to only log assertions that fail.

As a workaround for assertions that are easily checked up front, you can use a somewhat redundant approach like:

            let actual = ctx.maybeGet(key);
            // if we always perform the 'expect', cypress log becomes very busy.
            // detect the failure condition and repeat with chai assertion so it 
            // surfaces in the log and fails the test
            if (!actual) {
                expect(actual, `${this.id}:unreadactBody:${key}`).to.not.be.empty;
            }
AFM-Horizon commented 3 years ago

I'll add my name to the list - this would be great

uday-nitjsr commented 3 years ago

Hard +1 on this. I was adding log options to reduce the noise in our logs, only to find i cant add it for should 😰

carla-at-wiris commented 3 years ago

It would be very usefull

stychu commented 3 years ago

++

mduft commented 3 years ago

We're checking for downloads of ZIP files, using the cypress examples as a basis, which has an assertion for the files length to be at least 300 bytes which floods the log - does not look that nice..

zdebski commented 3 years ago

@jennifer-shehane is there any news about this enhancement?

DanaGoyette commented 3 years ago

I'm using a function like this, that keeps running into "element is detached", so I had to add assertions, but they're a whole lot of clutter. I'd like to be able to hide the interim assertions if they pass.

export function getTableVal(row: string, column: 'left' | 'center' | 'right' = 'center') {
  return cy.get(`[data-row=${row}]`).should('exist').find(`[data-column=${column}]`).should('exist').find(`[data-testid=value]`)
}

image

PierreTurnbull commented 3 years ago

I'd love this too.

CoryDanielson commented 2 years ago

@DanaGoyette, you can combine your selectors into a single get.

  return cy.get(`[data-row=${row}] [data-column=${column}] [data-testid=value]`);
DanaGoyette commented 2 years ago

@DanaGoyette, you can combine your selectors into a single get.

  return cy.get(`[data-row=${row}] [data-column=${column}] [data-testid=value]`);

I've tried that, and the result is that I get tests failing with "component became detached from the DOM" quite often. Using the separate selectors seems to fix that. Also, the log tends to show line breaks at the dashes, which is ugly, instead of breaking at the logical place of the space between selectors.

What I get:

[data-test-row=phone] [data-test-
column=center] [data-
testid=value]

What I'd want:

[data-test-row=phone]
 [data-test-column=center]
 [data-testid=value]

The chained .get/.find makes the logs neater, except for the assertions in between.

MoKhajavi75 commented 2 years ago

+1

Would be great to check password input values!

laurentRank commented 2 years ago

+1 Coupling this with Gherkin, I'm trying to get all my assertions to have specific messages when passed. automatic assertions in .should() and .and() are currently polluting the output logs.

jmicu commented 2 years ago

+1. I have a custom command with several expects that clutter the log when they pass.

sarahTheTester commented 2 years ago

As a work around, "native" chai expect() will not generate a Cypress log.

If assertion fails, the error appears in the log in the normal way.

Anybody see any cons for this method?

pkoral commented 2 years ago

+1

esudaley commented 2 years ago

Aside from the issue of log clutter, when performing some large validations, I noticed that using expect() takes far longer than a plain JS conditional, which I assume is due to the logging behavior.

Here's a sample I prepared to reproduce the behavior.

describe('Compare Chai expect() to JS conditional', () => {
    let sampleString = "expect vs conditional"

    it('Check equality using expect()', () => {
        for (let i=0; i < 4000; i++){
            expect(sampleString).to.equal(sampleString)
        }
    })

    it('Check equality using JS to trigger expect()', () => {
        for (let i=0; i < 4000; i++){
            if(sampleString !== sampleString)
                expect(sampleString).to.equal(sampleString)
        }
    })
})

Using expect() took ~30 seconds, whereas the conditional took about 0.02 seconds.

For the time being, is there anything lacking in simply using a plain conditional to trigger expect() when the assertion should fail?

Lagluck07 commented 2 years ago

Hi all,

I just found on web a solution to hide all the "xhr" logs. So I´ve just included the "..command-name-assert" (class for the <"Li"> selector that displays the assert logs). I know that´s not the best way to do that, but it works (sorry for the poor english rs):

//Put the code below in the support/index.js file, create a hideXHR config (just in case u want to disable) and add in //style.innerHTML all the classes (LI lines) u want hide. // Hide all fetch/XHR requests in Cy console, toggle via cypress.json

if (Cypress.config('hideXHR')) { const app = window.top if (!app.document.head.querySelector('[data-hide-command-log-request]')) { const style = app.document.createElement('style') style.innerHTML = '.command-name-page-load, .command-name-new-url, .command-name-request, .command-name-xhr, .command-name-assert { display: none }' style.setAttribute('data-hide-command-log-request', '') app.document.head.appendChild(style) } }

udayivaturi commented 1 year ago

+1

leila-c908 commented 1 year ago

+1.

THEtheChad commented 1 year ago

If you use the function signature form of .should, you can eliminate the logging clutter.

.should($subject => { if( {condition ) throw new Error('This is whack yo!'); })

Cypress.Commands.add('waitOnLoad', () => {

    cy.get(".fa-spinner", { log: false })
        .should($subject => {
            if (!$subject.length) throw new Error("Should exist.");
        })
        .then($el =>
            Cypress.log({
                name: "waitOnLoad",
                displayName: "waitOnLoad",
                message: "",
                $el
            })
        );

    cy.get(".fa-spinner", { log: false }).should($subject => {
        if ($subject.length) throw new Error("Should not exist.");
    });
})
lacma2011 commented 1 year ago

+1

goska-malaga commented 1 year ago

allowing hiding assertion logs would be a good option, just like you can hide every other log { log: false }, case to show the log on failure could be additional option when you run E2E test and you need to wait until loader is not visible - what other option do you have except for should('not.be.visible')? even worse is if the loader show up and then disappear so first I have to wait for it to be visible and then not.to.exist - so those are 2 assertions that I have hard time to avoid and it is not the assertion that is a goal of the test, it is just an intermediate step I want the final test assertions to be logged and being clear from looking at log what actually was asserted in the test

ameduza commented 1 year ago

+1 Still looking for that enhancement - also want to hide successful assertion or just always hide to reduce Cypress log. In my case it might be just huge

datashard commented 1 year ago

+1

I'd also love this enhancement, it'd make it a lot nicer for plugin developers (like me), especially if you use any form of .should

aKzenT commented 1 year ago

it sucks that there is still no solution to this issue after more than 3 years. In our case we want to assert on the contents of a file, which results in the whole file being printed out on the log... :-(

ParTee71 commented 6 months ago

+1 Would be great to have