mirror of
https://github.com/documenso/documenso.git
synced 2026-08-27 00:32:29 +10:00
fix: wip
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
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');
|
||||
});
|
||||
Reference in New Issue
Block a user