const assert = require('node:assert/strict'); const { chromium, request } = require('playwright'); const webBase = process.env.YOUTHOME_WEB_URL || 'http://127.0.0.1:4173/pages'; const apiBase = process.env.YOUTHOME_BACKEND_URL || 'http://127.0.0.1:8009'; if (process.env.YOUTHOME_LIVE_BACKEND !== '1') { console.error('Set YOUTHOME_LIVE_BACKEND=1 to run the write-and-cleanup test.'); process.exit(1); } (async () => { const browser = await chromium.launch({ channel: 'msedge', headless: true }); const api = await request.newContext({ baseURL: apiBase }); const page = await browser.newPage({ viewport: { width: 1440, height: 900 } }); page.on('response', (response) => { if (response.url().includes('/api/campus/moments') && response.request().method() === 'POST') { console.log(`Create response: HTTP ${response.status()}`); } }); page.on('pageerror', (error) => console.log(`Page error: ${error.message}`)); const phone = `199${String(Date.now()).slice(-8)}`; const password = `Webtest${String(Date.now()).slice(-6)}a`; console.log(`Temporary test phone: ${phone}`); let token; let momentId; let uploadUrl; try { const registration = await api.post('/api/auth/register', { data: { phone, password, captcha: '111111', universityName: '复旦大学', nickname: '网页发布回归', platform: 'WEB' } }); const registered = await registration.json(); assert.equal(registration.status(), 200, JSON.stringify(registered)); assert.equal(registered.code, 200, JSON.stringify(registered)); token = registered.data.token; await page.goto(`${webBase}/login.html?next=publish-post.html&demo=0`); await page.locator('#panel-password input[type="tel"]').fill(phone); await page.locator('#panel-password input[type="password"]').fill(password); await page.locator('#panel-password .btn-primary').click(); await page.waitForURL('**/publish-post.html'); await page.locator('.post-textarea').fill('网页端发布流程临时回归测试动态'); await page.locator('input[type="file"]').setInputFiles({ name: 'web-publishing-smoke.png', mimeType: 'image/png', buffer: Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIHWP4z8DwHwAFgAI/ScL/nwAAAABJRU5ErkJggg==', 'base64') }); const uploadResponse = page.waitForResponse((response) => response.url().includes('/api/file/upload/image')); await page.locator('.web-publish-actions .btn-primary').click(); const uploaded = await uploadResponse; const uploadData = await uploaded.json(); assert.equal(uploaded.status(), 200, JSON.stringify(uploadData)); uploadUrl = uploadData.data?.url || uploadData.url; await page.waitForURL('**/post-detail.html?moment=*', { timeout: 15000 }); momentId = new URL(page.url()).searchParams.get('moment'); assert.ok(momentId); await page.locator('html:not(.notification-route-pending)').waitFor(); assert.ok((await page.locator('.post-detail-content').innerText()).includes('网页端发布流程临时回归测试动态')); assert.equal(await page.locator('.post-detail-images img').count(), 1); await page.locator('.post-detail-images img').evaluate((image) => image.decode()); assert.ok(await page.locator('.post-detail-images img').evaluate((image) => image.naturalWidth > 0)); await page.goto(`${webBase}/me.html`); await page.locator('.web-live-card').waitFor(); assert.ok((await page.locator('.web-live-card').innerText()).includes('网页端发布流程')); console.log('Real backend login, publish, detail, and profile passed'); } finally { if (token && momentId) { const deletion = await api.delete(`/api/campus/moments?id=${encodeURIComponent(momentId)}`, { headers: { access_token: token } }); console.log(`Temporary moment cleanup: HTTP ${deletion.status()}`); } if (uploadUrl) { const deletion = await api.delete(`/api/file/delete?url=${encodeURIComponent(uploadUrl)}`, { headers: { access_token: token } }); console.log(`Temporary image cleanup: HTTP ${deletion.status()}`); } if (token) { const deactivation = await api.post('/api/users/deactivate?confirm=true', { headers: { access_token: token } }); console.log(`Temporary account cleanup: HTTP ${deactivation.status()}`); } await api.dispose(); await browser.close(); } })().catch((error) => { console.error(error); process.exitCode = 1; });