Is there a way to not close pages for specific tagged scenarios in Cucumber-Playwright?

13 views Asked by At

I'm currently using the Cucumber-Playwright framework starter code by tallyb to write UI tests as ADO pipelines for my company. However, I thing I don't like is how after every scenario the page fixture is teared down and then set up again. This wastes alot of time when I need to log in which takes around a minute for every single scenario.

Especially for Scenario Outline's where I have a scenario that loops through Examples like this

Scenario Outline: all portlets collapse and expand
    When I collapse portlet "<PORTLET>"
    Then I cannot see portlet body "<PORTLET>"
    When I expand portlet "<PORTLET>"
    Then I can see portlet body "<PORTLET>"

    Examples:
      | PORTLET                                 |
      | fum_portlet                             |
      | inflow_chart_portlet                    |
      | fees_chart_portlet                      |
      | pending_investment_instructions_portlet |
      | cash_portlet                            |
      | task_portlet                            |

it wastes alot of time when ran in the pipeline. So what I want is a solution where I tag these Scenario Outlines with something like @preserve so that the page fixture is preserved throughout the examples instead of being torn down and set-up.

I have somewhat of an idea that I need to change up the Before/After hooks however I don't really know how to implement that. This is what my Before/After hooks look right right now:

Before(async function (this: ICustomWorld, { pickle }: ITestCaseHookParameter) {
  this.startTime = new Date();
  this.testName = pickle.name.replace(/\W/g, '-');
  // customize the [browser context](https://playwright.dev/docs/next/api/class-browser#browsernewcontextoptions)
  this.context = await browser.newContext({
    acceptDownloads: true,
    recordVideo: process.env.PWVIDEO ? { dir: 'screenshots' } : undefined,
    viewport: { width: 1200, height: 800 },
  });
  this.server = await request.newContext({
    // All requests we send go to this API endpoint.
    baseURL: config.BASE_API_URL,
  });

  await this.context.tracing.start({ screenshots: true, snapshots: true });
  this.page = await this.context.newPage();
  this.page.on('console', async (msg: ConsoleMessage) => {
    if (msg.type() === 'log') {
      await this.attach(msg.text());
    }
  });
  this.feature = pickle;
});

After(async function (this: ICustomWorld, { result }: ITestCaseHookParameter) {
  if (result) {
    await this.attach(`Status: ${result?.status}. Duration:${result.duration?.seconds}s`);

    if (result.status !== Status.PASSED) {
      const image = await this.page?.screenshot();

      // Replace : with _ because colons aren't allowed in Windows paths
      const timePart = this.startTime?.toISOString().split('.')[0].replaceAll(':', '_');

      image && (await this.attach(image, 'image/png'));
      await this.context?.tracing.stop({
        path: `${tracesDir}/${this.testName}-${timePart}trace.zip`,
      });
    }
  }
  await this.page?.close();
  await this.context?.close();
});

Perhaps I could do something like

Before({tag: '@preserve'}, async function (this: ICustomWorld) {
    // don't set up new context/page
});

After({tag: '@preserve'}, async function (this: ICustomWorld) {
    // don't close page/context
});

but I'm not sure to go about it.

0

There are 0 answers