Clarify transfer rejections and improve storage readability
This commit is contained in:
@@ -160,7 +160,40 @@ try {
|
||||
await admin.locator('.admin-file').filter({ hasText: 'sample.mp4' }).waitFor();
|
||||
assert.match(await admin.locator('.admin-file').innerText(), /중국\(CN\) · Beijing/);
|
||||
assert.match(await admin.locator('.admin-file').innerText(), /1\.1\.1\.1/);
|
||||
assert.match(await admin.locator('.admin-file-owner').innerText(), /^[a-f0-9-]{36}\s+비로그인$/);
|
||||
assert.match(
|
||||
await admin.locator('.admin-file-owner').innerText(),
|
||||
/^[a-f0-9-]{36}\s*·\s*게스트\(Guest\)$/,
|
||||
);
|
||||
assert.match(await admin.locator('.admin-file').innerText(), /Beijing\s*·\s*1\.1\.1\.1/);
|
||||
const sizeStyle = await admin
|
||||
.locator('.admin-stats article')
|
||||
.nth(1)
|
||||
.locator('strong .file-size')
|
||||
.evaluate((label) => {
|
||||
const fraction = label.querySelector('.file-size-fraction');
|
||||
const whole = label.querySelector('.file-size-whole');
|
||||
const unit = label.querySelector('.file-size-unit');
|
||||
return {
|
||||
whole: whole.textContent,
|
||||
fraction: fraction.textContent,
|
||||
unit: unit.textContent,
|
||||
dimmed: Number(getComputedStyle(fraction).opacity) < 1,
|
||||
smaller:
|
||||
parseFloat(getComputedStyle(fraction).fontSize) <
|
||||
parseFloat(getComputedStyle(whole).fontSize),
|
||||
inline: getComputedStyle(fraction).display === 'inline',
|
||||
unitGap: parseFloat(getComputedStyle(unit).marginInlineStart) > 0,
|
||||
};
|
||||
});
|
||||
assert.deepEqual(sizeStyle, {
|
||||
whole: '7,687',
|
||||
fraction: '.0',
|
||||
unit: 'GB',
|
||||
dimmed: true,
|
||||
smaller: true,
|
||||
inline: true,
|
||||
unitGap: true,
|
||||
});
|
||||
assert.doesNotMatch(await admin.locator('.admin-file-owner').innerText(), /guest-|user-/);
|
||||
assert.match(await admin.locator('.admin-file').innerText(), /접속 지역 · 중국\(CN\) · Beijing/);
|
||||
assert.doesNotMatch(await admin.locator('.admin-file').innerText(), /최근 접속/);
|
||||
@@ -475,7 +508,7 @@ try {
|
||||
const ownedCard = admin.locator('.admin-file').filter({ hasText: 'account-owner.txt' });
|
||||
await ownedCard.waitFor();
|
||||
const ownerLabel = await ownedCard.locator('.admin-file-owner').innerText();
|
||||
assert.match(ownerLabel, /^[a-f0-9-]{36}\s+other@hop\.test$/);
|
||||
assert.match(ownerLabel, /^[a-f0-9-]{36}\s*·\s*other@hop\.test$/);
|
||||
assert.doesNotMatch(ownerLabel, /user-|guest-|\[/);
|
||||
await admin.screenshot({ path: 'tests/e2e/admin-file-account.png', fullPage: true });
|
||||
await admin.getByRole('button', { name: '관리 기록', exact: true }).click();
|
||||
|
||||
@@ -280,6 +280,14 @@ try {
|
||||
await storedLinkPage.waitForURL('https://example.com/saved');
|
||||
await storedLinkPage.close();
|
||||
await receiver.locator('.item-body').filter({ hasText: 'https://example.com/saved' }).waitFor();
|
||||
await sender.locator('.send-dialog').waitFor({ state: 'hidden' });
|
||||
await sender.locator('.peer-card').first().click();
|
||||
await sender.getByRole('button', { name: '보관함에서 가져오기', exact: true }).click();
|
||||
await sender.locator('.send-dialog .vault-choice').filter({ hasText: '업무 링크' }).click();
|
||||
await sender.getByRole('button', { name: '전송하기', exact: true }).click();
|
||||
await receiver.getByRole('button', { name: '거절', exact: true }).click();
|
||||
await sender.locator('.send-dialog').waitFor({ state: 'hidden' });
|
||||
await sender.locator('.toast').filter({ hasText: '전송을 거절했어요.' }).waitFor();
|
||||
await navigate(sender, '보관함');
|
||||
await sender.getByRole('button', { name: '보관함에 담기', exact: true }).click();
|
||||
await sender
|
||||
|
||||
@@ -194,9 +194,52 @@ try {
|
||||
await expect(blocked.getByText('차단한 기기가 없어요.')).toBeVisible();
|
||||
await expect(receiver.locator('.peer-card')).toHaveCount(1);
|
||||
assert.equal((await api(receiver, '/device/blocks')).blocks.length, 0);
|
||||
await blocked.getByRole('button', { name: '대화상자 닫기', exact: true }).click();
|
||||
const recipientName = (await api(receiver, '/device/me')).device.name;
|
||||
// Reject the first request before its POST response reaches the sender. This
|
||||
// must still close the composer even if it never observed a pending snapshot.
|
||||
await sender.route('**/api/transfer-requests', async (route) => {
|
||||
const response = await route.fetch();
|
||||
assert.equal(response.status(), 200);
|
||||
const { requestId } = await response.json();
|
||||
await api(receiver, `/transfer-requests/${requestId}/reject`, 'POST', {});
|
||||
await route.fulfill({ response });
|
||||
});
|
||||
for (const kind of ['text', 'file', 'url']) {
|
||||
await sender.locator('.peer-card').first().click();
|
||||
if (kind === 'file')
|
||||
await sender.getByLabel('보낼 파일 선택', { exact: true }).setInputFiles({
|
||||
name: 'declined.txt',
|
||||
mimeType: 'text/plain',
|
||||
buffer: Buffer.from('test'),
|
||||
});
|
||||
else
|
||||
await sender
|
||||
.getByLabel('보낼 텍스트', { exact: true })
|
||||
.fill(kind === 'url' ? 'https://example.com/declined' : '빠른 거절도 놓치지 않습니다.');
|
||||
await sender.getByRole('button', { name: '전송하기', exact: true }).click();
|
||||
if (kind !== 'text') {
|
||||
const incoming = receiver.getByRole('dialog', { name: '전송 수락 요청' });
|
||||
await incoming.getByRole('button', { name: '거절', exact: true }).click();
|
||||
}
|
||||
await expect(sender.locator('.send-dialog')).toHaveCount(0);
|
||||
await expect(sender.locator('.toast')).toHaveText(`${recipientName}에서 전송을 거절했어요.`);
|
||||
if (kind === 'text') await sender.unroute('**/api/transfer-requests');
|
||||
}
|
||||
// History must not replay rejection notifications after a reload; the fourth
|
||||
// request now gets the real pair cooldown and visible remaining seconds.
|
||||
await sender.reload();
|
||||
await sender.locator('.peer-card').first().waitFor();
|
||||
await expect(sender.locator('.toast')).toHaveCount(0);
|
||||
await sender.locator('.peer-card').first().click();
|
||||
await sender.getByLabel('보낼 텍스트', { exact: true }).fill('세 번 거절 이후의 대기');
|
||||
await sender.getByRole('button', { name: '전송하기', exact: true }).click();
|
||||
await expect(sender.locator('.content-submit')).toBeDisabled();
|
||||
await expect(sender.locator('.content-submit')).toHaveText(/\d+초 후 전송 가능/);
|
||||
await expect(sender.locator('.error-toast')).toContainText('연속 3회 거절');
|
||||
assert.deepEqual(errors, []);
|
||||
console.log(
|
||||
'PASS: content icons/titles, desktop/mobile 2:1 buttons, consistent single file sizes 97.7KB/1.3MB/1.6GB, no list indent or overflow, retry countdown and draft preservation, block confirmation and private unblock UI.',
|
||||
'PASS: receive icons/sizes, desktop/mobile 2:1 controls, retry countdown/draft preservation, block/unblock, first two rejections allow retries, text/file/link rejection closes sender and notifies, decision before HTTP response and reload deduplication, third rejection triggers pair cooldown.',
|
||||
);
|
||||
} finally {
|
||||
await browser?.close();
|
||||
|
||||
Reference in New Issue
Block a user