Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't run audit on authenticated pages #109

Open
alionatudan opened this issue Sep 3, 2024 · 4 comments
Open

Can't run audit on authenticated pages #109

alionatudan opened this issue Sep 3, 2024 · 4 comments

Comments

@alionatudan
Copy link

alionatudan commented Sep 3, 2024

Maybe I am missing something, but I tried two approaches and none works: audit opens the session which is not authenticated even when logs show cookies passed into the page object passed into audit.
So, approach 1:
Logging in the test

import { test, expect } from "@playwright/test";
import { playAudit } from "playwright-lighthouse";

test("Run lighthouse audit", async () => {
  const url = process.env.STAGING_URL ?? "";
  const user = process.env.USER_NAME ?? "";
  const password = process.env.PASSWORD ?? "";
  const playwright = await import("playwright");
  const browser = await playwright["chromium"].launch({
    args: ["--remote-debugging-port=9222"],
  });
  // const context = await browser.newContext();
  const page = await browser.newPage();

  await test.step("Log in ", async () => {
    console.log(`Authenticating ON STAGING ${url} with user: ${user}`);
    await page.goto(url);
    await page.getByPlaceholder("Username").fill(user);
    await page.getByPlaceholder("Password").fill(password);
    await page.getByRole("button", { name: "Log In" }).click();
    await page.waitForLoadState("load");
    await expect(
      page.getByRole("heading", { name: "Welcome" }).isVisible()
    ).toBeTruthy();
    const cookies = await page.context().cookies();
    console.log("Cookies when logged : ", cookies);
  });

  await test.step("Run lighthouse audit", async () => {
    const cookies = await page.context().cookies();
    console.log("Cookies before audit : ", cookies);
    await playAudit({
      page: page,
      port: 9222,
      thresholds: {
        performance: 0,
        accessibility: 0,
        "best-practices": 0,
        seo: 0,
        pwa: 0,
      },
      reports: {
        formats: {
          html: true,
          json: false,
          csv: false,
        },
        directory: "litghthouse-reports-" + Date(),
      },
    });
  });

  await browser.close();
});

Cookies are logged in both steps, but audit is ran on the non-authorized page.

Approach 2:
setting up configurations to auth before running test

Config:

mport { chromium, test as base } from "@playwright/test";
import type { BrowserContext, Page } from "@playwright/test";
import getPort from "get-port";
import os from "os";
import path from "path";
import authState from "./.auth/user.json";
import fs from "fs";

type LocalStorage = Array<{ name: string; value: string }>;

type AuthState = {
  origins: Array<{
    origin: string;
    localStorage: Array<{
      name: string;
      value: string;
    }>;
  }>;
};
export const lighthouseTest = test.extend<
  {
    lighthouseAuthenticatedPage: Page;
    lighthousePage: Page;
    context: BrowserContext;
  },
  {
    port: number;
    storage: LocalStorage;
  }
>({
  port: [
    async ({}, use) => {
      // Assign a unique port for each playwright worker to support parallel tests
      const port = await getPort();
      await use(port);
    },
    { scope: "worker" },
  ],

// As there's currently no way to insert auth-state into a PersistentContext we
 // need to explicity load and insert the auth storage. In our case we only care
 // about localStorage for auth.
 storage: [
   async ({}, use) => {
     const rootUrl = process.env.STAGING_URL || "";
     const localhostStorage = (authState as AuthState).origins.find(
       ({ origin }) => {
         return origin === new URL(rootUrl).origin;
       }
     );
     if (!localhostStorage) {
       throw new Error(`No storage state found in ${authState}`);
     }
     if (!localhostStorage.localStorage.length) {
       throw new Error(`No localStorage state found in ${authState}`);
     }
     await use(localhostStorage.localStorage);
   },
   { scope: "worker" },
 ],

 context: [
   async ({ port, launchOptions }, use) => {
     const userDataDir = path.join(os.tmpdir(), "pw", String(Math.random()));
     const cookies = require(path.resolve(
       __dirname,
       "./.auth/user.json"
     )).cookies;

     // Convert cookies to the correct format for the header
     const cookieHeader = cookies
       .map((cookie) => `${cookie.name}=${cookie.value}`)
       .join("; ");

     const context = await chromium.launchPersistentContext(userDataDir, {
       args: [
         ...(launchOptions.args || []),
         `--remote-debugging-port=${port}`,
       ],
       extraHTTPHeaders: {
         cookie: cookieHeader,
       },
     });
    // apply state previously saved in the the `globalSetup`
     await context.addCookies(require("./.auth/user.json").cookies);
     await context.storageState({ path: "./.auth/user.json" });
     await use(context);
     await context.close();
   },
   { scope: "test" },
 ],

   lighthousePage: [
     async ({ context: context }, use) => {
        const page = await context.newPage();
        await use(page);
      },
      { scope: "test" },
    ],

    lighthouseAuthenticatedPage: [
      async ({ context: context, lighthousePage: page, storage }, use) => {
        const hostname = new URL(process.env.STAGING_URL || "").hostname;
        await page.goto("dashboard");
        await insertAuthStorage(page);
        type AuthState = {
        cookies: Array<{
            name: string;
            value: string;
            domain: string;
            path: string;
           expires: number;
            httpOnly: boolean;
           secure: boolean;
          sameSite: "Strict" | "Lax" | "None";
          }>;
          origins: Array<{
            origin: string;
           localStorage: Array<{
              name: string;
             value: string;
            }>;
          }>;
       };

//       async function insertAuthStorage(page: Page): Promise<void> {
 //         const authState: AuthState = JSON.parse(
 //           fs.readFileSync(
 //             // getAuthArtifactFilePath("state", "storageState.json"),
 //             path.resolve(__dirname, "./.auth/user.json"),
 //             "utf8"
 //           )
 //         );
 //         // Set cookies
 //         for (let cookie of authState.cookies) {
 //           if (cookie.domain === hostname) {
 //             const cookieValue = `${cookie.name}=${
 //               cookie.value
 //             };expires=${new Date(cookie.expires * 1000).toUTCString()};path=${
 //               cookie.path
 //             };domain=${cookie.domain};secure=${cookie.secure};httponly=${
 //               cookie.httpOnly
 //             };samesite=${cookie.sameSite}`;

 //             await page.evaluate(
 //               (cookieValue) => (document.cookie = cookieValue),
 //               cookieValue
 //             );
 //           }
 //         }

 //         // Set local storage
 //         const origin = "https://" + hostname;
 //         console.log("ORIGIN: ", origin);
 //         const localStorageKVPs = authState.origins.find((o) => {
 //           return o.origin === origin;
 //         });
 //         if (localStorageKVPs) {
 //           for (let kvp of localStorageKVPs.localStorage) {
 //             await page.evaluate(
 //               (kvp) => localStorage.setItem(kvp[0], kvp[1]),
 //               [kvp.name, kvp.value]
 //             );
 //           }
 //         }
 //       }
 //       await use(page);
 //     },
 //     { scope: "test" },
 //   ],
});
export async function lighthouseAudit(
  page: Page,
  port: number,
  pageName: string
  // thresholds?: LighthouseThresholds,
  // config = lighthouseMobileConfig
): Promise<void> {
  const { playAudit } = await import("playwright-lighthouse");
  const fileName = `performance-scan-results-${pageName}-${new Date().getDate()}`;
  await playAudit({
    page,
    // config,
    port,
    reports: {
      formats: {
        html: true,
        json: true,
        csv: false,
      },
      name: fileName,
      directory: "./lighthouse",
    },
    thresholds: {
      performance: 0, //70,
      accessibility: 0, // 95,
      pwa: 0, // 50,
      "best-practices": 0, // 95,
      // ...thresholds,
    },
    opts: {
      logLevel: "error",
    },
  });
}

Commented code was also tested and did not influence anything.
Test:

import { lighthouseTest, lighthouseAudit, expect } from "../../../my-test";

lighthouseTest.describe("Authenticated route after globalSetup", () => {
  lighthouseTest.use({
    storageState: ".auth/user.json", // Load the authenticated state
  });
  lighthouseTest(
    "should pass lighthouse tests",
    async ({ port, dashboardPage, page }, testInfo) => {
      const pageName = "dashboard";
      const fileName = `performance-scan-results-${pageName}-${new Date().getDate()}`;
      await dashboardPage.goto();
      expect(await dashboardPage.header.isVisible()).toBeTruthy();
      await lighthouseAudit(dashboardPage.page, port, pageName);
      await testInfo.attach(`performance-scan-results-${pageName}`, {
        body: fileName,
        contentType: "csv",
      });
    }
  );
});


@alionatudan
Copy link
Author

Used info from here:
#14
And here:
microsoft/playwright#7447 (comment)

@ritesh-csg
Copy link

Hi @alionatudan

Did you found a way to solve the above issue? Even i have the same issue, for me when i'm passing the page object to playaudit, it is opening a new window which doesn't have auth info so while accessing the it is again redirected to auth service which shouldn't be the case as testcases are working fine.

@alionatudan
Copy link
Author

Hi @alionatudan

Did you found a way to solve the above issue? Even i have the same issue, for me when i'm passing the page object to playaudit, it is opening a new window which doesn't have auth info so while accessing the it is again redirected to auth service which shouldn't be the case as testcases are working fine.

No, I could not resolve this.
Switched to Artillery.

@Arghajit47
Copy link

Even I have found the same issue when tried to login via cookies. Kindly mention if any solution comes up

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants