Skip to content

Commit

Permalink
test(e2e): test on monetization event, add custom spy matchers
Browse files Browse the repository at this point in the history
  • Loading branch information
sidvishnoi committed Jan 9, 2025
1 parent 0413c96 commit ab44ead
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 16 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"react-scan": "^0.0.35",
"sade": "^1.8.1",
"tailwindcss": "^3.4.17",
"tinyspy": "^3.0.2",
"ts-jest": "^29.2.5",
"tsx": "^4.19.2",
"typescript": "^5.7.2"
Expand Down
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

134 changes: 120 additions & 14 deletions tests/e2e/fixtures/base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { test as base, type BrowserContext, type Page } from '@playwright/test';
import type { SpyFn } from 'tinyspy';
import {
getBackground,
getStorage,
Expand All @@ -7,6 +8,7 @@ import {
type Background,
} from './helpers';
import { openPopup, type Popup } from '../pages/popup';
import { sleep } from '@/shared/helpers';
import type { DeepPartial, Storage } from '@/shared/types';

type BaseScopeWorker = {
Expand Down Expand Up @@ -89,23 +91,127 @@ export const expect = test.expect.extend({

const message = pass
? () =>
this.utils.matcherHint(assertionName, undefined, undefined, {
`${this.utils.matcherHint(assertionName, undefined, undefined, {
isNot: this.isNot,
}) +
'\n\n' +
`Expected: not ${this.utils.printExpected(expected)}\n` +
(matcherResult
? `Received: ${this.utils.printReceived(matcherResult.actual)}`
: '')
})}\n\nExpected: not ${this.utils.printExpected(expected)}\n${
matcherResult
? `Received: ${this.utils.printReceived(matcherResult.actual)}`
: ''
}`
: () =>
this.utils.matcherHint(assertionName, undefined, undefined, {
`${this.utils.matcherHint(assertionName, undefined, undefined, {
isNot: this.isNot,
}) +
'\n\n' +
`Expected: ${this.utils.printExpected(expected)}\n` +
(matcherResult
? `Received: ${this.utils.printReceived(matcherResult.actual)}`
: '');
})}\n\nExpected: ${this.utils.printExpected(expected)}\n${
matcherResult
? `Received: ${this.utils.printReceived(matcherResult.actual)}`
: ''
}`;

return {
name: assertionName,
pass,
expected,
actual: matcherResult?.actual,
message,
};
},

async toHaveBeenCalledTimes(
fn: SpyFn,
expectedTimes: number,
{ timeout = 5000, wait = 1000 }: { timeout?: number; wait?: number } = {},
) {
const assertionName = 'toHaveBeenCalledTimes';

let pass: boolean;
let matcherResult: { actual: number } | undefined;

await sleep(wait);
let remainingTime = timeout;
do {
try {
test.expect(fn.callCount).toBe(expectedTimes);
pass = true;
break;
} catch {
matcherResult = { actual: fn.callCount };
pass = false;
remainingTime -= 500;
await sleep(500);
}
} while (remainingTime > 0);

const message = pass
? () =>
`${this.utils.matcherHint(assertionName, undefined, undefined, {
isNot: this.isNot,
})}\n\nExpected: not ${this.utils.printExpected(expectedTimes)}\n${
matcherResult
? `Received: ${this.utils.printReceived(matcherResult.actual)}`
: ''
}`
: () =>
`${this.utils.matcherHint(assertionName, undefined, undefined, {
isNot: this.isNot,
})}\n\nExpected: ${this.utils.printExpected(expectedTimes)}\n${
matcherResult
? `Received: ${this.utils.printReceived(matcherResult.actual)}`
: ''
}`;

return {
name: assertionName,
pass,
expected: expectedTimes,
actual: matcherResult?.actual,
message,
};
},

async toHaveBeenLastCalledWithMatching(
fn: SpyFn,
expected: Record<string, unknown>,
{ timeout = 5000, wait = 1000 }: { timeout?: number; wait?: number } = {},
) {
const assertionName = 'toHaveBeenLastCalledWithMatching';

let pass: boolean;
let matcherResult: { actual: unknown } | undefined;

await sleep(wait);
let remainingTime = timeout;
do {
try {
// we only support matching first argument of last call
const lastCallArg = fn.calls[fn.calls.length - 1][0];
test.expect(lastCallArg).toMatchObject(expected);
pass = true;
break;
} catch {
matcherResult = { actual: fn.calls[fn.calls.length - 1]?.[0] };
pass = false;
remainingTime -= 500;
await sleep(500);
}
} while (remainingTime > 0);

const message = pass
? () =>
`${this.utils.matcherHint(assertionName, undefined, undefined, {
isNot: this.isNot,
})}\n\nExpected: not ${this.utils.printExpected(expected)}\n${
matcherResult
? `Received: ${this.utils.printReceived(matcherResult.actual)}`
: ''
}`
: () =>
`${this.utils.matcherHint(assertionName, undefined, undefined, {
isNot: this.isNot,
})}\n\nExpected: ${this.utils.printExpected(expected)}\n${
matcherResult
? `Received: ${this.utils.printReceived(matcherResult.actual)}`
: ''
}`;

return {
name: assertionName,
Expand Down
18 changes: 16 additions & 2 deletions tests/e2e/simple.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { spy } from 'tinyspy';
import { test, expect } from './fixtures/connected';

test.beforeEach(async ({ popup }) => {
Expand All @@ -13,15 +14,18 @@ test('should monetize site with single wallet address', async ({

await page.goto(playgroundUrl);

const monetizationCallback = (ev: any) => ev;
const monetizationCallback = spy<[Event], void>();
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(page.locator(`link[rel=monetization]`)).toHaveAttribute(
await expect(page.locator('link[rel=monetization]')).toHaveAttribute(
'href',
walletAddressUrl,
);
Expand All @@ -32,6 +36,16 @@ test('should monetize site with single wallet address', async ({
'Load Event',
);

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

await popup.reload({ waitUntil: 'networkidle' });
await page.bringToFront();
await popup.waitForSelector(`[data-testid="home-page"]`);
Expand Down

0 comments on commit ab44ead

Please sign in to comment.