mirror of
https://github.com/documenso/documenso.git
synced 2025-11-12 15:53:02 +10:00
feat: add organisations (#1820)
This commit is contained in:
@ -5,15 +5,12 @@ import path from 'path';
|
||||
|
||||
import { extractDocumentAuthMethods } from '@documenso/lib/utils/document-auth';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { seedUserSubscription } from '@documenso/prisma/seed/subscriptions';
|
||||
import { seedTeam } from '@documenso/prisma/seed/teams';
|
||||
import { seedTeam, seedTeamMember } from '@documenso/prisma/seed/teams';
|
||||
import { seedBlankTemplate } from '@documenso/prisma/seed/templates';
|
||||
import { seedUser } from '@documenso/prisma/seed/users';
|
||||
|
||||
import { apiSignin } from '../fixtures/authentication';
|
||||
|
||||
const enterprisePriceId = '';
|
||||
|
||||
const EXAMPLE_PDF_PATH = path.join(__dirname, '../../../../assets/example.pdf');
|
||||
|
||||
/**
|
||||
@ -26,21 +23,13 @@ const EXAMPLE_PDF_PATH = path.join(__dirname, '../../../../assets/example.pdf');
|
||||
* If you update this test please update that test as well.
|
||||
*/
|
||||
test('[TEMPLATE]: should create a document from a template', async ({ page }) => {
|
||||
const user = await seedUser();
|
||||
const template = await seedBlankTemplate(user);
|
||||
|
||||
const isBillingEnabled =
|
||||
process.env.NEXT_PUBLIC_FEATURE_BILLING_ENABLED === 'true' && enterprisePriceId;
|
||||
|
||||
await seedUserSubscription({
|
||||
userId: user.id,
|
||||
priceId: enterprisePriceId,
|
||||
});
|
||||
const { user, team } = await seedUser();
|
||||
const template = await seedBlankTemplate(user, team.id);
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: user.email,
|
||||
redirectPath: `/templates/${template.id}/edit`,
|
||||
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
|
||||
});
|
||||
|
||||
// Set template title.
|
||||
@ -51,13 +40,6 @@ test('[TEMPLATE]: should create a document from a template', async ({ page }) =>
|
||||
await page.getByRole('option').filter({ hasText: 'Require account' }).click();
|
||||
await expect(page.getByTestId('documentAccessSelectValue')).toContainText('Require account');
|
||||
|
||||
// Set EE action auth.
|
||||
if (isBillingEnabled) {
|
||||
await page.getByTestId('documentActionSelectValue').click();
|
||||
await page.getByRole('option').filter({ hasText: 'Require passkey' }).click();
|
||||
await expect(page.getByTestId('documentActionSelectValue')).toContainText('Require passkey');
|
||||
}
|
||||
|
||||
// Set email options.
|
||||
await page.getByRole('button', { name: 'Email Options' }).click();
|
||||
await page.getByLabel('Subject (Optional)').fill('SUBJECT');
|
||||
@ -82,25 +64,18 @@ test('[TEMPLATE]: should create a document from a template', async ({ page }) =>
|
||||
await page.getByPlaceholder('Email').nth(1).fill('recipient2@documenso.com');
|
||||
await page.getByPlaceholder('Name').nth(1).fill('Recipient 2');
|
||||
|
||||
// Apply require passkey for Recipient 1.
|
||||
if (isBillingEnabled) {
|
||||
await page.getByLabel('Show advanced settings').check();
|
||||
await page.getByTestId('documentActionSelectValue').click();
|
||||
await page.getByRole('option').filter({ hasText: 'Require passkey' }).click();
|
||||
}
|
||||
|
||||
await page.getByRole('button', { name: 'Continue' }).click();
|
||||
await expect(page.getByRole('heading', { name: 'Add Fields' })).toBeVisible();
|
||||
|
||||
await page.getByRole('button', { name: 'Save template' }).click();
|
||||
|
||||
// Use template
|
||||
await page.waitForURL('/templates');
|
||||
await page.waitForURL(`/t/${team.url}/templates`);
|
||||
await page.getByRole('button', { name: 'Use Template' }).click();
|
||||
await page.getByRole('button', { name: 'Create as draft' }).click();
|
||||
|
||||
// Review that the document was created with the correct values.
|
||||
await page.waitForURL(/documents/);
|
||||
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
|
||||
|
||||
const documentId = Number(page.url().split('/').pop());
|
||||
|
||||
@ -121,10 +96,6 @@ test('[TEMPLATE]: should create a document from a template', async ({ page }) =>
|
||||
expect(document.title).toEqual('TEMPLATE_TITLE');
|
||||
expect(documentAuth.documentAuthOption.globalAccessAuth).toContain('ACCOUNT');
|
||||
|
||||
if (isBillingEnabled) {
|
||||
expect(documentAuth.documentAuthOption.globalActionAuth).toContain('PASSKEY');
|
||||
}
|
||||
|
||||
expect(document.documentMeta?.dateFormat).toEqual('dd/MM/yyyy hh:mm a');
|
||||
expect(document.documentMeta?.message).toEqual('MESSAGE');
|
||||
expect(document.documentMeta?.redirectUrl).toEqual('https://documenso.com');
|
||||
@ -144,10 +115,6 @@ test('[TEMPLATE]: should create a document from a template', async ({ page }) =>
|
||||
recipientAuth: recipientTwo.authOptions,
|
||||
});
|
||||
|
||||
if (isBillingEnabled) {
|
||||
expect(recipientOneAuth.derivedRecipientActionAuth).toContain('PASSKEY');
|
||||
}
|
||||
|
||||
expect(recipientOneAuth.derivedRecipientAccessAuth).toContain('ACCOUNT');
|
||||
expect(recipientTwoAuth.derivedRecipientAccessAuth).toContain('ACCOUNT');
|
||||
});
|
||||
@ -156,23 +123,11 @@ test('[TEMPLATE]: should create a document from a template', async ({ page }) =>
|
||||
* This is a direct copy paste of the above test but for teams.
|
||||
*/
|
||||
test('[TEMPLATE]: should create a team document from a team template', async ({ page }) => {
|
||||
const { owner, ...team } = await seedTeam({
|
||||
const { team, owner, organisation } = await seedTeam({
|
||||
createTeamMembers: 2,
|
||||
});
|
||||
|
||||
const template = await seedBlankTemplate(owner, {
|
||||
createTemplateOptions: {
|
||||
teamId: team.id,
|
||||
},
|
||||
});
|
||||
|
||||
const isBillingEnabled =
|
||||
process.env.NEXT_PUBLIC_FEATURE_BILLING_ENABLED === 'true' && enterprisePriceId;
|
||||
|
||||
await seedUserSubscription({
|
||||
userId: owner.id,
|
||||
priceId: enterprisePriceId,
|
||||
});
|
||||
const template = await seedBlankTemplate(owner, team.id);
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
@ -188,13 +143,6 @@ test('[TEMPLATE]: should create a team document from a team template', async ({
|
||||
await page.getByRole('option').filter({ hasText: 'Require account' }).click();
|
||||
await expect(page.getByTestId('documentAccessSelectValue')).toContainText('Require account');
|
||||
|
||||
// Set EE action auth.
|
||||
if (isBillingEnabled) {
|
||||
await page.getByTestId('documentActionSelectValue').click();
|
||||
await page.getByRole('option').filter({ hasText: 'Require passkey' }).click();
|
||||
await expect(page.getByTestId('documentActionSelectValue')).toContainText('Require passkey');
|
||||
}
|
||||
|
||||
// Set email options.
|
||||
await page.getByRole('button', { name: 'Email Options' }).click();
|
||||
await page.getByLabel('Subject (Optional)').fill('SUBJECT');
|
||||
@ -219,13 +167,6 @@ test('[TEMPLATE]: should create a team document from a team template', async ({
|
||||
await page.getByPlaceholder('Email').nth(1).fill('recipient2@documenso.com');
|
||||
await page.getByPlaceholder('Name').nth(1).fill('Recipient 2');
|
||||
|
||||
// Apply require passkey for Recipient 1.
|
||||
if (isBillingEnabled) {
|
||||
await page.getByLabel('Show advanced settings').check();
|
||||
await page.getByTestId('documentActionSelectValue').click();
|
||||
await page.getByRole('option').filter({ hasText: 'Require passkey' }).click();
|
||||
}
|
||||
|
||||
await page.getByRole('button', { name: 'Continue' }).click();
|
||||
await expect(page.getByRole('heading', { name: 'Add Fields' })).toBeVisible();
|
||||
|
||||
@ -237,7 +178,7 @@ 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(/documents/);
|
||||
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
|
||||
|
||||
const documentId = Number(page.url().split('/').pop());
|
||||
|
||||
@ -259,11 +200,6 @@ test('[TEMPLATE]: should create a team document from a team template', async ({
|
||||
|
||||
expect(document.title).toEqual('TEMPLATE_TITLE');
|
||||
expect(documentAuth.documentAuthOption.globalAccessAuth).toContain('ACCOUNT');
|
||||
|
||||
if (isBillingEnabled) {
|
||||
expect(documentAuth.documentAuthOption.globalActionAuth).toContain('PASSKEY');
|
||||
}
|
||||
|
||||
expect(document.documentMeta?.dateFormat).toEqual('dd/MM/yyyy hh:mm a');
|
||||
expect(document.documentMeta?.message).toEqual('MESSAGE');
|
||||
expect(document.documentMeta?.redirectUrl).toEqual('https://documenso.com');
|
||||
@ -283,10 +219,6 @@ test('[TEMPLATE]: should create a team document from a team template', async ({
|
||||
recipientAuth: recipientTwo.authOptions,
|
||||
});
|
||||
|
||||
if (isBillingEnabled) {
|
||||
expect(recipientOneAuth.derivedRecipientActionAuth).toContain('PASSKEY');
|
||||
}
|
||||
|
||||
expect(recipientOneAuth.derivedRecipientAccessAuth).toContain('ACCOUNT');
|
||||
expect(recipientTwoAuth.derivedRecipientAccessAuth).toContain('ACCOUNT');
|
||||
});
|
||||
@ -298,8 +230,8 @@ test('[TEMPLATE]: should create a team document from a team template', async ({
|
||||
test('[TEMPLATE]: should create a document from a template with custom document', async ({
|
||||
page,
|
||||
}) => {
|
||||
const user = await seedUser();
|
||||
const template = await seedBlankTemplate(user);
|
||||
const { user, team } = await seedUser();
|
||||
const template = await seedBlankTemplate(user, team.id);
|
||||
|
||||
// Create a temporary PDF file for upload
|
||||
|
||||
@ -308,7 +240,7 @@ test('[TEMPLATE]: should create a document from a template with custom document'
|
||||
await apiSignin({
|
||||
page,
|
||||
email: user.email,
|
||||
redirectPath: `/templates/${template.id}/edit`,
|
||||
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
|
||||
});
|
||||
|
||||
// Set template title
|
||||
@ -327,7 +259,7 @@ test('[TEMPLATE]: should create a document from a template with custom document'
|
||||
await page.getByRole('button', { name: 'Save template' }).click();
|
||||
|
||||
// Use template with custom document
|
||||
await page.waitForURL('/templates');
|
||||
await page.waitForURL(`/t/${team.url}/templates`);
|
||||
await page.getByRole('button', { name: 'Use Template' }).click();
|
||||
|
||||
// Enable custom document upload and upload file
|
||||
@ -352,7 +284,7 @@ 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(/documents/);
|
||||
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
|
||||
|
||||
const documentId = Number(page.url().split('/').pop());
|
||||
|
||||
@ -378,15 +310,11 @@ test('[TEMPLATE]: should create a document from a template with custom document'
|
||||
test('[TEMPLATE]: should create a team document from a template with custom document', async ({
|
||||
page,
|
||||
}) => {
|
||||
const { owner, ...team } = await seedTeam({
|
||||
const { team, owner, organisation } = await seedTeam({
|
||||
createTeamMembers: 2,
|
||||
});
|
||||
|
||||
const template = await seedBlankTemplate(owner, {
|
||||
createTemplateOptions: {
|
||||
teamId: team.id,
|
||||
},
|
||||
});
|
||||
const template = await seedBlankTemplate(owner, team.id);
|
||||
|
||||
const pdfContent = fs.readFileSync(EXAMPLE_PDF_PATH).toString('base64');
|
||||
|
||||
@ -437,7 +365,7 @@ 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(/documents/);
|
||||
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
|
||||
|
||||
const documentId = Number(page.url().split('/').pop());
|
||||
|
||||
@ -464,13 +392,13 @@ test('[TEMPLATE]: should create a team document from a template with custom docu
|
||||
test('[TEMPLATE]: should create a document from a template using template document when custom document is not enabled', async ({
|
||||
page,
|
||||
}) => {
|
||||
const user = await seedUser();
|
||||
const template = await seedBlankTemplate(user);
|
||||
const { user, team } = await seedUser();
|
||||
const template = await seedBlankTemplate(user, team.id);
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: user.email,
|
||||
redirectPath: `/templates/${template.id}/edit`,
|
||||
redirectPath: `/t/${team.url}/templates/${template.id}/edit`,
|
||||
});
|
||||
|
||||
// Set template title
|
||||
@ -489,7 +417,7 @@ test('[TEMPLATE]: should create a document from a template using template docume
|
||||
await page.getByRole('button', { name: 'Save template' }).click();
|
||||
|
||||
// Use template without custom document
|
||||
await page.waitForURL('/templates');
|
||||
await page.waitForURL(`/t/${team.url}/templates`);
|
||||
await page.getByRole('button', { name: 'Use Template' }).click();
|
||||
|
||||
// Verify custom document upload is not checked by default
|
||||
@ -499,7 +427,7 @@ 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(/documents/);
|
||||
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
|
||||
|
||||
const documentId = Number(page.url().split('/').pop());
|
||||
|
||||
@ -532,15 +460,11 @@ test('[TEMPLATE]: should create a document from a template using template docume
|
||||
test('[TEMPLATE]: should persist document visibility when creating from template', async ({
|
||||
page,
|
||||
}) => {
|
||||
const { owner, ...team } = await seedTeam({
|
||||
const { team, owner, organisation } = await seedTeam({
|
||||
createTeamMembers: 2,
|
||||
});
|
||||
|
||||
const template = await seedBlankTemplate(owner, {
|
||||
createTemplateOptions: {
|
||||
teamId: team.id,
|
||||
},
|
||||
});
|
||||
const template = await seedBlankTemplate(owner, team.id);
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
@ -569,17 +493,11 @@ test('[TEMPLATE]: should persist document visibility when creating from template
|
||||
await page.getByRole('button', { name: 'Save template' }).click();
|
||||
|
||||
// Test creating document as team manager
|
||||
await prisma.teamMember.update({
|
||||
where: {
|
||||
id: team.members[1].id,
|
||||
},
|
||||
data: {
|
||||
role: TeamMemberRole.MANAGER,
|
||||
},
|
||||
const managerUser = await seedTeamMember({
|
||||
teamId: team.id,
|
||||
role: TeamMemberRole.MANAGER,
|
||||
});
|
||||
|
||||
const managerUser = team.members[1].user;
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: managerUser.email,
|
||||
@ -590,7 +508,7 @@ 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(/documents/);
|
||||
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
|
||||
|
||||
const documentId = Number(page.url().split('/').pop());
|
||||
|
||||
@ -605,7 +523,11 @@ test('[TEMPLATE]: should persist document visibility when creating from template
|
||||
expect(document.teamId).toEqual(team.id);
|
||||
|
||||
// Test that regular member cannot create document from restricted template
|
||||
const memberUser = team.members[2].user;
|
||||
const memberUser = await seedTeamMember({
|
||||
teamId: team.id,
|
||||
role: TeamMemberRole.MEMBER,
|
||||
});
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: memberUser.email,
|
||||
|
||||
@ -2,10 +2,6 @@ import { expect, test } from '@playwright/test';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||
import {
|
||||
DIRECT_TEMPLATE_RECIPIENT_EMAIL,
|
||||
DIRECT_TEMPLATE_RECIPIENT_NAME,
|
||||
} from '@documenso/lib/constants/direct-templates';
|
||||
import { createDocumentAuthOptions } from '@documenso/lib/utils/document-auth';
|
||||
import { formatDirectTemplatePath } from '@documenso/lib/utils/templates';
|
||||
import { seedTeam } from '@documenso/prisma/seed/teams';
|
||||
@ -13,29 +9,18 @@ import { seedDirectTemplate, seedTemplate } from '@documenso/prisma/seed/templat
|
||||
import { seedTestEmail, seedUser } from '@documenso/prisma/seed/users';
|
||||
|
||||
import { apiSignin } from '../fixtures/authentication';
|
||||
import { checkDocumentTabCount } from '../fixtures/documents';
|
||||
|
||||
// Duped from `packages/lib/utils/teams.ts` due to errors when importing that file.
|
||||
const formatDocumentsPath = (teamUrl?: string) =>
|
||||
teamUrl ? `/t/${teamUrl}/documents` : '/documents';
|
||||
const formatTemplatesPath = (teamUrl?: string) =>
|
||||
teamUrl ? `/t/${teamUrl}/templates` : '/templates';
|
||||
const formatDocumentsPath = (teamUrl: string) => `/t/${teamUrl}/documents`;
|
||||
const formatTemplatesPath = (teamUrl: string) => `/t/${teamUrl}/templates`;
|
||||
|
||||
const nanoid = customAlphabet('1234567890abcdef', 10);
|
||||
|
||||
test('[DIRECT_TEMPLATES]: create direct link for template', async ({ page }) => {
|
||||
const team = await seedTeam({
|
||||
const { team, owner, organisation } = await seedTeam({
|
||||
createTeamMembers: 1,
|
||||
});
|
||||
|
||||
const owner = team.owner;
|
||||
|
||||
// Should only be visible to the owner in personal templates.
|
||||
const personalTemplate = await seedTemplate({
|
||||
title: 'Personal template',
|
||||
userId: owner.id,
|
||||
});
|
||||
|
||||
// Should be visible to team members.
|
||||
const teamTemplate = await seedTemplate({
|
||||
title: 'Team template 1',
|
||||
@ -46,49 +31,35 @@ test('[DIRECT_TEMPLATES]: create direct link for template', async ({ page }) =>
|
||||
await apiSignin({
|
||||
page,
|
||||
email: owner.email,
|
||||
redirectPath: '/templates',
|
||||
redirectPath: `/t/${team.url}/templates`,
|
||||
});
|
||||
|
||||
const urls = [
|
||||
`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates/${teamTemplate.id}`,
|
||||
`${NEXT_PUBLIC_WEBAPP_URL()}/templates/${personalTemplate.id}`,
|
||||
];
|
||||
const url = `${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates/${teamTemplate.id}`;
|
||||
|
||||
// Run test for personal and team templates.
|
||||
for (const url of urls) {
|
||||
// Owner should see list of templates with no direct link badge.
|
||||
await page.goto(url);
|
||||
await expect(page.getByRole('button', { name: 'direct link' })).toHaveCount(1);
|
||||
// Owner should see list of templates with no direct link badge.
|
||||
await page.goto(url);
|
||||
await expect(page.getByRole('button', { name: 'direct link' })).toHaveCount(1);
|
||||
|
||||
// Create direct link.
|
||||
await page.getByRole('button', { name: 'Create Direct Link' }).click();
|
||||
await page.getByRole('button', { name: 'Enable direct link signing' }).click();
|
||||
await page.getByRole('button', { name: 'Create one automatically' }).click();
|
||||
await expect(page.getByRole('heading', { name: 'Direct Link Signing' })).toBeVisible();
|
||||
// Create direct link.
|
||||
await page.getByRole('button', { name: 'Create Direct Link' }).click();
|
||||
await page.getByRole('button', { name: 'Enable direct link signing' }).click();
|
||||
await page.getByRole('button', { name: 'Create one automatically' }).click();
|
||||
await expect(page.getByRole('heading', { name: 'Direct Link Signing' })).toBeVisible();
|
||||
|
||||
await page.waitForTimeout(1000);
|
||||
await page.getByTestId('btn-dialog-close').click();
|
||||
await page.waitForTimeout(1000);
|
||||
await page.getByTestId('btn-dialog-close').click();
|
||||
|
||||
// Expect badge to appear.
|
||||
await expect(page.getByRole('button', { name: 'direct link' })).toHaveCount(2);
|
||||
}
|
||||
// Expect badge to appear.
|
||||
await expect(page.getByRole('button', { name: 'direct link' })).toHaveCount(2);
|
||||
});
|
||||
|
||||
test('[DIRECT_TEMPLATES]: toggle direct template link', async ({ page }) => {
|
||||
const team = await seedTeam({
|
||||
const { team, owner, organisation } = await seedTeam({
|
||||
createTeamMembers: 1,
|
||||
});
|
||||
|
||||
const owner = team.owner;
|
||||
|
||||
// Should only be visible to the owner in personal templates.
|
||||
const personalDirectTemplate = await seedDirectTemplate({
|
||||
title: 'Personal direct template link',
|
||||
userId: owner.id,
|
||||
});
|
||||
|
||||
// Should be visible to team members.
|
||||
const teamDirectTemplate = await seedDirectTemplate({
|
||||
const template = await seedDirectTemplate({
|
||||
title: 'Team direct template link 1',
|
||||
userId: owner.id,
|
||||
teamId: team.id,
|
||||
@ -99,41 +70,30 @@ test('[DIRECT_TEMPLATES]: toggle direct template link', async ({ page }) => {
|
||||
email: owner.email,
|
||||
});
|
||||
|
||||
// Run test for personal and team templates.
|
||||
for (const template of [personalDirectTemplate, teamDirectTemplate]) {
|
||||
// Check that the direct template link is accessible.
|
||||
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
|
||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||
// Check that the direct template link is accessible.
|
||||
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
|
||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||
|
||||
// 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.getByRole('switch').click();
|
||||
await page.getByRole('button', { name: 'Save' }).click();
|
||||
await expect(page.getByText('Direct link signing has been').first()).toBeVisible();
|
||||
// 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.getByRole('switch').click();
|
||||
await page.getByRole('button', { name: 'Save' }).click();
|
||||
await expect(page.getByText('Direct link signing has been').first()).toBeVisible();
|
||||
|
||||
// Check that the direct template link is no longer accessible.
|
||||
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
|
||||
await expect(page.getByText('404 not found')).toBeVisible();
|
||||
}
|
||||
// Check that the direct template link is no longer accessible.
|
||||
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
|
||||
await expect(page.getByText('404 not found')).toBeVisible();
|
||||
});
|
||||
|
||||
test('[DIRECT_TEMPLATES]: delete direct template link', async ({ page }) => {
|
||||
const team = await seedTeam({
|
||||
const { team, owner, organisation } = await seedTeam({
|
||||
createTeamMembers: 1,
|
||||
});
|
||||
|
||||
const owner = team.owner;
|
||||
|
||||
// Should only be visible to the owner in personal templates.
|
||||
const personalDirectTemplate = await seedDirectTemplate({
|
||||
title: 'Personal direct template link',
|
||||
userId: owner.id,
|
||||
});
|
||||
|
||||
// Should be visible to team members.
|
||||
const teamDirectTemplate = await seedDirectTemplate({
|
||||
const template = await seedDirectTemplate({
|
||||
title: 'Team direct template link 1',
|
||||
userId: owner.id,
|
||||
teamId: team.id,
|
||||
@ -144,32 +104,30 @@ test('[DIRECT_TEMPLATES]: delete direct template link', async ({ page }) => {
|
||||
email: owner.email,
|
||||
});
|
||||
|
||||
// Run test for personal and team templates.
|
||||
for (const template of [personalDirectTemplate, teamDirectTemplate]) {
|
||||
// Check that the direct template link is accessible.
|
||||
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
|
||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||
// Check that the direct template link is accessible.
|
||||
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
|
||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||
|
||||
// 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.getByRole('button', { name: 'Remove' }).click();
|
||||
await page.getByRole('button', { name: 'Confirm' }).click();
|
||||
await expect(page.getByText('Direct template link deleted').first()).toBeVisible();
|
||||
// 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.getByRole('button', { name: 'Remove' }).click();
|
||||
await page.getByRole('button', { name: 'Confirm' }).click();
|
||||
await expect(page.getByText('Direct template link deleted').first()).toBeVisible();
|
||||
|
||||
// Check that the direct template link is no longer accessible.
|
||||
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
|
||||
await expect(page.getByText('404 not found')).toBeVisible();
|
||||
}
|
||||
// Check that the direct template link is no longer accessible.
|
||||
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
|
||||
await expect(page.getByText('404 not found')).toBeVisible();
|
||||
});
|
||||
|
||||
test('[DIRECT_TEMPLATES]: direct template link auth access', async ({ page }) => {
|
||||
const user = await seedUser();
|
||||
const { user, team } = await seedUser();
|
||||
|
||||
const directTemplateWithAuth = await seedDirectTemplate({
|
||||
title: 'Personal direct template link',
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
createTemplateOptions: {
|
||||
authOptions: createDocumentAuthOptions({
|
||||
globalAccessAuth: ['ACCOUNT'],
|
||||
@ -198,136 +156,26 @@ test('[DIRECT_TEMPLATES]: direct template link auth access', async ({ page }) =>
|
||||
});
|
||||
|
||||
test('[DIRECT_TEMPLATES]: use direct template link with 1 recipient', async ({ page }) => {
|
||||
const team = await seedTeam({
|
||||
const { team, owner, organisation } = await seedTeam({
|
||||
createTeamMembers: 1,
|
||||
});
|
||||
|
||||
const owner = team.owner;
|
||||
|
||||
// Should only be visible to the owner in personal templates.
|
||||
const personalDirectTemplate = await seedDirectTemplate({
|
||||
title: 'Personal direct template link',
|
||||
userId: owner.id,
|
||||
});
|
||||
|
||||
// Should be visible to team members.
|
||||
const teamDirectTemplate = await seedDirectTemplate({
|
||||
const template = await seedDirectTemplate({
|
||||
title: 'Team direct template link 1',
|
||||
userId: owner.id,
|
||||
teamId: team.id,
|
||||
});
|
||||
|
||||
// Run test for personal and team templates.
|
||||
for (const template of [personalDirectTemplate, teamDirectTemplate]) {
|
||||
// Check that the direct template link is accessible.
|
||||
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
|
||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||
// Check that the direct template link is accessible.
|
||||
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
|
||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||
|
||||
await page.getByPlaceholder('recipient@documenso.com').fill(seedTestEmail());
|
||||
await page.getByPlaceholder('recipient@documenso.com').fill(seedTestEmail());
|
||||
|
||||
await page.getByRole('button', { name: 'Continue' }).click();
|
||||
await page.getByRole('button', { name: 'Complete' }).click();
|
||||
await page.getByRole('button', { name: 'Sign' }).click();
|
||||
await page.waitForURL(/\/sign/);
|
||||
await expect(page.getByRole('heading', { name: 'Document Signed' })).toBeVisible();
|
||||
}
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: owner.email,
|
||||
});
|
||||
|
||||
// Check that the owner has the documents.
|
||||
for (const template of [personalDirectTemplate, teamDirectTemplate]) {
|
||||
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}${formatDocumentsPath(template.team?.url)}`);
|
||||
|
||||
await expect(async () => {
|
||||
// Check that the document is in the 'All' tab.
|
||||
await checkDocumentTabCount(page, 'Completed', 1);
|
||||
}).toPass();
|
||||
}
|
||||
});
|
||||
|
||||
test('[DIRECT_TEMPLATES]: use direct template link with 2 recipients', async ({ page }) => {
|
||||
const team = await seedTeam({
|
||||
createTeamMembers: 1,
|
||||
});
|
||||
|
||||
const owner = team.owner;
|
||||
|
||||
const secondRecipient = await seedUser();
|
||||
|
||||
const createTemplateOptions = {
|
||||
recipients: {
|
||||
createMany: {
|
||||
data: [
|
||||
{
|
||||
email: DIRECT_TEMPLATE_RECIPIENT_EMAIL,
|
||||
name: DIRECT_TEMPLATE_RECIPIENT_NAME,
|
||||
token: nanoid(),
|
||||
},
|
||||
{
|
||||
email: secondRecipient.email,
|
||||
token: nanoid(),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Should only be visible to the owner in personal templates.
|
||||
const personalDirectTemplate = await seedDirectTemplate({
|
||||
title: 'Personal direct template link',
|
||||
userId: owner.id,
|
||||
createTemplateOptions,
|
||||
});
|
||||
|
||||
// Should be visible to team members.
|
||||
const teamDirectTemplate = await seedDirectTemplate({
|
||||
title: 'Team direct template link 1',
|
||||
userId: owner.id,
|
||||
teamId: team.id,
|
||||
createTemplateOptions,
|
||||
});
|
||||
|
||||
// Run test for personal and team templates.
|
||||
for (const template of [personalDirectTemplate, teamDirectTemplate]) {
|
||||
// Check that the direct template link is accessible.
|
||||
await page.goto(formatDirectTemplatePath(template.directLink?.token || ''));
|
||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||
|
||||
await page.waitForTimeout(1000);
|
||||
await page.getByPlaceholder('recipient@documenso.com').fill(seedTestEmail());
|
||||
|
||||
await page.getByRole('button', { name: 'Continue' }).click();
|
||||
await page.getByRole('button', { name: 'Complete' }).click();
|
||||
await page.getByRole('button', { name: 'Sign' }).click();
|
||||
await page.waitForURL(/\/sign/);
|
||||
await expect(page.getByText('Waiting for others to sign')).toBeVisible();
|
||||
}
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: owner.email,
|
||||
});
|
||||
|
||||
// Check that the owner has the documents.
|
||||
for (const template of [personalDirectTemplate, teamDirectTemplate]) {
|
||||
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);
|
||||
await checkDocumentTabCount(page, 'Pending', 1);
|
||||
}
|
||||
|
||||
// Check that the second recipient has the 2 pending documents.
|
||||
await apiSignin({
|
||||
page,
|
||||
email: secondRecipient.email,
|
||||
});
|
||||
|
||||
await page.goto('/documents');
|
||||
|
||||
await checkDocumentTabCount(page, 'All', 2);
|
||||
await checkDocumentTabCount(page, 'Inbox', 2);
|
||||
await page.getByRole('button', { name: 'Continue' }).click();
|
||||
await page.getByRole('button', { name: 'Complete' }).click();
|
||||
await page.getByRole('button', { name: 'Sign' }).click();
|
||||
await page.waitForURL(/\/sign/);
|
||||
await expect(page.getByRole('heading', { name: 'Document Signed' })).toBeVisible();
|
||||
});
|
||||
|
||||
@ -1,23 +1,19 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { TeamMemberRole } from '@prisma/client';
|
||||
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||
import { seedTeam } from '@documenso/prisma/seed/teams';
|
||||
import { seedTeam, seedTeamMember } from '@documenso/prisma/seed/teams';
|
||||
import { seedTemplate } from '@documenso/prisma/seed/templates';
|
||||
|
||||
import { apiSignin } from '../fixtures/authentication';
|
||||
|
||||
test('[TEMPLATES]: view templates', async ({ page }) => {
|
||||
const team = await seedTeam({
|
||||
const { team, owner, organisation } = await seedTeam({
|
||||
createTeamMembers: 1,
|
||||
});
|
||||
|
||||
const owner = team.owner;
|
||||
const teamMemberUser = team.members[1].user;
|
||||
|
||||
// Should only be visible to the owner in personal templates.
|
||||
await seedTemplate({
|
||||
title: 'Personal template',
|
||||
userId: owner.id,
|
||||
const teamMemberUser = await seedTeamMember({
|
||||
teamId: team.id,
|
||||
role: TeamMemberRole.MEMBER,
|
||||
});
|
||||
|
||||
// Should be visible to team members.
|
||||
@ -37,29 +33,21 @@ test('[TEMPLATES]: view templates', async ({ page }) => {
|
||||
await apiSignin({
|
||||
page,
|
||||
email: owner.email,
|
||||
redirectPath: '/templates',
|
||||
redirectPath: `/t/${team.url}/templates`,
|
||||
});
|
||||
|
||||
// Only should only see their personal template.
|
||||
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 }) => {
|
||||
const team = await seedTeam({
|
||||
const { team, owner, organisation } = await seedTeam({
|
||||
createTeamMembers: 1,
|
||||
});
|
||||
|
||||
const owner = team.owner;
|
||||
const teamMemberUser = team.members[1].user;
|
||||
|
||||
// Should only be visible to the owner in personal templates.
|
||||
await seedTemplate({
|
||||
title: 'Personal template',
|
||||
userId: owner.id,
|
||||
const teamMemberUser = await seedTeamMember({
|
||||
teamId: team.id,
|
||||
role: TeamMemberRole.MEMBER,
|
||||
});
|
||||
|
||||
// Should be visible to team members.
|
||||
@ -79,18 +67,9 @@ test('[TEMPLATES]: delete template', async ({ page }) => {
|
||||
await apiSignin({
|
||||
page,
|
||||
email: owner.email,
|
||||
redirectPath: '/templates',
|
||||
redirectPath: `/t/${team.url}/templates`,
|
||||
});
|
||||
|
||||
// Owner should be able to delete their personal template.
|
||||
await page.getByRole('cell', { name: 'Use Template' }).getByRole('button').nth(1).click();
|
||||
await page.getByRole('menuitem', { name: 'Delete' }).click();
|
||||
await page.getByRole('button', { name: 'Delete' }).click();
|
||||
await expect(page.getByText('Template deleted').first()).toBeVisible();
|
||||
|
||||
// Team member should be able to delete all templates.
|
||||
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates`);
|
||||
|
||||
for (const template of ['Team template 1', 'Team template 2']) {
|
||||
await page
|
||||
.getByRole('row', { name: template })
|
||||
@ -108,17 +87,13 @@ test('[TEMPLATES]: delete template', async ({ page }) => {
|
||||
});
|
||||
|
||||
test('[TEMPLATES]: duplicate template', async ({ page }) => {
|
||||
const team = await seedTeam({
|
||||
const { team, owner, organisation } = await seedTeam({
|
||||
createTeamMembers: 1,
|
||||
});
|
||||
|
||||
const owner = team.owner;
|
||||
const teamMemberUser = team.members[1].user;
|
||||
|
||||
// Should only be visible to the owner in personal templates.
|
||||
await seedTemplate({
|
||||
title: 'Personal template',
|
||||
userId: owner.id,
|
||||
const teamMemberUser = await seedTeamMember({
|
||||
teamId: team.id,
|
||||
role: TeamMemberRole.MEMBER,
|
||||
});
|
||||
|
||||
// Should be visible to team members.
|
||||
@ -131,18 +106,9 @@ test('[TEMPLATES]: duplicate template', async ({ page }) => {
|
||||
await apiSignin({
|
||||
page,
|
||||
email: owner.email,
|
||||
redirectPath: '/templates',
|
||||
redirectPath: `/t/${team.url}/templates`,
|
||||
});
|
||||
|
||||
// Duplicate personal 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.getByTestId('data-table-count')).toContainText('Showing 2 results');
|
||||
|
||||
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();
|
||||
@ -152,17 +118,13 @@ test('[TEMPLATES]: duplicate template', async ({ page }) => {
|
||||
});
|
||||
|
||||
test('[TEMPLATES]: use template', async ({ page }) => {
|
||||
const team = await seedTeam({
|
||||
const { team, owner, organisation } = await seedTeam({
|
||||
createTeamMembers: 1,
|
||||
});
|
||||
|
||||
const owner = team.owner;
|
||||
const teamMemberUser = team.members[1].user;
|
||||
|
||||
// Should only be visible to the owner in personal templates.
|
||||
await seedTemplate({
|
||||
title: 'Personal template',
|
||||
userId: owner.id,
|
||||
const teamMemberUser = await seedTeamMember({
|
||||
teamId: team.id,
|
||||
role: TeamMemberRole.MEMBER,
|
||||
});
|
||||
|
||||
// Should be visible to team members.
|
||||
@ -175,27 +137,9 @@ test('[TEMPLATES]: use template', async ({ page }) => {
|
||||
await apiSignin({
|
||||
page,
|
||||
email: owner.email,
|
||||
redirectPath: '/templates',
|
||||
redirectPath: `/t/${team.url}/templates`,
|
||||
});
|
||||
|
||||
// Use personal template.
|
||||
await page.getByRole('button', { name: 'Use Template' }).click();
|
||||
|
||||
// Enter template values.
|
||||
await page.getByPlaceholder('recipient.1@documenso.com').click();
|
||||
await page.getByPlaceholder('recipient.1@documenso.com').fill(teamMemberUser.email);
|
||||
await page.getByPlaceholder('Recipient 1').click();
|
||||
await page.getByPlaceholder('Recipient 1').fill('name');
|
||||
|
||||
await page.getByRole('button', { name: 'Create as draft' }).click();
|
||||
await page.waitForURL(/documents/);
|
||||
await page.getByRole('main').getByRole('link', { name: 'Documents' }).click();
|
||||
await page.waitForURL('/documents');
|
||||
await expect(page.getByTestId('data-table-count')).toContainText('Showing 1 result');
|
||||
|
||||
await page.goto(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${team.url}/templates`);
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Use team template.
|
||||
await page.getByRole('button', { name: 'Use Template' }).click();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user