DEV Community

ruthmoog
ruthmoog

Posted on

🩰 Schedule automated tests; become premier ballet artiste

I've been checking this page of the Royal Opera House website everyday lately:
Events page on the Royal Ballet's website

The website shows three sold-out workshops with The Royal Ballet.

There's three sold out events and I want to go to any one of them, so I am keeping an eye out for return tickets going on resale. But wait! Computers can help automate this...

1. Write a test to check the page automatically

I am not sure how the page will look when a ticket goes back on sale, but I am confident that the page will change so that the header with the words "Sold out" do not appear 3 times. (I expect this will also decrease by 1 after any of the dates have passed - but I haven't written this into my test yet).

I created an empty Vue.js project - I don't need a UI, I just want to use tests, so Vue will create a dummy project for me.

Playwright

I am going to use a browser based testing tool called Playwright (But you could use Capybara, or Selenium WebDriver etc.).

First I'm going to write a 'Hello World' style test to make sure I am on the correct page. When I navigate to the url, do I see the title I expect?

test('a hello world check that we have the right page', async ({ page }) => {
  await page.goto('https://www.roh.org.uk/tickets-and-events/dance-with-the-royal-ballet-dates');
  await expect(page).toHaveTitle(/Dance with The Royal Ballet/);
});
Enter fullscreen mode Exit fullscreen mode

Then, I'll write my useful test. I want the headless browser to go to the webpage at the given URL. I'm using JavaScript, so I am going to make my test method async and use await for actions that will create a Promise which needs to be fulfilled.

I used the Chrome DevTools to investigate what elements are used for the "Sold out" text. The Inspect tool tells me this is a h4 and therefore it has the heading Role.

Use the inspect tool to find out a page elements role

The element has a 'heading' Role.

I use Playwright's getByRole method with arguments describing that the role I want is a heading, with the exact text "Sold out".
Then I can add an assertion that I expect there to be three sold out items on the page - I made sure to break my assertion to check that the test can fail, before using the correct assertion.

test('check for sold out items', async ({ page }) => {
  await page.goto('https://www.roh.org.uk/tickets-and-events/dance-with-the-royal-ballet-dates');
  const soldOutItems = await page.getByRole('heading', { name: 'Sold out' });

  // Expects page to have three Sold out items.
  // If there are not 3 sold out items, there may be returns for sale!
  await expect(soldOutItems).toHaveCount(3);
});
Enter fullscreen mode Exit fullscreen mode

The test file on GitHub

2. Trigger the test workflows on automated schedule

I've pushed my changes to my GitHub repo, and use Actions to set up an automatic test run.

The playwright.yml file is automatically configured to run when code is pushed or a pull-request is merged, and it will run the browser tests:

name: Playwright Tests
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
    ...
    - name: Run Playwright tests
      run: npx playwright test
Enter fullscreen mode Exit fullscreen mode

To run these tests on a schedule, I need to add another item within the on section:

  schedule:
    - cron:  '1 1,10,15 * * *'
Enter fullscreen mode Exit fullscreen mode

This uses the POSIX cron syntax to add a schedule event. The example above will schedule the tests to run at 1 minute past 2am, 11am and 4pm local time (or, 01:01, 10:01, 15:01 UTC).

The GitHub Actions docs explain how to use schedule events to trigger workflows, including how the cron syntax works.

For the time being, I have guessed which intervals to use - but I have contacted the box office about when tickets are released on the website, so that I can run the tests as few times as possible.

Workflow configuration YAML on GitHub

And with that, my alerts (ballerts...) are done. GitHub will run my tests at the given times (deferring for heavy usage times) and their email notifications will let me know if there is a test failure and therefore that I should jump over to the website to try and buy a ticket (or update my test!).

*curtsy*

qο½₯:*:ο½₯οΎŸβ˜†Graceful curtsyβ˜†ο½₯゚:*:ο½₯q

Top comments (5)

Collapse
 
code42cate profile image
Jonas Scholz

Nice, I've done this a few times myself for different websites :D Have you tried to just use basic fetch + html scraping to reduce the execution time / resource needs? You could probably run it once per hour with the same total execution time :)

Collapse
 
ruthmoog profile image
ruthmoog

Ah cool, no I just figured, I have the tools, let's go! But would be good to do less πŸ‘

Collapse
 
shinyhappydan profile image
Daniel Bell

Doing this makes you a nerd-ball(et)er

Collapse
 
ruthmoog profile image
ruthmoog

Just got the alert and got myself a ticket, feeling pretty pleased with myself πŸ˜‚

Collapse
 
balagmadhu profile image
Bala Madhusoodhanan

hope you managed to get the tickets πŸ‘