feat: migrate nextjs to rr7

This commit is contained in:
David Nguyen
2025-01-02 15:33:37 +11:00
parent 9183f668d3
commit 383b5f78f0
898 changed files with 31175 additions and 24615 deletions

View File

@ -1,6 +1,6 @@
import { expect, test } from '@playwright/test';
import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { createApiToken } from '@documenso/lib/server-only/public-api/create-api-token';
import { prisma } from '@documenso/prisma';
import { seedPendingDocumentWithFullFields } from '@documenso/prisma/seed/documents';
@ -22,15 +22,18 @@ test.describe('Document API', () => {
});
// Test with sendCompletionEmails: false
const response = await request.post(`${WEBAPP_BASE_URL}/api/v1/documents/${document.id}/send`, {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
const response = await request.post(
`${NEXT_PUBLIC_WEBAPP_URL()}/api/v1/documents/${document.id}/send`,
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
data: {
sendCompletionEmails: false,
},
},
data: {
sendCompletionEmails: false,
},
});
);
expect(response.ok()).toBeTruthy();
expect(response.status()).toBe(200);
@ -48,7 +51,7 @@ test.describe('Document API', () => {
// Test with sendCompletionEmails: true
const response2 = await request.post(
`${WEBAPP_BASE_URL}/api/v1/documents/${document.id}/send`,
`${NEXT_PUBLIC_WEBAPP_URL()}/api/v1/documents/${document.id}/send`,
{
headers: {
Authorization: `Bearer ${token}`,
@ -110,15 +113,18 @@ test.describe('Document API', () => {
expiresIn: null,
});
const response = await request.post(`${WEBAPP_BASE_URL}/api/v1/documents/${document.id}/send`, {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
const response = await request.post(
`${NEXT_PUBLIC_WEBAPP_URL()}/api/v1/documents/${document.id}/send`,
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
data: {
sendEmail: true,
},
},
data: {
sendEmail: true,
},
});
);
expect(response.ok()).toBeTruthy();
expect(response.status()).toBe(200);

View File

@ -7,7 +7,7 @@ import {
ZSuccessfulUpdateTeamMemberResponseSchema,
ZUnsuccessfulResponseSchema,
} from '@documenso/api/v1/schema';
import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { createApiToken } from '@documenso/lib/server-only/public-api/create-api-token';
import { prisma } from '@documenso/prisma';
import { TeamMemberRole } from '@documenso/prisma/client';
@ -32,11 +32,14 @@ test.describe('Team API', () => {
expiresIn: null,
});
const response = await request.get(`${WEBAPP_BASE_URL}/api/v1/team/${team.id}/members`, {
headers: {
Authorization: `Bearer ${token}`,
const response = await request.get(
`${NEXT_PUBLIC_WEBAPP_URL()}/api/v1/team/${team.id}/members`,
{
headers: {
Authorization: `Bearer ${token}`,
},
},
});
);
expect(response.ok()).toBeTruthy();
expect(response.status()).toBe(200);
@ -74,7 +77,7 @@ test.describe('Team API', () => {
const newUser = await seedUser();
const response = await request.post(
`${WEBAPP_BASE_URL}/api/v1/team/${team.id}/members/invite`,
`${NEXT_PUBLIC_WEBAPP_URL()}/api/v1/team/${team.id}/members/invite`,
{
headers: {
Authorization: `Bearer ${token}`,
@ -126,7 +129,7 @@ test.describe('Team API', () => {
expect(member).toBeTruthy();
const response = await request.put(
`${WEBAPP_BASE_URL}/api/v1/team/${team.id}/members/${member.id}`,
`${NEXT_PUBLIC_WEBAPP_URL()}/api/v1/team/${team.id}/members/${member.id}`,
{
headers: {
Authorization: `Bearer ${token}`,
@ -171,7 +174,7 @@ test.describe('Team API', () => {
expect(member).toBeTruthy();
const response = await request.delete(
`${WEBAPP_BASE_URL}/api/v1/team/${team.id}/members/${member.id}`,
`${NEXT_PUBLIC_WEBAPP_URL()}/api/v1/team/${team.id}/members/${member.id}`,
{
headers: {
Authorization: `Bearer ${token}`,
@ -221,7 +224,7 @@ test.describe('Team API', () => {
expect(ownerMember).toBeTruthy();
const response = await request.delete(
`${WEBAPP_BASE_URL}/api/v1/team/${team.id}/members/${ownerMember.id}`,
`${NEXT_PUBLIC_WEBAPP_URL()}/api/v1/team/${team.id}/members/${ownerMember.id}`,
{
headers: {
Authorization: `Bearer ${token}`,
@ -261,7 +264,7 @@ test.describe('Team API', () => {
});
const response = await request.delete(
`${WEBAPP_BASE_URL}/api/v1/team/${team.id}/members/${member.id}`,
`${NEXT_PUBLIC_WEBAPP_URL()}/api/v1/team/${team.id}/members/${member.id}`,
{
headers: {
Authorization: `Bearer ${token}`,

View File

@ -13,6 +13,7 @@ import {
import { seedTestEmail, seedUser } from '@documenso/prisma/seed/users';
import { apiSignin, apiSignout } from '../fixtures/authentication';
import { signSignaturePad } from '../fixtures/signature';
test.describe.configure({ mode: 'parallel', timeout: 60000 });
@ -35,15 +36,7 @@ test('[DOCUMENT_AUTH]: should allow signing when no auth setup', async ({ page }
await page.goto(signUrl);
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
// Add signature.
const canvas = page.locator('canvas').first();
const box = await canvas.boundingBox();
if (box) {
await page.mouse.move(box.x + 40, box.y + 40);
await page.mouse.down();
await page.mouse.move(box.x + box.width - 2, box.y + box.height - 2);
await page.mouse.up();
}
await signSignaturePad(page);
for (const field of fields) {
await page.locator(`#field-${field.id}`).getByRole('button').click();
@ -92,15 +85,7 @@ test('[DOCUMENT_AUTH]: should allow signing with valid global auth', async ({ pa
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
// Add signature.
const canvas = page.locator('canvas').first();
const box = await canvas.boundingBox();
if (box) {
await page.mouse.move(box.x + 40, box.y + 40);
await page.mouse.down();
await page.mouse.move(box.x + box.width - 2, box.y + box.height - 2);
await page.mouse.up();
}
await signSignaturePad(page);
for (const field of fields) {
await page.locator(`#field-${field.id}`).getByRole('button').click();
@ -261,15 +246,7 @@ test('[DOCUMENT_AUTH]: should allow field signing when required for recipient au
});
}
// Add signature.
const canvas = page.locator('canvas').first();
const box = await canvas.boundingBox();
if (box) {
await page.mouse.move(box.x + 40, box.y + 40);
await page.mouse.down();
await page.mouse.move(box.x + box.width - 2, box.y + box.height - 2);
await page.mouse.up();
}
await signSignaturePad(page);
for (const field of fields) {
await page.locator(`#field-${field.id}`).getByRole('button').click();
@ -372,15 +349,7 @@ test('[DOCUMENT_AUTH]: should allow field signing when required for recipient an
});
}
// Add signature.
const canvas = page.locator('canvas').first();
const box = await canvas.boundingBox();
if (box) {
await page.mouse.move(box.x + 40, box.y + 40);
await page.mouse.down();
await page.mouse.move(box.x + box.width - 2, box.y + box.height - 2);
await page.mouse.up();
}
await signSignaturePad(page);
for (const field of fields) {
await page.locator(`#field-${field.id}`).getByRole('button').click();

View File

@ -18,6 +18,7 @@ import {
import { seedUser } from '@documenso/prisma/seed/users';
import { apiSignin } from '../fixtures/authentication';
import { signSignaturePad } from '../fixtures/signature';
// Can't use the function in server-only/document due to it indirectly using
// require imports.
@ -368,15 +369,7 @@ test('[DOCUMENT_FLOW]: should be able to approve a document', async ({ page }) =
}),
).toBeVisible();
// Add signature.
const canvas = page.locator('canvas');
const box = await canvas.boundingBox();
if (box) {
await page.mouse.move(box.x + 40, box.y + 40);
await page.mouse.down();
await page.mouse.move(box.x + box.width - 2, box.y + box.height - 2);
await page.mouse.up();
}
await signSignaturePad(page);
for (const field of fields) {
await page.locator(`#field-${field.id}`).getByRole('button').click();
@ -607,19 +600,10 @@ test('[DOCUMENT_FLOW]: should be able to create and sign a document with 3 recip
await page.goto(`/sign/${recipient?.token}`);
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
await signSignaturePad(page);
await page.locator(`#field-${recipientField.id}`).getByRole('button').click();
const canvas = page.locator('canvas#signature');
const box = await canvas.boundingBox();
if (box) {
await page.mouse.move(box.x + 40, box.y + 40);
await page.mouse.down();
await page.mouse.move(box.x + box.width - 2, box.y + box.height - 2);
await page.mouse.up();
}
await page.getByRole('button', { name: 'Sign', exact: true }).click();
await page.getByRole('button', { name: 'Complete' }).click();
await page.getByRole('button', { name: 'Sign' }).click();

View File

@ -10,6 +10,7 @@ import { seedTeam } from '@documenso/prisma/seed/teams';
import { seedUser } from '@documenso/prisma/seed/users';
import { apiSignin } from '../fixtures/authentication';
import { signSignaturePad } from '../fixtures/signature';
test.describe('Signing Certificate Tests', () => {
test('individual document should always include signing certificate', async ({ page }) => {
@ -36,14 +37,7 @@ test.describe('Signing Certificate Tests', () => {
// Sign the document
await page.goto(`/sign/${recipient.token}`);
const canvas = page.locator('canvas');
const box = await canvas.boundingBox();
if (box) {
await page.mouse.move(box.x + 40, box.y + 40);
await page.mouse.down();
await page.mouse.move(box.x + box.width - 2, box.y + box.height - 2);
await page.mouse.up();
}
await signSignaturePad(page);
for (const field of recipient.fields) {
await page.locator(`#field-${field.id}`).getByRole('button').click();
@ -113,14 +107,7 @@ test.describe('Signing Certificate Tests', () => {
// Sign the document
await page.goto(`/sign/${recipient.token}`);
const canvas = page.locator('canvas');
const box = await canvas.boundingBox();
if (box) {
await page.mouse.move(box.x + 40, box.y + 40);
await page.mouse.down();
await page.mouse.move(box.x + box.width - 2, box.y + box.height - 2);
await page.mouse.up();
}
await signSignaturePad(page);
for (const field of recipient.fields) {
await page.locator(`#field-${field.id}`).getByRole('button').click();
@ -190,14 +177,7 @@ test.describe('Signing Certificate Tests', () => {
// Sign the document
await page.goto(`/sign/${recipient.token}`);
const canvas = page.locator('canvas');
const box = await canvas.boundingBox();
if (box) {
await page.mouse.move(box.x + 40, box.y + 40);
await page.mouse.down();
await page.mouse.move(box.x + box.width - 2, box.y + box.height - 2);
await page.mouse.up();
}
await signSignaturePad(page);
for (const field of recipient.fields) {
await page.locator(`#field-${field.id}`).getByRole('button').click();

View File

@ -1,6 +1,6 @@
import { type Page } from '@playwright/test';
import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
type LoginOptions = {
page: Page;
@ -23,41 +23,35 @@ export const apiSignin = async ({
const csrfToken = await getCsrfToken(page);
await request.post(`${WEBAPP_BASE_URL}/api/auth/callback/credentials`, {
form: {
await request.post(`${NEXT_PUBLIC_WEBAPP_URL()}/api/auth/email-password/authorize`, {
data: {
email,
password,
json: true,
csrfToken,
},
});
await page.goto(`${WEBAPP_BASE_URL}${redirectPath}`);
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}${redirectPath}`);
await page.waitForTimeout(500);
};
export const apiSignout = async ({ page }: { page: Page }) => {
const { request } = page.context();
const csrfToken = await getCsrfToken(page);
await request.post(`${NEXT_PUBLIC_WEBAPP_URL()}/api/auth/signout`);
await request.post(`${WEBAPP_BASE_URL}/api/auth/signout`, {
form: {
csrfToken,
json: true,
},
});
await page.goto(`${WEBAPP_BASE_URL}/signin`);
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/signin`);
};
const getCsrfToken = async (page: Page) => {
const { request } = page.context();
const response = await request.fetch(`${WEBAPP_BASE_URL}/api/auth/csrf`, {
const response = await request.fetch(`${NEXT_PUBLIC_WEBAPP_URL()}/api/auth/csrf`, {
method: 'get',
});
const { csrfToken } = await response.json();
if (!csrfToken) {
throw new Error('Invalid session');
}

View File

@ -0,0 +1,40 @@
import type { Page } from '@playwright/test';
export const signSignaturePad = async (page: Page) => {
await page.waitForTimeout(200);
const canvas = page.getByTestId('signature-pad');
const box = await canvas.boundingBox();
if (!box) {
throw new Error('Signature pad not found');
}
// Calculate center point
const centerX = box.x + box.width / 2;
const centerY = box.y + box.height / 2;
// Calculate square size (making it slightly smaller than the canvas)
const squareSize = Math.min(box.width, box.height) * 0.4; // 40% of the smallest dimension
// Move to center
await page.mouse.move(centerX, centerY);
await page.mouse.down();
// Draw square clockwise from center
// Move right
await page.mouse.move(centerX + squareSize, centerY, { steps: 10 });
// Move down
await page.mouse.move(centerX + squareSize, centerY + squareSize, { steps: 10 });
// Move left
await page.mouse.move(centerX - squareSize, centerY + squareSize, { steps: 10 });
// Move up
await page.mouse.move(centerX - squareSize, centerY - squareSize, { steps: 10 });
// Move right
await page.mouse.move(centerX + squareSize, centerY - squareSize, { steps: 10 });
// Move down to close the square
await page.mouse.move(centerX + squareSize, centerY, { steps: 10 });
await page.mouse.up();
};

View File

@ -1,6 +1,6 @@
import { test } from '@playwright/test';
import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { seedTeam } from '@documenso/prisma/seed/teams';
import { seedUser } from '@documenso/prisma/seed/users';
@ -50,7 +50,7 @@ test('[TEAMS]: delete team', async ({ page }) => {
await page.getByRole('button', { name: 'Delete' }).click();
// Check that we have been redirected to the teams page.
await page.waitForURL(`${WEBAPP_BASE_URL}/settings/teams`);
await page.waitForURL(`${NEXT_PUBLIC_WEBAPP_URL()}/settings/teams`);
});
test('[TEAMS]: update team', async ({ page }) => {
@ -81,5 +81,5 @@ test('[TEAMS]: update team', async ({ page }) => {
await page.getByRole('button', { name: 'Update team' }).click();
// Check we have been redirected to the new team URL and the name is updated.
await page.waitForURL(`${WEBAPP_BASE_URL}/t/${updatedTeamId}/settings`);
await page.waitForURL(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${updatedTeamId}/settings`);
});

View File

@ -61,7 +61,7 @@ test('[TEAMS]: search respects team document visibility', async ({ page }) => {
});
await page.getByPlaceholder('Search documents...').fill('Searchable');
await page.waitForURL(/search=Searchable/);
await page.waitForURL(/query=Searchable/);
await checkDocumentTabCount(page, 'All', visibleDocs);
@ -103,7 +103,7 @@ test('[TEAMS]: search does not reveal documents from other teams', async ({ page
});
await page.getByPlaceholder('Search documents...').fill('Unique');
await page.waitForURL(/search=Unique/);
await page.waitForURL(/query=Unique/);
await checkDocumentTabCount(page, 'All', 1);
await expect(page.getByRole('link', { name: 'Unique Team A Document' })).toBeVisible();
@ -144,7 +144,7 @@ test('[PERSONAL]: search does not reveal team documents in personal account', as
});
await page.getByPlaceholder('Search documents...').fill('Unique');
await page.waitForURL(/search=Unique/);
await page.waitForURL(/query=Unique/);
await checkDocumentTabCount(page, 'All', 1);
await expect(page.getByRole('link', { name: 'Personal Unique Document' })).toBeVisible();
@ -179,7 +179,7 @@ test('[TEAMS]: search respects recipient visibility regardless of team visibilit
});
await page.getByPlaceholder('Search documents...').fill('Admin Document');
await page.waitForURL(/search=Admin(%20|\+|\s)Document/);
await page.waitForURL(/query=Admin(%20|\+|\s)Document/);
await checkDocumentTabCount(page, 'All', 1);
await expect(
@ -221,7 +221,7 @@ test('[TEAMS]: search by recipient name respects visibility', async ({ page }) =
});
await page.getByPlaceholder('Search documents...').fill('Unique Recipient');
await page.waitForURL(/search=Unique(%20|\+|\s)Recipient/);
await page.waitForURL(/query=Unique(%20|\+|\s)Recipient/);
await checkDocumentTabCount(page, 'All', 1);
await expect(
@ -238,7 +238,7 @@ test('[TEAMS]: search by recipient name respects visibility', async ({ page }) =
});
await page.getByPlaceholder('Search documents...').fill('Unique Recipient');
await page.waitForURL(/search=Unique(%20|\+|\s)Recipient/);
await page.waitForURL(/query=Unique(%20|\+|\s)Recipient/);
await checkDocumentTabCount(page, 'All', 0);
await expect(

View File

@ -113,7 +113,7 @@ test('[TEAMS]: check team documents count with internal team email', async ({ pa
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/documents`,
redirectPath: `/t/${team.url}/documents?perPage=20`,
});
// Check document counts.
@ -422,10 +422,13 @@ test('[TEAMS]: check document visibility based on team member role', async ({ pa
},
]);
const teamUrlRedirect = `/t/${team.url}/documents?status=COMPLETED`;
// Test cases for each role
const testCases = [
{
user: adminUser,
path: teamUrlRedirect,
expectedDocuments: [
'Document Visible to Everyone',
'Document Visible to Manager and Above',
@ -435,14 +438,17 @@ test('[TEAMS]: check document visibility based on team member role', async ({ pa
},
{
user: managerUser,
path: teamUrlRedirect,
expectedDocuments: ['Document Visible to Everyone', 'Document Visible to Manager and Above'],
},
{
user: memberUser,
path: teamUrlRedirect,
expectedDocuments: ['Document Visible to Everyone'],
},
{
user: outsideUser,
path: '/documents',
expectedDocuments: ['Document Visible to Admin with Recipient'],
},
];
@ -451,7 +457,7 @@ test('[TEAMS]: check document visibility based on team member role', async ({ pa
await apiSignin({
page,
email: testCase.user.email,
redirectPath: `/t/${team.url}/documents?status=COMPLETED`,
redirectPath: testCase.path,
});
// Check that the user sees the expected documents

View File

@ -1,6 +1,6 @@
import { expect, test } from '@playwright/test';
import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { seedTeam, seedTeamEmailVerification } from '@documenso/prisma/seed/teams';
import { seedUser } from '@documenso/prisma/seed/users';
@ -43,7 +43,7 @@ test('[TEAMS]: accept team email request', async ({ page }) => {
teamId: team.id,
});
await page.goto(`${WEBAPP_BASE_URL}/team/verify/email/${teamEmailVerification.token}`);
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/team/verify/email/${teamEmailVerification.token}`);
await expect(page.getByRole('heading')).toContainText('Team email verified!');
});

View File

@ -1,6 +1,6 @@
import { expect, test } from '@playwright/test';
import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { seedTeam, seedTeamInvite } from '@documenso/prisma/seed/teams';
import { seedUser } from '@documenso/prisma/seed/users';
@ -33,7 +33,6 @@ test('[TEAMS]: update team member role', async ({ page }) => {
await page.getByLabel('Manager').click();
await page.getByRole('button', { name: 'Update' }).click();
// TODO: Remove me, but i don't care for now
await page.reload();
await expect(
@ -49,7 +48,7 @@ test('[TEAMS]: accept team invitation without account', async ({ page }) => {
teamId: team.id,
});
await page.goto(`${WEBAPP_BASE_URL}/team/invite/${teamInvite.token}`);
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/team/invite/${teamInvite.token}`);
await expect(page.getByRole('heading')).toContainText('Team invitation');
});
@ -62,7 +61,7 @@ test('[TEAMS]: accept team invitation with account', async ({ page }) => {
teamId: team.id,
});
await page.goto(`${WEBAPP_BASE_URL}/team/invite/${teamInvite.token}`);
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/team/invite/${teamInvite.token}`);
await expect(page.getByRole('heading')).toContainText('Invitation accepted!');
});

View File

@ -1,6 +1,6 @@
import { expect, test } from '@playwright/test';
import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { seedTeam, seedTeamTransfer } from '@documenso/prisma/seed/teams';
import { apiSignin } from '../fixtures/authentication';
@ -60,6 +60,6 @@ test.skip('[TEAMS]: accept team transfer', async ({ page }) => {
newOwnerUserId: newOwnerMember.userId,
});
await page.goto(`${WEBAPP_BASE_URL}/team/verify/transfer/${teamTransferRequest.token}`);
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/team/verify/transfer/${teamTransferRequest.token}`);
await expect(page.getByRole('heading')).toContainText('Team ownership transferred!');
});

View File

@ -1,7 +1,7 @@
import { expect, test } from '@playwright/test';
import { customAlphabet } from 'nanoid';
import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import {
DIRECT_TEMPLATE_RECIPIENT_EMAIL,
DIRECT_TEMPLATE_RECIPIENT_NAME,
@ -52,8 +52,8 @@ test('[DIRECT_TEMPLATES]: create direct link for template', async ({ page }) =>
});
const urls = [
`${WEBAPP_BASE_URL}/t/${team.url}/templates/${teamTemplate.id}`,
`${WEBAPP_BASE_URL}/templates/${personalTemplate.id}`,
`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates/${teamTemplate.id}`,
`${NEXT_PUBLIC_WEBAPP_URL()}/templates/${personalTemplate.id}`,
];
// Run test for personal and team templates.
@ -108,7 +108,7 @@ test('[DIRECT_TEMPLATES]: toggle direct template link', async ({ page }) => {
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
// Navigate to template settings and disable access.
await page.goto(`${WEBAPP_BASE_URL}${formatTemplatesPath(template.team?.url)}`);
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.getByRole('switch').click();
@ -117,7 +117,7 @@ test('[DIRECT_TEMPLATES]: toggle direct template link', async ({ page }) => {
// Check that the direct template link is no longer accessible.
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
await expect(page.getByText('Template not found')).toBeVisible();
await expect(page.getByText('404 not found')).toBeVisible();
}
});
@ -153,7 +153,7 @@ test('[DIRECT_TEMPLATES]: delete direct template link', async ({ page }) => {
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
// Navigate to template settings and delete the access.
await page.goto(`${WEBAPP_BASE_URL}${formatTemplatesPath(template.team?.url)}`);
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.getByRole('button', { name: 'Remove' }).click();
@ -162,7 +162,7 @@ test('[DIRECT_TEMPLATES]: delete direct template link', async ({ page }) => {
// Check that the direct template link is no longer accessible.
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
await expect(page.getByText('Template not found')).toBeVisible();
await expect(page.getByText('404 not found')).toBeVisible();
}
});
@ -241,7 +241,7 @@ test('[DIRECT_TEMPLATES]: use direct template link with 1 recipient', async ({ p
// Check that the owner has the documents.
for (const template of [personalDirectTemplate, teamDirectTemplate]) {
await page.goto(`${WEBAPP_BASE_URL}${formatDocumentsPath(template.team?.url)}`);
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}${formatDocumentsPath(template.team?.url)}`);
await expect(async () => {
// Check that the document is in the 'All' tab.
@ -314,7 +314,7 @@ test('[DIRECT_TEMPLATES]: use direct template link with 2 recipients', async ({
// Check that the owner has the documents.
for (const template of [personalDirectTemplate, teamDirectTemplate]) {
await page.goto(`${WEBAPP_BASE_URL}${formatDocumentsPath(template.team?.url)}`);
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}${formatDocumentsPath(template.team?.url)}`);
// Check that the document is in the 'All' tab.
await checkDocumentTabCount(page, 'All', 1);

View File

@ -1,6 +1,6 @@
import { expect, test } from '@playwright/test';
import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { seedTeam } from '@documenso/prisma/seed/teams';
import { seedTemplate } from '@documenso/prisma/seed/templates';
@ -42,13 +42,12 @@ test('[TEMPLATES]: view templates', async ({ page }) => {
redirectPath: '/templates',
});
// Owner should see both team templates.
await page.goto(`${WEBAPP_BASE_URL}/t/${team.url}/templates`);
await expect(page.getByRole('main')).toContainText('Showing 2 results');
// Only should only see their personal template.
await page.goto(`${WEBAPP_BASE_URL}/templates`);
await expect(page.getByRole('main')).toContainText('Showing 1 result');
await expect(page.getByTestId('data-table-count')).toContainText('Showing 1 result');
// Owner should see both team templates.
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates`);
await expect(page.getByTestId('data-table-count')).toContainText('Showing 2 results');
});
test('[TEMPLATES]: delete template', async ({ page }) => {
@ -92,7 +91,7 @@ test('[TEMPLATES]: delete template', async ({ page }) => {
await expect(page.getByText('Template deleted').first()).toBeVisible();
// Team member should be able to delete all templates.
await page.goto(`${WEBAPP_BASE_URL}/t/${team.url}/templates`);
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates`);
for (const template of ['Team template 1', 'Team template 2']) {
await page
@ -142,16 +141,16 @@ test('[TEMPLATES]: duplicate template', async ({ page }) => {
await page.getByRole('menuitem', { name: 'Duplicate' }).click();
await page.getByRole('button', { name: 'Duplicate' }).click();
await expect(page.getByText('Template duplicated').first()).toBeVisible();
await expect(page.getByRole('main')).toContainText('Showing 2 results');
await expect(page.getByTestId('data-table-count')).toContainText('Showing 2 results');
await page.goto(`${WEBAPP_BASE_URL}/t/${team.url}/templates`);
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates`);
// Duplicate team template.
await page.getByRole('cell', { name: 'Use Template' }).getByRole('button').nth(1).click();
await page.getByRole('menuitem', { name: 'Duplicate' }).click();
await page.getByRole('button', { name: 'Duplicate' }).click();
await expect(page.getByText('Template duplicated').first()).toBeVisible();
await expect(page.getByRole('main')).toContainText('Showing 2 results');
await expect(page.getByTestId('data-table-count')).toContainText('Showing 2 results');
});
test('[TEMPLATES]: use template', async ({ page }) => {
@ -194,9 +193,9 @@ test('[TEMPLATES]: use template', async ({ page }) => {
await page.waitForURL(/documents/);
await page.getByRole('main').getByRole('link', { name: 'Documents' }).click();
await page.waitForURL('/documents');
await expect(page.getByRole('main')).toContainText('Showing 1 result');
await expect(page.getByTestId('data-table-count')).toContainText('Showing 1 result');
await page.goto(`${WEBAPP_BASE_URL}/t/${team.url}/templates`);
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates`);
await page.waitForTimeout(1000);
// Use team template.
@ -212,5 +211,5 @@ test('[TEMPLATES]: use template', async ({ page }) => {
await page.waitForURL(/\/t\/.+\/documents/);
await page.getByRole('main').getByRole('link', { name: 'Documents' }).click();
await page.waitForURL(`/t/${team.url}/documents`);
await expect(page.getByRole('main')).toContainText('Showing 1 result');
await expect(page.getByTestId('data-table-count')).toContainText('Showing 1 result');
});

View File

@ -6,6 +6,8 @@ import {
seedUser,
} from '@documenso/prisma/seed/users';
import { signSignaturePad } from '../fixtures/signature';
test.use({ storageState: { cookies: [], origins: [] } });
test('[USER] can sign up with email and password', async ({ page }: { page: Page }) => {
@ -18,14 +20,7 @@ test('[USER] can sign up with email and password', async ({ page }: { page: Page
await page.getByLabel('Email').fill(email);
await page.getByLabel('Password', { exact: true }).fill(password);
const canvas = page.locator('canvas').first();
const box = await canvas.boundingBox();
if (box) {
await page.mouse.move(box.x + 40, box.y + 40);
await page.mouse.down();
await page.mouse.move(box.x + box.width - 2, box.y + box.height - 2);
await page.mouse.up();
}
await signSignaturePad(page);
await page.getByRole('button', { name: 'Next', exact: true }).click();
await page.getByLabel('Public profile username').fill(Date.now().toString());
@ -41,7 +36,7 @@ test('[USER] can sign up with email and password', async ({ page }: { page: Page
await expect(page.getByRole('heading')).toContainText('Email Confirmed!');
// We now automatically redirect to the home page
// await page.getByRole('link', { name: 'Go back home' }).click();
await page.getByRole('link', { name: 'Continue' }).click();
await page.waitForURL('/documents');

View File

@ -1,6 +1,6 @@
import { expect, test } from '@playwright/test';
import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { getUserByEmail } from '@documenso/lib/server-only/user/get-user-by-email';
import { seedUser } from '@documenso/prisma/seed/users';
@ -17,7 +17,7 @@ test('[USER] delete account', async ({ page }) => {
await expect(page.getByRole('button', { name: 'Confirm Deletion' })).not.toBeDisabled();
await page.getByRole('button', { name: 'Confirm Deletion' }).click();
await page.waitForURL(`${WEBAPP_BASE_URL}/signin`);
await page.waitForURL(`${NEXT_PUBLIC_WEBAPP_URL()}/signin`);
// Verify that the user no longer exists in the database
await expect(getUserByEmail({ email: user.email })).rejects.toThrow();

View File

@ -7,7 +7,7 @@
"scripts": {
"test:dev": "NODE_OPTIONS=--experimental-require-module playwright test",
"test-ui:dev": "NODE_OPTIONS=--experimental-require-module playwright test --ui",
"test:e2e": "NODE_OPTIONS=--experimental-require-module start-server-and-test \"npm run start -w @documenso/web\" http://localhost:3000 \"playwright test $E2E_TEST_PATH\""
"test:e2e": "NODE_OPTIONS=--experimental-require-module start-server-and-test \"npm run start -w @documenso/remix\" http://localhost:3000 \"playwright test $E2E_TEST_PATH\""
},
"keywords": [],
"author": "",
@ -16,7 +16,6 @@
"@types/node": "^20",
"@documenso/lib": "*",
"@documenso/prisma": "*",
"@documenso/web": "*",
"pdf-lib": "^1.17.1"
},
"dependencies": {