You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

101 lines
5.7 KiB

const assert = require('node:assert/strict');
const { chromium } = require('playwright');
const baseUrl = process.env.YOUTHOME_WEB_URL || 'http://127.0.0.1:4173/pages';
(async () => {
const browser = await chromium.launch({ channel: 'msedge', headless: true });
const context = await browser.newContext({ viewport: { width: 1440, height: 900 } });
const page = await context.newPage();
await context.addInitScript(() => localStorage.setItem('youthome:web:dataSource', 'local'));
const errors = [];
page.on('pageerror', (error) => errors.push(error.message));
page.on('response', (response) => {
if (response.status() >= 400) errors.push(`${response.status()} ${response.url()}`);
});
await page.goto(`${baseUrl}/feed.html`);
await page.locator('.web-nav-link[data-href^="notification.html"]').click();
await page.waitForURL('**/notification.html?v=*');
assert.ok((await page.locator('.message-list').innerText()).includes('校园十佳歌手大赛'));
assert.equal((await page.locator('.message-list').innerText()).includes('校园音乐节'), false);
const plainResponse = await page.goto(`${baseUrl}/notification.html`);
assert.ok(plainResponse.headers()['cache-control'].includes('no-store'));
assert.equal(await page.locator('.message-item[href]').count(), 6);
const cases = [
{ id: 'like-canteen', path: 'post-detail.html?post=canteen', text: '今天食堂的新菜也太好吃了吧!' },
{ id: 'comment-canteen', path: 'post-detail.html?post=canteen', text: '好棒!我也想去~', target: 'li-mengqi' },
{ id: 'mention-milk-tea', path: 'post-detail.html?post=milk-tea', text: '学校西门的奶茶店', target: 'wang-haoran' },
{ id: 'follow-chen-shiyu', path: 'user.html?name=', text: '华东师范大学' },
{ id: 'activity-singer', path: 'activity-detail.html', text: '校园十佳歌手大赛' },
{ id: 'privacy-settings', path: 'settings.html?section=privacy', text: '谁可以查看我的动态' }
];
for (const item of cases) {
await page.goto(`${baseUrl}/notification.html`);
await page.locator(`[data-notification-id="${item.id}"]`).click();
await page.waitForURL(`**/${item.path.split('?')[0]}*`);
await page.locator('body.web-shell-ready').waitFor();
assert.ok(page.url().includes(item.path), `${item.id}: unexpected URL ${page.url()}`);
assert.ok((await page.locator('body').innerText()).includes(item.text), `${item.id}: expected content not visible`);
if (item.path.startsWith('post-detail.html')) {
assert.equal(await page.locator('html.notification-route-pending').count(), 0);
assert.equal((await page.locator('.post-detail-content').innerText()).includes('今天图书馆自习'), false);
}
if (['like-canteen', 'comment-canteen', 'mention-milk-tea', 'follow-chen-shiyu'].includes(item.id)) {
assert.ok((await page.locator('.web-nav-link.is-active').innerText()).includes('消息通知'));
}
if (item.target) {
assert.ok(await page.locator(`#comment-${item.target}`).evaluate((element) => element.classList.contains('is-targeted')));
}
assert.equal(await page.evaluate((id) => localStorage.getItem(`youthome:web:notification-read:${id}`), item.id), 'true');
}
await page.goto(`${baseUrl}/notification.html`);
assert.equal(await page.locator('.category-item:first-child .category-badge').innerText(), '0');
assert.equal(await page.locator('.web-nav-badge:visible').count(), 0);
await page.goto(`${baseUrl}/activity-detail.html`);
assert.equal(await page.locator('.web-nav-badge:visible').count(), 0);
await page.goto(`${baseUrl}/settings.html?section=privacy`);
assert.equal(await page.locator('.web-nav-badge:visible').count(), 0);
await page.goto(`${baseUrl}/me.html`);
assert.equal(await page.locator('.notification-work-card').count(), 2);
await page.locator('.notification-work-card').first().click();
assert.ok(page.url().includes('post=canteen'));
await page.goto(`${baseUrl}/user.html?name=%E9%99%88%E8%AF%97%E9%9B%A8`);
assert.equal(await page.locator('.profile-name').innerText(), '陈诗雨');
assert.equal(await page.locator('.post-mini-card:visible').count(), 0);
assert.equal(await page.locator('.web-empty-state:visible').count(), 1);
const withoutScript = await context.newPage();
await withoutScript.route('**/js/web-shell.js*', (route) => route.abort());
await withoutScript.goto(`${baseUrl}/post-detail.html?post=canteen`);
assert.equal(await withoutScript.locator('.detail-layout').isVisible(), false);
assert.equal(await withoutScript.locator('html.notification-route-pending').count(), 1);
await withoutScript.close();
const nativeLink = await context.newPage();
const blockScript = (route) => route.abort();
await nativeLink.route('**/js/web-shell.js*', blockScript);
await nativeLink.goto(`${baseUrl}/notification.html`);
await nativeLink.unroute('**/js/web-shell.js*', blockScript);
await nativeLink.locator('[data-notification-id="like-canteen"]').click();
await nativeLink.waitForURL('**/post-detail.html?post=canteen*');
assert.ok((await nativeLink.locator('.post-detail-content').innerText()).includes('今天食堂的新菜'));
await nativeLink.close();
await page.setViewportSize({ width: 390, height: 844 });
for (const path of ['notification.html', 'post-detail.html?post=canteen', 'user.html?name=%E9%99%88%E8%AF%97%E9%9B%A8']) {
await page.goto(`${baseUrl}/${path}`);
const overflow = await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth);
assert.ok(overflow <= 1, `${path}: horizontal overflow ${overflow}px`);
}
assert.deepEqual(errors, []);
console.log('6 notification routes, read state, cross-page badge, and 390px layout passed');
await browser.close();
})().catch((error) => {
console.error(error);
process.exitCode = 1;
});