mirror of
https://github.com/documenso/documenso.git
synced 2026-08-27 00:32:29 +10:00
117 lines
4.4 KiB
TypeScript
117 lines
4.4 KiB
TypeScript
import { prisma } from '@documenso/prisma';
|
|
import { seedPendingDocumentWithFullFields } from '@documenso/prisma/seed/documents';
|
|
import { seedUser } from '@documenso/prisma/seed/users';
|
|
import { expect, test } from '@playwright/test';
|
|
import { DocumentSigningOrder, FieldType, RecipientRole, SigningStatus } from '@prisma/client';
|
|
|
|
import { signDirectSignaturePad } from '../fixtures/signature';
|
|
|
|
/**
|
|
* An assistant sharing a signing step with an unsigned peer cannot dictate
|
|
* the next signer: the flow does not advance until the whole step completes,
|
|
* so the server ignores any dictated identity. The signing page must
|
|
* therefore not OFFER dictation in that state — historically it did, because
|
|
* the assistant's recipient list excludes their own group peers, and the
|
|
* client derived dictation eligibility from that truncated list while the
|
|
* server decided from the full one.
|
|
*/
|
|
test('[NEXT_RECIPIENT_DICTATION]: assistant with an unsigned group peer is not offered dictation', async ({ page }) => {
|
|
const { user, team } = await seedUser();
|
|
const { user: assistant } = await seedUser();
|
|
const { user: peerSigner } = await seedUser();
|
|
const { user: lastSigner } = await seedUser();
|
|
|
|
const { recipients, document } = await seedPendingDocumentWithFullFields({
|
|
owner: user,
|
|
teamId: team.id,
|
|
recipients: [assistant, peerSigner, lastSigner],
|
|
recipientsCreateOptions: [
|
|
// The assistant shares step 1 with an unsigned peer; step 2 holds a
|
|
// single recipient — the exact shape where dictation looks available
|
|
// from the assistant's truncated recipient list.
|
|
{ signingOrder: 1, role: RecipientRole.ASSISTANT },
|
|
{ signingOrder: 1, role: RecipientRole.SIGNER },
|
|
{ signingOrder: 2, role: RecipientRole.SIGNER },
|
|
],
|
|
updateDocumentOptions: {
|
|
documentMeta: {
|
|
upsert: {
|
|
create: {
|
|
signingOrder: DocumentSigningOrder.SEQUENTIAL,
|
|
allowDictateNextSigner: true,
|
|
},
|
|
update: {
|
|
signingOrder: DocumentSigningOrder.SEQUENTIAL,
|
|
allowDictateNextSigner: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
const assistantRecipient = recipients[0];
|
|
const lastRecipient = recipients[2];
|
|
|
|
const signUrl = `/sign/${assistantRecipient.token}`;
|
|
|
|
await page.goto(signUrl);
|
|
await expect(page.getByRole('heading', { name: 'Assist Document' })).toBeVisible();
|
|
|
|
await page.waitForTimeout(1000);
|
|
|
|
await page.getByRole('radio', { name: assistantRecipient.name }).click();
|
|
|
|
// Fill in the assistant's own fields.
|
|
for (const field of assistantRecipient.fields) {
|
|
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
|
|
|
if (field.type === FieldType.SIGNATURE) {
|
|
await signDirectSignaturePad(page);
|
|
await page.getByRole('button', { name: 'Sign', exact: true }).click();
|
|
}
|
|
|
|
if (field.type === FieldType.TEXT) {
|
|
await page.locator('#custom-text').fill('TEXT');
|
|
await page.getByRole('button', { name: 'Save' }).click();
|
|
}
|
|
|
|
await expect(page.locator(`#field-${field.id}`)).toHaveAttribute('data-inserted', 'true');
|
|
}
|
|
|
|
await page.getByRole('button', { name: 'Continue' }).click();
|
|
|
|
const dialog = page.getByRole('dialog');
|
|
|
|
await expect(dialog).toBeVisible();
|
|
|
|
// The unsigned peer blocks advancement, so dictation must not be offered.
|
|
await expect(dialog.getByText('The next recipient to sign this document will be')).not.toBeVisible();
|
|
await expect(dialog.getByRole('button', { name: 'Update Recipient' })).not.toBeVisible();
|
|
|
|
// Later recipients' fields are still uninserted, so the confirm button
|
|
// reads "Proceed" rather than "Continue".
|
|
await dialog.getByRole('button', { name: /Continue|Proceed/ }).click();
|
|
await page.waitForURL(`${signUrl}/complete`);
|
|
|
|
// The assistant completed; nobody was renamed and the flow did not advance
|
|
// past the unsigned peer.
|
|
await expect
|
|
.poll(async () => {
|
|
const assistantAfter = await prisma.recipient.findUniqueOrThrow({
|
|
where: { id: assistantRecipient.id },
|
|
});
|
|
|
|
return assistantAfter.signingStatus;
|
|
})
|
|
.toBe(SigningStatus.SIGNED);
|
|
|
|
const lastAfter = await prisma.recipient.findUniqueOrThrow({ where: { id: lastRecipient.id } });
|
|
|
|
expect(lastAfter.name).toBe(lastRecipient.name);
|
|
expect(lastAfter.email).toBe(lastRecipient.email);
|
|
|
|
const envelope = await prisma.envelope.findUniqueOrThrow({ where: { id: document.id } });
|
|
|
|
expect(envelope.status).toBe('PENDING');
|
|
});
|