Skip to content

[🐛 Bug]: CLI cache building fails - extractWalletSetupFunction causes catastrophic backtracking #1286

@hobadams

Description

@hobadams

🔎 Have you searched existing issues to avoid duplicates?

  • I have made sure that my issue is not a duplicate.

🧪 Have you tested your code using latest version of Synpress?

💡 Are you able to provide enough information to be able to reproduce your issue locally?

  • I can provide enough details to reproduce my issue on local environment.

Synpress version

4.1.0

Node.js version

22.12.0

Operating system

macOS Sequoia 15.5

Run mode

Playwright + Synpress (as plugin)

CI platform (if applicable)

No response

Are you running your tests inside docker? (if applicable)

  • This issue could be related to docker.

What happened?

Overview

When running npx sympress to build the cache with a simple metamask config build hangs.

Details

I have cloned synpress locally and added debugging and found the issue comes from this line

The regex cannot handle more complex config. https://www.regular-expressions.info/catastrophic.html

If my defineWalletSetup function is empty it builds correctly.

Here is my config, it's not huge but the regex pattern matcher can't handle it.

// Import necessary Synpress modules
import { defineWalletSetup } from "@synthetixio/synpress";
import { MetaMask, getExtensionId } from "@synthetixio/synpress/playwright";
import { BrowserContext, Page } from "@playwright/test";
import "dotenv/config";

// Define a test seed phrase and password
const SEED_PHRASE = process.env.METAMASK_SEED_PHRASE;
const PASSWORD = process.env.METAMASK_PASSWORD;

// Define the basic wallet setup
export default defineWalletSetup(
  PASSWORD,
  async (context: BrowserContext, walletPage: Page) => {
    // This is a workaround for the fact that the MetaMask extension ID changes, and this ID is required to detect the pop-ups. // [!code focus]
    // It won't be needed in the near future! 😇 // [!code focus]
    const extensionId = await getExtensionId(context, "MetaMask");
    console.log("MetaMask extension ID:", extensionId);

    // Create a new MetaMask instance
    const metamask = new MetaMask(context, walletPage, PASSWORD, extensionId);

    // Import the wallet using the seed phrase
    await metamask.importWallet(SEED_PHRASE);

    // Additional setup steps can be added here, such as:
    // - Adding custom networks
    // - Importing tokens
    // - Setting up specific account states

    const page = await context.newPage();

    // 1. Set HTTP Auth headers BEFORE visiting the dapp
    const username = process.env.HTTP_USERNAME;
    const password = process.env.HTTP_PASSWORD;
    const auth = Buffer.from(`${username}:${password}`).toString("base64");
    await page.setExtraHTTPHeaders({
      Authorization: `Basic ${auth}`,
    });

    // Visit the dapp URL for the staker using MetaMask
    await page.goto("page here");

    await page
      .getByRole("banner")
      .getByRole("button", { name: "Connect wallet" })
      .click();
    await page.getByRole("button", { name: "MetaMask" }).click();

    await metamask.connectToDapp(["Account 1"]);
  },
);

Solution

A good solution could be to use a parser rather than regex here. Or find another way to load the config.

What is your expected behavior?

My expected behaviour is that my cache is built correctly.

How to reproduce the bug.

To reproduce the bug you can copy the config here into your playwrite project

// Import necessary Synpress modules
import { defineWalletSetup } from "@synthetixio/synpress";
import { MetaMask, getExtensionId } from "@synthetixio/synpress/playwright";
import { BrowserContext, Page } from "@playwright/test";
import "dotenv/config";

// Define a test seed phrase and password
const SEED_PHRASE = process.env.METAMASK_SEED_PHRASE;
const PASSWORD = process.env.METAMASK_PASSWORD;

// Define the basic wallet setup
export default defineWalletSetup(
  PASSWORD,
  async (context: BrowserContext, walletPage: Page) => {
    // This is a workaround for the fact that the MetaMask extension ID changes, and this ID is required to detect the pop-ups. // [!code focus]
    // It won't be needed in the near future! 😇 // [!code focus]
    const extensionId = await getExtensionId(context, "MetaMask");
    console.log("MetaMask extension ID:", extensionId);

    // Create a new MetaMask instance
    const metamask = new MetaMask(context, walletPage, PASSWORD, extensionId);

    // Import the wallet using the seed phrase
    await metamask.importWallet(SEED_PHRASE);

    // Additional setup steps can be added here, such as:
    // - Adding custom networks
    // - Importing tokens
    // - Setting up specific account states

    const page = await context.newPage();

    // 1. Set HTTP Auth headers BEFORE visiting the dapp
    const username = process.env.HTTP_USERNAME;
    const password = process.env.HTTP_PASSWORD;
    const auth = Buffer.from(`${username}:${password}`).toString("base64");
    await page.setExtraHTTPHeaders({
      Authorization: `Basic ${auth}`,
    });

    // Visit the dapp URL for the staker using MetaMask
    await page.goto("page here");

    await page
      .getByRole("banner")
      .getByRole("button", { name: "Connect wallet" })
      .click();
    await page.getByRole("button", { name: "MetaMask" }).click();

    await metamask.connectToDapp(["Account 1"]);
  },
);

Now run npx sympress

You should see it hanging it the build step.

Alternatively go to https://regex101.com/

Paste the regex defineWalletSetup\s*\([^,]*,\s*(async\s*\([^)]*\)\s*=>\s*{(?:[^{}]*|{(?:[^{}]*|{[^{}]*})*})*})\s*\)

and the code (above)

And run...you will see it hangs.

Relevant log output

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions