mirror of
https://github.com/zhigang1992/wallet.git
synced 2026-01-12 22:53:27 +08:00
feat: migrate profile legacy test, closes #3709
This commit is contained in:
@@ -23,4 +23,9 @@ export default defineConfig({
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
],
|
||||
webServer: {
|
||||
command: 'yarn dev:test-app',
|
||||
port: 3000,
|
||||
timeout: 15000,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export enum ProfileUpdatingSelectors {
|
||||
BtnUpdateProfile = 'btn-update-profile',
|
||||
ErrorMessage = 'error-message',
|
||||
}
|
||||
@@ -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'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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}`);
|
||||
}
|
||||
}
|
||||
17
tests/page-object-models/profile-updating.page.ts
Normal file
17
tests/page-object-models/profile-updating.page.ts
Normal 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}`);
|
||||
}
|
||||
}
|
||||
36
tests/page-object-models/test-app.page.ts
Normal file
36
tests/page-object-models/test-app.page.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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',
|
||||
}
|
||||
76
tests/specs/profile/profile.spec.ts
Normal file
76
tests/specs/profile/profile.spec.ts
Normal 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'
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user