ReferenceError: document אינו מוגדר שגיאה ב-Typescript ב-Playwright


הרעיון הוא שאני מנסה לקבל את כל הכותרות ב-HTML (h1 h2 h3 h4 h5 h6) ולבדוק אם הן בסדר ידידותי ל-SEO. אם אני מנסה להריץ את זה אני מקבל את השגיאה ReferenceError: document is not defined שגיאת Typescript ב-Playwright

async assertHeadingsOrder2() {
  // eslint-disable-next-line @typescript-eslint/require-await
  await test.step('Test html header structure for catalog page', async () => {
    // Get all the heading tags (h1, h2, h3, h4, h5, h6) in the document
    const headingTags = document.querySelectorAll('h1, h2, h3, h4, h5, h6');

    // Define a function to test the hierarchy
    function testHeadingHierarchy() {
      const hierarchy = [];

      headingTags.forEach(heading => {
        const tagName = heading.tagName.toLowerCase(); // Get the tag name (e.g., "h1", "h2")
        const level = parseInt(tagName.charAt(1), 10); // Extract the numeric level from the tag name

        // Check if the hierarchy is valid
        if (level > hierarchy.length + 1) {
          console.error(`Invalid hierarchy: ${tagName} is not in the correct order.`);
        }

        // Update the hierarchy array with the current level
        hierarchy[level - 1] = tagName;
      });

      console.log('Heading hierarchy is valid:', hierarchy.join(' > '));
    }

    // Call the function to test the hierarchy
    testHeadingHierarchy();
  });
}

תשובה #1

Playwright לא מספק אוטומטית את document לשימושך ב-Node. במקום זאת, הוא נותן לך את האובייקטים browser ו-page עם API נרחב כדי לתפעל את האתר דרכם.

אתה יכול להשתמש ב-page.evaluate() כדי להריץ קוד בדפדפן ולהיכנס ל-document, אבל בדרך כלל, תבחר אלמנטים עם ה-API של המקומות (locators) על האובייקט page.

הסלקטור CSS שלך צריך להיות "h1, h2, h3, h4, h5, h6" במקום "h1 h2 h3 h4 h5 h6". הראשון משתמש בפסיקים עבור לוגיקת "או", בעוד שהשני בוחר ב-<h6> שמוטבע בתוך כל הכותרות האחרות.

הנה דוגמה:

import {expect, test} from "@playwright/test"; // ^1.39.0

const failMsg = (prev, curr) =>
  `h${curr} was more than one level deeper than previous header h${prev}`;

test("detects a skipped heading", async ({page}) => {
  test.fail(); // expect this test to fail
  const html = `<!DOCTYPE html><html><body>
  <h1>1</h1>
  <h2>2</h2>
  <h4>4</h4>
  </body></html>`;
  await page.setContent(html); // replace with page.goto("<Your URL>"); when you're working with a real site
  const headers = await page
    .locator("h1, h2, h3, h4, h5, h6")
    .evaluateAll(els => els.map(el => +el.tagName.slice(1)));

  for (let i = 1; i < headers.length; i++) {
    expect(
      headers[i] - headers[i-1],
      failMsg(headers[i-1], headers[i])
    ).toBeLessThan(2);
  }
});

test("handles a valid structure", async ({page}) => {
  const html = `<!DOCTYPE html><html><body>
  <h1>1</h1>
  <h2>2</h2>
  <h3>3</h3>
  <h4>4</h4>
  <h4>4</h4>
  <h2>2</h2> <!-- it's OK to skip back, just not forward -->
  <h3>3</h3>
  </body></html>`;
  await page.setContent(html);
  const headers = await page
    .locator("h1, h2, h3, h4, h5, h6")
    .evaluateAll(els => els.map(el => +el.tagName.slice(1)));

  for (let i = 1; i < headers.length; i++) {
    expect(
      headers[i] - headers[i-1],
      failMsg(headers[i-1], headers[i])
    ).toBeLessThan(2);
  }
});

test("handles a valid structure on a real site", async ({page}) => {
  await page.goto("https://playwright.dev/docs/test-assertions");
  const headers = await page
    .locator("h1, h2, h3, h4, h5, h6")
    .evaluateAll(els => els.map(el => +el.tagName.slice(1)));

  for (let i = 1; i < headers.length; i++) {
    expect(
      headers[i] - headers[i-1],
      failMsg(headers[i-1], headers[i])
    ).toBeLessThan(2);
  }
});

למבחנים הממשיים שלך, סביר שתשתמש ב-page.goto() במקום ב-page.setContent, שמשמש כאן רק כדי להקל על הדגמת לוגיקת האישור בצורה פשוטה.

ייתכן שתרצה להשתמש במתאם מותאם אישית שיעזור להסיר את הפרטים המיותרים של הודעת התבנית של השגיאה ואת הלולאה המפורשת ו/או לכתוב פונקציית עזר כדי להוציא את הכותרות.

גם, הטענה הזו לא מחכה אוטומטית, אבל אני מניח שהכותרות כנראה בסדר לקחת יותר או פחות בבת אחת. אם ההנחה הזו לא נכונה, נסו poll או toPass.