Upgrade to Pro — share decks privately, control downloads, hide ads and more …

It's a (testing) trap! - Common end-to-end pitfalls and how to solve them

It's a (testing) trap! - Common end-to-end pitfalls and how to solve them

“It’s a trap” - a call or feeling we all might be familiar with, not only when it comes to Star Wars. It signalizes a sudden moment of noticing imminent danger. This situation is an excellent allegory for an unpleasant realization in testing. Imagine having the best intentions regarding testing but still ending up with tests failing to deliver any value. Tests who are feeling like a pain to deal with?

When writing frontend tests, there are lots of pitfalls on the way. In sum, they can lead to lousy maintainability, slow execution time, and - in the worst-case - tests you cannot trust. But it doesn’t have to be that way. In this session, I will talk about developers’ common mistakes (including mine) in tests using Jest and Cypress, at least from my experience. And, of course, how to avoid them using best practices. Testing doesn’t need to be painful, after all.

Ramona Schwering

October 20, 2023
Tweet

More Decks by Ramona Schwering

Other Decks in Programming

Transcript

  1. .
    describe('do stuff in my Onlineshop', () => {
    beforeEach(() => {
    // Login user using their credentials
    cy.login('user', 'pass');
    });
    // … tests will start below
    })

    View full-size slide

  2. .
    describe('do stuff in my Onlineshop', () => {
    beforeEach(() => {
    cy.get('#sw-field--username').type('username');
    cy.get('#sw-field--password').type('pass');
    cy.get('.sw-login-login').submit();
    cy.contains('Dashboard');
    });
    // … tests will start below
    })

    View full-size slide

  3. Use shortcuts: Lösung mit Abkürzung
    .
    describe('do stuff in my Onlineshop', () => {
    beforeEach(() => {
    cy.request(
    'POST',
    '/api/oauth/token',
    {
    // payload: Send all data you need
    }
    ).then(() => {
    cy.contains('Dashboard');
    });
    }):
    // … tests will start below
    })

    View full-size slide

  4. describe('Context menu', () => {
    it('should open the context menu on click', async () => {
    const wrapper = createWrapper();
    expect(wrapper.vm).toBeTruthy();
    await wrapper.trigger('click');
    const selector = '.sw-context-menu';
    expect(wrapper.find(selector).isVisible()).toBeTruthy();
    });
    });

    View full-size slide

  5. describe('E2E with AAA pattern‘, () => {
    it('should open the context menu on click', () => {
    });
    });
    // Act
    // All the steps you need to come to the
    // scenario to test
    // Assert
    // Checks and assertions of your test
    beforeEach(() => {
    // Arrange
    // All the preparations you need
    });

    View full-size slide

  6. “…arrange my test == what I’m given.”
    “…act in my test == when something happens.”
    “…assert the results == something happens
    then this is what I expect as the outcome.”

    View full-size slide

  7. describe('E2E with Given When Then', () => {
    it('should use Given When Then', () => {
    });
    });
    // When
    // All the steps +assertions you need to come to the
    // scenario to test
    // Then
    // Scenario to test
    beforeEach(() => {
    // Given
    // All the preparations you need
    });

    View full-size slide

  8. Isolated test data
    .
    describe('Customer login', () => {
    let customer = {};
    beforeEach(() => {
    // Set application to clean state
    cy.setInitialState()
    .then(() => {
    // Create test data
    return cy.setFixture('customer');
    })
    }):
    // … tests will start below
    })

    View full-size slide

  9. it('should create and read product', () => {

    cy.get('.sw-field—product-name').type('T-Shirt Ackbar');
    cy.get('.sw-select-product__select_manufacturer')
    .type('Space Company’);

    });

    View full-size slide

  10. Cypress.Commands.add('typeSingleSelect', {
    prevSubject: 'element',
    },
    (subject, value, selector) => {

    cy.wait(500);
    cy.get(`${selector} input`)
    .type(value);
    });

    View full-size slide

  11. describe('Example test', () => {
    // Source Cypress docs
    it('Just doing things', () => {
    cy.visit('/my/resource/path');
    cy.get('.awesome- selector’).click();
    let el = Cypress.$('.new-el');
    if (el.length) {
    cy.get('.another-selector');
    } else {
    cy.get('.optional-selector');
    }
    });
    });

    View full-size slide

  12. describe(‚Example Test', () => {
    // Source: Cypress docs
    it('Doing things right'‚ () => {
    cy.visit('/my/resource/path')
    cy.get('.awesome-selector')
    .click()
    .then(() => {
    let el = Cypress.$('.new-el');
    if (el.length) {
    cy.get(‚.another-selector');
    } else {
    cy.get(‚.optional-selector');
    };
    });
    });
    });

    View full-size slide