vitalets / playwright-bdd

BDD testing with Playwright runner
https://vitalets.github.io/playwright-bdd/
MIT License
302 stars 35 forks source link

Question: trying to figure out how I use beforeAll & afterAll following the examples provided #117

Closed odeatomas closed 6 months ago

odeatomas commented 7 months ago

Hi I'm having issues running custom fixtures in berforeAll / afterAll i'll use the example of berforeAll which collects some data to be used in cucumber multi reporter

I have created a custom fixture

`import { Page } from '@playwright/test';
import { Fixture} from 'playwright-bdd/decorators'

export
@Fixture("reportBeforeDataHook")
class ReportBeforeDataHook {
    private page: Page;

    constructor(page: Page) {
        this.page = page;
    }

async getReportDataBeforeAll() {
    console.log(`BEFORE HOOK RUNNING`);
    startTimeDate = new Date();
    startTime = performance.now();
    await this.page.goto(``);
    const buildNumberElement = await this.page.locator(`//span[@class='ms-2']`).first();
    buildNumber = await buildNumberElement.textContent() ?? '';
    const getUA = await this.page.evaluate(() => navigator.userAgent);
    userAgentInfo = uaParser(getUA);
    browserName = userAgentInfo.browser.name;
    browserVersion = userAgentInfo.browser.version;
    console.log('browser name:', browserName, 'browser version:', browserVersion);
    osName = userAgentInfo.os.name;
    osVersion = userAgentInfo.os.version;
    console.log('os name:', osName, 'os version:', osVersion);
    await this.page.close();
}`

Then in fixtures.ts

`import fs from 'fs';
import path from 'path';

import { test as base } from 'playwright-bdd';
import {ReportBeforeDataHook } from './Hooks/reportBeforeDataHook';
import {ReportAfterDataHook} from "./Hooks/reportAfterDataHook";

export const test = base.extend<{
  reportBeforeDataHook: ReportBeforeDataHook
  reportAfterDataHook: ReportAfterDataHook
  slowTest: void

}>( {

  reportAfterDataHook: async ( { page }, use ) => use( new ReportAfterDataHook( page)  ),
  reportBeforeDataHook:async ( { page }, use ) =>  use( new ReportBeforeDataHook( page ) ),
),

  //checks all features and  updates time out 
  slowTest: [ async ( { $tags }, use, test ) => {
    if ( $tags.includes( '@slow' ) ) {
      const slowms = 300000;
      const slowtimeout = test.setTimeout( slowms );

      // test.slow()
      console.log( `slow test found extending time out to ${ slowms }  ` )
      await use( slowtimeout );

    }
    else {
      const fastms = 180000;
      const fasttimeout = test.setTimeout( fastms );
      console.log( `slow test not found using time out ${ fastms }  ` )
      await use( fasttimeout );

    }
  }, { auto: true } ],

  });

` then when I try to use the fixture in beforeAll

`import { createBdd } from 'playwright-bdd';
import { test } from '../../steps/fixtures';

const { BeforeAll, AfterAll } = createBdd(test);

BeforeAll(async function ({ reportBeforeDataHook }) {

});`

I get error

Property 'reportBeforeDataHook' does not exist on type 'PlaywrightWorkerArgs & PlaywrightWorkerOptions & BddFixturesWorker & { $workerInfo: WorkerInfo; }'.ts(2339)

when i try to add the worker scope matching the syntax in the example reportBeforeDataHook:[async ( { page }, use ) => use( new ReportBeforeDataHook( page ) ),{scope: 'worker'}]}),

I get error

Type at position 1 in source is not compatible with type at position 1 in target. The types of 'scope' are incompatible between these types. Type '"worker"' is not assignable to type '"test"'.ts(2322)

I am bit confused on what I need to to do to get my custom fixtures working in the hooks

vitalets commented 7 months ago

Hi @odeatomas Worker scoped fixtures should be defined as a second generic argument in test.extend. E.g.:

export const test = base.extend<{ /* test-scoped fixtures */ }, {
  reportBeforeDataHook: ReportBeforeDataHook
  reportAfterDataHook: ReportAfterDataHook
}>( ... )

Feel free to reopen in case of any issues on that.

odeatomas commented 7 months ago

thanks for the quick response @vitalets updated the worker scoped fixtures as a second generic argument in test.extend

reportBeforeDataHook: [async ({ }, use) => { await use( new ReportBeforeDataHook() ); }, { scope: 'worker' }],

but get error Property 'page' does not exist on type '{ reportBeforeDataHook: ReportBeforeDataHook; reportAfterDataHook: ReportAfterDataHook; } & PlaywrightWorkerArgs & PlaywrightWorkerOptions & BddFixturesWorker'.

vitalets commented 7 months ago

but get error Property 'page' does not exist on type '{ reportBeforeDataHook: ReportBeforeDataHook; reportAfterDataHook: ReportAfterDataHook; } & PlaywrightWorkerArgs & PlaywrightWorkerOptions & BddFixturesWorker'.

That is expected. As worker fixtures run once before all tests, they can't have access to some particular page (b/c each test has own instance of page). What is shared between all tests is browser fixture. You can extract some values from it (e.g. version), but not many as from userAgent.

Another idea is to instantiate new Page manually in beforeAll fixture and grab userAgent from it:

reportBeforeDataHook: [async ({ browser }, use) => {
  // Create a new incognito browser context.
  const context = await browser.newContext();
  // Create a new page in a pristine context.
  const page = await context.newPage();
  const getUA = await this.page.evaluate(() => navigator.userAgent);
  // ...
}, { scope: 'worker' }],
odeatomas commented 6 months ago

thanks for the quick reply. sorted now