TenKeyLabs / dappwright

🏌🏼‍E2E testing for dApps using Playwright + MetaMask & Coinbase Wallet
https://www.npmjs.com/package/@tenkeylabs/dappwright
Other
84 stars 22 forks source link

`signin` method not signing SIWE message #366

Open iankressin opened 3 weeks ago

iankressin commented 3 weeks ago

Describe the bug I’m encountering an issue when writing a test to sign a SIWE message. The problem occurs when the await wallet.signin() function is called—nothing happens, and the test appears to get stuck at this step.

To investigate further, I ran the test with the --headed flag in Playwright. The test visibly hangs during the signing process (see the recording below). Eventually, the test fails due to a timeout.

To Reproduce Steps to reproduce the behavior:

Test:

import { expect } from '@playwright/test';
import { test } from '../utils/dappwright';

test.describe('Login - Registered Users', () => {
    test.beforeEach(async ({ page }) => {
        await page.goto('/login');
    });

    test.only('should set cookie with jwt on successful login', async ({ page, wallet }) => {
        await page.click('#login');
        await wallet.signin();

        const cookies = await page.context().cookies();

        expect(cookies).toContainEqual(expect.objectContaining({ name: 'jwt' }));
    });
});
import { type BrowserContext, test as baseTest } from '@playwright/test';
import dappwright, { type Dappwright, MetaMaskWallet } from '@tenkeylabs/dappwright';

export const test = baseTest.extend<{
    context: BrowserContext;
    wallet: Dappwright;
}>({
    context: async ({}, use) => {
        const [, , context] = await dappwright.bootstrap('', {
            wallet: 'metamask',
            version: MetaMaskWallet.recommendedVersion,
            seed: 'test test test test test test test test test test test junk',
            headless: false
        });

        await use(context);
    },

    wallet: async ({ context }, use) => {
        const metamask = await dappwright.getWallet('metamask', context);

        await use(metamask);
    }
});

Function that initiates the signin:

import { createWalletClient } from 'viem'

async function getClient() {
    const browserProvider = window.ethereum;

    if (!browserProvider) {
        throw new Error('Wallet extension not found');
    }

    return createWalletClient({
        chain: mainnet,
        transport: custom(browserProvider)
    });

}

async function handleWalletLogin(address: string, message: string): Promise<void> {
    const signature = await getClient().signMessage({
        account,
        message,
    });

    return signature
}

Logs

 1) [MetaMask] › login/registered-users.spec.ts:9:7 › Login - Registered Users › should set cookie with jwt on successful login

    Test timeout of 30000ms exceeded.

  Slow test file: [MetaMask] › login/registered-users.spec.ts (30.0s)
  Consider splitting slow test files to speed up parallel execution
  1 failed
    [MetaMask] › login/registered-users.spec.ts:9:7 › Login - Registered Users › should set cookie with jwt on successful login

Expected behavior The wallet.signin() should complete and allow the test to proceed.

Screenshots

https://github.com/user-attachments/assets/f531c6f2-74ff-4a57-8f89-4d6b1b6a509b

System:

iankressin commented 3 weeks ago

Debugging further, I noticed that the text is different from the signature request generated by Dappwright's test app and mine.

When a message is SIWE compliant, Metamask shows a different UI. Instead of Signature request the heading is changed to Sign-in request, therefore the assertion below will always evaluate to false. https://github.com/TenKeyLabs/dappwright/blob/386b19987eec2a7de18f98ec8ca86e8096e4a4ba/src/wallets/metamask/actions/signin.ts#L12

osis commented 1 week ago

Good call-out. Is this something that can make its way into a PR?

iankressin commented 1 week ago

Good call-out. Is this something that can make its way into a PR?

Yeah, I can work on it either late this week or early next one. Shouldn't be too hard to handle