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,89 @@
|
||||
import { completeDocumentWithToken } from '@documenso/lib/server-only/document/complete-document-with-token';
|
||||
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, SigningStatus } from '@prisma/client';
|
||||
|
||||
/**
|
||||
* Rejecting a document only marks the recipient; the envelope is moved to
|
||||
* REJECTED later, asynchronously, by the seal job. Until that lands the
|
||||
* envelope is still PENDING, so another recipient can complete and the
|
||||
* advancement logic runs with a REJECTED recipient in the list.
|
||||
*
|
||||
* That recipient must never be treated as the next signing group — doing so
|
||||
* re-marks them as sent and emails them a signing request for a document they
|
||||
* declined. (For rejected TSP envelopes the seal job always throws, so this
|
||||
* state is permanent rather than a narrow race.)
|
||||
*/
|
||||
|
||||
const expectSigningRequestJobCount = async (recipientId: number, expected: number) => {
|
||||
const jobs = await prisma.backgroundJob.findMany({
|
||||
where: {
|
||||
jobId: 'send.signing.requested.email',
|
||||
payload: {
|
||||
path: ['recipientId'],
|
||||
equals: recipientId,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(jobs.length).toBe(expected);
|
||||
};
|
||||
|
||||
test('[REJECTED_ADVANCEMENT]: a rejected recipient is skipped when the next group is activated', async () => {
|
||||
const { user, team } = await seedUser();
|
||||
const { user: firstSigner } = await seedUser();
|
||||
const { user: rejectedSigner } = await seedUser();
|
||||
const { user: laterSigner } = await seedUser();
|
||||
|
||||
const { recipients } = await seedPendingDocumentWithFullFields({
|
||||
owner: user,
|
||||
teamId: team.id,
|
||||
recipients: [firstSigner, rejectedSigner, laterSigner],
|
||||
recipientsCreateOptions: [
|
||||
{ signingOrder: 1, signingStatus: SigningStatus.NOT_SIGNED },
|
||||
{ signingOrder: 2, signingStatus: SigningStatus.REJECTED },
|
||||
{ signingOrder: 3, signingStatus: SigningStatus.NOT_SIGNED },
|
||||
],
|
||||
// No fields, so completion is not blocked by unsigned required fields.
|
||||
fields: [],
|
||||
updateDocumentOptions: {
|
||||
documentMeta: {
|
||||
upsert: {
|
||||
create: { signingOrder: DocumentSigningOrder.SEQUENTIAL },
|
||||
update: { signingOrder: DocumentSigningOrder.SEQUENTIAL },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const first = recipients.find((recipient) => recipient.email === firstSigner.email);
|
||||
const rejected = recipients.find((recipient) => recipient.email === rejectedSigner.email);
|
||||
const later = recipients.find((recipient) => recipient.email === laterSigner.email);
|
||||
|
||||
if (!first || !rejected || !later) {
|
||||
throw new Error('Seeded recipients not found');
|
||||
}
|
||||
|
||||
// The seed never sets sentAt, so it is a clean signal for "was activated".
|
||||
expect(rejected.sentAt).toBeNull();
|
||||
expect(later.sentAt).toBeNull();
|
||||
|
||||
await completeDocumentWithToken({
|
||||
token: first.token,
|
||||
id: { type: 'envelopeId', id: first.envelopeId },
|
||||
});
|
||||
|
||||
const rejectedAfter = await prisma.recipient.findUniqueOrThrow({ where: { id: rejected.id } });
|
||||
const laterAfter = await prisma.recipient.findUniqueOrThrow({ where: { id: later.id } });
|
||||
|
||||
// The rejected recipient is left alone entirely.
|
||||
expect(rejectedAfter.sentAt).toBeNull();
|
||||
expect(rejectedAfter.signingStatus).toBe(SigningStatus.REJECTED);
|
||||
await expectSigningRequestJobCount(rejected.id, 0);
|
||||
|
||||
// The genuinely pending next step is activated instead.
|
||||
expect(laterAfter.sentAt).not.toBeNull();
|
||||
await expectSigningRequestJobCount(later.id, 1);
|
||||
});
|
||||
Reference in New Issue
Block a user