Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest + puppeteer best architecture practices

I just entered the world of testing with puppeteer and jest, and I was wondering what the best practice was in terms of folder architecture and logic.

I've never done testing before and I think I'm getting a little lost in the different principles and concepts and how it all fits together.

I learned to do my tests based on the page-object model, so I have classes for each of my pages, but also for each of my modules ( or components ). For example, in my application, the header or the login modal are components.

Then I have a test file per page or per component. (for example the landingPage.tests.js file, which uses the model of the LandingPage class in the LandingPage.js file)

Here is a concrete example: I have different login cases and I'd like to test them all. For example I want to test to connect with a "normal" user, for which the process is simply login then password. Then I need to test with a user who has activated 2FA, or with a user from a company that uses SSO.

I first thought about putting my different tests in authentication.tests.js, in different describe blocks, thinking it would open a new tab each time, but it doesn't... I use puppeteer in incognito mode to make sure each tab is an isolated session.


So my questions are:

  • Where is the best place to do these test suites?

  • Am I supposed to have test files that "describe" the pages ( for example, the button must be present, such text must be here etc) and also have "scenario type" test file ( a set of contextual actions to a user, like for my different login cases) ?

Here is authentication.tests.js, in which I would like to tests all my different ways of logging in :

import HeaderComponent from "../../../pages/components/HeaderComponent";
import AuthenticationComponent from "../../../pages/components/AuthenticationComponent";
import LandingPage from "../../../pages/landing/LandingPage";

import {
    JEST_TIMEOUT,
    CREDENTIALS
} from "../../../config";


describe('Component:Authentication', () => {
    let headerComponent;
    let authenticationComponent;
    let landingPage;

    beforeAll(async () => {
        jest.setTimeout(JEST_TIMEOUT);
        headerComponent = new HeaderComponent;
        authenticationComponent = new AuthenticationComponent;
        landingPage = new LandingPage;
    });


    describe('Normal login ', () => {

        it('should click on login and open modal', async () => {
            await landingPage.visit();
            await headerComponent.isVisible();
            await headerComponent.clickOnLogin();
            await authenticationComponent.isVisible();
        });

        it('should type a normal user email adress and validate', async () => {
            await authenticationComponent.typeUsername(CREDENTIALS.normal.username);
            await authenticationComponent.clickNext();
        });

        it('should type the correct password and validate', async () => {
            await authenticationComponent.typePassword(CREDENTIALS.normal.password);
            await authenticationComponent.clickNext();
        });

        it('should be logged in', async () => {
            await waitForText(page, 'body', 'Success !');
        });

    });

    describe('SSO login ', () => {
        // todo ...
    });


});

Thank you and sorry if it sounds confusing, like I said I'm trying to figure out how it all fits together.

like image 309
Nuzzob Avatar asked Feb 27 '20 22:02

Nuzzob


1 Answers

Regarding the folder structure, Jest will find any files according to the match config, basically anything called *.spec.js or *.test.js. Looks like you know that already.

What that means is the folder structure is completely up to you. Some people like to have the tests for components in the same folders as the components themselves. Personally I prefer to have all the tests in one folder as it makes the project look cleaner.

The other benefit of having all the tests in one folder is that you can then start to distinguish between the types of tests. Component tests check that pure components render and operate as expected. You don't need Puppeteer for this, use snapshots if you're in a React app. Puppeteer is good for integration tests that navigate through so-called 'happy paths', login, signup, add to cart etc., using a headless Chromium browser.

To answer the specific problem you have been having with Jest / Puppeteer on a new page for each test:

//keep a reference to the browser 
let browser
//keep a reference to the page
let page

// open puppeteer before all tests
beforeAll(async () => {
  browser = await puppeteer.launch()
})

// close puppeteer after all tests
afterAll(async () => {
  await browser.close()
})

// Get a new page for each test so that we start fresh.
beforeEach(async () => {
  page = await browser.newPage()
})

// Remember to close pages after each test.
afterEach(async () => {
  await page.close()
})

describe('Counter', () => {
  // "it" blocks go here.
})

Hope that helps a bit.

like image 86
Tom Avatar answered Nov 08 '22 20:11

Tom