feat: add envelope editor

This commit is contained in:
David Nguyen
2025-10-12 23:35:54 +11:00
parent bf89bc781b
commit 0da8e7dbc6
307 changed files with 24657 additions and 3681 deletions

View File

@ -295,19 +295,13 @@ test('[NEXT_RECIPIENT_DICTATION]: should allow assistant to dictate next signer'
{ signingOrder: 2, role: RecipientRole.SIGNER },
{ signingOrder: 3, role: RecipientRole.SIGNER },
],
updateDocumentOptions: {
documentMeta: {
upsert: {
create: {
allowDictateNextSigner: true,
signingOrder: DocumentSigningOrder.SEQUENTIAL,
},
update: {
allowDictateNextSigner: true,
signingOrder: DocumentSigningOrder.SEQUENTIAL,
},
},
},
});
await prisma.documentMeta.update({
where: { id: document.documentMetaId },
data: {
allowDictateNextSigner: true,
signingOrder: DocumentSigningOrder.SEQUENTIAL,
},
});

View File

@ -1,7 +1,7 @@
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { getFieldsForDocument } from '@documenso/lib/server-only/field/get-fields-for-document';
import { prisma } from '@documenso/prisma';
import { seedBlankDocument } from '@documenso/prisma/seed/documents';
import { seedUser } from '@documenso/prisma/seed/users';
@ -14,7 +14,7 @@ const setupDocumentAndNavigateToFieldsStep = async (page: Page) => {
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
await page.getByRole('button', { name: 'Continue' }).click();
@ -84,10 +84,8 @@ test.describe('AutoSave Fields Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrievedFields = await getFieldsForDocument({
documentId: document.id,
userId: user.id,
teamId: team.id,
const retrievedFields = await getFieldsForEnvelope({
envelopeId: document.id,
});
expect(retrievedFields.length).toBe(3);
@ -149,10 +147,8 @@ test.describe('AutoSave Fields Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrievedFields = await getFieldsForDocument({
documentId: document.id,
userId: user.id,
teamId: team.id,
const retrievedFields = await getFieldsForEnvelope({
envelopeId: document.id,
});
expect(retrievedFields.length).toBe(2);
@ -213,10 +209,8 @@ test.describe('AutoSave Fields Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrievedFields = await getFieldsForDocument({
documentId: document.id,
userId: user.id,
teamId: team.id,
const retrievedFields = await getFieldsForEnvelope({
envelopeId: document.id,
});
expect(retrievedFields.length).toBe(4);
@ -260,10 +254,8 @@ test.describe('AutoSave Fields Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrievedFields = await getFieldsForDocument({
documentId: document.id,
userId: user.id,
teamId: team.id,
const retrievedFields = await getFieldsForEnvelope({
envelopeId: document.id,
});
expect(retrievedFields.length).toBe(2);
@ -291,3 +283,28 @@ test.describe('AutoSave Fields Step', () => {
}).toPass();
});
});
const getFieldsForEnvelope = async ({ envelopeId }: { envelopeId: string }) => {
const fields = await prisma.field.findMany({
where: {
envelope: {
id: envelopeId,
},
},
include: {
signature: true,
recipient: {
select: {
name: true,
email: true,
signingStatus: true,
},
},
},
orderBy: {
id: 'asc',
},
});
return fields;
};

View File

@ -1,7 +1,8 @@
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { EnvelopeType } from '@prisma/client';
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
import { getEnvelopeById } from '@documenso/lib/server-only/envelope/get-envelope-by-id';
import { seedBlankDocument } from '@documenso/prisma/seed/documents';
import { seedUser } from '@documenso/prisma/seed/users';
@ -17,7 +18,7 @@ const setupDocument = async (page: Page) => {
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
return { user, team, document };
@ -41,8 +42,12 @@ test.describe('AutoSave Settings Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrieved = await getDocumentById({
documentId: document.id,
const retrieved = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});
@ -63,8 +68,12 @@ test.describe('AutoSave Settings Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrieved = await getDocumentById({
documentId: document.id,
const retrieved = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});
@ -85,8 +94,12 @@ test.describe('AutoSave Settings Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrieved = await getDocumentById({
documentId: document.id,
const retrieved = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});
@ -107,8 +120,12 @@ test.describe('AutoSave Settings Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrieved = await getDocumentById({
documentId: document.id,
const retrieved = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});
@ -129,8 +146,12 @@ test.describe('AutoSave Settings Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrieved = await getDocumentById({
documentId: document.id,
const retrieved = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});
@ -152,8 +173,12 @@ test.describe('AutoSave Settings Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrieved = await getDocumentById({
documentId: document.id,
const retrieved = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});
@ -173,8 +198,12 @@ test.describe('AutoSave Settings Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrieved = await getDocumentById({
documentId: document.id,
const retrieved = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});
@ -195,8 +224,12 @@ test.describe('AutoSave Settings Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrieved = await getDocumentById({
documentId: document.id,
const retrieved = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});
@ -227,8 +260,12 @@ test.describe('AutoSave Settings Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrieved = await getDocumentById({
documentId: document.id,
const retrieved = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});

View File

@ -1,8 +1,10 @@
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { EnvelopeType } from '@prisma/client';
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
import { getEnvelopeById } from '@documenso/lib/server-only/envelope/get-envelope-by-id';
import { getRecipientsForDocument } from '@documenso/lib/server-only/recipient/get-recipients-for-document';
import { mapSecondaryIdToDocumentId } from '@documenso/lib/utils/envelope';
import { seedBlankDocument } from '@documenso/prisma/seed/documents';
import { seedUser } from '@documenso/prisma/seed/users';
@ -17,7 +19,7 @@ const setupDocumentAndNavigateToSignersStep = async (page: Page) => {
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
await page.getByRole('button', { name: 'Continue' }).click();
@ -47,7 +49,7 @@ test.describe('AutoSave Signers Step', () => {
await expect(async () => {
const retrievedRecipients = await getRecipientsForDocument({
documentId: document.id,
documentId: mapSecondaryIdToDocumentId(document.secondaryId),
userId: user.id,
teamId: team.id,
});
@ -71,7 +73,7 @@ test.describe('AutoSave Signers Step', () => {
await expect(async () => {
const retrievedRecipients = await getRecipientsForDocument({
documentId: document.id,
documentId: mapSecondaryIdToDocumentId(document.secondaryId),
userId: user.id,
teamId: team.id,
});
@ -99,7 +101,7 @@ test.describe('AutoSave Signers Step', () => {
await expect(async () => {
const retrievedRecipients = await getRecipientsForDocument({
documentId: document.id,
documentId: mapSecondaryIdToDocumentId(document.secondaryId),
userId: user.id,
teamId: team.id,
});
@ -145,14 +147,18 @@ test.describe('AutoSave Signers Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrievedDocumentData = await getDocumentById({
documentId: document.id,
const retrievedDocumentData = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});
const retrievedRecipients = await getRecipientsForDocument({
documentId: document.id,
documentId: mapSecondaryIdToDocumentId(document.secondaryId),
userId: user.id,
teamId: team.id,
});

View File

@ -1,7 +1,8 @@
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { EnvelopeType } from '@prisma/client';
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
import { getEnvelopeById } from '@documenso/lib/server-only/envelope/get-envelope-by-id';
import { seedBlankDocument } from '@documenso/prisma/seed/documents';
import { seedUser } from '@documenso/prisma/seed/users';
@ -16,7 +17,7 @@ export const setupDocumentAndNavigateToSubjectStep = async (page: Page) => {
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
await page.getByRole('button', { name: 'Continue' }).click();
@ -59,8 +60,12 @@ test.describe('AutoSave Subject Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrievedDocumentData = await getDocumentById({
documentId: document.id,
const retrievedDocumentData = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});
@ -81,8 +86,12 @@ test.describe('AutoSave Subject Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrievedDocumentData = await getDocumentById({
documentId: document.id,
const retrievedDocumentData = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});
@ -105,8 +114,12 @@ test.describe('AutoSave Subject Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrievedDocumentData = await getDocumentById({
documentId: document.id,
const retrievedDocumentData = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});
@ -156,8 +169,12 @@ test.describe('AutoSave Subject Step', () => {
await triggerAutosave(page);
await expect(async () => {
const retrievedDocumentData = await getDocumentById({
documentId: document.id,
const retrievedDocumentData = await getEnvelopeById({
id: {
type: 'envelopeId',
id: document.id,
},
type: EnvelopeType.DOCUMENT,
userId: user.id,
teamId: team.id,
});

View File

@ -50,7 +50,7 @@ test('[DOCUMENT_FLOW]: Simple duplicate recipients test', async ({ page }) => {
await page.waitForTimeout(2500);
await page.getByRole('button', { name: 'Send' }).click();
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
await expect(page.getByRole('link', { name: document.title })).toBeVisible();
});

View File

@ -69,7 +69,7 @@ const completeDocumentFlowWithDuplicateRecipients = async (options: {
await page.getByRole('button', { name: 'Send' }).click();
// Wait for send confirmation
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(`/t/${team.url}/documents`);
await expect(page.getByRole('link', { name: document.title })).toBeVisible();
};
@ -157,7 +157,7 @@ test.describe('[DOCUMENT_FLOW]: Duplicate Recipients', () => {
await page.waitForTimeout(2500);
await page.getByRole('button', { name: 'Send' }).click();
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
await expect(page.getByRole('link', { name: document.title })).toBeVisible();
});
@ -188,7 +188,7 @@ test.describe('[DOCUMENT_FLOW]: Duplicate Recipients', () => {
const recipients = await prisma.recipient.findMany({
where: {
documentId: document.id,
envelopeId: document.id,
},
});
@ -286,7 +286,7 @@ test.describe('[DOCUMENT_FLOW]: Duplicate Recipients', () => {
await page.getByRole('button', { name: 'Send' }).click();
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
await expect(page.getByRole('link', { name: document.title })).toBeVisible();
});
@ -348,7 +348,7 @@ test.describe('[DOCUMENT_FLOW]: Duplicate Recipients', () => {
await page.waitForTimeout(2500);
await page.getByRole('button', { name: 'Send' }).click();
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
await expect(page.getByRole('link', { name: document.title })).toBeVisible();
});

View File

@ -1,6 +1,5 @@
import { expect, test } from '@playwright/test';
import { mapSecondaryIdToDocumentId } from '@documenso/lib/utils/envelope';
import {
seedBlankDocument,
seedDraftDocument,
@ -17,7 +16,7 @@ test('[DOCUMENT_FLOW]: add settings', async ({ page }) => {
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
// Set title.
@ -53,15 +52,13 @@ test('[DOCUMENT_FLOW]: title should be disabled depending on document status', a
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(pendingDocument.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${pendingDocument.id}/edit`,
});
// Should be disabled for pending documents.
await expect(page.getByLabel('Title')).toBeDisabled();
// Should be enabled for draft documents.
await page.goto(
`/t/${team.url}/documents/${mapSecondaryIdToDocumentId(draftDocument.secondaryId)}/edit`,
);
await page.goto(`/t/${team.url}/documents/${draftDocument.id}/edit`);
await expect(page.getByLabel('Title')).toBeEnabled();
});

View File

@ -1,6 +1,5 @@
import { expect, test } from '@playwright/test';
import { mapSecondaryIdToDocumentId } from '@documenso/lib/utils/envelope';
import { seedBlankDocument } from '@documenso/prisma/seed/documents';
import { seedUser } from '@documenso/prisma/seed/users';
@ -13,7 +12,7 @@ test('[DOCUMENT_FLOW]: add signers', async ({ page }) => {
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
// Save the settings by going to the next step.

View File

@ -9,10 +9,6 @@ import {
import { DateTime } from 'luxon';
import path from 'node:path';
import {
mapDocumentIdToSecondaryId,
mapSecondaryIdToDocumentId,
} from '@documenso/lib/utils/envelope';
import { prisma } from '@documenso/prisma';
import {
seedBlankDocument,
@ -62,7 +58,7 @@ test('[DOCUMENT_FLOW]: should be able to upload a PDF document', async ({ page }
await fileChooser.setFiles(path.join(__dirname, '../../../../assets/example.pdf'));
// Wait to be redirected to the edit page.
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
});
test('[DOCUMENT_FLOW]: should be able to create a document', async ({ page }) => {
@ -72,7 +68,7 @@ test('[DOCUMENT_FLOW]: should be able to create a document', async ({ page }) =>
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
const documentTitle = `example-${Date.now()}.pdf`;
@ -118,7 +114,7 @@ test('[DOCUMENT_FLOW]: should be able to create a document', async ({ page }) =>
await page.waitForTimeout(2500);
await page.getByRole('button', { name: 'Send' }).click();
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
// Assert document was created
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();
@ -133,7 +129,7 @@ test('[DOCUMENT_FLOW]: should be able to create a document with multiple recipie
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
const documentTitle = `example-${Date.now()}.pdf`;
@ -203,7 +199,7 @@ test('[DOCUMENT_FLOW]: should be able to create a document with multiple recipie
await page.waitForTimeout(2500);
await page.getByRole('button', { name: 'Send' }).click();
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
// Assert document was created
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();
@ -218,7 +214,7 @@ test('[DOCUMENT_FLOW]: should be able to create a document with multiple recipie
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
// Set title
@ -301,7 +297,7 @@ test('[DOCUMENT_FLOW]: should be able to create a document with multiple recipie
await page.waitForTimeout(2500);
await page.getByRole('button', { name: 'Send' }).click();
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
// Assert document was created
await expect(page.getByRole('link', { name: 'Test Title' })).toBeVisible();
@ -316,7 +312,7 @@ test('[DOCUMENT_FLOW]: should not be able to create a document without signature
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
const documentTitle = `example-${Date.now()}.pdf`;
@ -404,7 +400,7 @@ test('[DOCUMENT_FLOW]: should be able to create, send with redirect url, sign a
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
const documentTitle = `example-${Date.now()}.pdf`;
@ -440,7 +436,7 @@ test('[DOCUMENT_FLOW]: should be able to create, send with redirect url, sign a
// Assert document was created
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();
await page.getByRole('link', { name: documentTitle }).click();
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
const url = page.url().split('/');
const documentId = url[url.length - 1];
@ -448,7 +444,7 @@ test('[DOCUMENT_FLOW]: should be able to create, send with redirect url, sign a
const { token } = await prisma.recipient.findFirstOrThrow({
where: {
envelope: {
secondaryId: mapDocumentIdToSecondaryId(Number(documentId)),
id: documentId,
},
email: 'user1@example.com',
},
@ -532,7 +528,7 @@ test('[DOCUMENT_FLOW]: should be able to create and sign a document with 3 recip
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
const documentTitle = `Sequential-Signing-${Date.now()}.pdf`;
@ -590,7 +586,7 @@ test('[DOCUMENT_FLOW]: should be able to create and sign a document with 3 recip
await page.waitForTimeout(2500);
await page.getByRole('button', { name: 'Send' }).click();
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();

View File

@ -1,7 +1,6 @@
import { expect, test } from '@playwright/test';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { mapSecondaryIdToDocumentId } from '@documenso/lib/utils/envelope';
import {
seedBlankDocument,
seedCompletedDocument,
@ -28,10 +27,8 @@ test.describe('Unauthorized Access to Documents', () => {
redirectPath: `/t/${team.url}/documents`,
});
await page.goto(
`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}`,
);
await expect(page.getByRole('heading', { name: 'Oops! Something went wrong.' })).toBeVisible();
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/documents/${document.id}`);
await expect(page.getByRole('heading', { name: 'Team not found' })).toBeVisible();
});
test('should block unauthorized access to the draft document edit page', async ({ page }) => {
@ -43,13 +40,11 @@ test.describe('Unauthorized Access to Documents', () => {
await apiSignin({
page,
email: unauthorizedUser.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
await page.goto(
`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
);
await expect(page.getByRole('heading', { name: 'Oops! Something went wrong.' })).toBeVisible();
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/documents/${document.id}/edit`);
await expect(page.getByRole('heading', { name: 'Team not found' })).toBeVisible();
});
test('should block unauthorized access to the pending document page', async ({ page }) => {
@ -62,13 +57,11 @@ test.describe('Unauthorized Access to Documents', () => {
await apiSignin({
page,
email: unauthorizedUser.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}`,
redirectPath: `/t/${team.url}/documents/${document.id}`,
});
await page.goto(
`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}`,
);
await expect(page.getByRole('heading', { name: 'Oops! Something went wrong.' })).toBeVisible();
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/documents/${document.id}`);
await expect(page.getByRole('heading', { name: 'Team not found' })).toBeVisible();
});
test('should block unauthorized access to pending document edit page', async ({ page }) => {
@ -81,13 +74,11 @@ test.describe('Unauthorized Access to Documents', () => {
await apiSignin({
page,
email: unauthorizedUser.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
await page.goto(
`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
);
await expect(page.getByRole('heading', { name: 'Oops! Something went wrong.' })).toBeVisible();
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/documents/${document.id}/edit`);
await expect(page.getByRole('heading', { name: 'Team not found' })).toBeVisible();
});
test('should block unauthorized access to completed document page', async ({ page }) => {
@ -100,12 +91,10 @@ test.describe('Unauthorized Access to Documents', () => {
await apiSignin({
page,
email: unauthorizedUser.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}`,
redirectPath: `/t/${team.url}/documents/${document.id}`,
});
await page.goto(
`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}`,
);
await expect(page.getByRole('heading', { name: 'Oops! Something went wrong.' })).toBeVisible();
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/documents/${document.id}`);
await expect(page.getByRole('heading', { name: 'Team not found' })).toBeVisible();
});
});

View File

@ -1,6 +1,6 @@
import { PDFDocument } from '@cantoo/pdf-lib';
import { expect, test } from '@playwright/test';
import { DocumentStatus, FieldType } from '@prisma/client';
import { PDFDocument } from 'pdf-lib';
import { getDocumentByToken } from '@documenso/lib/server-only/document/get-document-by-token';
import { getFile } from '@documenso/lib/universal/upload/get-file';

View File

@ -44,12 +44,6 @@ test('[TEAMS]: can create document folder', async ({ page }) => {
test('[TEAMS]: can create document subfolder within a document folder', async ({ page }) => {
const { team, teamOwner } = await seedTeamDocuments();
await apiSignin({
page,
email: teamOwner.email,
redirectPath: `/t/${team.url}`,
});
const teamFolder = await seedBlankFolder(teamOwner, team.id, {
createFolderOptions: {
name: 'Team Folder',
@ -57,7 +51,11 @@ test('[TEAMS]: can create document subfolder within a document folder', async ({
},
});
await page.goto(`/t/${team.url}/documents/f/${teamFolder.id}`);
await apiSignin({
page,
email: teamOwner.email,
redirectPath: `/t/${team.url}/documents/f/${teamFolder.id}`,
});
await page.getByTestId('folder-create-button').click();

View File

@ -146,6 +146,7 @@ test('[TEAMS]: search does not reveal documents from other teams', async ({ page
redirectPath: `/t/${teamA.url}/documents`,
});
await page.waitForTimeout(100);
await page.getByPlaceholder('Search documents...').fill('Unique');
await page.waitForURL(/query=Unique/);

View File

@ -1,7 +1,6 @@
import { expect, test } from '@playwright/test';
import { DocumentStatus, DocumentVisibility, TeamMemberRole } from '@prisma/client';
import { mapSecondaryIdToDocumentId } from '@documenso/lib/utils/envelope';
import {
seedBlankDocument,
seedDocuments,
@ -751,7 +750,7 @@ test('[TEAMS]: check that ADMIN role can change document visibility', async ({ p
await apiSignin({
page,
email: adminUser.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
await page.getByTestId('documentVisibilitySelectValue').click();
@ -785,7 +784,7 @@ test('[TEAMS]: check that MEMBER role cannot change visibility of EVERYONE docum
await apiSignin({
page,
email: teamMember.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
await expect(page.getByTestId('documentVisibilitySelectValue')).toHaveText('Everyone');
@ -811,7 +810,7 @@ test('[TEAMS]: check that MEMBER role cannot change visibility of MANAGER_AND_AB
await apiSignin({
page,
email: teamMember.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
await expect(page.getByTestId('documentVisibilitySelectValue')).toHaveText('Managers and above');
@ -837,7 +836,7 @@ test('[TEAMS]: check that MEMBER role cannot change visibility of ADMIN document
await apiSignin({
page,
email: teamMember.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
await expect(page.getByTestId('documentVisibilitySelectValue')).toHaveText('Admins only');
@ -863,7 +862,7 @@ test('[TEAMS]: check that MANAGER role cannot change visibility of ADMIN documen
await apiSignin({
page,
email: teamManager.email,
redirectPath: `/t/${team.url}/documents/${mapSecondaryIdToDocumentId(document.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
await expect(page.getByTestId('documentVisibilitySelectValue')).toHaveText('Admins only');

View File

@ -1,5 +1,5 @@
import { type Page, expect, test } from '@playwright/test';
import type { Team, Template } from '@prisma/client';
import type { Envelope, Team } from '@prisma/client';
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
import { prisma } from '@documenso/prisma';
@ -14,7 +14,7 @@ import { apiSignin } from '../fixtures/authentication';
const completeTemplateFlowWithDuplicateRecipients = async (options: {
page: Page;
team: Team;
template: Template;
template: Envelope;
}) => {
const { page, team, template } = options;
// Step 1: Settings - Continue with defaults
@ -131,20 +131,20 @@ test.describe('[TEMPLATE_FLOW]: Duplicate Recipients', () => {
// Create document
await page.getByRole('button', { name: 'Create and send' }).click();
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
// Get the document ID from URL for database queries
const url = page.url();
const documentIdMatch = url.match(/\/documents\/(\d+)/);
const documentIdMatch = url.match(/\/documents\/envelope_(.*)/);
const documentId = documentIdMatch ? parseInt(documentIdMatch[1]) : null;
const envelopeId = documentIdMatch ? documentIdMatch[1] : null;
expect(documentId).not.toBeNull();
expect(envelopeId).not.toBeNull();
// Get recipients directly from database
const recipients = await prisma.recipient.findMany({
where: {
documentId: documentId!,
envelopeId: `envelope_${envelopeId}`,
},
});

View File

@ -2,6 +2,7 @@ import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
import { mapSecondaryIdToTemplateId } from '@documenso/lib/utils/envelope';
import { seedBlankTemplate } from '@documenso/prisma/seed/templates';
import { seedUser } from '@documenso/prisma/seed/users';
@ -14,7 +15,7 @@ const setupTemplateAndNavigateToFieldsStep = async (page: Page) => {
await apiSignin({
page,
email: user.email,
redirectPath: `/templates/${template.id}/edit`,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
});
await page.getByRole('button', { name: 'Continue' }).click();
@ -85,7 +86,10 @@ test.describe('AutoSave Fields Step', () => {
await expect(async () => {
const retrievedFields = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});
@ -152,7 +156,10 @@ test.describe('AutoSave Fields Step', () => {
await expect(async () => {
const retrievedFields = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});
@ -218,7 +225,11 @@ test.describe('AutoSave Fields Step', () => {
await expect(async () => {
const retrievedFields = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});
@ -270,7 +281,10 @@ test.describe('AutoSave Fields Step', () => {
await expect(async () => {
const retrievedTemplate = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});

View File

@ -2,6 +2,7 @@ import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
import { mapSecondaryIdToTemplateId } from '@documenso/lib/utils/envelope';
import { seedBlankTemplate } from '@documenso/prisma/seed/templates';
import { seedUser } from '@documenso/prisma/seed/users';
@ -16,7 +17,7 @@ const setupTemplate = async (page: Page) => {
await apiSignin({
page,
email: user.email,
redirectPath: `/templates/${template.id}/edit`,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
});
return { user, team, template };
@ -41,7 +42,10 @@ test.describe('AutoSave Settings Step - Templates', () => {
await expect(async () => {
const retrievedTemplate = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});
@ -65,7 +69,10 @@ test.describe('AutoSave Settings Step - Templates', () => {
await expect(async () => {
const retrievedTemplate = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});
@ -87,7 +94,10 @@ test.describe('AutoSave Settings Step - Templates', () => {
await expect(async () => {
const retrievedTemplate = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});
@ -109,7 +119,10 @@ test.describe('AutoSave Settings Step - Templates', () => {
await expect(async () => {
const retrievedTemplate = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});
@ -131,7 +144,10 @@ test.describe('AutoSave Settings Step - Templates', () => {
await expect(async () => {
const retrievedTemplate = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});
@ -154,7 +170,10 @@ test.describe('AutoSave Settings Step - Templates', () => {
await expect(async () => {
const retrievedTemplate = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});
@ -175,7 +194,10 @@ test.describe('AutoSave Settings Step - Templates', () => {
await expect(async () => {
const retrievedTemplate = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});
@ -197,7 +219,10 @@ test.describe('AutoSave Settings Step - Templates', () => {
await expect(async () => {
const retrievedTemplate = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});
@ -229,7 +254,10 @@ test.describe('AutoSave Settings Step - Templates', () => {
await expect(async () => {
const retrievedTemplate = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});

View File

@ -1,8 +1,11 @@
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { EnvelopeType } from '@prisma/client';
import { getRecipientsForTemplate } from '@documenso/lib/server-only/recipient/get-recipients-for-template';
import { getEnvelopeWhereInput } from '@documenso/lib/server-only/envelope/get-envelope-by-id';
import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
import { mapSecondaryIdToTemplateId } from '@documenso/lib/utils/envelope';
import { prisma } from '@documenso/prisma';
import { seedBlankTemplate } from '@documenso/prisma/seed/templates';
import { seedUser } from '@documenso/prisma/seed/users';
@ -17,7 +20,7 @@ const setupTemplateAndNavigateToSignersStep = async (page: Page) => {
await apiSignin({
page,
email: user.email,
redirectPath: `/templates/${template.id}/edit`,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
});
await page.getByRole('button', { name: 'Continue' }).click();
@ -47,7 +50,7 @@ test.describe('AutoSave Signers Step - Templates', () => {
await expect(async () => {
const retrievedRecipients = await getRecipientsForTemplate({
templateId: template.id,
templateId: mapSecondaryIdToTemplateId(template.secondaryId),
userId: user.id,
teamId: team.id,
});
@ -71,7 +74,7 @@ test.describe('AutoSave Signers Step - Templates', () => {
await expect(async () => {
const retrievedRecipients = await getRecipientsForTemplate({
templateId: template.id,
templateId: mapSecondaryIdToTemplateId(template.secondaryId),
userId: user.id,
teamId: team.id,
});
@ -99,7 +102,7 @@ test.describe('AutoSave Signers Step - Templates', () => {
await expect(async () => {
const retrievedRecipients = await getRecipientsForTemplate({
templateId: template.id,
templateId: mapSecondaryIdToTemplateId(template.secondaryId),
userId: user.id,
teamId: team.id,
});
@ -152,13 +155,16 @@ test.describe('AutoSave Signers Step - Templates', () => {
await expect(async () => {
const retrievedTemplate = await getTemplateById({
id: template.id,
id: {
type: 'envelopeId',
id: template.id,
},
userId: user.id,
teamId: team.id,
});
const retrievedRecipients = await getRecipientsForTemplate({
templateId: template.id,
templateId: mapSecondaryIdToTemplateId(template.secondaryId),
userId: user.id,
teamId: team.id,
});
@ -172,3 +178,36 @@ test.describe('AutoSave Signers Step - Templates', () => {
}).toPass();
});
});
export interface GetRecipientsForTemplateOptions {
templateId: number;
userId: number;
teamId: number;
}
const getRecipientsForTemplate = async ({
templateId,
userId,
teamId,
}: GetRecipientsForTemplateOptions) => {
const { envelopeWhereInput } = await getEnvelopeWhereInput({
id: {
type: 'templateId',
id: templateId,
},
type: EnvelopeType.TEMPLATE,
userId,
teamId,
});
const recipients = await prisma.recipient.findMany({
where: {
envelope: envelopeWhereInput,
},
orderBy: {
id: 'asc',
},
});
return recipients;
};

View File

@ -15,7 +15,7 @@ test('[TEMPLATE_FLOW]: add settings', async ({ page }) => {
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
});
// Set title.
@ -49,7 +49,7 @@ test('[TEMPLATE_FLOW] add document visibility settings', async ({ page }) => {
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
});
// Set document visibility.
@ -64,9 +64,7 @@ test('[TEMPLATE_FLOW] add document visibility settings', async ({ page }) => {
await expect(page.getByRole('heading', { name: 'Add Placeholders' })).toBeVisible();
// Navigate back to the edit page to check that the settings are saved correctly.
await page.goto(
`/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
);
await page.goto(`/t/${team.url}/templates/${template.id}/edit`);
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
await expect(page.getByTestId('documentVisibilitySelectValue')).toContainText(
@ -99,7 +97,7 @@ test('[TEMPLATE_FLOW] team member visibility permissions', async ({ page }) => {
await apiSignin({
page,
email: managerUser.email,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
});
// Manager should be able to set visibility to managers and above
@ -118,12 +116,13 @@ test('[TEMPLATE_FLOW] team member visibility permissions', async ({ page }) => {
await apiSignin({
page,
email: memberUser.email,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
});
// A regular member should not be able to see the template.
// They should be redirected to the templates page.
expect(new URL(page.url()).pathname).toBe(`/t/${team.url}/templates`);
await expect(page.getByText('Not Found').first()).toBeVisible();
await page.goto(`/t/${team.url}/templates`);
// Create a new template with 'everyone' visibility
const everyoneTemplate = await seedBlankTemplate(owner, team.id, {

View File

@ -1,6 +1,5 @@
import { expect, test } from '@playwright/test';
import { mapSecondaryIdToTemplateId } from '@documenso/lib/utils/envelope';
import { seedBlankTemplate } from '@documenso/prisma/seed/templates';
import { seedUser } from '@documenso/prisma/seed/users';
@ -80,7 +79,7 @@ test('[TEMPLATE_FLOW]: add placeholder', async ({ page }) => {
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
});
// Save the settings by going to the next step.

View File

@ -4,10 +4,6 @@ import fs from 'fs';
import path from 'path';
import { extractDocumentAuthMethods } from '@documenso/lib/utils/document-auth';
import {
mapDocumentIdToSecondaryId,
mapSecondaryIdToTemplateId,
} from '@documenso/lib/utils/envelope';
import { prisma } from '@documenso/prisma';
import { seedTeam, seedTeamMember } from '@documenso/prisma/seed/teams';
import { seedBlankTemplate } from '@documenso/prisma/seed/templates';
@ -33,7 +29,7 @@ test('[TEMPLATE]: should create a document from a template', async ({ page }) =>
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
});
// Set template title.
@ -79,13 +75,13 @@ test('[TEMPLATE]: should create a document from a template', async ({ page }) =>
await page.getByRole('button', { name: 'Create as draft' }).click();
// Review that the document was created with the correct values.
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
const documentId = Number(page.url().split('/').pop());
const documentId = page.url().split('/').pop();
const document = await prisma.envelope.findFirstOrThrow({
where: {
secondaryId: mapDocumentIdToSecondaryId(documentId),
id: documentId,
},
include: {
recipients: true,
@ -136,7 +132,7 @@ test('[TEMPLATE]: should create a team document from a team template', async ({
await apiSignin({
page,
email: owner.email,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
});
// Set template title.
@ -182,13 +178,13 @@ test('[TEMPLATE]: should create a team document from a team template', async ({
await page.getByRole('button', { name: 'Create as draft' }).click();
// Review that the document was created with the correct values.
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
const documentId = Number(page.url().split('/').pop());
const documentId = page.url().split('/').pop();
const document = await prisma.envelope.findFirstOrThrow({
where: {
secondaryId: mapDocumentIdToSecondaryId(documentId),
id: documentId,
},
include: {
recipients: true,
@ -244,7 +240,7 @@ test('[TEMPLATE]: should create a document from a template with custom document'
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
});
// Set template title
@ -288,13 +284,13 @@ test('[TEMPLATE]: should create a document from a template with custom document'
await page.getByRole('button', { name: 'Create as draft' }).click();
// Review that the document was created with the custom document data
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
const documentId = Number(page.url().split('/').pop());
const documentId = page.url().split('/').pop();
const document = await prisma.envelope.findFirstOrThrow({
where: {
secondaryId: mapDocumentIdToSecondaryId(documentId),
id: documentId,
},
include: {
envelopeItems: {
@ -343,7 +339,7 @@ test('[TEMPLATE]: should create a team document from a template with custom docu
await apiSignin({
page,
email: owner.email,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
});
// Set template title
@ -387,13 +383,13 @@ test('[TEMPLATE]: should create a team document from a template with custom docu
await page.getByRole('button', { name: 'Create as draft' }).click();
// Review that the document was created with the custom document data
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
const documentId = Number(page.url().split('/').pop());
const documentId = page.url().split('/').pop();
const document = await prisma.envelope.findFirstOrThrow({
where: {
secondaryId: mapDocumentIdToSecondaryId(documentId),
id: documentId,
},
include: {
envelopeItems: {
@ -438,7 +434,7 @@ test('[TEMPLATE]: should create a document from a template using template docume
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
});
// Set template title
@ -467,13 +463,13 @@ test('[TEMPLATE]: should create a document from a template using template docume
await page.getByRole('button', { name: 'Create as draft' }).click();
// Review that the document was created with the template's document data
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
const documentId = Number(page.url().split('/').pop());
const documentId = page.url().split('/').pop();
const document = await prisma.envelope.findFirstOrThrow({
where: {
secondaryId: mapDocumentIdToSecondaryId(documentId),
id: documentId,
},
include: {
envelopeItems: {
@ -519,7 +515,7 @@ test('[TEMPLATE]: should persist document visibility when creating from template
await apiSignin({
page,
email: owner.email,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
});
// Set template title and visibility
@ -558,13 +554,13 @@ test('[TEMPLATE]: should persist document visibility when creating from template
await page.getByRole('button', { name: 'Create as draft' }).click();
// Review that the document was created with the correct visibility
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await page.waitForURL(new RegExp(`/t/${team.url}/documents/envelope_.*`));
const documentId = Number(page.url().split('/').pop());
const documentId = page.url().split('/').pop();
const document = await prisma.envelope.findFirstOrThrow({
where: {
secondaryId: mapDocumentIdToSecondaryId(documentId),
id: documentId,
},
include: {
envelopeItems: {

View File

@ -3,7 +3,6 @@ import { customAlphabet } from 'nanoid';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { createDocumentAuthOptions } from '@documenso/lib/utils/document-auth';
import { mapSecondaryIdToTemplateId } from '@documenso/lib/utils/envelope';
import { formatDirectTemplatePath } from '@documenso/lib/utils/templates';
import { seedTeam } from '@documenso/prisma/seed/teams';
import { seedDirectTemplate, seedTemplate } from '@documenso/prisma/seed/templates';
@ -35,7 +34,7 @@ test('[DIRECT_TEMPLATES]: create direct link for template', async ({ page }) =>
redirectPath: `/t/${team.url}/templates`,
});
const url = `${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates/${mapSecondaryIdToTemplateId(teamTemplate.secondaryId)}`;
const url = `${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates/${teamTemplate.id}`;
// Owner should see list of templates with no direct link badge.
await page.goto(url);
@ -78,7 +77,7 @@ test('[DIRECT_TEMPLATES]: toggle direct template link', async ({ page }) => {
// Navigate to template settings and disable access.
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}${formatTemplatesPath(template.team?.url)}`);
await page.getByRole('cell', { name: 'Use Template' }).getByRole('button').nth(1).click();
await page.getByRole('menuitem', { name: 'Direct link' }).click();
await page.getByTestId('template-direct-link').click();
await page.getByRole('switch').click();
await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByText('Direct link signing has been').first()).toBeVisible();
@ -112,7 +111,7 @@ test('[DIRECT_TEMPLATES]: delete direct template link', async ({ page }) => {
// Navigate to template settings and delete the access.
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}${formatTemplatesPath(template.team?.url)}`);
await page.getByRole('cell', { name: 'Use Template' }).getByRole('button').nth(1).click();
await page.getByRole('menuitem', { name: 'Direct link' }).click();
await page.getByTestId('template-direct-link').click();
await page.getByRole('button', { name: 'Remove' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
await expect(page.getByText('Direct template link deleted').first()).toBeVisible();
@ -172,6 +171,7 @@ test('[DIRECT_TEMPLATES]: use direct template link with 1 recipient', async ({ p
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
await page.waitForTimeout(100);
await page.getByPlaceholder('recipient@documenso.com').fill(seedTestEmail());
await page.getByRole('button', { name: 'Continue' }).click();

View File

@ -1,7 +1,6 @@
import { expect, test } from '@playwright/test';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { mapSecondaryIdToTemplateId } from '@documenso/lib/utils/envelope';
import { seedBlankTemplate } from '@documenso/prisma/seed/templates';
import { seedUser } from '@documenso/prisma/seed/users';
@ -21,13 +20,11 @@ test.describe('Unauthorized Access to Templates', () => {
await apiSignin({
page,
email: unauthorizedUser.email,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}`,
redirectPath: `/t/${team.url}/templates/${template.id}`,
});
await page.goto(
`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}`,
);
await expect(page.getByRole('heading', { name: 'Oops! Something went wrong.' })).toBeVisible();
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates/${template.id}`);
await expect(page.getByRole('heading', { name: 'Team not found' })).toBeVisible();
});
test('should block unauthorized access to the template edit page', async ({ page }) => {
@ -39,12 +36,10 @@ test.describe('Unauthorized Access to Templates', () => {
await apiSignin({
page,
email: unauthorizedUser.email,
redirectPath: `/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
});
await page.goto(
`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates/${mapSecondaryIdToTemplateId(template.secondaryId)}/edit`,
);
await expect(page.getByRole('heading', { name: 'Oops! Something went wrong.' })).toBeVisible();
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates/${template.id}/edit`);
await expect(page.getByRole('heading', { name: 'Team not found' })).toBeVisible();
});
});

View File

@ -12,13 +12,12 @@
"keywords": [],
"author": "",
"devDependencies": {
"@playwright/test": "1.52.0",
"@types/node": "^20",
"@documenso/lib": "*",
"@documenso/prisma": "*",
"pdf-lib": "^1.17.1"
"@playwright/test": "1.52.0",
"@types/node": "^20"
},
"dependencies": {
"start-server-and-test": "^2.0.12"
}
}
}