Skip to content

Commit

Permalink
Merge branch 'main' into bug-iframe-navigate-notMonetized
Browse files Browse the repository at this point in the history
  • Loading branch information
sidvishnoi authored Jan 15, 2025
2 parents f768e3a + bb3e0a7 commit b554bad
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/tests-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ jobs:
environment: test
steps:
- uses: actions/checkout@v4
with:
# In a pull request trigger, ref is required as GitHub Actions checks out in detached HEAD mode, meaning it doesn’t check out your branch by default.
ref: ${{ github.event.pull_request.head.sha }}

- name: Environment setup
uses: ./.github/actions/setup
Expand Down
8 changes: 8 additions & 0 deletions tests/e2e/helpers/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ export async function waitForWelcomePage(page: Page) {
);
}

export async function waitForReconnectWelcomePage(page: Page) {
await page.waitForURL(
(url) =>
url.href.startsWith(OPEN_PAYMENTS_REDIRECT_URL) &&
url.searchParams.get('result') === 'key_add_success',
);
}

export async function getContinueWaitTime(
context: BrowserContext,
params: Pick<ConnectDetails, 'walletAddressUrl'>,
Expand Down
195 changes: 195 additions & 0 deletions tests/e2e/reconnectAutoKeyTestWallet.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import { test, expect } from './fixtures/base';
import { getJWKS, withResolvers } from '@/shared/helpers';
import {
acceptGrant,
API_URL_ORIGIN,
DEFAULT_CONTINUE_WAIT_MS,
KEYS_PAGE_URL,
revokeKey,
waitForGrantConsentPage,
} from './helpers/testWallet';
import { getStorage } from './fixtures/helpers';
import { spy } from 'tinyspy';
import {
getContinueWaitTime,
waitForWelcomePage,
waitForReconnectWelcomePage,
} from './helpers/common';
import { disconnectWallet, fillPopup } from './pages/popup';

test('Reconnect to test wallet with automatic key addition', async ({
page,
popup,
persistentContext: context,
background,
i18n,
}) => {
const walletAddressUrl = process.env.TEST_WALLET_ADDRESS_URL;
const monetizationCallback = spy<[Event], void>();
const revokeInfo = await test.step('connect wallet', async () => {
const connectButton = await test.step('fill popup', async () => {
const connectButton = await fillPopup(popup, i18n, {
walletAddressUrl,
amount: '10',
recurring: false,
});
return connectButton;
});

await test.step('asks for key-add consent', async () => {
await connectButton.click();
expect(
popup.getByTestId('connect-wallet-auto-key-consent'),
).toBeVisible();
await popup
.getByRole('button', {
name: i18n.getMessage('connectWalletKeyService_label_consentAccept'),
})
.click();
});

const continueWaitMsPromise = getContinueWaitTime(
context,
{ walletAddressUrl },
DEFAULT_CONTINUE_WAIT_MS,
);

const revokeInfo = await test.step('adds key to wallet', async () => {
page = await context.waitForEvent('page', {
predicate: (page) => page.url().startsWith(KEYS_PAGE_URL),
});

const { resolve, reject, promise } = withResolvers<{
accountId: string;
walletId: string;
}>();
page.on('requestfinished', async function intercept(req) {
if (req.serviceWorker()) return;
if (req.method() !== 'POST') return;
const url = new URL(req.url());
if (url.origin !== API_URL_ORIGIN) return;
if (!url.pathname.startsWith('/accounts/')) return;
if (!url.pathname.includes('/upload-key')) return;

const pattern =
/^\/accounts\/(?<accountId>.+)\/wallet-addresses\/(?<walletId>.+)\/upload-key$/;
const match = url.pathname.match(pattern);
if (!match) {
throw new Error('no match for URL pattern');
}
const result = match.groups as { accountId: string; walletId: string };

const res = await req.response();
page.off('requestfinished', intercept);
if (!res) {
reject('no response from /upload-key API');
} else {
resolve(result);
}
});

const { keyId } = await getStorage(background, ['keyId']);
const { accountId, walletId } = await promise;

const jwks = await getJWKS(walletAddressUrl);
expect(jwks.keys.length).toBeGreaterThan(0);
const key = jwks.keys.find((key) => key.kid === keyId);
expect(key).toMatchObject({ kid: keyId });

return { accountId, walletId, keyId };
});

await test.step('shows connect consent page', async () => {
await page.waitForURL((url) =>
url.pathname.startsWith('/grant-interactions'),
);
await waitForGrantConsentPage(page);
});

await test.step('connects', async () => {
const continueWaitMs = await continueWaitMsPromise;
await acceptGrant(page, continueWaitMs);
await waitForWelcomePage(page);

await expect(background).toHaveStorage({ connected: true });
});

return revokeInfo;
});

await test.step('revoke key', async () => {
const newPage = await context.newPage();
await revokeKey(newPage, revokeInfo);
await newPage.close();

const { keys } = await getJWKS(walletAddressUrl);
expect(keys.find((key) => key.kid === revokeInfo.keyId)).toBeUndefined();
});

await test.step('start monetization', async () => {
const playgroundUrl = 'https://webmonetization.org/play/';
await page.goto(playgroundUrl);

await page.exposeFunction('monetizationCallback', monetizationCallback);
await page.evaluate(() => {
window.addEventListener('monetization', monetizationCallback);
});

await page
.getByLabel('Wallet address/Payment pointer')
.fill(walletAddressUrl);
await page.getByRole('button', { name: 'Add monetization link' }).click();

await expect(monetizationCallback).toHaveBeenCalledTimes(0);
});

await test.step('asks for key-add consent to reconnect wallet', async () => {
const reconnectButton = popup.getByRole('button', {
name: i18n.getMessage('keyRevoked_action_reconnect'),
});
await expect(reconnectButton).toBeVisible();
await reconnectButton.click();

expect(popup.getByTestId('connect-wallet-auto-key-consent')).toBeVisible();
await popup
.getByRole('button', {
name: i18n.getMessage('connectWalletKeyService_label_consentAccept'),
})
.click();

const newPage = await context.waitForEvent('page', {
predicate: (page) => page.url().startsWith(KEYS_PAGE_URL),
});

await waitForReconnectWelcomePage(newPage);
await newPage.close();
});

await test.step('make one-time payment after reconnecting the wallet', async () => {
await popup.reload();
await expect(popup.getByTestId('home-page')).toBeVisible();
await expect(popup.getByRole('button', { name: 'Send now' })).toBeVisible();

await popup.getByRole('textbox').fill('1.5');
await popup.getByRole('button', { name: 'Send now' }).click();

await expect(monetizationCallback).toHaveBeenCalledTimes(1, {
timeout: 1000,
});
await expect(monetizationCallback).toHaveBeenLastCalledWithMatching({
paymentPointer: walletAddressUrl,
amountSent: {
currency: expect.stringMatching(/^[A-Z]{3}$/),
value: expect.stringMatching(/^1\.\d+$/),
},
incomingPayment: expect.stringContaining(
new URL(walletAddressUrl).origin,
),
});
});

await test.step('revoke keys and disconnect wallet', async () => {
await disconnectWallet(popup);
await revokeKey(page, revokeInfo);
});
});

0 comments on commit b554bad

Please sign in to comment.