feat: migrate profile legacy test, closes #3709

This commit is contained in:
alter-eggo
2023-06-20 18:23:25 +04:00
committed by Anastasios
parent 91bc023b88
commit 1c01d544a2
10 changed files with 142 additions and 150 deletions

View File

@@ -23,4 +23,9 @@ export default defineConfig({
use: { ...devices['Desktop Chrome'] },
},
],
webServer: {
command: 'yarn dev:test-app',
port: 3000,
timeout: 15000,
},
});

View File

@@ -1,5 +1,5 @@
import { Button, Stack } from '@stacks/ui';
import { ProfileUpdatingSelectors } from '@tests-legacy/integration/profile/profile-updating.selector';
import { TestAppSelectors } from '@tests/selectors/test-app.selectors';
interface UpdateActionProfileProps {
onUpdateProfile: () => Promise<void>;
@@ -18,7 +18,7 @@ export function UpdateActionLayout({
Cancel
</Button>
<Button
data-testid={ProfileUpdatingSelectors.BtnUpdateProfile}
data-testid={TestAppSelectors.BtnUpdateProfile}
type="submit"
flexGrow={1}
borderRadius="10px"

View File

@@ -6,7 +6,7 @@ import { openProfileUpdateRequestPopup } from '@stacks/connect';
import { StacksNetwork } from '@stacks/network';
import { PublicPersonProfile, PublicProfile } from '@stacks/profile';
import { Box, Button, ButtonGroup, Text } from '@stacks/ui';
import { ProfileTabSelectors } from '@tests-legacy/integration/profile/profile-test-app.selectors';
import { TestAppSelectors } from '@tests/selectors/test-app.selectors';
export const Profile = () => {
const name = 'Name ' + new Date().getTime().toString();
@@ -47,7 +47,7 @@ export const Profile = () => {
)}
<ButtonGroup spacing={4} my="base">
<Button
data-testid={ProfileTabSelectors.BtnUpdateValidProfile}
data-testid={TestAppSelectors.BtnUpdateValidProfile}
mt={3}
onClick={() =>
updateProfile(
@@ -76,7 +76,7 @@ export const Profile = () => {
</Button>
<Button
data-testid={ProfileTabSelectors.BtnUpdateInvalidProfile}
data-testid={TestAppSelectors.BtnUpdateInvalidProfile}
mt={3}
onClick={() =>
updateProfile(

View File

@@ -1,4 +0,0 @@
export enum ProfileUpdatingSelectors {
BtnUpdateProfile = 'btn-update-profile',
ErrorMessage = 'error-message',
}

View File

@@ -1,110 +0,0 @@
import { Page } from '@playwright/test';
import { DemoPage } from '@tests-legacy/page-objects/demo.page';
import { ProfileUpdatingPage } from '@tests-legacy/page-objects/profile-updating.page';
import { WalletPage } from '@tests-legacy/page-objects/wallet.page';
import { RouteUrls } from '@shared/route-urls';
import { BrowserDriver, createTestSelector, getCurrentTestName, setupBrowser } from '../utils';
import { ProfileTabSelectors } from './profile-test-app.selectors';
import { ProfileUpdatingSelectors } from './profile-updating.selector';
jest.setTimeout(120_000);
jest.retryTimes(process.env.CI ? 2 : 0);
describe(`Profile updating`, () => {
let browser: BrowserDriver;
let wallet: WalletPage;
let demo: DemoPage;
beforeEach(async () => {
browser = await setupBrowser();
await browser.context.tracing.start({ screenshots: true, snapshots: true });
wallet = await WalletPage.init(browser, RouteUrls.Onboarding);
demo = browser.demo;
});
afterEach(async () => {
try {
await browser.context.tracing.stop({
path: `trace-${getCurrentTestName()}.trace.zip`,
});
await browser.context.close();
} catch (error) {
console.log(error);
}
});
describe('New created wallet scenarios', () => {
let profileUpdatingPage: ProfileUpdatingPage;
const clickBtn = async (selector: ProfileTabSelectors) => {
const [page] = await Promise.all([
browser.context.waitForEvent('page'),
demo.page.click('text=Profile'),
demo.page.click(createTestSelector(selector)),
]);
profileUpdatingPage = new ProfileUpdatingPage(page);
};
function interceptGaiaRequest(page: Page): Promise<Buffer> {
return new Promise(resolve => {
page.on('request', request => {
if (request.url().startsWith('https://hub.blockstack.org/store')) {
const requestBody = request.postDataBuffer();
if (request.method() === 'GET') return;
if (requestBody === null) return;
resolve(requestBody);
}
});
});
}
beforeEach(async () => {
await wallet.signUp();
await demo.page.reload();
const [popup] = await Promise.all([
browser.context.waitForEvent('page'),
browser.demo.openConnect(),
]);
await popup.click(createTestSelector('account-account-1-0'));
await wallet.page.close();
await demo.page.bringToFront();
await demo.page.click('text=Profile');
});
it('should show profile details', async () => {
await clickBtn(ProfileTabSelectors.BtnUpdateValidProfile);
const name = await profileUpdatingPage.page.textContent('text=twitter ');
expect(name).toBe('https://twitter.com/twitterHandle');
});
it('should show an error for invalid profile', async () => {
await clickBtn(ProfileTabSelectors.BtnUpdateInvalidProfile);
const error = await profileUpdatingPage.waitForError(
'Invalid profile update request (Profile must follow Person schema).'
);
expect(error).toBeTruthy();
});
it('should send a signed profile token to gaia', async () => {
await clickBtn(ProfileTabSelectors.BtnUpdateValidProfile);
const [gaiaRequestBody] = await Promise.all([
interceptGaiaRequest(profileUpdatingPage.page),
profileUpdatingPage.page
.locator(createTestSelector(ProfileUpdatingSelectors.BtnUpdateProfile))
.click(),
]);
const { decodedToken } = JSON.parse(gaiaRequestBody.toString())[0];
console.log(decodedToken.payload);
expect(decodedToken?.header?.alg).toEqual('ES256K');
expect(decodedToken?.payload?.claim?.name).toContain('Name ');
expect(decodedToken?.payload?.claim?.image?.[0]?.contentUrl).toEqual(
'https://byzantion.mypinata.cloud/ipfs/Qmb84UcaMr1MUwNbYBnXWHM3kEaDcYrKuPWwyRLVTNKELC/2256.png'
);
});
});
});

View File

@@ -1,30 +0,0 @@
import { ProfileUpdatingSelectors } from '@tests-legacy/integration/profile/profile-updating.selector';
import { Page } from 'playwright-core';
import { createTestSelector } from '../integration/utils';
const selectors = {
$updateProfileBtn: createTestSelector(ProfileUpdatingSelectors.BtnUpdateProfile),
};
export class ProfileUpdatingPage {
selectors = selectors;
page: Page;
constructor(page: Page) {
this.page = page;
}
async select(selector: keyof typeof selectors) {
return this.page.$(selectors[selector]);
}
async clickUpdateProfileButton() {
return this.page.click(selectors.$updateProfileBtn);
}
async waitForError(msg: string) {
return this.page.waitForSelector(`text=${msg}`);
}
}

View File

@@ -0,0 +1,17 @@
import { Page } from '@playwright/test';
import { TestAppSelectors } from '@tests/selectors/test-app.selectors';
import { createTestSelector } from '@tests/utils';
export class ProfileUpdatingPage {
readonly updateProfileBtnSelector = createTestSelector(TestAppSelectors.BtnUpdateProfile);
constructor(readonly page: Page) {}
async clickUpdateProfileButton() {
return this.page.click(this.updateProfileBtnSelector);
}
async waitForError(msg: string) {
return this.page.waitForSelector(`text=${msg}`);
}
}

View File

@@ -0,0 +1,36 @@
import { BrowserContext, Page } from '@playwright/test';
import { OnboardingSelectors } from '@tests/selectors/onboarding.selectors';
import { TestAppSelectors } from '@tests/selectors/test-app.selectors';
import { createTestSelector } from '@tests/utils';
export class TestAppPage {
static readonly url = 'http://localhost:3000';
page: Page;
readonly signInBtnSelector = createTestSelector(OnboardingSelectors.SignUpBtn);
readonly updateProfileBtnSelector = createTestSelector(TestAppSelectors.BtnUpdateValidProfile);
readonly updateInvalidProfileBtnSelector = createTestSelector(
TestAppSelectors.BtnUpdateInvalidProfile
);
constructor(page: Page) {
this.page = page;
}
static async openDemoPage(context: BrowserContext) {
const newPage = await context.newPage();
await newPage.goto(TestAppPage.url);
return new TestAppPage(newPage);
}
async signIn() {
return this.page.click(this.signInBtnSelector, { timeout: 10000 });
}
async clickUpdateProfileButton() {
return this.page.click(this.updateProfileBtnSelector);
}
async clickUpdateInvalidProfileButton() {
return this.page.click(this.updateInvalidProfileBtnSelector);
}
}

View File

@@ -1,4 +1,6 @@
export enum ProfileTabSelectors {
export enum TestAppSelectors {
BtnUpdateValidProfile = 'btn-update-valid-profile',
BtnUpdateInvalidProfile = 'btn-update-invalid-profile',
BtnUpdateProfile = 'btn-update-profile',
ErrorMessage = 'error-message',
}

View File

@@ -0,0 +1,76 @@
import { Page } from '@playwright/test';
import { ProfileUpdatingPage } from '@tests/page-object-models/profile-updating.page';
import { TestAppPage } from '@tests/page-object-models/test-app.page';
import { test } from '../../fixtures/fixtures';
test.describe.configure({ mode: 'serial' });
test.describe('Profile updating', () => {
function interceptGaiaRequest(page: Page): Promise<Buffer> {
return new Promise(resolve => {
page.on('request', request => {
if (request.url().startsWith('https://hub.blockstack.org/store')) {
const requestBody = request.postDataBuffer();
if (request.method() === 'GET') return;
if (requestBody === null) return;
resolve(requestBody);
}
});
});
}
let testAppPage: TestAppPage;
test.beforeEach(async ({ extensionId, globalPage, onboardingPage, context }) => {
await globalPage.setupAndUseApiCalls(extensionId);
await onboardingPage.signInWithTestAccount(extensionId);
testAppPage = await TestAppPage.openDemoPage(context);
await testAppPage.signIn();
const accountsPage = await context.waitForEvent('page');
await accountsPage.locator('text="Account 1"').click();
await testAppPage.page.bringToFront();
await testAppPage.page.click('text=Profile', {
timeout: 30000,
});
await accountsPage.close();
});
test('should show profile details', async ({ context }) => {
await testAppPage.clickUpdateProfileButton();
const profileUpdatingPage = new ProfileUpdatingPage(await context.waitForEvent('page'));
const name = profileUpdatingPage.page.getByText('twitter');
const nameText = await name.innerText();
test.expect(nameText).toBe('https://twitter.com/twitterHandle');
});
test('should show an error for invalid profile', async ({ context }) => {
await testAppPage.clickUpdateInvalidProfileButton();
const profileUpdatingPage = new ProfileUpdatingPage(await context.waitForEvent('page'));
const error = await profileUpdatingPage.waitForError(
'Invalid profile update request (Profile must follow Person schema).'
);
test.expect(error).toBeTruthy();
});
test('should send a signed profile token to gaia', async ({ context }) => {
await testAppPage.clickUpdateProfileButton();
const profileUpdatingPage = new ProfileUpdatingPage(await context.waitForEvent('page'));
const [gaiaRequestBody] = await Promise.all([
interceptGaiaRequest(profileUpdatingPage.page),
profileUpdatingPage.clickUpdateProfileButton(),
]);
const { decodedToken } = JSON.parse(gaiaRequestBody.toString())[0];
test.expect(decodedToken?.header?.alg).toEqual('ES256K');
test.expect(decodedToken?.payload?.claim?.name).toContain('Name ');
test
.expect(decodedToken?.payload?.claim?.image?.[0]?.contentUrl)
.toEqual(
'https://byzantion.mypinata.cloud/ipfs/Qmb84UcaMr1MUwNbYBnXWHM3kEaDcYrKuPWwyRLVTNKELC/2256.png'
);
});
});