The address is now a required field beside the label, the links table shows where each link was sent, and the admin is told plainly when the mail did not go — with the link still on screen to copy, which is the case that matters in QA and in local development where there is no mail at all. Two specs in unrelated features created links with only a label and the route now refuses that, so they are updated here rather than left to go red on somebody else's branch. That is the cost of making the address required, and it is a small one: the compiler and the suite find every call site. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
86 lines
3.7 KiB
TypeScript
86 lines
3.7 KiB
TypeScript
import { test, expect, uniqueSuffix } from './fixtures';
|
|
|
|
/**
|
|
* Issuing and revoking upload links from the admin (#222).
|
|
*
|
|
* Every link is labelled with a fresh run id and every assertion is scoped to
|
|
* that row. The suite is fullyParallel against one shared database, so an
|
|
* assertion on the table as a whole would be an assertion on whatever other
|
|
* specs happen to be doing (#241).
|
|
*/
|
|
|
|
test.describe('Managing upload links', () => {
|
|
test('issues a link, shows its token once, and lists it bounded', async ({ page, admin }) => {
|
|
const label = `Sarah ${uniqueSuffix()}`;
|
|
|
|
await admin.goto();
|
|
await page.getByRole('tab', { name: 'Upload links' }).click();
|
|
|
|
await page.getByLabel('Link label').fill(label);
|
|
await page.getByLabel('Contributor email').fill(`${uniqueSuffix()}@example.com`);
|
|
await page.getByRole('button', { name: 'Create link' }).click();
|
|
|
|
// Shown exactly once. The server keeps only a digest, so there is no
|
|
// reveal to come back to — the copy has to say so.
|
|
await expect(page.getByText('Copy this link now')).toBeVisible();
|
|
await expect(page.getByText(/\/submit\//)).toBeVisible();
|
|
await expect(page.getByText(/cannot be shown again/)).toBeVisible();
|
|
|
|
const row = page.getByRole('row', { name: new RegExp(label) });
|
|
await expect(row).toBeVisible();
|
|
// The default cap, not unlimited. An unbounded link should be asked for.
|
|
await expect(row.getByText('0 of 25')).toBeVisible();
|
|
await expect(row.getByText('Active')).toBeVisible();
|
|
});
|
|
|
|
test('revokes a link, naming the action on the confirm', async ({ page, admin }) => {
|
|
const label = `Temporary ${uniqueSuffix()}`;
|
|
|
|
await admin.goto();
|
|
await page.getByRole('tab', { name: 'Upload links' }).click();
|
|
await page.getByLabel('Link label').fill(label);
|
|
await page.getByLabel('Contributor email').fill(`${uniqueSuffix()}@example.com`);
|
|
await page.getByRole('button', { name: 'Create link' }).click();
|
|
|
|
const row = page.getByRole('row', { name: new RegExp(label) });
|
|
await row.getByRole('button', { name: 'Revoke' }).click();
|
|
|
|
// The confirm names what it does rather than saying OK, which is what the
|
|
// rest of this admin's destructive actions do.
|
|
await page.getByRole('tooltip').getByRole('button', { name: 'Revoke' }).click();
|
|
|
|
await expect(row.getByText('Revoked')).toBeVisible();
|
|
// The row stays: what arrived through the link is kept, and the record of
|
|
// where it came from with it.
|
|
await expect(row).toBeVisible();
|
|
});
|
|
|
|
// Blank-means-unlimited would make the least deliberate action produce the
|
|
// least bounded link, so unlimited is a checkbox rather than an empty field.
|
|
test('makes unlimited a deliberate choice', async ({ page, admin }) => {
|
|
const label = `Always on ${uniqueSuffix()}`;
|
|
|
|
await admin.goto();
|
|
await page.getByRole('tab', { name: 'Upload links' }).click();
|
|
await page.getByLabel('Link label').fill(label);
|
|
await page.getByLabel('Contributor email').fill(`${uniqueSuffix()}@example.com`);
|
|
await page.getByText('No limit').click();
|
|
await page.getByRole('button', { name: 'Create link' }).click();
|
|
|
|
const row = page.getByRole('row', { name: new RegExp(label) });
|
|
await expect(row).toBeVisible();
|
|
// A bare count rather than "0 of N".
|
|
await expect(row.getByText('0 of', { exact: false })).toHaveCount(0);
|
|
});
|
|
|
|
// The address is the point of the change: a link nobody can be sent is the
|
|
// thing this replaced.
|
|
test('will not create a link without an address', async ({ page, admin }) => {
|
|
await admin.goto();
|
|
await page.getByRole('tab', { name: 'Upload links' }).click();
|
|
await page.getByLabel('Link label').fill(`Nameless ${uniqueSuffix()}`);
|
|
|
|
await expect(page.getByRole('button', { name: 'Create link' })).toBeDisabled();
|
|
});
|
|
});
|