Jordan Does Integration Tests On AD2L

Demo Code Here

As I’ve talked about in other posts, automated tests are important. They give you the confidence to make quick changes and confirm that those changes aren’t breaking your existing functionality. I’ve discussed unit tests in other posts and this time I want to discuss integration tests.

Puppeteer (which is awesome) can be used for things like integration tests. While it’s not strictly web scraping for data, it is automating tasks and doing the same kind of thing that web scraping does. In this example, I simply combine testing frameworks like mocha and chai to easily display passes and failures and then use Puppeteer to get the data I want to test.

In this case, I am testing Amateur Dota 2 League. This is a site that runs Dota 2 leagues that I’ve had for about 5 years. The idea is that this is a test that can run on a schedule weekly or daily and will just confirm that the site is working as expected. While I’m not implementing it here, if I had it running automatically I’d put in some kind of notification when something was not as expected, like email or a discord/slack notification.

I use Mocha and Chai for my testing frameworks. Because I’m not spying on any functions at all, I don’t need anything for spies. The cool part about this kind of integration testing is that I don’t need to know anything about the code behind the site under test. I just want the functionality to happen as I expect it to happen.

I run four tests here. The first is one that just tests that the nav has the amount of tabs that I expect it to have if I’m not signed in. With my tests I try to be verbose with the test name and just have one expectation per test so that it’s easy to find any problems that happen. If I was automating this, I’d probably put try / catch blocks around all of my promise functions (the ones with await) so that I could handle any exceptions that happen and send a notification of what failed.

    it('should have 7 tabs if not signed in', async () => {
        const url = 'https://dota.playon.gg/seasons';
        await page.goto(url);

        await page.waitForSelector('ul.nav > li');
        const tabs = await page.$$('ul.nav > li');

        expect(tabs.length).to.equal(7);
    });

For example, in the test above, I navigate to the home page and before I go to check the tabs, I wait for that selector (ul.nav > li in this case) and then get all the elements (using the puppeteer page function of $$) with that selector.

HTML structure for tabs

My next test compares the open tournaments/seasons in the “TOURNAMENTS” dropdown with the amount of seasons on the actual home page. I do the same kind of thing as with the other test, wait for the selector to load in and then get the seasons in the dropdown in dropDownSeasons and the seasons on the page in seasonsOnPage and then just compare the length.

    it('should have the same amount of seasons in the dropdown and on the page', async () => {
        const url = 'https://dota.playon.gg/seasons';
        await page.goto(url);

        await page.waitForSelector('li.dropdown > ul li');
        const dropDownSeasons = await page.$$('li.dropdown > ul li');

        const seasonsOnPage = await page.$$('.row .col-md-4');

        expect(dropDownSeasons.length).to.equal(seasonsOnPage.length);

    });

AD2L shows all of their seasons on this page and in their dropdown, both ones in progress and ones that are still up for registration. The third test I do compares that the number of open seasons in the dropdown matches the number of open seasons on the page. Open seasons are slightly different in the dropdown because they have a start date, which is held in a <small> html element. I grab all of the seasons in the dropdown and then increment my openSeasonCountOnDropdown if it has that element.

    it('it should have the same amount of open seasons in the dropdown and on the page', async () => {
        const url = 'https://dota.playon.gg/seasons';
        await page.goto(url);

        await page.waitForSelector('li.dropdown > ul li');
        const seasons = await page.$$('li.dropdown > ul li');
        let openSeasonCountOnDropdown = 0;
        let openSeasonCountOnPage = 0;

        for (let season of seasons) {
            const seasonTitle = await getPropertyBySelector(season, 'a', 'innerHTML');

            // If we have the small element, that means that it's a season open for registration
            if (seasonTitle.includes('<small>')) {
                openSeasonCountOnDropdown++;
            }
        }

        const seasonsOnPage = await page.$$('.row .col-md-4');
        for (let season of seasonsOnPage) {
            const seasonInformation = await getPropertyByHandle(season, 'innerHTML');

            // If we have an 'i', that means that it's a season open for registration
            if (seasonInformation.includes('<i>')) {
                openSeasonCountOnPage++;
            }
        }

        expect(openSeasonCountOnDropdown).to.equal(openSeasonCountOnPage);

    });

For the seasons on page, I can tell if it’s open if there is a price on it, held in an <i> element. I do the same thing as above, looping through the seasons and if it has that element, I increment openSeasonCountOnPage.

For the final test, I confirm that clicking the “Sign in through STEAM” button takes us to the right place.

Sign in through STEAM button
    it('should redirect to steam login when you click "Sign in through STEAM"', async () => {
        const url = 'https://dota.playon.gg/seasons';
        await page.goto(url);

        await page.waitForSelector('.loginBlock img');
        const loginButton = await page.$('.loginBlock a');

        if (loginButton) {
            console.log('found a login button?');
            await loginButton.click();
        }

        await page.waitForSelector('#logo_holder');

        const currentUrl = await page.url();

        expect(currentUrl.split('/openid')[0]).to.equal('https://steamcommunity.com');

    });

I just wait for that selector to be on on the page, then click it and check my current url with page.url(). I get just the domain by splitting on “/openid” and then taking the first part. Then I just compare with my expected domain and I’m done!

Demo Code Here

Leave a Reply

Your email address will not be published. Required fields are marked *