fix: refactor tests (#1066)
## Changes Made - Refactor/optimise tests - Reduce flakiness - Add parallel tests (if there's enough CPU capacity) - Removed explicit worker count when running parallel tests. Defaults to 50% of CPU capacity. Might want to consider sharding the test across runners in the future as our tests grows.
This commit is contained in:
54
packages/app-tests/e2e/command-menu/document-search.spec.ts
Normal file
54
packages/app-tests/e2e/command-menu/document-search.spec.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
|
import { seedPendingDocument } from '@documenso/prisma/seed/documents';
|
||||||
|
import { seedUser } from '@documenso/prisma/seed/users';
|
||||||
|
|
||||||
|
import { apiSignin } from '../fixtures/authentication';
|
||||||
|
|
||||||
|
test('[COMMAND_MENU]: should see sent documents', async ({ page }) => {
|
||||||
|
const user = await seedUser();
|
||||||
|
const recipient = await seedUser();
|
||||||
|
const document = await seedPendingDocument(user, [recipient]);
|
||||||
|
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: user.email,
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.keyboard.press('Meta+K');
|
||||||
|
|
||||||
|
await page.getByPlaceholder('Type a command or search...').first().fill(document.title);
|
||||||
|
await expect(page.getByRole('option', { name: document.title })).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[COMMAND_MENU]: should see received documents', async ({ page }) => {
|
||||||
|
const user = await seedUser();
|
||||||
|
const recipient = await seedUser();
|
||||||
|
const document = await seedPendingDocument(user, [recipient]);
|
||||||
|
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: recipient.email,
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.keyboard.press('Meta+K');
|
||||||
|
|
||||||
|
await page.getByPlaceholder('Type a command or search...').first().fill(document.title);
|
||||||
|
await expect(page.getByRole('option', { name: document.title })).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[COMMAND_MENU]: should be able to search by recipient', async ({ page }) => {
|
||||||
|
const user = await seedUser();
|
||||||
|
const recipient = await seedUser();
|
||||||
|
const document = await seedPendingDocument(user, [recipient]);
|
||||||
|
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: recipient.email,
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.keyboard.press('Meta+K');
|
||||||
|
|
||||||
|
await page.getByPlaceholder('Type a command or search...').first().fill(recipient.email);
|
||||||
|
await expect(page.getByRole('option', { name: document.title })).toBeVisible();
|
||||||
|
});
|
||||||
@@ -71,7 +71,6 @@ test('[DOCUMENT_AUTH]: should allow or deny access when required', async ({ page
|
|||||||
await apiSignin({
|
await apiSignin({
|
||||||
page,
|
page,
|
||||||
email: recipientWithAccount.email,
|
email: recipientWithAccount.email,
|
||||||
redirectPath: '/',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check that the one logged in is granted access.
|
// Check that the one logged in is granted access.
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { seedTestEmail, seedUser, unseedUser } from '@documenso/prisma/seed/user
|
|||||||
|
|
||||||
import { apiSignin, apiSignout } from '../fixtures/authentication';
|
import { apiSignin, apiSignout } from '../fixtures/authentication';
|
||||||
|
|
||||||
test.describe.configure({ mode: 'parallel' });
|
test.describe.configure({ mode: 'parallel', timeout: 60000 });
|
||||||
|
|
||||||
test('[DOCUMENT_AUTH]: should allow signing when no auth setup', async ({ page }) => {
|
test('[DOCUMENT_AUTH]: should allow signing when no auth setup', async ({ page }) => {
|
||||||
const user = await seedUser();
|
const user = await seedUser();
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ import path from 'node:path';
|
|||||||
import { getRecipientByEmail } from '@documenso/lib/server-only/recipient/get-recipient-by-email';
|
import { getRecipientByEmail } from '@documenso/lib/server-only/recipient/get-recipient-by-email';
|
||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
import { DocumentStatus } from '@documenso/prisma/client';
|
import { DocumentStatus } from '@documenso/prisma/client';
|
||||||
import { seedUser } from '@documenso/prisma/seed/users';
|
import { seedBlankDocument } from '@documenso/prisma/seed/documents';
|
||||||
|
import { seedUser, unseedUser } from '@documenso/prisma/seed/users';
|
||||||
|
|
||||||
import { apiSignin } from './fixtures/authentication';
|
import { apiSignin } from '../fixtures/authentication';
|
||||||
|
|
||||||
|
// Can't use the function in server-only/document due to it indirectly using
|
||||||
|
// require imports.
|
||||||
const getDocumentByToken = async (token: string) => {
|
const getDocumentByToken = async (token: string) => {
|
||||||
return await prisma.document.findFirstOrThrow({
|
return await prisma.document.findFirstOrThrow({
|
||||||
where: {
|
where: {
|
||||||
@@ -20,11 +23,7 @@ const getDocumentByToken = async (token: string) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
test(`[PR-718]: should be able to create a document`, async ({ page }) => {
|
test('[DOCUMENT_FLOW]: should be able to upload a PDF document', async ({ page }) => {
|
||||||
await page.goto('/signin');
|
|
||||||
|
|
||||||
const documentTitle = `example-${Date.now()}.pdf`;
|
|
||||||
|
|
||||||
const user = await seedUser();
|
const user = await seedUser();
|
||||||
|
|
||||||
await apiSignin({
|
await apiSignin({
|
||||||
@@ -32,7 +31,7 @@ test(`[PR-718]: should be able to create a document`, async ({ page }) => {
|
|||||||
email: user.email,
|
email: user.email,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Upload document
|
// Upload document.
|
||||||
const [fileChooser] = await Promise.all([
|
const [fileChooser] = await Promise.all([
|
||||||
page.waitForEvent('filechooser'),
|
page.waitForEvent('filechooser'),
|
||||||
page.locator('input[type=file]').evaluate((e) => {
|
page.locator('input[type=file]').evaluate((e) => {
|
||||||
@@ -42,10 +41,23 @@ test(`[PR-718]: should be able to create a document`, async ({ page }) => {
|
|||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await fileChooser.setFiles(path.join(__dirname, '../../../assets/example.pdf'));
|
await fileChooser.setFiles(path.join(__dirname, '../../../../assets/example.pdf'));
|
||||||
|
|
||||||
// Wait to be redirected to the edit page
|
// Wait to be redirected to the edit page.
|
||||||
await page.waitForURL(/\/documents\/\d+/);
|
await page.waitForURL(/\/documents\/\d+/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[DOCUMENT_FLOW]: should be able to create a document', async ({ page }) => {
|
||||||
|
const user = await seedUser();
|
||||||
|
const document = await seedBlankDocument(user);
|
||||||
|
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: user.email,
|
||||||
|
redirectPath: `/documents/${document.id}/edit`,
|
||||||
|
});
|
||||||
|
|
||||||
|
const documentTitle = `example-${Date.now()}.pdf`;
|
||||||
|
|
||||||
// Set general settings
|
// Set general settings
|
||||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||||
@@ -91,34 +103,23 @@ test(`[PR-718]: should be able to create a document`, async ({ page }) => {
|
|||||||
|
|
||||||
// Assert document was created
|
// Assert document was created
|
||||||
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();
|
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();
|
||||||
|
|
||||||
|
await unseedUser(user.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to create a document with multiple recipients', async ({ page }) => {
|
test('[DOCUMENT_FLOW]: should be able to create a document with multiple recipients', async ({
|
||||||
await page.goto('/signin');
|
page,
|
||||||
|
}) => {
|
||||||
const documentTitle = `example-${Date.now()}.pdf`;
|
|
||||||
|
|
||||||
const user = await seedUser();
|
const user = await seedUser();
|
||||||
|
const document = await seedBlankDocument(user);
|
||||||
|
|
||||||
await apiSignin({
|
await apiSignin({
|
||||||
page,
|
page,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
|
redirectPath: `/documents/${document.id}/edit`,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Upload document
|
const documentTitle = `example-${Date.now()}.pdf`;
|
||||||
const [fileChooser] = await Promise.all([
|
|
||||||
page.waitForEvent('filechooser'),
|
|
||||||
page.locator('input[type=file]').evaluate((e) => {
|
|
||||||
if (e instanceof HTMLInputElement) {
|
|
||||||
e.click();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
await fileChooser.setFiles(path.join(__dirname, '../../../assets/example.pdf'));
|
|
||||||
|
|
||||||
// Wait to be redirected to the edit page
|
|
||||||
await page.waitForURL(/\/documents\/\d+/);
|
|
||||||
|
|
||||||
// Set title
|
// Set title
|
||||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||||
@@ -187,34 +188,21 @@ test('should be able to create a document with multiple recipients', async ({ pa
|
|||||||
|
|
||||||
// Assert document was created
|
// Assert document was created
|
||||||
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();
|
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();
|
||||||
|
|
||||||
|
await unseedUser(user.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to create, send and sign a document', async ({ page }) => {
|
test('[DOCUMENT_FLOW]: should be able to create, send and sign a document', async ({ page }) => {
|
||||||
await page.goto('/signin');
|
|
||||||
|
|
||||||
const documentTitle = `example-${Date.now()}.pdf`;
|
|
||||||
|
|
||||||
const user = await seedUser();
|
const user = await seedUser();
|
||||||
|
const document = await seedBlankDocument(user);
|
||||||
|
|
||||||
await apiSignin({
|
await apiSignin({
|
||||||
page,
|
page,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
|
redirectPath: `/documents/${document.id}/edit`,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Upload document
|
const documentTitle = `example-${Date.now()}.pdf`;
|
||||||
const [fileChooser] = await Promise.all([
|
|
||||||
page.waitForEvent('filechooser'),
|
|
||||||
page.locator('input[type=file]').evaluate((e) => {
|
|
||||||
if (e instanceof HTMLInputElement) {
|
|
||||||
e.click();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
await fileChooser.setFiles(path.join(__dirname, '../../../assets/example.pdf'));
|
|
||||||
|
|
||||||
// Wait to be redirected to the edit page
|
|
||||||
await page.waitForURL(/\/documents\/\d+/);
|
|
||||||
|
|
||||||
// Set title
|
// Set title
|
||||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||||
@@ -271,36 +259,23 @@ test('should be able to create, send and sign a document', async ({ page }) => {
|
|||||||
// Check if document has been signed
|
// Check if document has been signed
|
||||||
const { status: completedStatus } = await getDocumentByToken(token);
|
const { status: completedStatus } = await getDocumentByToken(token);
|
||||||
expect(completedStatus).toBe(DocumentStatus.COMPLETED);
|
expect(completedStatus).toBe(DocumentStatus.COMPLETED);
|
||||||
|
|
||||||
|
await unseedUser(user.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to create, send with redirect url, sign a document and redirect to redirect url', async ({
|
test('[DOCUMENT_FLOW]: should be able to create, send with redirect url, sign a document and redirect to redirect url', async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
await page.goto('/signin');
|
|
||||||
|
|
||||||
const documentTitle = `example-${Date.now()}.pdf`;
|
|
||||||
|
|
||||||
const user = await seedUser();
|
const user = await seedUser();
|
||||||
|
const document = await seedBlankDocument(user);
|
||||||
|
|
||||||
await apiSignin({
|
await apiSignin({
|
||||||
page,
|
page,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
|
redirectPath: `/documents/${document.id}/edit`,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Upload document
|
const documentTitle = `example-${Date.now()}.pdf`;
|
||||||
const [fileChooser] = await Promise.all([
|
|
||||||
page.waitForEvent('filechooser'),
|
|
||||||
page.locator('input[type=file]').evaluate((e) => {
|
|
||||||
if (e instanceof HTMLInputElement) {
|
|
||||||
e.click();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
await fileChooser.setFiles(path.join(__dirname, '../../../assets/example.pdf'));
|
|
||||||
|
|
||||||
// Wait to be redirected to the edit page
|
|
||||||
await page.waitForURL(/\/documents\/\d+/);
|
|
||||||
|
|
||||||
// Set title & advanced redirect
|
// Set title & advanced redirect
|
||||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||||
@@ -355,4 +330,6 @@ test('should be able to create, send with redirect url, sign a document and redi
|
|||||||
// Check if document has been signed
|
// Check if document has been signed
|
||||||
const { status: completedStatus } = await getDocumentByToken(token);
|
const { status: completedStatus } = await getDocumentByToken(token);
|
||||||
expect(completedStatus).toBe(DocumentStatus.COMPLETED);
|
expect(completedStatus).toBe(DocumentStatus.COMPLETED);
|
||||||
|
|
||||||
|
await unseedUser(user.id);
|
||||||
});
|
});
|
||||||
172
packages/app-tests/e2e/documents/delete-documents.spec.ts
Normal file
172
packages/app-tests/e2e/documents/delete-documents.spec.ts
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
|
import {
|
||||||
|
seedCompletedDocument,
|
||||||
|
seedDraftDocument,
|
||||||
|
seedPendingDocument,
|
||||||
|
} from '@documenso/prisma/seed/documents';
|
||||||
|
import { seedUser } from '@documenso/prisma/seed/users';
|
||||||
|
|
||||||
|
import { apiSignin, apiSignout } from '../fixtures/authentication';
|
||||||
|
|
||||||
|
test.describe.configure({ mode: 'serial' });
|
||||||
|
|
||||||
|
const seedDeleteDocumentsTestRequirements = async () => {
|
||||||
|
const [sender, recipientA, recipientB] = await Promise.all([seedUser(), seedUser(), seedUser()]);
|
||||||
|
|
||||||
|
const [draftDocument, pendingDocument, completedDocument] = await Promise.all([
|
||||||
|
seedDraftDocument(sender, [recipientA, recipientB], {
|
||||||
|
createDocumentOptions: { title: 'Document 1 - Draft' },
|
||||||
|
}),
|
||||||
|
seedPendingDocument(sender, [recipientA, recipientB], {
|
||||||
|
createDocumentOptions: { title: 'Document 1 - Pending' },
|
||||||
|
}),
|
||||||
|
seedCompletedDocument(sender, [recipientA, recipientB], {
|
||||||
|
createDocumentOptions: { title: 'Document 1 - Completed' },
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
sender,
|
||||||
|
recipients: [recipientA, recipientB],
|
||||||
|
draftDocument,
|
||||||
|
pendingDocument,
|
||||||
|
completedDocument,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
test('[DOCUMENTS]: seeded documents should be visible', async ({ page }) => {
|
||||||
|
const { sender, recipients } = await seedDeleteDocumentsTestRequirements();
|
||||||
|
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: sender.email,
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(page.getByRole('link', { name: 'Document 1 - Completed' })).toBeVisible();
|
||||||
|
await expect(page.getByRole('link', { name: 'Document 1 - Pending' })).toBeVisible();
|
||||||
|
await expect(page.getByRole('link', { name: 'Document 1 - Draft' })).toBeVisible();
|
||||||
|
|
||||||
|
await apiSignout({ page });
|
||||||
|
|
||||||
|
for (const recipient of recipients) {
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: recipient.email,
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(page.getByRole('link', { name: 'Document 1 - Completed' })).toBeVisible();
|
||||||
|
await expect(page.getByRole('link', { name: 'Document 1 - Pending' })).toBeVisible();
|
||||||
|
|
||||||
|
await expect(page.getByRole('link', { name: 'Document 1 - Draft' })).not.toBeVisible();
|
||||||
|
|
||||||
|
await apiSignout({ page });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[DOCUMENTS]: deleting a completed document should not remove it from recipients', async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const { sender, recipients } = await seedDeleteDocumentsTestRequirements();
|
||||||
|
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: sender.email,
|
||||||
|
});
|
||||||
|
|
||||||
|
// open actions menu
|
||||||
|
await page
|
||||||
|
.locator('tr', { hasText: 'Document 1 - Completed' })
|
||||||
|
.getByRole('cell', { name: 'Download' })
|
||||||
|
.getByRole('button')
|
||||||
|
.nth(1)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
// delete document
|
||||||
|
await page.getByRole('menuitem', { name: 'Delete' }).click();
|
||||||
|
await page.getByPlaceholder("Type 'delete' to confirm").fill('delete');
|
||||||
|
await page.getByRole('button', { name: 'Delete' }).click();
|
||||||
|
|
||||||
|
await expect(page.getByRole('row', { name: /Document 1 - Completed/ })).not.toBeVisible();
|
||||||
|
|
||||||
|
await apiSignout({ page });
|
||||||
|
|
||||||
|
for (const recipient of recipients) {
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: recipient.email,
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(page.getByRole('link', { name: 'Document 1 - Completed' })).toBeVisible();
|
||||||
|
await page.getByRole('link', { name: 'Document 1 - Completed' }).click();
|
||||||
|
await expect(page.getByText('Everyone has signed').nth(0)).toBeVisible();
|
||||||
|
|
||||||
|
await apiSignout({ page });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[DOCUMENTS]: deleting a pending document should remove it from recipients', async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const { sender, pendingDocument } = await seedDeleteDocumentsTestRequirements();
|
||||||
|
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: sender.email,
|
||||||
|
});
|
||||||
|
|
||||||
|
// open actions menu
|
||||||
|
await page.locator('tr', { hasText: 'Document 1 - Pending' }).getByRole('button').nth(1).click();
|
||||||
|
|
||||||
|
// delete document
|
||||||
|
await page.getByRole('menuitem', { name: 'Delete' }).click();
|
||||||
|
await page.getByPlaceholder("Type 'delete' to confirm").fill('delete');
|
||||||
|
await page.getByRole('button', { name: 'Delete' }).click();
|
||||||
|
|
||||||
|
await expect(page.getByRole('row', { name: /Document 1 - Pending/ })).not.toBeVisible();
|
||||||
|
|
||||||
|
// signout
|
||||||
|
await apiSignout({ page });
|
||||||
|
|
||||||
|
for (const recipient of pendingDocument.Recipient) {
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: recipient.email,
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(page.getByRole('link', { name: 'Document 1 - Pending' })).not.toBeVisible();
|
||||||
|
|
||||||
|
await page.goto(`/sign/${recipient.token}`);
|
||||||
|
await expect(page.getByText(/document.*cancelled/i).nth(0)).toBeVisible();
|
||||||
|
|
||||||
|
await page.goto('/documents');
|
||||||
|
await page.waitForURL('/documents');
|
||||||
|
|
||||||
|
await apiSignout({ page });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[DOCUMENTS]: deleting a draft document should remove it without additional prompting', async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const { sender } = await seedDeleteDocumentsTestRequirements();
|
||||||
|
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: sender.email,
|
||||||
|
});
|
||||||
|
|
||||||
|
// open actions menu
|
||||||
|
await page
|
||||||
|
.locator('tr', { hasText: 'Document 1 - Draft' })
|
||||||
|
.getByRole('cell', { name: 'Edit' })
|
||||||
|
.getByRole('button')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
// delete document
|
||||||
|
await page.getByRole('menuitem', { name: 'Delete' }).click();
|
||||||
|
await expect(page.getByPlaceholder("Type 'delete' to confirm")).not.toBeVisible();
|
||||||
|
await page.getByRole('button', { name: 'Delete' }).click();
|
||||||
|
|
||||||
|
await expect(page.getByRole('row', { name: /Document 1 - Draft/ })).not.toBeVisible();
|
||||||
|
});
|
||||||
@@ -13,38 +13,11 @@ type LoginOptions = {
|
|||||||
redirectPath?: string;
|
redirectPath?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const manualLogin = async ({
|
|
||||||
page,
|
|
||||||
email = 'example@documenso.com',
|
|
||||||
password = 'password',
|
|
||||||
redirectPath,
|
|
||||||
}: LoginOptions) => {
|
|
||||||
await page.goto(`${WEBAPP_BASE_URL}/signin`);
|
|
||||||
|
|
||||||
await page.getByLabel('Email').click();
|
|
||||||
await page.getByLabel('Email').fill(email);
|
|
||||||
|
|
||||||
await page.getByLabel('Password', { exact: true }).fill(password);
|
|
||||||
await page.getByLabel('Password', { exact: true }).press('Enter');
|
|
||||||
|
|
||||||
if (redirectPath) {
|
|
||||||
await page.waitForURL(`${WEBAPP_BASE_URL}/documents`);
|
|
||||||
await page.goto(`${WEBAPP_BASE_URL}${redirectPath}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const manualSignout = async ({ page }: LoginOptions) => {
|
|
||||||
await page.waitForTimeout(1000);
|
|
||||||
await page.getByTestId('menu-switcher').click();
|
|
||||||
await page.getByRole('menuitem', { name: 'Sign Out' }).click();
|
|
||||||
await page.waitForURL(`${WEBAPP_BASE_URL}/signin`);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const apiSignin = async ({
|
export const apiSignin = async ({
|
||||||
page,
|
page,
|
||||||
email = 'example@documenso.com',
|
email = 'example@documenso.com',
|
||||||
password = 'password',
|
password = 'password',
|
||||||
redirectPath = '/',
|
redirectPath = '/documents',
|
||||||
}: LoginOptions) => {
|
}: LoginOptions) => {
|
||||||
const { request } = page.context();
|
const { request } = page.context();
|
||||||
|
|
||||||
@@ -59,9 +32,7 @@ export const apiSignin = async ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (redirectPath) {
|
await page.goto(`${WEBAPP_BASE_URL}${redirectPath}`);
|
||||||
await page.goto(`${WEBAPP_BASE_URL}${redirectPath}`);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const apiSignout = async ({ page }: { page: Page }) => {
|
export const apiSignout = async ({ page }: { page: Page }) => {
|
||||||
|
|||||||
@@ -1,159 +0,0 @@
|
|||||||
import { expect, test } from '@playwright/test';
|
|
||||||
|
|
||||||
import { TEST_USERS } from '@documenso/prisma/seed/pr-711-deletion-of-documents';
|
|
||||||
|
|
||||||
import { manualLogin, manualSignout } from './fixtures/authentication';
|
|
||||||
|
|
||||||
test.describe.configure({ mode: 'serial' });
|
|
||||||
|
|
||||||
test('[PR-711]: seeded documents should be visible', async ({ page }) => {
|
|
||||||
const [sender, ...recipients] = TEST_USERS;
|
|
||||||
|
|
||||||
await page.goto('/signin');
|
|
||||||
|
|
||||||
await page.getByLabel('Email').fill(sender.email);
|
|
||||||
await page.getByLabel('Password', { exact: true }).fill(sender.password);
|
|
||||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
|
||||||
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
|
|
||||||
await expect(page.getByRole('link', { name: 'Document 1 - Completed' })).toBeVisible();
|
|
||||||
await expect(page.getByRole('link', { name: 'Document 1 - Pending' })).toBeVisible();
|
|
||||||
await expect(page.getByRole('link', { name: 'Document 1 - Draft' })).toBeVisible();
|
|
||||||
|
|
||||||
await manualSignout({ page });
|
|
||||||
|
|
||||||
for (const recipient of recipients) {
|
|
||||||
await page.waitForURL('/signin');
|
|
||||||
await manualLogin({ page, email: recipient.email, password: recipient.password });
|
|
||||||
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
|
|
||||||
await expect(page.getByRole('link', { name: 'Document 1 - Completed' })).toBeVisible();
|
|
||||||
await expect(page.getByRole('link', { name: 'Document 1 - Pending' })).toBeVisible();
|
|
||||||
|
|
||||||
await expect(page.getByRole('link', { name: 'Document 1 - Draft' })).not.toBeVisible();
|
|
||||||
|
|
||||||
await manualSignout({ page });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('[PR-711]: deleting a completed document should not remove it from recipients', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const [sender, ...recipients] = TEST_USERS;
|
|
||||||
|
|
||||||
await page.goto('/signin');
|
|
||||||
|
|
||||||
// sign in
|
|
||||||
await page.getByLabel('Email').fill(sender.email);
|
|
||||||
await page.getByLabel('Password', { exact: true }).fill(sender.password);
|
|
||||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
|
||||||
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
|
|
||||||
// open actions menu
|
|
||||||
await page
|
|
||||||
.locator('tr', { hasText: 'Document 1 - Completed' })
|
|
||||||
.getByRole('cell', { name: 'Download' })
|
|
||||||
.getByRole('button')
|
|
||||||
.nth(1)
|
|
||||||
.click();
|
|
||||||
|
|
||||||
// delete document
|
|
||||||
await page.getByRole('menuitem', { name: 'Delete' }).click();
|
|
||||||
await page.getByPlaceholder("Type 'delete' to confirm").fill('delete');
|
|
||||||
await page.getByRole('button', { name: 'Delete' }).click();
|
|
||||||
|
|
||||||
await expect(page.getByRole('row', { name: /Document 1 - Completed/ })).not.toBeVisible();
|
|
||||||
|
|
||||||
await manualSignout({ page });
|
|
||||||
|
|
||||||
for (const recipient of recipients) {
|
|
||||||
await page.waitForURL('/signin');
|
|
||||||
await page.goto('/signin');
|
|
||||||
|
|
||||||
// sign in
|
|
||||||
await page.getByLabel('Email').fill(recipient.email);
|
|
||||||
await page.getByLabel('Password', { exact: true }).fill(recipient.password);
|
|
||||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
|
||||||
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
|
|
||||||
await expect(page.getByRole('link', { name: 'Document 1 - Completed' })).toBeVisible();
|
|
||||||
|
|
||||||
await page.goto(`/sign/completed-token-${recipients.indexOf(recipient)}`);
|
|
||||||
await expect(page.getByText('Everyone has signed').nth(0)).toBeVisible();
|
|
||||||
|
|
||||||
await page.goto('/documents');
|
|
||||||
await manualSignout({ page });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('[PR-711]: deleting a pending document should remove it from recipients', async ({ page }) => {
|
|
||||||
const [sender, ...recipients] = TEST_USERS;
|
|
||||||
|
|
||||||
for (const recipient of recipients) {
|
|
||||||
await page.goto(`/sign/pending-token-${recipients.indexOf(recipient)}`);
|
|
||||||
|
|
||||||
await expect(page.getByText('Waiting for others to sign').nth(0)).toBeVisible();
|
|
||||||
}
|
|
||||||
|
|
||||||
await page.goto('/signin');
|
|
||||||
|
|
||||||
await manualLogin({ page, email: sender.email, password: sender.password });
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
|
|
||||||
// open actions menu
|
|
||||||
await page.locator('tr', { hasText: 'Document 1 - Pending' }).getByRole('button').nth(1).click();
|
|
||||||
|
|
||||||
// delete document
|
|
||||||
await page.getByRole('menuitem', { name: 'Delete' }).click();
|
|
||||||
await page.getByPlaceholder("Type 'delete' to confirm").fill('delete');
|
|
||||||
await page.getByRole('button', { name: 'Delete' }).click();
|
|
||||||
|
|
||||||
await expect(page.getByRole('row', { name: /Document 1 - Pending/ })).not.toBeVisible();
|
|
||||||
|
|
||||||
// signout
|
|
||||||
await manualSignout({ page });
|
|
||||||
|
|
||||||
for (const recipient of recipients) {
|
|
||||||
await page.waitForURL('/signin');
|
|
||||||
|
|
||||||
await manualLogin({ page, email: recipient.email, password: recipient.password });
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
|
|
||||||
await expect(page.getByRole('link', { name: 'Document 1 - Pending' })).not.toBeVisible();
|
|
||||||
|
|
||||||
await page.goto(`/sign/pending-token-${recipients.indexOf(recipient)}`);
|
|
||||||
await expect(page.getByText(/document.*cancelled/i).nth(0)).toBeVisible();
|
|
||||||
|
|
||||||
await page.goto('/documents');
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
|
|
||||||
await manualSignout({ page });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('[PR-711]: deleting a draft document should remove it without additional prompting', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const [sender] = TEST_USERS;
|
|
||||||
|
|
||||||
await manualLogin({ page, email: sender.email, password: sender.password });
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
|
|
||||||
// open actions menu
|
|
||||||
await page
|
|
||||||
.locator('tr', { hasText: 'Document 1 - Draft' })
|
|
||||||
.getByRole('cell', { name: 'Edit' })
|
|
||||||
.getByRole('button')
|
|
||||||
.click();
|
|
||||||
|
|
||||||
// delete document
|
|
||||||
await page.getByRole('menuitem', { name: 'Delete' }).click();
|
|
||||||
await expect(page.getByPlaceholder("Type 'delete' to confirm")).not.toBeVisible();
|
|
||||||
await page.getByRole('button', { name: 'Delete' }).click();
|
|
||||||
|
|
||||||
await expect(page.getByRole('row', { name: /Document 1 - Draft/ })).not.toBeVisible();
|
|
||||||
});
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
import { expect, test } from '@playwright/test';
|
|
||||||
|
|
||||||
import { TEST_USERS } from '@documenso/prisma/seed/pr-713-add-document-search-to-command-menu';
|
|
||||||
|
|
||||||
test('[PR-713]: should see sent documents', async ({ page }) => {
|
|
||||||
const [user] = TEST_USERS;
|
|
||||||
|
|
||||||
await page.goto('/signin');
|
|
||||||
|
|
||||||
await page.getByLabel('Email').fill(user.email);
|
|
||||||
await page.getByLabel('Password', { exact: true }).fill(user.password);
|
|
||||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
|
||||||
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
|
|
||||||
await page.keyboard.press('Meta+K');
|
|
||||||
|
|
||||||
await page.getByPlaceholder('Type a command or search...').first().fill('sent');
|
|
||||||
await expect(page.getByRole('option', { name: '[713] Document - Sent' })).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('[PR-713]: should see received documents', async ({ page }) => {
|
|
||||||
const [user] = TEST_USERS;
|
|
||||||
|
|
||||||
await page.goto('/signin');
|
|
||||||
|
|
||||||
await page.getByLabel('Email').fill(user.email);
|
|
||||||
await page.getByLabel('Password', { exact: true }).fill(user.password);
|
|
||||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
|
||||||
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
|
|
||||||
await page.keyboard.press('Meta+K');
|
|
||||||
|
|
||||||
await page.getByPlaceholder('Type a command or search...').first().fill('received');
|
|
||||||
await expect(page.getByRole('option', { name: '[713] Document - Received' })).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('[PR-713]: should be able to search by recipient', async ({ page }) => {
|
|
||||||
const [user, recipient] = TEST_USERS;
|
|
||||||
|
|
||||||
await page.goto('/signin');
|
|
||||||
|
|
||||||
await page.getByLabel('Email').fill(user.email);
|
|
||||||
await page.getByLabel('Password', { exact: true }).fill(user.password);
|
|
||||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
|
||||||
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
|
|
||||||
await page.keyboard.press('Meta+K');
|
|
||||||
|
|
||||||
await page.getByPlaceholder('Type a command or search...').first().fill(recipient.email);
|
|
||||||
await expect(page.getByRole('option', { name: '[713] Document - Sent' })).toBeVisible();
|
|
||||||
});
|
|
||||||
@@ -11,6 +11,11 @@ test.describe.configure({ mode: 'parallel' });
|
|||||||
test('[TEAMS]: create team', async ({ page }) => {
|
test('[TEAMS]: create team', async ({ page }) => {
|
||||||
const user = await seedUser();
|
const user = await seedUser();
|
||||||
|
|
||||||
|
test.skip(
|
||||||
|
process.env.NEXT_PUBLIC_FEATURE_BILLING_ENABLED === 'true',
|
||||||
|
'Test skipped because billing is enabled.',
|
||||||
|
);
|
||||||
|
|
||||||
await apiSignin({
|
await apiSignin({
|
||||||
page,
|
page,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
@@ -26,9 +31,6 @@ test('[TEAMS]: create team', async ({ page }) => {
|
|||||||
|
|
||||||
await page.getByTestId('dialog-create-team-button').waitFor({ state: 'hidden' });
|
await page.getByTestId('dialog-create-team-button').waitFor({ state: 'hidden' });
|
||||||
|
|
||||||
const isCheckoutRequired = page.url().includes('pending');
|
|
||||||
test.skip(isCheckoutRequired, 'Test skipped because billing is enabled.');
|
|
||||||
|
|
||||||
// Goto new team settings page.
|
// Goto new team settings page.
|
||||||
await page.getByRole('row').filter({ hasText: teamId }).getByRole('link').nth(1).click();
|
await page.getByRole('row').filter({ hasText: teamId }).getByRole('link').nth(1).click();
|
||||||
|
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ test('[TEMPLATES]: delete template', async ({ page }) => {
|
|||||||
await page.getByRole('button', { name: 'Delete' }).click();
|
await page.getByRole('button', { name: 'Delete' }).click();
|
||||||
await expect(page.getByText('Template deleted').first()).toBeVisible();
|
await expect(page.getByText('Template deleted').first()).toBeVisible();
|
||||||
|
|
||||||
await page.waitForTimeout(1000);
|
await page.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
await unseedTeam(team.url);
|
await unseedTeam(team.url);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { type Page, expect, test } from '@playwright/test';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
extractUserVerificationToken,
|
extractUserVerificationToken,
|
||||||
|
seedTestEmail,
|
||||||
seedUser,
|
seedUser,
|
||||||
unseedUser,
|
unseedUser,
|
||||||
unseedUserByEmail,
|
unseedUserByEmail,
|
||||||
@@ -9,9 +10,9 @@ import {
|
|||||||
|
|
||||||
test.use({ storageState: { cookies: [], origins: [] } });
|
test.use({ storageState: { cookies: [], origins: [] } });
|
||||||
|
|
||||||
test('user can sign up with email and password', async ({ page }: { page: Page }) => {
|
test('[USER] can sign up with email and password', async ({ page }: { page: Page }) => {
|
||||||
const username = 'Test User';
|
const username = 'Test User';
|
||||||
const email = `test-user-${Date.now()}@auth-flow.documenso.com`;
|
const email = seedTestEmail();
|
||||||
const password = 'Password123#';
|
const password = 'Password123#';
|
||||||
|
|
||||||
await page.goto('/signup');
|
await page.goto('/signup');
|
||||||
@@ -50,7 +51,7 @@ test('user can sign up with email and password', async ({ page }: { page: Page }
|
|||||||
await unseedUserByEmail(email);
|
await unseedUserByEmail(email);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('user can login with user and password', async ({ page }: { page: Page }) => {
|
test('[USER] can sign in using email and password', async ({ page }: { page: Page }) => {
|
||||||
const user = await seedUser();
|
const user = await seedUser();
|
||||||
|
|
||||||
await page.goto('/signin');
|
await page.goto('/signin');
|
||||||
@@ -4,19 +4,16 @@ import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
|
|||||||
import { getUserByEmail } from '@documenso/lib/server-only/user/get-user-by-email';
|
import { getUserByEmail } from '@documenso/lib/server-only/user/get-user-by-email';
|
||||||
import { seedUser } from '@documenso/prisma/seed/users';
|
import { seedUser } from '@documenso/prisma/seed/users';
|
||||||
|
|
||||||
import { manualLogin } from './fixtures/authentication';
|
import { apiSignin } from '../fixtures/authentication';
|
||||||
|
|
||||||
test('delete user', async ({ page }) => {
|
test('[USER] delete account', async ({ page }) => {
|
||||||
const user = await seedUser();
|
const user = await seedUser();
|
||||||
|
|
||||||
await manualLogin({
|
await apiSignin({ page, email: user.email, redirectPath: '/settings' });
|
||||||
page,
|
|
||||||
email: user.email,
|
|
||||||
redirectPath: '/settings',
|
|
||||||
});
|
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Delete Account' }).click();
|
await page.getByRole('button', { name: 'Delete Account' }).click();
|
||||||
await page.getByLabel('Confirm Email').fill(user.email);
|
await page.getByLabel('Confirm Email').fill(user.email);
|
||||||
|
|
||||||
await expect(page.getByRole('button', { name: 'Confirm Deletion' })).not.toBeDisabled();
|
await expect(page.getByRole('button', { name: 'Confirm Deletion' })).not.toBeDisabled();
|
||||||
await page.getByRole('button', { name: 'Confirm Deletion' }).click();
|
await page.getByRole('button', { name: 'Confirm Deletion' }).click();
|
||||||
|
|
||||||
@@ -3,16 +3,12 @@ import { expect, test } from '@playwright/test';
|
|||||||
import { getUserByEmail } from '@documenso/lib/server-only/user/get-user-by-email';
|
import { getUserByEmail } from '@documenso/lib/server-only/user/get-user-by-email';
|
||||||
import { seedUser } from '@documenso/prisma/seed/users';
|
import { seedUser } from '@documenso/prisma/seed/users';
|
||||||
|
|
||||||
import { manualLogin } from './fixtures/authentication';
|
import { apiSignin } from '../fixtures/authentication';
|
||||||
|
|
||||||
test('update user name', async ({ page }) => {
|
test('[USER] update full name', async ({ page }) => {
|
||||||
const user = await seedUser();
|
const user = await seedUser();
|
||||||
|
|
||||||
await manualLogin({
|
await apiSignin({ page, email: user.email, redirectPath: '/settings/profile' });
|
||||||
page,
|
|
||||||
email: user.email,
|
|
||||||
redirectPath: '/settings/profile',
|
|
||||||
});
|
|
||||||
|
|
||||||
await page.getByLabel('Full Name').fill('John Doe');
|
await page.getByLabel('Full Name').fill('John Doe');
|
||||||
|
|
||||||
@@ -17,12 +17,11 @@ export default defineConfig({
|
|||||||
testDir: './e2e',
|
testDir: './e2e',
|
||||||
/* Run tests in files in parallel */
|
/* Run tests in files in parallel */
|
||||||
fullyParallel: true,
|
fullyParallel: true,
|
||||||
|
workers: '50%',
|
||||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
forbidOnly: !!process.env.CI,
|
forbidOnly: !!process.env.CI,
|
||||||
/* Retry on CI only */
|
/* Retry on CI only */
|
||||||
retries: process.env.CI ? 2 : 0,
|
retries: process.env.CI ? 2 : 1,
|
||||||
/* Opt out of parallel tests on CI. */
|
|
||||||
workers: process.env.CI ? 1 : undefined,
|
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: 'html',
|
reporter: 'html',
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
|||||||
@@ -213,7 +213,14 @@ export const seedPendingDocument = async (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return document;
|
return prisma.document.findFirstOrThrow({
|
||||||
|
where: {
|
||||||
|
id: document.id,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
Recipient: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const seedPendingDocumentNoFields = async ({
|
export const seedPendingDocumentNoFields = async ({
|
||||||
|
|||||||
@@ -1,223 +0,0 @@
|
|||||||
import type { User } from '@prisma/client';
|
|
||||||
import fs from 'node:fs';
|
|
||||||
import path from 'node:path';
|
|
||||||
|
|
||||||
import { hashSync } from '@documenso/lib/server-only/auth/hash';
|
|
||||||
|
|
||||||
import { prisma } from '..';
|
|
||||||
import {
|
|
||||||
DocumentDataType,
|
|
||||||
DocumentStatus,
|
|
||||||
FieldType,
|
|
||||||
Prisma,
|
|
||||||
ReadStatus,
|
|
||||||
SendStatus,
|
|
||||||
SigningStatus,
|
|
||||||
} from '../client';
|
|
||||||
|
|
||||||
const PULL_REQUEST_NUMBER = 711;
|
|
||||||
const EMAIL_DOMAIN = `pr-${PULL_REQUEST_NUMBER}.documenso.com`;
|
|
||||||
|
|
||||||
export const TEST_USERS = [
|
|
||||||
{
|
|
||||||
name: 'Sender 1',
|
|
||||||
email: `sender1@${EMAIL_DOMAIN}`,
|
|
||||||
password: 'Password123',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Sender 2',
|
|
||||||
email: `sender2@${EMAIL_DOMAIN}`,
|
|
||||||
password: 'Password123',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Sender 3',
|
|
||||||
email: `sender3@${EMAIL_DOMAIN}`,
|
|
||||||
password: 'Password123',
|
|
||||||
},
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
const examplePdf = fs
|
|
||||||
.readFileSync(path.join(__dirname, '../../../assets/example.pdf'))
|
|
||||||
.toString('base64');
|
|
||||||
|
|
||||||
export const seedDatabase = async () => {
|
|
||||||
const users = await Promise.all(
|
|
||||||
TEST_USERS.map(async (u) =>
|
|
||||||
prisma.user.create({
|
|
||||||
data: {
|
|
||||||
name: u.name,
|
|
||||||
email: u.email,
|
|
||||||
password: hashSync(u.password),
|
|
||||||
emailVerified: new Date(),
|
|
||||||
url: u.email,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
const [user1, user2, user3] = users;
|
|
||||||
|
|
||||||
await createDraftDocument(user1, [user2, user3]);
|
|
||||||
await createPendingDocument(user1, [user2, user3]);
|
|
||||||
await createCompletedDocument(user1, [user2, user3]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const createDraftDocument = async (sender: User, recipients: User[]) => {
|
|
||||||
const documentData = await prisma.documentData.create({
|
|
||||||
data: {
|
|
||||||
type: DocumentDataType.BYTES_64,
|
|
||||||
data: examplePdf,
|
|
||||||
initialData: examplePdf,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const document = await prisma.document.create({
|
|
||||||
data: {
|
|
||||||
title: `[${PULL_REQUEST_NUMBER}] Document 1 - Draft`,
|
|
||||||
status: DocumentStatus.DRAFT,
|
|
||||||
documentDataId: documentData.id,
|
|
||||||
userId: sender.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const recipient of recipients) {
|
|
||||||
const index = recipients.indexOf(recipient);
|
|
||||||
|
|
||||||
await prisma.recipient.create({
|
|
||||||
data: {
|
|
||||||
email: String(recipient.email),
|
|
||||||
name: String(recipient.name),
|
|
||||||
token: `draft-token-${index}`,
|
|
||||||
readStatus: ReadStatus.NOT_OPENED,
|
|
||||||
sendStatus: SendStatus.NOT_SENT,
|
|
||||||
signingStatus: SigningStatus.NOT_SIGNED,
|
|
||||||
signedAt: new Date(),
|
|
||||||
Document: {
|
|
||||||
connect: {
|
|
||||||
id: document.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Field: {
|
|
||||||
create: {
|
|
||||||
page: 1,
|
|
||||||
type: FieldType.NAME,
|
|
||||||
inserted: true,
|
|
||||||
customText: String(recipient.name),
|
|
||||||
positionX: new Prisma.Decimal(1),
|
|
||||||
positionY: new Prisma.Decimal(1),
|
|
||||||
width: new Prisma.Decimal(1),
|
|
||||||
height: new Prisma.Decimal(1),
|
|
||||||
documentId: document.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const createPendingDocument = async (sender: User, recipients: User[]) => {
|
|
||||||
const documentData = await prisma.documentData.create({
|
|
||||||
data: {
|
|
||||||
type: DocumentDataType.BYTES_64,
|
|
||||||
data: examplePdf,
|
|
||||||
initialData: examplePdf,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const document = await prisma.document.create({
|
|
||||||
data: {
|
|
||||||
title: `[${PULL_REQUEST_NUMBER}] Document 1 - Pending`,
|
|
||||||
status: DocumentStatus.PENDING,
|
|
||||||
documentDataId: documentData.id,
|
|
||||||
userId: sender.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const recipient of recipients) {
|
|
||||||
const index = recipients.indexOf(recipient);
|
|
||||||
|
|
||||||
await prisma.recipient.create({
|
|
||||||
data: {
|
|
||||||
email: String(recipient.email),
|
|
||||||
name: String(recipient.name),
|
|
||||||
token: `pending-token-${index}`,
|
|
||||||
readStatus: ReadStatus.OPENED,
|
|
||||||
sendStatus: SendStatus.SENT,
|
|
||||||
signingStatus: SigningStatus.SIGNED,
|
|
||||||
signedAt: new Date(),
|
|
||||||
Document: {
|
|
||||||
connect: {
|
|
||||||
id: document.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Field: {
|
|
||||||
create: {
|
|
||||||
page: 1,
|
|
||||||
type: FieldType.NAME,
|
|
||||||
inserted: true,
|
|
||||||
customText: String(recipient.name),
|
|
||||||
positionX: new Prisma.Decimal(1),
|
|
||||||
positionY: new Prisma.Decimal(1),
|
|
||||||
width: new Prisma.Decimal(1),
|
|
||||||
height: new Prisma.Decimal(1),
|
|
||||||
documentId: document.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const createCompletedDocument = async (sender: User, recipients: User[]) => {
|
|
||||||
const documentData = await prisma.documentData.create({
|
|
||||||
data: {
|
|
||||||
type: DocumentDataType.BYTES_64,
|
|
||||||
data: examplePdf,
|
|
||||||
initialData: examplePdf,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const document = await prisma.document.create({
|
|
||||||
data: {
|
|
||||||
title: `[${PULL_REQUEST_NUMBER}] Document 1 - Completed`,
|
|
||||||
status: DocumentStatus.COMPLETED,
|
|
||||||
documentDataId: documentData.id,
|
|
||||||
completedAt: new Date(),
|
|
||||||
userId: sender.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const recipient of recipients) {
|
|
||||||
const index = recipients.indexOf(recipient);
|
|
||||||
|
|
||||||
await prisma.recipient.create({
|
|
||||||
data: {
|
|
||||||
email: String(recipient.email),
|
|
||||||
name: String(recipient.name),
|
|
||||||
token: `completed-token-${index}`,
|
|
||||||
readStatus: ReadStatus.OPENED,
|
|
||||||
sendStatus: SendStatus.SENT,
|
|
||||||
signingStatus: SigningStatus.SIGNED,
|
|
||||||
signedAt: new Date(),
|
|
||||||
Document: {
|
|
||||||
connect: {
|
|
||||||
id: document.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Field: {
|
|
||||||
create: {
|
|
||||||
page: 1,
|
|
||||||
type: FieldType.NAME,
|
|
||||||
inserted: true,
|
|
||||||
customText: String(recipient.name),
|
|
||||||
positionX: new Prisma.Decimal(1),
|
|
||||||
positionY: new Prisma.Decimal(1),
|
|
||||||
width: new Prisma.Decimal(1),
|
|
||||||
height: new Prisma.Decimal(1),
|
|
||||||
documentId: document.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
import type { User } from '@prisma/client';
|
|
||||||
import fs from 'node:fs';
|
|
||||||
import path from 'node:path';
|
|
||||||
|
|
||||||
import { hashSync } from '@documenso/lib/server-only/auth/hash';
|
|
||||||
|
|
||||||
import { prisma } from '..';
|
|
||||||
import {
|
|
||||||
DocumentDataType,
|
|
||||||
DocumentStatus,
|
|
||||||
FieldType,
|
|
||||||
Prisma,
|
|
||||||
ReadStatus,
|
|
||||||
SendStatus,
|
|
||||||
SigningStatus,
|
|
||||||
} from '../client';
|
|
||||||
|
|
||||||
//
|
|
||||||
// https://github.com/documenso/documenso/pull/713
|
|
||||||
//
|
|
||||||
|
|
||||||
const PULL_REQUEST_NUMBER = 713;
|
|
||||||
|
|
||||||
const EMAIL_DOMAIN = `pr-${PULL_REQUEST_NUMBER}.documenso.com`;
|
|
||||||
|
|
||||||
export const TEST_USERS = [
|
|
||||||
{
|
|
||||||
name: 'User 1',
|
|
||||||
email: `user1@${EMAIL_DOMAIN}`,
|
|
||||||
password: 'Password123',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'User 2',
|
|
||||||
email: `user2@${EMAIL_DOMAIN}`,
|
|
||||||
password: 'Password123',
|
|
||||||
},
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
const examplePdf = fs
|
|
||||||
.readFileSync(path.join(__dirname, '../../../assets/example.pdf'))
|
|
||||||
.toString('base64');
|
|
||||||
|
|
||||||
export const seedDatabase = async () => {
|
|
||||||
const users = await Promise.all(
|
|
||||||
TEST_USERS.map(async (u) =>
|
|
||||||
prisma.user.create({
|
|
||||||
data: {
|
|
||||||
name: u.name,
|
|
||||||
email: u.email,
|
|
||||||
password: hashSync(u.password),
|
|
||||||
emailVerified: new Date(),
|
|
||||||
url: u.email,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
const [user1, user2] = users;
|
|
||||||
|
|
||||||
await createSentDocument(user1, [user2]);
|
|
||||||
await createReceivedDocument(user2, [user1]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const createSentDocument = async (sender: User, recipients: User[]) => {
|
|
||||||
const documentData = await prisma.documentData.create({
|
|
||||||
data: {
|
|
||||||
type: DocumentDataType.BYTES_64,
|
|
||||||
data: examplePdf,
|
|
||||||
initialData: examplePdf,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const document = await prisma.document.create({
|
|
||||||
data: {
|
|
||||||
title: `[${PULL_REQUEST_NUMBER}] Document - Sent`,
|
|
||||||
status: DocumentStatus.PENDING,
|
|
||||||
documentDataId: documentData.id,
|
|
||||||
userId: sender.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const recipient of recipients) {
|
|
||||||
const index = recipients.indexOf(recipient);
|
|
||||||
|
|
||||||
await prisma.recipient.create({
|
|
||||||
data: {
|
|
||||||
email: String(recipient.email),
|
|
||||||
name: String(recipient.name),
|
|
||||||
token: `sent-token-${index}`,
|
|
||||||
readStatus: ReadStatus.NOT_OPENED,
|
|
||||||
sendStatus: SendStatus.SENT,
|
|
||||||
signingStatus: SigningStatus.NOT_SIGNED,
|
|
||||||
signedAt: new Date(),
|
|
||||||
Document: {
|
|
||||||
connect: {
|
|
||||||
id: document.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Field: {
|
|
||||||
create: {
|
|
||||||
page: 1,
|
|
||||||
type: FieldType.NAME,
|
|
||||||
inserted: true,
|
|
||||||
customText: String(recipient.name),
|
|
||||||
positionX: new Prisma.Decimal(1),
|
|
||||||
positionY: new Prisma.Decimal(1),
|
|
||||||
width: new Prisma.Decimal(1),
|
|
||||||
height: new Prisma.Decimal(1),
|
|
||||||
documentId: document.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const createReceivedDocument = async (sender: User, recipients: User[]) => {
|
|
||||||
const documentData = await prisma.documentData.create({
|
|
||||||
data: {
|
|
||||||
type: DocumentDataType.BYTES_64,
|
|
||||||
data: examplePdf,
|
|
||||||
initialData: examplePdf,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const document = await prisma.document.create({
|
|
||||||
data: {
|
|
||||||
title: `[${PULL_REQUEST_NUMBER}] Document - Received`,
|
|
||||||
status: DocumentStatus.PENDING,
|
|
||||||
documentDataId: documentData.id,
|
|
||||||
userId: sender.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const recipient of recipients) {
|
|
||||||
const index = recipients.indexOf(recipient);
|
|
||||||
|
|
||||||
await prisma.recipient.create({
|
|
||||||
data: {
|
|
||||||
email: String(recipient.email),
|
|
||||||
name: String(recipient.name),
|
|
||||||
token: `received-token-${index}`,
|
|
||||||
readStatus: ReadStatus.NOT_OPENED,
|
|
||||||
sendStatus: SendStatus.SENT,
|
|
||||||
signingStatus: SigningStatus.NOT_SIGNED,
|
|
||||||
signedAt: new Date(),
|
|
||||||
Document: {
|
|
||||||
connect: {
|
|
||||||
id: document.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Field: {
|
|
||||||
create: {
|
|
||||||
page: 1,
|
|
||||||
type: FieldType.NAME,
|
|
||||||
inserted: true,
|
|
||||||
customText: String(recipient.name),
|
|
||||||
positionX: new Prisma.Decimal(1),
|
|
||||||
positionY: new Prisma.Decimal(1),
|
|
||||||
width: new Prisma.Decimal(1),
|
|
||||||
height: new Prisma.Decimal(1),
|
|
||||||
documentId: document.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
|
import { customAlphabet } from 'nanoid';
|
||||||
|
|
||||||
import { prisma } from '..';
|
import { prisma } from '..';
|
||||||
import { TeamMemberInviteStatus, TeamMemberRole } from '../client';
|
import { TeamMemberInviteStatus, TeamMemberRole } from '../client';
|
||||||
import { seedUser } from './users';
|
import { seedUser } from './users';
|
||||||
|
|
||||||
const EMAIL_DOMAIN = `test.documenso.com`;
|
const EMAIL_DOMAIN = `test.documenso.com`;
|
||||||
|
const nanoid = customAlphabet('1234567890abcdef', 10);
|
||||||
|
|
||||||
type SeedTeamOptions = {
|
type SeedTeamOptions = {
|
||||||
createTeamMembers?: number;
|
createTeamMembers?: number;
|
||||||
@@ -13,7 +16,7 @@ export const seedTeam = async ({
|
|||||||
createTeamMembers = 0,
|
createTeamMembers = 0,
|
||||||
createTeamEmail,
|
createTeamEmail,
|
||||||
}: SeedTeamOptions = {}) => {
|
}: SeedTeamOptions = {}) => {
|
||||||
const teamUrl = `team-${Date.now()}`;
|
const teamUrl = `team-${nanoid()}`;
|
||||||
const teamEmail = createTeamEmail === true ? `${teamUrl}@${EMAIL_DOMAIN}` : createTeamEmail;
|
const teamEmail = createTeamEmail === true ? `${teamUrl}@${EMAIL_DOMAIN}` : createTeamEmail;
|
||||||
|
|
||||||
const teamOwner = await seedUser({
|
const teamOwner = await seedUser({
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { customAlphabet } from 'nanoid';
|
||||||
|
|
||||||
import { hashSync } from '@documenso/lib/server-only/auth/hash';
|
import { hashSync } from '@documenso/lib/server-only/auth/hash';
|
||||||
|
|
||||||
import { prisma } from '..';
|
import { prisma } from '..';
|
||||||
@@ -11,12 +13,22 @@ type SeedUserOptions = {
|
|||||||
verified?: boolean;
|
verified?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const nanoid = customAlphabet('1234567890abcdef', 10);
|
||||||
|
|
||||||
export const seedUser = async ({
|
export const seedUser = async ({
|
||||||
name = `user-${Date.now()}`,
|
name,
|
||||||
email = `user-${Date.now()}@test.documenso.com`,
|
email,
|
||||||
password = 'password',
|
password = 'password',
|
||||||
verified = true,
|
verified = true,
|
||||||
}: SeedUserOptions = {}) => {
|
}: SeedUserOptions = {}) => {
|
||||||
|
if (!name) {
|
||||||
|
name = nanoid();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!email) {
|
||||||
|
email = `${nanoid()}@test.documenso.com`;
|
||||||
|
}
|
||||||
|
|
||||||
return await prisma.user.create({
|
return await prisma.user.create({
|
||||||
data: {
|
data: {
|
||||||
name,
|
name,
|
||||||
|
|||||||
Reference in New Issue
Block a user