Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions playwright-tests/helpers/friendStatusHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const { expect } = require('@playwright/test');

const FriendStatus = Object.freeze({
BLOCKED: 0,
OTHER: 1,
CONNECTION: 2,
});

async function waitForFriendStatusTransaction(page) {
await page.waitForEvent('console', {
timeout: 60_000,
predicate: (msg) => /update_toll_required transaction successfully processed/i.test(msg.text()),
});
}

async function setFriendStatus(page, username, status) {
// Use the contacts screen path when the caller only knows the username and
// does not already have that chat open.
await page.locator('#switchToContacts').click();
await expect(page.locator('#contactsScreen.active')).toBeVisible();
await page.locator('#contactsList .chat-name', { hasText: username }).click();
await expect(page.locator('#contactInfoModal.active')).toBeVisible();
await page.locator('#addFriendButtonContactInfo').click();
await expect(page.locator('#friendModal.active')).toBeVisible();
await page.locator(`#friendForm input[type=radio][value="${status}"]`).check();

await Promise.all([
waitForFriendStatusTransaction(page),
page.locator('#friendForm button[type="submit"]').click(),
]);

await page.locator('#closeContactInfoModal').click();
await expect(page.locator('#contactInfoModal')).not.toHaveClass(/active/);
}

async function setFriendStatusInChat(page, status) {
// Use the chat header button when the caller already has the relevant chat
// modal open and wants to keep working in that conversation.
await page.locator('#addFriendButtonChat').click();
await expect(page.locator('#friendModal.active')).toBeVisible();
await page.locator(`#friendForm input[type=radio][value="${status}"]`).check();

await Promise.all([
waitForFriendStatusTransaction(page),
page.locator('#friendForm button[type="submit"]').click(),
]);

await expect(page.locator('#friendModal')).not.toHaveClass(/active/);
}

async function getCurrentFriendStatus(page, username) {
// Open the friend modal just long enough to read the selected radio value,
// then return the page to its previous modal-free state.
await page.locator('#switchToContacts').click();
await expect(page.locator('#contactsScreen.active')).toBeVisible();
await page.locator('#contactsList .chat-name', { hasText: username }).click();
await expect(page.locator('#contactInfoModal.active')).toBeVisible();
await page.locator('#addFriendButtonContactInfo').click();
await expect(page.locator('#friendModal.active')).toBeVisible();

const checked = await page.locator('#friendForm input[type=radio]:checked').getAttribute('value');

await page.locator('#closeFriendModal').click();
await page.locator('#closeContactInfoModal').click();
await expect(page.locator('#contactInfoModal')).not.toHaveClass(/active/);

return Number(checked);
}

module.exports = {
FriendStatus,
getCurrentFriendStatus,
setFriendStatus,
setFriendStatusInChat,
};
88 changes: 88 additions & 0 deletions playwright-tests/helpers/injectHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
async function holdNextInject(page, responseBody) {
await page.evaluate((mockResponseBody) => {
if (!window.__injectMockOriginalFetch) {
window.__injectMockOriginalFetch = window.fetch.bind(window);
}

let releaseResponse;
const state = {
intercepted: false,
postData: null,
released: false,
responded: false,
responseBody: mockResponseBody,
url: null,
};

state.releasePromise = new Promise((resolve) => {
releaseResponse = resolve;
});

state.release = () => {
state.released = true;
releaseResponse();
};

window.__injectMockState = state;
window.fetch = async (input, init = {}) => {
const url = typeof input === 'string' ? input : input?.url || String(input);
const method = (init?.method || input?.method || 'GET').toUpperCase();

if (!state.intercepted && method === 'POST' && /\/inject(?:$|\?)/.test(url)) {
state.intercepted = true;
state.postData = init?.body || null;
state.url = url;

await state.releasePromise;
state.responded = true;
return new Response(JSON.stringify(state.responseBody), {
status: 200,
headers: {
'Content-Type': 'application/json',
},
});
}

return window.__injectMockOriginalFetch(input, init);
};
}, responseBody);

return {
dispose: async () => {
await page.evaluate(() => {
if (window.__injectMockOriginalFetch) {
window.fetch = window.__injectMockOriginalFetch;
}
delete window.__injectMockOriginalFetch;
delete window.__injectMockState;
}).catch(() => {});
},
fulfill: async () => {
await page.evaluate(() => window.__injectMockState?.release());
await page.waitForFunction(() => window.__injectMockState?.responded === true);
},
intercepted: page.waitForFunction(() => window.__injectMockState?.intercepted === true).then(() => {
return page.evaluate(() => ({
postData: window.__injectMockState.postData,
url: window.__injectMockState.url,
}));
}),
release: async () => {
await page.evaluate(() => window.__injectMockState?.release()).catch(() => {});
},
};
}

function failedInjectResponse(reason = 'forced_inject_failure') {
return {
result: {
success: false,
reason,
},
};
}

module.exports = {
failedInjectResponse,
holdNextInject,
};
45 changes: 1 addition & 44 deletions playwright-tests/tests/friendStatus.e2e.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { test: base, expect } = require('../fixtures/base');
const { createAndSignInUser, generateUsername } = require('../helpers/userHelpers');
const { getLiberdusBalance } = require('../helpers/walletHelpers');
const { FriendStatus, getCurrentFriendStatus, setFriendStatus } = require('../helpers/friendStatusHelpers');
const { sendMessageTo } = require('../helpers/messageHelpers');
const networkParams = require('../helpers/networkParams');
const { newContext } = require('../helpers/toastHelpers');
Expand All @@ -15,30 +16,6 @@
const TOLL_NUM = Number(tollWei) / 1e18;
const DEFAULT_TOLL = networkParams.defaultTollLib;

// enum for friend status
const FriendStatus = {
BLOCKED: 0,
OTHER: 1,
CONNECTION: 2
};

async function setFriendStatus(page, username, status) {
await page.click('#switchToContacts');
await expect(page.locator('#contactsScreen.active')).toBeVisible();
await page.locator('#contactsList .chat-name', { hasText: username }).click();
await expect(page.locator('#contactInfoModal.active')).toBeVisible();
await page.click('#addFriendButtonContactInfo');
await expect(page.locator('#friendModal.active')).toBeVisible();
await page.check(`#friendForm input[type=radio][value="${status.toString()}"]`);
await page.click('#friendForm button[type="submit"]');
await page.waitForEvent('console', {
timeout: 60_000,
predicate: msg =>
/update_toll_required transaction successfully processed/i.test(msg.text())
});
await page.click('#closeContactInfoModal');
}

async function setToll(page, amount) {
await page.click('#toggleSettings');
await expect(page.locator('#settingsModal')).toBeVisible();
Expand All @@ -56,26 +33,6 @@
await page.click('#closeSettings');
}

/**
* Opens the friend modal for the given username and returns the current friend status value.
* Closes the modals after retrieving the value.
* @param {import('@playwright/test').Page} page
* @param {string} username
* @returns {Promise<number>} The current friend status value
*/
async function getCurrentFriendStatus(page, username) {
await page.click('#switchToContacts');
await expect(page.locator('#contactsScreen.active')).toBeVisible();
await page.locator('#contactsList .chat-name', { hasText: username }).click();
await expect(page.locator('#contactInfoModal.active')).toBeVisible();
await page.click('#addFriendButtonContactInfo');
await expect(page.locator('#friendModal.active')).toBeVisible();
const checked = await page.locator('#friendForm input[type=radio]:checked').getAttribute('value');
await page.click('#closeFriendModal');
await page.click('#closeContactInfoModal');
return Number(checked);
}

const test = base.extend({
users: async ({ browser, browserName }, use, testInfo) => {
const ctxA = await newContext(browser);
Expand Down Expand Up @@ -107,7 +64,7 @@
await pageA.click('#switchToChats');
await expect(
pageA.locator('#chatList .chat-name', { hasText: userB })
).toBeVisible({ timeout: 15_000 });

Check failure on line 67 in playwright-tests/tests/friendStatus.e2e.test.js

View workflow job for this annotation

GitHub Actions / e2e

[chromium] › tests/friendStatus.e2e.test.js:114:5 › Friend Status E2E › Block: User A blocks User B

3) [chromium] › tests/friendStatus.e2e.test.js:114:5 › Friend Status E2E › Block: User A blocks User B, B cannot send money Error: Timed out 15000ms waiting for expect(locator).toBeVisible() Locator: locator('#chatList .chat-name').filter({ hasText: 'c13029223963964' }) Expected: visible Received: <element(s) not found> Call log: - expect.toBeVisible with timeout 15000ms - waiting for locator('#chatList .chat-name').filter({ hasText: 'c13029223963964' }) 65 | await expect( 66 | pageA.locator('#chatList .chat-name', { hasText: userB }) > 67 | ).toBeVisible({ timeout: 15_000 }); | ^ 68 | // User A sets a toll 69 | await setToll(pageA, TOLL); 70 | balanceA -= NETWORK_FEE; // A pays network fee for setting toll at Object.users (/home/runner/work/client-testing/client-testing/playwright-tests/tests/friendStatus.e2e.test.js:67:15)
// User A sets a toll
await setToll(pageA, TOLL);
balanceA -= NETWORK_FEE; // A pays network fee for setting toll
Expand Down
Loading
Loading