diff --git a/e2e/bot-firewall.spec.ts b/e2e/bot-firewall.spec.ts index ca0aa9f5..8041e9b3 100644 --- a/e2e/bot-firewall.spec.ts +++ b/e2e/bot-firewall.spec.ts @@ -1,4 +1,4 @@ -import { expect, test } from '@playwright/test'; +import { Locator, Page, expect, test } from '@playwright/test'; import { resetScenarios } from './resetHelper'; import { TEST_IDS } from '../src/client/testIDs'; import { BOT_FIREWALL_COPY } from '../src/client/bot-firewall/botFirewallCopy'; @@ -8,15 +8,15 @@ const WEB_SCRAPING_URL = PRODUCTION_E2E_TEST_BASE_URL ? `${PRODUCTION_E2E_TEST_BASE_URL}/web-scraping` : 'https://staging.fingerprinthub.com/web-scraping'; -const CLOUDFLARE_WAIT_MS = 20000; -const TEST_TIMEOUT_MS = 45000 + 2 * CLOUDFLARE_WAIT_MS; - /** * Only run this test in Chrome * This test relies on a single common Cloudflare ruleset, we cannot run multiple instances of it at the same time. */ test.skip(({ browserName }) => browserName !== 'chromium', 'Chrome-only'); -test.setTimeout(TEST_TIMEOUT_MS); +/** + * Increase timeout to give Cloudflare time to update the ruleset + */ +test.setTimeout(60000); test.describe('Bot Firewall Demo CHROME_ONLY', () => { test.beforeEach(async ({ page }) => { @@ -33,29 +33,56 @@ test.describe('Bot Firewall Demo CHROME_ONLY', () => { await page.goto('/bot-firewall'); await page.getByRole('button', { name: BOT_FIREWALL_COPY.blockIp }).first().click(); await page.getByText('was blocked in the application firewall').waitFor(); - // Give Cloudflare some time to change the firewall rule - await page.waitForTimeout(CLOUDFLARE_WAIT_MS); /** - * Try to visit web-scraping page, should be blocked by Cloudflare - * Checking the response code here as parsing the actual page if flaky for some reason. + * Try to visit web-scraping page, should be blocked by Cloudflare. * Using a separate tab also seems to help with flakiness. */ const secondTab = await context.newPage(); await secondTab.goto(WEB_SCRAPING_URL); - await secondTab.reload(); - await secondTab.getByRole('heading', { name: 'Sorry, you have been blocked' }).waitFor(); + + await assertElementWhileRepeatedlyReloadingPage( + secondTab, + secondTab.getByRole('heading', { name: 'Sorry, you have been blocked' }), + ); // Unblock IP await page.goto('/bot-firewall'); await page.getByRole('button', { name: BOT_FIREWALL_COPY.unblockIp }).first().click(); await page.getByText('was unblocked in the application firewall').waitFor(); - // Give Cloudflare some time to change the firewall rule - await page.waitForTimeout(CLOUDFLARE_WAIT_MS); // Try to visit web-scraping page, should be allowed again await secondTab.goto(WEB_SCRAPING_URL); - await secondTab.reload(); - await expect(secondTab.getByRole('heading', { name: 'Web Scraping Prevention' })).toBeVisible(); + await assertElementWhileRepeatedlyReloadingPage( + secondTab, + secondTab.getByRole('heading', { name: 'Web Scraping Prevention' }), + ); }); }); + +/** + * Asserts the visibility of a given element by repeatedly reloading the page and waiting for the element to become visible. + * + * @param {Page} page - The page object to interact with. + * @param {Locator} locator - The locator for the element to be checked for visibility. + * @param {number} waitBetweenAttempts - The time to wait between each visibility check attempt, in milliseconds. Defaults to 5000. + * @param {number} tries - The number of attempts to check the visibility of the element. Defaults to 5. + * @return {Promise} - A promise that resolves when the element becomes visible, or rejects with an error if the element is not visible after the specified number of attempts. + */ +const assertElementWhileRepeatedlyReloadingPage = async ( + page: Page, + locator: Locator, + waitBetweenAttempts = 5000, + tries = 5, +) => { + for (let i = 0; i < tries; i++) { + const isVisible = await locator.isVisible(); + if (isVisible) { + break; + } else { + await page.waitForTimeout(waitBetweenAttempts); + await page.reload(); + } + } + await expect(locator).toBeVisible(); +};