feat: add organisations (#1820)

This commit is contained in:
David Nguyen
2025-06-10 11:49:52 +10:00
committed by GitHub
parent 0b37f19641
commit e6dc237ad2
631 changed files with 37616 additions and 25695 deletions

View File

@ -5,137 +5,18 @@ import {
seedDraftDocument,
seedPendingDocument,
} from '@documenso/prisma/seed/documents';
import { seedUserSubscription } from '@documenso/prisma/seed/subscriptions';
import { seedTeam } from '@documenso/prisma/seed/teams';
import { seedUser } from '@documenso/prisma/seed/users';
import { apiSignin } from '../fixtures/authentication';
test.describe('[EE_ONLY]', () => {
// eslint-disable-next-line turbo/no-undeclared-env-vars
const enterprisePriceId = process.env.NEXT_PUBLIC_STRIPE_ENTERPRISE_PLAN_MONTHLY_PRICE_ID || '';
test.beforeEach(() => {
test.skip(
process.env.NEXT_PUBLIC_FEATURE_BILLING_ENABLED !== 'true' || !enterprisePriceId,
'Billing required for this test',
);
});
test('[DOCUMENT_FLOW] add action auth settings', async ({ page }) => {
const user = await seedUser();
await seedUserSubscription({
userId: user.id,
priceId: enterprisePriceId,
});
const document = await seedBlankDocument(user);
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
});
// Set EE action auth.
await page.getByTestId('documentActionSelectValue').click();
await page.getByRole('option').filter({ hasText: 'Require passkey' }).click();
await expect(page.getByTestId('documentActionSelectValue')).toContainText('Require passkey');
// Save the settings by going to the next step.
await page.getByRole('button', { name: 'Continue' }).click();
await expect(page.getByRole('heading', { name: 'Add Signers' })).toBeVisible();
// Return to the settings step to check that the results are saved correctly.
await page.getByRole('button', { name: 'Go Back' }).click();
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
await expect(page.getByTestId('documentActionSelectValue')).toContainText('Require passkey');
});
test('[DOCUMENT_FLOW] enterprise team member can add action auth settings', async ({ page }) => {
const team = await seedTeam({
createTeamMembers: 1,
});
const owner = team.owner;
const teamMemberUser = team.members[1].user;
// Make the team enterprise by giving the owner the enterprise subscription.
await seedUserSubscription({
userId: team.ownerUserId,
priceId: enterprisePriceId,
});
const document = await seedBlankDocument(owner, {
createDocumentOptions: {
teamId: team.id,
},
});
await apiSignin({
page,
email: teamMemberUser.email,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
// Set EE action auth.
await page.getByTestId('documentActionSelectValue').click();
await page.getByRole('option').filter({ hasText: 'Require passkey' }).click();
await expect(page.getByTestId('documentActionSelectValue')).toContainText('Require passkey');
// Save the settings by going to the next step.
await page.getByRole('button', { name: 'Continue' }).click();
await expect(page.getByRole('heading', { name: 'Add Signers' })).toBeVisible();
// Advanced settings should be visible.
await expect(page.getByLabel('Show advanced settings')).toBeVisible();
});
test('[DOCUMENT_FLOW] enterprise team member should not have access to enterprise on personal account', async ({
page,
}) => {
const team = await seedTeam({
createTeamMembers: 1,
});
const teamMemberUser = team.members[1].user;
// Make the team enterprise by giving the owner the enterprise subscription.
await seedUserSubscription({
userId: team.ownerUserId,
priceId: enterprisePriceId,
});
const document = await seedBlankDocument(teamMemberUser);
await apiSignin({
page,
email: teamMemberUser.email,
redirectPath: `/documents/${document.id}/edit`,
});
// Global action auth should not be visible.
await expect(page.getByTestId('documentActionSelectValue')).not.toBeVisible();
// Next step.
await page.getByRole('button', { name: 'Continue' }).click();
await expect(page.getByRole('heading', { name: 'Add Signers' })).toBeVisible();
// Advanced settings should not be visible.
await expect(page.getByLabel('Show advanced settings')).not.toBeVisible();
});
});
test('[DOCUMENT_FLOW]: add settings', async ({ page }) => {
const user = await seedUser();
const document = await seedBlankDocument(user);
const { user, team } = await seedUser();
const document = await seedBlankDocument(user, team.id);
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
// Set title.
@ -163,21 +44,21 @@ test('[DOCUMENT_FLOW]: add settings', async ({ page }) => {
});
test('[DOCUMENT_FLOW]: title should be disabled depending on document status', async ({ page }) => {
const user = await seedUser();
const { user, team } = await seedUser();
const pendingDocument = await seedPendingDocument(user, []);
const draftDocument = await seedDraftDocument(user, []);
const pendingDocument = await seedPendingDocument(user, team.id, []);
const draftDocument = await seedDraftDocument(user, team.id, []);
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${pendingDocument.id}/edit`,
redirectPath: `/t/${team.url}/documents/${pendingDocument.id}/edit`,
});
// Should be disabled for pending documents.
await expect(page.getByLabel('Title')).toBeDisabled();
// Should be enabled for draft documents.
await page.goto(`/documents/${draftDocument.id}/edit`);
await page.goto(`/t/${team.url}/documents/${draftDocument.id}/edit`);
await expect(page.getByLabel('Title')).toBeEnabled();
});

View File

@ -1,71 +1,18 @@
import { expect, test } from '@playwright/test';
import { seedBlankDocument } from '@documenso/prisma/seed/documents';
import { seedUserSubscription } from '@documenso/prisma/seed/subscriptions';
import { seedUser } from '@documenso/prisma/seed/users';
import { apiSignin } from '../fixtures/authentication';
test.describe('[EE_ONLY]', () => {
// eslint-disable-next-line turbo/no-undeclared-env-vars
const enterprisePriceId = process.env.NEXT_PUBLIC_STRIPE_ENTERPRISE_PLAN_MONTHLY_PRICE_ID || '';
test.beforeEach(() => {
test.skip(
process.env.NEXT_PUBLIC_FEATURE_BILLING_ENABLED !== 'true' || !enterprisePriceId,
'Billing required for this test',
);
});
test('[DOCUMENT_FLOW] add EE settings', async ({ page }) => {
const user = await seedUser();
await seedUserSubscription({
userId: user.id,
priceId: enterprisePriceId,
});
const document = await seedBlankDocument(user);
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
});
// Save the settings by going to the next step.
await page.getByRole('button', { name: 'Continue' }).click();
await expect(page.getByRole('heading', { name: 'Add Signers' })).toBeVisible();
// Add 2 signers.
await page.getByPlaceholder('Email').fill('recipient1@documenso.com');
await page.getByPlaceholder('Name').fill('Recipient 1');
await page.getByRole('button', { name: 'Add Signer' }).click();
await page.getByLabel('Email').nth(1).fill('recipient2@documenso.com');
await page.getByLabel('Name').nth(1).fill('Recipient 2');
// Display advanced settings.
await page.getByLabel('Show advanced settings').check();
// Navigate to the next step and back.
await page.getByRole('button', { name: 'Continue' }).click();
await expect(page.getByRole('heading', { name: 'Add Fields' })).toBeVisible();
await page.getByRole('button', { name: 'Go Back' }).click();
await expect(page.getByRole('heading', { name: 'Add Signers' })).toBeVisible();
// Todo: Fix stepper component back issue before finishing test.
});
});
test('[DOCUMENT_FLOW]: add signers', async ({ page }) => {
const user = await seedUser();
const document = await seedBlankDocument(user);
const { user, team } = await seedUser();
const document = await seedBlankDocument(user, team.id);
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
// Save the settings by going to the next step.

View File

@ -35,11 +35,12 @@ const getDocumentByToken = async (token: string) => {
};
test('[DOCUMENT_FLOW]: should be able to upload a PDF document', async ({ page }) => {
const user = await seedUser();
const { user, team } = await seedUser();
await apiSignin({
page,
email: user.email,
redirectPath: `/t/${team.url}/documents`,
});
// Upload document.
@ -58,17 +59,17 @@ test('[DOCUMENT_FLOW]: should be able to upload a PDF document', async ({ page }
await fileChooser.setFiles(path.join(__dirname, '../../../../assets/example.pdf'));
// Wait to be redirected to the edit page.
await page.waitForURL(/\/documents\/\d+/);
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
});
test('[DOCUMENT_FLOW]: should be able to create a document', async ({ page }) => {
const user = await seedUser();
const document = await seedBlankDocument(user);
const { user, team } = await seedUser();
const document = await seedBlankDocument(user, team.id);
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
const documentTitle = `example-${Date.now()}.pdf`;
@ -114,7 +115,7 @@ test('[DOCUMENT_FLOW]: should be able to create a document', async ({ page }) =>
await page.waitForTimeout(2500);
await page.getByRole('button', { name: 'Send' }).click();
await page.waitForURL('/documents');
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
// Assert document was created
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();
@ -123,13 +124,13 @@ test('[DOCUMENT_FLOW]: should be able to create a document', async ({ page }) =>
test('[DOCUMENT_FLOW]: should be able to create a document with multiple recipients', async ({
page,
}) => {
const user = await seedUser();
const document = await seedBlankDocument(user);
const { user, team } = await seedUser();
const document = await seedBlankDocument(user, team.id);
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
const documentTitle = `example-${Date.now()}.pdf`;
@ -199,7 +200,7 @@ test('[DOCUMENT_FLOW]: should be able to create a document with multiple recipie
await page.waitForTimeout(2500);
await page.getByRole('button', { name: 'Send' }).click();
await page.waitForURL('/documents');
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
// Assert document was created
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();
@ -208,13 +209,13 @@ test('[DOCUMENT_FLOW]: should be able to create a document with multiple recipie
test('[DOCUMENT_FLOW]: should be able to create a document with multiple recipients with different roles', async ({
page,
}) => {
const user = await seedUser();
const document = await seedBlankDocument(user);
const { user, team } = await seedUser();
const document = await seedBlankDocument(user, team.id);
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
// Set title
@ -297,7 +298,7 @@ test('[DOCUMENT_FLOW]: should be able to create a document with multiple recipie
await page.waitForTimeout(2500);
await page.getByRole('button', { name: 'Send' }).click();
await page.waitForURL('/documents');
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
// Assert document was created
await expect(page.getByRole('link', { name: 'Test Title' })).toBeVisible();
@ -306,13 +307,13 @@ test('[DOCUMENT_FLOW]: should be able to create a document with multiple recipie
test('[DOCUMENT_FLOW]: should not be able to create a document without signatures', async ({
page,
}) => {
const user = await seedUser();
const document = await seedBlankDocument(user);
const { user, team } = await seedUser();
const document = await seedBlankDocument(user, team.id);
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
const documentTitle = `example-${Date.now()}.pdf`;
@ -342,10 +343,11 @@ test('[DOCUMENT_FLOW]: should not be able to create a document without signature
});
test('[DOCUMENT_FLOW]: should be able to approve a document', async ({ page }) => {
const user = await seedUser();
const { user, team } = await seedUser();
const { recipients } = await seedPendingDocumentWithFullFields({
owner: user,
teamId: team.id,
recipients: ['user@documenso.com', 'approver@documenso.com'],
recipientsCreateOptions: [
{
@ -393,13 +395,13 @@ test('[DOCUMENT_FLOW]: should be able to approve a document', async ({ page }) =
test('[DOCUMENT_FLOW]: should be able to create, send with redirect url, sign a document and redirect to redirect url', async ({
page,
}) => {
const user = await seedUser();
const document = await seedBlankDocument(user);
const { user, team } = await seedUser();
const document = await seedBlankDocument(user, team.id);
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
const documentTitle = `example-${Date.now()}.pdf`;
@ -430,12 +432,12 @@ test('[DOCUMENT_FLOW]: should be able to create, send with redirect url, sign a
await page.waitForTimeout(2500);
await page.getByRole('button', { name: 'Send' }).click();
await page.waitForURL('/documents');
await page.waitForURL(`/t/${team.url}/documents`);
// Assert document was created
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();
await page.getByRole('link', { name: documentTitle }).click();
await page.waitForURL(/\/documents\/\d+/);
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
const url = page.url().split('/');
const documentId = url[url.length - 1];
@ -467,11 +469,12 @@ test('[DOCUMENT_FLOW]: should be able to create, send with redirect url, sign a
});
test('[DOCUMENT_FLOW]: should be able to sign a document with custom date', async ({ page }) => {
const user = await seedUser();
const { user, team } = await seedUser();
const now = DateTime.utc();
const { document, recipients } = await seedPendingDocumentWithFullFields({
teamId: team.id,
owner: user,
recipients: ['user1@example.com'],
fields: [FieldType.DATE],
@ -516,13 +519,13 @@ test('[DOCUMENT_FLOW]: should be able to sign a document with custom date', asyn
test('[DOCUMENT_FLOW]: should be able to create and sign a document with 3 recipients in sequential order', async ({
page,
}) => {
const user = await seedUser();
const document = await seedBlankDocument(user);
const { user, team } = await seedUser();
const document = await seedBlankDocument(user, team.id);
await apiSignin({
page,
email: user.email,
redirectPath: `/documents/${document.id}/edit`,
redirectPath: `/t/${team.url}/documents/${document.id}/edit`,
});
const documentTitle = `Sequential-Signing-${Date.now()}.pdf`;
@ -579,7 +582,7 @@ test('[DOCUMENT_FLOW]: should be able to create and sign a document with 3 recip
await page.waitForTimeout(2500);
await page.getByRole('button', { name: 'Send' }).click();
await page.waitForURL('/documents');
await page.waitForURL(new RegExp(`/t/${team.url}/documents/\\d+`));
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();
@ -642,9 +645,10 @@ test('[DOCUMENT_FLOW]: should be able to create and sign a document with 3 recip
test('[DOCUMENT_FLOW]: should prevent out-of-order signing in sequential mode', async ({
page,
}) => {
const user = await seedUser();
const { user, team } = await seedUser();
const { recipients } = await seedPendingDocumentWithFullFields({
teamId: team.id,
owner: user,
recipients: ['user1@example.com', 'user2@example.com', 'user3@example.com'],
fields: [FieldType.SIGNATURE],