Skip to content
Clara Youdale edited this page Jun 24, 2024 · 7 revisions

Tips

  • use gatsby serve instead of gatsby develop to avoid building functions and pages before a test is run
  • set the number of workers to 1 if using gatsby develop in playwright.config.ts and SKIP_PAGE_CREATOR variable to limit what's built
  • use the vscode official Playwright extension to debug and run tests
  • start the test browser window with devtools open: use: { ...devices['Desktop Chrome'], launchOptions: {args: ['--auto-open-devtools-for-tabs']} },

Migration from Cypress prompt

I will ask you to convert the cypress tests to playwright.

Please take into account this:

  • Use typescript.

  • Be concise and only answer with the updated code.

  • Do not use jest.

  • test must be imported from '../utils'

  • Ignore cy.waitForStableDOM calls.

  • Ignore custom timeouts.

  • Ignore cy.wait(@somealias) that don't have expectations

  • Use page.locator('some selector').click() instead of page.click('some selector')

  • Use page.locator('some selector').fill('some value') instead of page.type('some selector', 'some value')

  • Favor page.getByText("some test") when matching objects by text

  • Use test instead of it, and don't forget to destructure from the first parameter the page property

  • cy.query now is just query

  • The conditionalIntercept function has been updated and looks like this:

const waitForRequestMap = new Map<string, Promise<Request>>();

export async function conditionalIntercept(
    page: Page,
    url: string,
    condition: (request: Request) => boolean,
    response,
    alias: string = null
) {
    await page.route(url, async (route: Route) => {

        const req = route.request();

        if (condition(req)) {
            await route.fulfill({
                contentType: 'application/json',
                body: JSON.stringify(response),
            });
        }
        else {
            await route.fallback();
        }
    });

    if (alias) {

        waitForRequestMap.set(alias, page.waitForRequest((req) => minimatch(req.url(), url) && condition(req)));
    }
}

It has a complementary function that should be used instead of cy.wait(@somealias):

export async function waitForRequest(alias: string) {

    const promise = waitForRequestMap.get(alias);

    waitForRequestMap.delete(alias);

    return promise;
}

For example:

cy.conditionalIntercept(
    '**/graphql',
    (req) => req.body.operationName == 'UpdateReport',
    'updateReport',
    flaggedReport
);

gets converted to:

await conditionalIntercept(
    '**/graphql',
    (req) => req.body.operationName == 'UpdateReport',
    flaggedReport,
    'updateReport',
);

And:

cy.wait('@updateReport')
    .its('request.body.variables')
    .then((variables) => {
        expect(variables.query.report_number).to.equal(23);
        expect(variables.set).deep.eq({
            flag: true,
            date_modified: now.toISOString(),
            epoch_date_modified: getUnixTime(now),
        });
});

gets converted to:

const updateReportRequest = (await waitForRequest('updateReport'))
const variables = updateReportRequest.postDataJSON().variables;
expect(variables.query.report_number).toBe(23);
expect(variables.set).toEqual({
    flag: true,
    date_modified: now.toISOString(),
    epoch_date_modified: getUnixTime(now),
});

The conditionalIt and maybeIt functions will not be used anymore

For tests that require login:

cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword'));

gets converted to

test('test name', async ({ page, login }) => {
  await login(config.E2E_ADMIN_USERNAME, config.E2E_ADMIN_PASSWORD);
  // test code
});

The setEditorText function has been updated and looks like this:

   export async function setEditorText(page: Page, value: string, selector: string = '.CodeMirror') {
    await page.locator(selector).first().click();
    await page.evaluate(
      ({ selector, value }) => {
        const editor = document.querySelector(selector) as HTMLElement & { CodeMirror?: any };
        if (editor?.CodeMirror) {
          editor.CodeMirror.setValue(value);
        }
      },
      { selector, value }
    );
  }

The getEditorText function has been updated and looks like this:

  export async function getEditorText(page: Page, selector: string = '.CodeMirror'): Promise<string> {
    return await page.evaluate(
      (selector) => {
        const editor = document.querySelector(selector) as HTMLElement & { CodeMirror?: any };
        return editor?.CodeMirror ? editor.CodeMirror.getValue() : '';
      },
      selector
    );
  }

If you encounter

conditionalIt(
  !Cypress.env('isEmptyEnvironment') && Cypress.env('e2eUsername') && Cypress.env('e2ePassword'),
  'test name',
  () => {
    // test code
  }
);

It should get converted to:

test('test name', async ({ page, skipOnEmptyEnvironment }) => {
  // test code
}

Now I'm going to give you cypress tests to convert: