Rayrun
← Back to Discord Forum

How to set hooks before/after each spec?

I want to do some kind of "reset" in a specific table after every spec. I could simply achieve it by setting up an afterAll in each spec but this is equal repeating the same line of code a lot (imagine 100 spec files).

So what my team did a while ago was adding hooks in our test.ts file. We really thought it was working like we imagined. "Oh, since we defined these hooks in the test file, it will act like a global hook". Little did we know that this is not true.

See this example: 3 specs, each of them have their own hooks and imagine also you set hooks inside your test file. Running these tests would result in this (see image).

The hooks declared inside test.ts were only executed in the context of the first spec ran. After the first spec, these hooks were completely ignored. I don't know who thought this would work, but I know we have this for a while now and this is probably one of the problems that is causing some retries in our pipeline.

I know pw has global setup and teardown, but AFAIK it will only run once, before everything and after everything. We really need a setup that runs after every spec file instead. Could be something after every describe too but I don't think we can override it.

Is this already being discussed / a requested feature ? If not, should I do it or is there a way / hack I can achieve the desired behaviour?

Thanks in advance! Really keen to read some suggestions.

image.png

This thread is trying to answer question "How can I set hooks to run after each spec in a test suite?"

3 replies

spec file

import { test, expect } from "../../lib/fixtures/hook";

test.describe("Highest Level", () => {
  let x: number;
  x = 1;

  test.beforeAll(() => {
    console.log("--Hello before all tests--");
  });

  test.afterAll(() => {
    console.log("--Hello after all tests--");
  });

  test.afterEach(() => {
    console.log("<<Hello after each test");
  });

  test.beforeEach(() => {
    console.log(">>Hello before each test");
  });

  test.afterAll(() => {
    console.log("Hello after all tests");
  });

  test("One", async ({ page }) => {
    await page.waitForTimeout(500);
    expect(x).toBe(1);
  });

  test("One v2", async ({ page }) => {
    expect(x).toBe(1);
  });

  test("Two", async ({ page }) => {
    expect(x).toBe(1);
  });

  test("Two v2", async ({ page }) => {
    expect(x).toBe(1);
  });
});

Fixture file

import { test as base } from "@playwright/test";

export const test = base.extend<{ testHook: void }>({
  testHook: [
    async ({}, use) => {
      await use();

      console.log("AFTER EACH HOOK FROM FIXTURE");
      // Put any code you want run automatically after each test here
    },
    { auto: true },
  ],
});

export { expect } from "@playwright/test"; //Exporting 'expect' from the base test so you have access in your spec.ts file.

The console output is attached as well.

image.png

Thanks for the suggestion. I guess automatic fixtures is not exactly the solution for this problem as it runs after every test. What I want to achieve is a hook that will only run after the entire spec (once per file/ or once per describe)

Answer

Using afterAll Hook in Playwright Test

When you need to perform cleanup tasks after all tests in a spec file have run, Playwright Test provides the afterAll hook. This hook is executed once per worker process after all tests in a spec file have finished running.

Here's how you can set it up:

import { test } from '@playwright/test';

test.afterAll(async () => {
  // Your cleanup tasks go here
});

Place this code at the end of your spec file. It ensures that the specified callback function is executed after all tests in that spec file have finished running.

Remember, if you have multiple spec files, each with their own set of tests, the afterAll hook defined in each spec file will run independently after their respective tests. This allows you to perform specific teardown actions for each individual spec file.

Also, Playwright Test uses worker processes for running tests. If a test fails and triggers a restart of the worker process, the afterAll hook will run again in the new worker process. This ensures that any necessary cleanup actions are performed consistently even in case of failures.

For more insights on handling flaky tests and maximizing test efficiency, check out these blog posts on Detecting and Handling Flaky Tests in Playwright and Maximizing Test Efficiency with Parallelism in Playwright.

Related Discord Threads

TwitterGitHubLinkedIn
AboutQuestionsDiscord ForumBrowser ExtensionTagsQA Jobs

Rayrun is a community for QA engineers. I am constantly looking for new ways to add value to people learning Playwright and other browser automation frameworks. If you have feedback, email luc@ray.run.