mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 16:23:06 +10:00
feat: add document auth (#1029)
This commit is contained in:
97
packages/app-tests/e2e/document-auth/access-auth.spec.ts
Normal file
97
packages/app-tests/e2e/document-auth/access-auth.spec.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { createDocumentAuthOptions } from '@documenso/lib/utils/document-auth';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { seedPendingDocument } from '@documenso/prisma/seed/documents';
|
||||
import { seedUser, unseedUser } from '@documenso/prisma/seed/users';
|
||||
|
||||
import { apiSignin } from '../fixtures/authentication';
|
||||
|
||||
test.describe.configure({ mode: 'parallel' });
|
||||
|
||||
test('[DOCUMENT_AUTH]: should grant access when not required', async ({ page }) => {
|
||||
const user = await seedUser();
|
||||
|
||||
const recipientWithAccount = await seedUser();
|
||||
|
||||
const document = await seedPendingDocument(user, [
|
||||
recipientWithAccount,
|
||||
'recipientwithoutaccount@documenso.com',
|
||||
]);
|
||||
|
||||
const recipients = await prisma.recipient.findMany({
|
||||
where: {
|
||||
documentId: document.id,
|
||||
},
|
||||
});
|
||||
|
||||
const tokens = recipients.map((recipient) => recipient.token);
|
||||
|
||||
for (const token of tokens) {
|
||||
await page.goto(`/sign/${token}`);
|
||||
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
|
||||
}
|
||||
|
||||
await unseedUser(user.id);
|
||||
});
|
||||
|
||||
test('[DOCUMENT_AUTH]: should allow or deny access when required', async ({ page }) => {
|
||||
const user = await seedUser();
|
||||
|
||||
const recipientWithAccount = await seedUser();
|
||||
|
||||
const document = await seedPendingDocument(
|
||||
user,
|
||||
[recipientWithAccount, 'recipientwithoutaccount@documenso.com'],
|
||||
{
|
||||
createDocumentOptions: {
|
||||
authOptions: createDocumentAuthOptions({
|
||||
globalAccessAuth: 'ACCOUNT',
|
||||
globalActionAuth: null,
|
||||
}),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const recipients = await prisma.recipient.findMany({
|
||||
where: {
|
||||
documentId: document.id,
|
||||
},
|
||||
});
|
||||
|
||||
// Check that both are denied access.
|
||||
for (const recipient of recipients) {
|
||||
const { email, token } = recipient;
|
||||
|
||||
await page.goto(`/sign/${token}`);
|
||||
await expect(page.getByRole('heading', { name: 'Authentication required' })).toBeVisible();
|
||||
await expect(page.getByRole('paragraph')).toContainText(email);
|
||||
}
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: recipientWithAccount.email,
|
||||
redirectPath: '/',
|
||||
});
|
||||
|
||||
// Check that the one logged in is granted access.
|
||||
for (const recipient of recipients) {
|
||||
const { email, token } = recipient;
|
||||
|
||||
await page.goto(`/sign/${token}`);
|
||||
|
||||
// Recipient should be granted access.
|
||||
if (recipient.email === recipientWithAccount.email) {
|
||||
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
|
||||
}
|
||||
|
||||
// Recipient should still be denied.
|
||||
if (recipient.email !== recipientWithAccount.email) {
|
||||
await expect(page.getByRole('heading', { name: 'Authentication required' })).toBeVisible();
|
||||
await expect(page.getByRole('paragraph')).toContainText(email);
|
||||
}
|
||||
}
|
||||
|
||||
await unseedUser(user.id);
|
||||
await unseedUser(recipientWithAccount.id);
|
||||
});
|
||||
418
packages/app-tests/e2e/document-auth/action-auth.spec.ts
Normal file
418
packages/app-tests/e2e/document-auth/action-auth.spec.ts
Normal file
@ -0,0 +1,418 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { ZRecipientAuthOptionsSchema } from '@documenso/lib/types/document-auth';
|
||||
import {
|
||||
createDocumentAuthOptions,
|
||||
createRecipientAuthOptions,
|
||||
} from '@documenso/lib/utils/document-auth';
|
||||
import { FieldType } from '@documenso/prisma/client';
|
||||
import {
|
||||
seedPendingDocumentNoFields,
|
||||
seedPendingDocumentWithFullFields,
|
||||
} from '@documenso/prisma/seed/documents';
|
||||
import { seedTestEmail, seedUser, unseedUser } from '@documenso/prisma/seed/users';
|
||||
|
||||
import { apiSignin, apiSignout } from '../fixtures/authentication';
|
||||
|
||||
test.describe.configure({ mode: 'parallel' });
|
||||
|
||||
test('[DOCUMENT_AUTH]: should allow signing when no auth setup', async ({ page }) => {
|
||||
const user = await seedUser();
|
||||
|
||||
const recipientWithAccount = await seedUser();
|
||||
|
||||
const { recipients } = await seedPendingDocumentWithFullFields({
|
||||
owner: user,
|
||||
recipients: [recipientWithAccount, seedTestEmail()],
|
||||
});
|
||||
|
||||
// Check that both are granted access.
|
||||
for (const recipient of recipients) {
|
||||
const { token, Field } = recipient;
|
||||
|
||||
const signUrl = `/sign/${token}`;
|
||||
|
||||
await page.goto(signUrl);
|
||||
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
|
||||
|
||||
// Add signature.
|
||||
const canvas = page.locator('canvas');
|
||||
const box = await canvas.boundingBox();
|
||||
if (box) {
|
||||
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(box.x + box.width / 4, box.y + box.height / 4);
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
for (const field of Field) {
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
|
||||
if (field.type === FieldType.TEXT) {
|
||||
await page.getByLabel('Custom Text').fill('TEXT');
|
||||
await page.getByRole('button', { name: 'Save Text' }).click();
|
||||
}
|
||||
|
||||
await expect(page.locator(`#field-${field.id}`)).toHaveAttribute('data-inserted', 'true');
|
||||
}
|
||||
|
||||
await page.getByRole('button', { name: 'Complete' }).click();
|
||||
await page.getByRole('button', { name: 'Sign' }).click();
|
||||
await page.waitForURL(`${signUrl}/complete`);
|
||||
}
|
||||
|
||||
await unseedUser(user.id);
|
||||
await unseedUser(recipientWithAccount.id);
|
||||
});
|
||||
|
||||
test('[DOCUMENT_AUTH]: should allow signing with valid global auth', async ({ page }) => {
|
||||
const user = await seedUser();
|
||||
|
||||
const recipientWithAccount = await seedUser();
|
||||
|
||||
const { recipients } = await seedPendingDocumentWithFullFields({
|
||||
owner: user,
|
||||
recipients: [recipientWithAccount],
|
||||
updateDocumentOptions: {
|
||||
authOptions: createDocumentAuthOptions({
|
||||
globalAccessAuth: null,
|
||||
globalActionAuth: 'ACCOUNT',
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
const recipient = recipients[0];
|
||||
|
||||
const { token, Field } = recipient;
|
||||
|
||||
const signUrl = `/sign/${token}`;
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: recipientWithAccount.email,
|
||||
redirectPath: signUrl,
|
||||
});
|
||||
|
||||
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
|
||||
|
||||
// Add signature.
|
||||
const canvas = page.locator('canvas');
|
||||
const box = await canvas.boundingBox();
|
||||
if (box) {
|
||||
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(box.x + box.width / 4, box.y + box.height / 4);
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
for (const field of Field) {
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
|
||||
if (field.type === FieldType.TEXT) {
|
||||
await page.getByLabel('Custom Text').fill('TEXT');
|
||||
await page.getByRole('button', { name: 'Save Text' }).click();
|
||||
}
|
||||
|
||||
await expect(page.locator(`#field-${field.id}`)).toHaveAttribute('data-inserted', 'true');
|
||||
}
|
||||
|
||||
await page.getByRole('button', { name: 'Complete' }).click();
|
||||
await page.getByRole('button', { name: 'Sign' }).click();
|
||||
await page.waitForURL(`${signUrl}/complete`);
|
||||
|
||||
await unseedUser(user.id);
|
||||
await unseedUser(recipientWithAccount.id);
|
||||
});
|
||||
|
||||
// Currently document auth for signing/approving/viewing is not required.
|
||||
test.skip('[DOCUMENT_AUTH]: should deny signing document when required for global auth', async ({
|
||||
page,
|
||||
}) => {
|
||||
const user = await seedUser();
|
||||
|
||||
const recipientWithAccount = await seedUser();
|
||||
|
||||
const { recipients } = await seedPendingDocumentNoFields({
|
||||
owner: user,
|
||||
recipients: [recipientWithAccount],
|
||||
updateDocumentOptions: {
|
||||
authOptions: createDocumentAuthOptions({
|
||||
globalAccessAuth: null,
|
||||
globalActionAuth: 'ACCOUNT',
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
const recipient = recipients[0];
|
||||
|
||||
const { token } = recipient;
|
||||
|
||||
await page.goto(`/sign/${token}`);
|
||||
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
|
||||
|
||||
await page.getByRole('button', { name: 'Complete' }).click();
|
||||
await expect(page.getByRole('paragraph')).toContainText(
|
||||
'Reauthentication is required to sign the document',
|
||||
);
|
||||
|
||||
await unseedUser(user.id);
|
||||
await unseedUser(recipientWithAccount.id);
|
||||
});
|
||||
|
||||
test('[DOCUMENT_AUTH]: should deny signing fields when required for global auth', async ({
|
||||
page,
|
||||
}) => {
|
||||
const user = await seedUser();
|
||||
|
||||
const recipientWithAccount = await seedUser();
|
||||
|
||||
const { recipients } = await seedPendingDocumentWithFullFields({
|
||||
owner: user,
|
||||
recipients: [recipientWithAccount, seedTestEmail()],
|
||||
updateDocumentOptions: {
|
||||
authOptions: createDocumentAuthOptions({
|
||||
globalAccessAuth: null,
|
||||
globalActionAuth: 'ACCOUNT',
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
// Check that both are denied access.
|
||||
for (const recipient of recipients) {
|
||||
const { token, Field } = recipient;
|
||||
|
||||
await page.goto(`/sign/${token}`);
|
||||
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
|
||||
|
||||
for (const field of Field) {
|
||||
if (field.type !== FieldType.SIGNATURE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
await expect(page.getByRole('paragraph')).toContainText(
|
||||
'Reauthentication is required to sign the field',
|
||||
);
|
||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||
}
|
||||
}
|
||||
|
||||
await unseedUser(user.id);
|
||||
await unseedUser(recipientWithAccount.id);
|
||||
});
|
||||
|
||||
test('[DOCUMENT_AUTH]: should allow field signing when required for recipient auth', async ({
|
||||
page,
|
||||
}) => {
|
||||
const user = await seedUser();
|
||||
|
||||
const recipientWithInheritAuth = await seedUser();
|
||||
const recipientWithExplicitNoneAuth = await seedUser();
|
||||
const recipientWithExplicitAccountAuth = await seedUser();
|
||||
|
||||
const { recipients } = await seedPendingDocumentWithFullFields({
|
||||
owner: user,
|
||||
recipients: [
|
||||
recipientWithInheritAuth,
|
||||
recipientWithExplicitNoneAuth,
|
||||
recipientWithExplicitAccountAuth,
|
||||
],
|
||||
recipientsCreateOptions: [
|
||||
{
|
||||
authOptions: createRecipientAuthOptions({
|
||||
accessAuth: null,
|
||||
actionAuth: null,
|
||||
}),
|
||||
},
|
||||
{
|
||||
authOptions: createRecipientAuthOptions({
|
||||
accessAuth: null,
|
||||
actionAuth: 'EXPLICIT_NONE',
|
||||
}),
|
||||
},
|
||||
{
|
||||
authOptions: createRecipientAuthOptions({
|
||||
accessAuth: null,
|
||||
actionAuth: 'ACCOUNT',
|
||||
}),
|
||||
},
|
||||
],
|
||||
fields: [FieldType.DATE],
|
||||
});
|
||||
|
||||
for (const recipient of recipients) {
|
||||
const { token, Field } = recipient;
|
||||
const { actionAuth } = ZRecipientAuthOptionsSchema.parse(recipient.authOptions);
|
||||
|
||||
// This document has no global action auth, so only account should require auth.
|
||||
const isAuthRequired = actionAuth === 'ACCOUNT';
|
||||
|
||||
const signUrl = `/sign/${token}`;
|
||||
|
||||
await page.goto(signUrl);
|
||||
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
|
||||
|
||||
if (isAuthRequired) {
|
||||
for (const field of Field) {
|
||||
if (field.type !== FieldType.SIGNATURE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
await expect(page.getByRole('paragraph')).toContainText(
|
||||
'Reauthentication is required to sign the field',
|
||||
);
|
||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||
}
|
||||
|
||||
// Sign in and it should work.
|
||||
await apiSignin({
|
||||
page,
|
||||
email: recipient.email,
|
||||
redirectPath: signUrl,
|
||||
});
|
||||
}
|
||||
|
||||
// Add signature.
|
||||
const canvas = page.locator('canvas');
|
||||
const box = await canvas.boundingBox();
|
||||
if (box) {
|
||||
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(box.x + box.width / 4, box.y + box.height / 4);
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
for (const field of Field) {
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
|
||||
if (field.type === FieldType.TEXT) {
|
||||
await page.getByLabel('Custom Text').fill('TEXT');
|
||||
await page.getByRole('button', { name: 'Save Text' }).click();
|
||||
}
|
||||
|
||||
await expect(page.locator(`#field-${field.id}`)).toHaveAttribute('data-inserted', 'true', {
|
||||
timeout: 5000,
|
||||
});
|
||||
}
|
||||
|
||||
await page.getByRole('button', { name: 'Complete' }).click();
|
||||
await page.getByRole('button', { name: 'Sign' }).click();
|
||||
await page.waitForURL(`${signUrl}/complete`);
|
||||
|
||||
if (isAuthRequired) {
|
||||
await apiSignout({ page });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('[DOCUMENT_AUTH]: should allow field signing when required for recipient and global auth', async ({
|
||||
page,
|
||||
}) => {
|
||||
const user = await seedUser();
|
||||
|
||||
const recipientWithInheritAuth = await seedUser();
|
||||
const recipientWithExplicitNoneAuth = await seedUser();
|
||||
const recipientWithExplicitAccountAuth = await seedUser();
|
||||
|
||||
const { recipients } = await seedPendingDocumentWithFullFields({
|
||||
owner: user,
|
||||
recipients: [
|
||||
recipientWithInheritAuth,
|
||||
recipientWithExplicitNoneAuth,
|
||||
recipientWithExplicitAccountAuth,
|
||||
],
|
||||
recipientsCreateOptions: [
|
||||
{
|
||||
authOptions: createRecipientAuthOptions({
|
||||
accessAuth: null,
|
||||
actionAuth: null,
|
||||
}),
|
||||
},
|
||||
{
|
||||
authOptions: createRecipientAuthOptions({
|
||||
accessAuth: null,
|
||||
actionAuth: 'EXPLICIT_NONE',
|
||||
}),
|
||||
},
|
||||
{
|
||||
authOptions: createRecipientAuthOptions({
|
||||
accessAuth: null,
|
||||
actionAuth: 'ACCOUNT',
|
||||
}),
|
||||
},
|
||||
],
|
||||
fields: [FieldType.DATE],
|
||||
updateDocumentOptions: {
|
||||
authOptions: createDocumentAuthOptions({
|
||||
globalAccessAuth: null,
|
||||
globalActionAuth: 'ACCOUNT',
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
for (const recipient of recipients) {
|
||||
const { token, Field } = recipient;
|
||||
const { actionAuth } = ZRecipientAuthOptionsSchema.parse(recipient.authOptions);
|
||||
|
||||
// This document HAS global action auth, so account and inherit should require auth.
|
||||
const isAuthRequired = actionAuth === 'ACCOUNT' || actionAuth === null;
|
||||
|
||||
const signUrl = `/sign/${token}`;
|
||||
|
||||
await page.goto(signUrl);
|
||||
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
|
||||
|
||||
if (isAuthRequired) {
|
||||
for (const field of Field) {
|
||||
if (field.type !== FieldType.SIGNATURE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
await expect(page.getByRole('paragraph')).toContainText(
|
||||
'Reauthentication is required to sign the field',
|
||||
);
|
||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||
}
|
||||
|
||||
// Sign in and it should work.
|
||||
await apiSignin({
|
||||
page,
|
||||
email: recipient.email,
|
||||
redirectPath: signUrl,
|
||||
});
|
||||
}
|
||||
|
||||
// Add signature.
|
||||
const canvas = page.locator('canvas');
|
||||
const box = await canvas.boundingBox();
|
||||
if (box) {
|
||||
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(box.x + box.width / 4, box.y + box.height / 4);
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
for (const field of Field) {
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
|
||||
if (field.type === FieldType.TEXT) {
|
||||
await page.getByLabel('Custom Text').fill('TEXT');
|
||||
await page.getByRole('button', { name: 'Save Text' }).click();
|
||||
}
|
||||
|
||||
await expect(page.locator(`#field-${field.id}`)).toHaveAttribute('data-inserted', 'true', {
|
||||
timeout: 5000,
|
||||
});
|
||||
}
|
||||
|
||||
await page.getByRole('button', { name: 'Complete' }).click();
|
||||
await page.getByRole('button', { name: 'Sign' }).click();
|
||||
await page.waitForURL(`${signUrl}/complete`);
|
||||
|
||||
if (isAuthRequired) {
|
||||
await apiSignout({ page });
|
||||
}
|
||||
}
|
||||
});
|
||||
200
packages/app-tests/e2e/document-flow/settings-step.spec.ts
Normal file
200
packages/app-tests/e2e/document-flow/settings-step.spec.ts
Normal file
@ -0,0 +1,200 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import {
|
||||
seedBlankDocument,
|
||||
seedDraftDocument,
|
||||
seedPendingDocument,
|
||||
} from '@documenso/prisma/seed/documents';
|
||||
import { seedUserSubscription } from '@documenso/prisma/seed/subscriptions';
|
||||
import { seedTeam, unseedTeam } from '@documenso/prisma/seed/teams';
|
||||
import { seedUser, unseedUser } from '@documenso/prisma/seed/users';
|
||||
|
||||
import { apiSignin } from '../fixtures/authentication';
|
||||
|
||||
test.describe.configure({ mode: 'parallel' });
|
||||
|
||||
test.describe('[EE_ONLY]', () => {
|
||||
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.getByLabel('Require account').getByText('Require account').click();
|
||||
await expect(page.getByTestId('documentActionSelectValue')).toContainText('Require account');
|
||||
|
||||
// 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();
|
||||
|
||||
// Todo: Verify that the values are correct once we fix the issue where going back
|
||||
// does not show the updated values.
|
||||
// await expect(page.getByLabel('Title')).toContainText('New Title');
|
||||
// await expect(page.getByTestId('documentAccessSelectValue')).toContainText('Require account');
|
||||
// await expect(page.getByTestId('documentActionSelectValue')).toContainText('Require account');
|
||||
|
||||
await unseedUser(user.id);
|
||||
});
|
||||
|
||||
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.getByLabel('Require account').getByText('Require account').click();
|
||||
await expect(page.getByTestId('documentActionSelectValue')).toContainText('Require account');
|
||||
|
||||
// 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();
|
||||
|
||||
await unseedTeam(team.url);
|
||||
});
|
||||
|
||||
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();
|
||||
|
||||
await unseedTeam(team.url);
|
||||
});
|
||||
});
|
||||
|
||||
test('[DOCUMENT_FLOW]: add settings', async ({ page }) => {
|
||||
const user = await seedUser();
|
||||
const document = await seedBlankDocument(user);
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: user.email,
|
||||
redirectPath: `/documents/${document.id}/edit`,
|
||||
});
|
||||
|
||||
// Set title.
|
||||
await page.getByLabel('Title').fill('New Title');
|
||||
|
||||
// Set access auth.
|
||||
await page.getByTestId('documentAccessSelectValue').click();
|
||||
await page.getByLabel('Require account').getByText('Require account').click();
|
||||
await expect(page.getByTestId('documentAccessSelectValue')).toContainText('Require account');
|
||||
|
||||
// Action auth should NOT be visible.
|
||||
await expect(page.getByTestId('documentActionSelectValue')).not.toBeVisible();
|
||||
|
||||
// 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();
|
||||
|
||||
// Todo: Verify that the values are correct once we fix the issue where going back
|
||||
// does not show the updated values.
|
||||
// await expect(page.getByLabel('Title')).toContainText('New Title');
|
||||
// await expect(page.getByTestId('documentAccessSelectValue')).toContainText('Require account');
|
||||
// await expect(page.getByTestId('documentActionSelectValue')).toContainText('Require account');
|
||||
|
||||
await unseedUser(user.id);
|
||||
});
|
||||
|
||||
test('[DOCUMENT_FLOW]: title should be disabled depending on document status', async ({ page }) => {
|
||||
const user = await seedUser();
|
||||
|
||||
const pendingDocument = await seedPendingDocument(user, []);
|
||||
const draftDocument = await seedDraftDocument(user, []);
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: user.email,
|
||||
redirectPath: `/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 expect(page.getByLabel('Title')).toBeEnabled();
|
||||
|
||||
await unseedUser(user.id);
|
||||
});
|
||||
118
packages/app-tests/e2e/document-flow/signers-step.spec.ts
Normal file
118
packages/app-tests/e2e/document-flow/signers-step.spec.ts
Normal file
@ -0,0 +1,118 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { seedBlankDocument } from '@documenso/prisma/seed/documents';
|
||||
import { seedUserSubscription } from '@documenso/prisma/seed/subscriptions';
|
||||
import { seedUser, unseedUser } from '@documenso/prisma/seed/users';
|
||||
|
||||
import { apiSignin } from '../fixtures/authentication';
|
||||
|
||||
test.describe.configure({ mode: 'parallel' });
|
||||
|
||||
test.describe('[EE_ONLY]', () => {
|
||||
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
|
||||
.getByRole('textbox', { name: 'Email', exact: true })
|
||||
.fill('recipient2@documenso.com');
|
||||
await page.getByRole('textbox', { name: 'Name', exact: true }).fill('Recipient 2');
|
||||
|
||||
// Display advanced settings.
|
||||
await page.getByLabel('Show advanced settings').click();
|
||||
|
||||
// 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.
|
||||
|
||||
await unseedUser(user.id);
|
||||
});
|
||||
});
|
||||
|
||||
// Note: Not complete yet due to issue with back button.
|
||||
test('[DOCUMENT_FLOW]: add signers', async ({ page }) => {
|
||||
const user = await seedUser();
|
||||
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.getByRole('textbox', { name: 'Email', exact: true }).fill('recipient2@documenso.com');
|
||||
await page.getByRole('textbox', { name: 'Name', exact: true }).fill('Recipient 2');
|
||||
|
||||
// Advanced settings should not be visible for non EE users.
|
||||
await expect(page.getByLabel('Show advanced settings')).toBeHidden();
|
||||
|
||||
// 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.
|
||||
|
||||
// // Expect that the advanced settings is unchecked, since no advanced settings were applied.
|
||||
// await expect(page.getByLabel('Show advanced settings')).toBeChecked({ checked: false });
|
||||
|
||||
// // Add advanced settings for a single recipient.
|
||||
// await page.getByLabel('Show advanced settings').click();
|
||||
// await page.getByRole('combobox').first().click();
|
||||
// await page.getByLabel('Require account').click();
|
||||
|
||||
// // 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();
|
||||
|
||||
// Expect that the advanced settings is visible, and the checkbox is hidden. Since advanced
|
||||
// settings were applied.
|
||||
|
||||
// Todo: Fix stepper component back issue before finishing test.
|
||||
|
||||
await unseedUser(user.id);
|
||||
});
|
||||
@ -1,8 +1,8 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { type Page } from '@playwright/test';
|
||||
|
||||
import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
|
||||
|
||||
type ManualLoginOptions = {
|
||||
type LoginOptions = {
|
||||
page: Page;
|
||||
email?: string;
|
||||
password?: string;
|
||||
@ -18,7 +18,7 @@ export const manualLogin = async ({
|
||||
email = 'example@documenso.com',
|
||||
password = 'password',
|
||||
redirectPath,
|
||||
}: ManualLoginOptions) => {
|
||||
}: LoginOptions) => {
|
||||
await page.goto(`${WEBAPP_BASE_URL}/signin`);
|
||||
|
||||
await page.getByLabel('Email').click();
|
||||
@ -33,9 +33,63 @@ export const manualLogin = async ({
|
||||
}
|
||||
};
|
||||
|
||||
export const manualSignout = async ({ page }: ManualLoginOptions) => {
|
||||
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 ({
|
||||
page,
|
||||
email = 'example@documenso.com',
|
||||
password = 'password',
|
||||
redirectPath = '/',
|
||||
}: LoginOptions) => {
|
||||
const { request } = page.context();
|
||||
|
||||
const csrfToken = await getCsrfToken(page);
|
||||
|
||||
await request.post(`${WEBAPP_BASE_URL}/api/auth/callback/credentials`, {
|
||||
form: {
|
||||
email,
|
||||
password,
|
||||
json: true,
|
||||
csrfToken,
|
||||
},
|
||||
});
|
||||
|
||||
if (redirectPath) {
|
||||
await page.goto(`${WEBAPP_BASE_URL}${redirectPath}`);
|
||||
}
|
||||
};
|
||||
|
||||
export const apiSignout = async ({ page }: { page: Page }) => {
|
||||
const { request } = page.context();
|
||||
|
||||
const csrfToken = await getCsrfToken(page);
|
||||
|
||||
await request.post(`${WEBAPP_BASE_URL}/api/auth/signout`, {
|
||||
form: {
|
||||
csrfToken,
|
||||
json: true,
|
||||
},
|
||||
});
|
||||
|
||||
await page.goto(`${WEBAPP_BASE_URL}/signin`);
|
||||
};
|
||||
|
||||
const getCsrfToken = async (page: Page) => {
|
||||
const { request } = page.context();
|
||||
|
||||
const response = await request.fetch(`${WEBAPP_BASE_URL}/api/auth/csrf`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const { csrfToken } = await response.json();
|
||||
if (!csrfToken) {
|
||||
throw new Error('Invalid session');
|
||||
}
|
||||
|
||||
return csrfToken;
|
||||
};
|
||||
|
||||
@ -4,17 +4,21 @@ import path from 'node:path';
|
||||
import { getDocumentByToken } from '@documenso/lib/server-only/document/get-document-by-token';
|
||||
import { getRecipientByEmail } from '@documenso/lib/server-only/recipient/get-recipient-by-email';
|
||||
import { DocumentStatus } from '@documenso/prisma/client';
|
||||
import { TEST_USER } from '@documenso/prisma/seed/pr-718-add-stepper-component';
|
||||
import { seedUser } from '@documenso/prisma/seed/users';
|
||||
|
||||
import { apiSignin } from './fixtures/authentication';
|
||||
|
||||
test(`[PR-718]: should be able to create a document`, async ({ page }) => {
|
||||
await page.goto('/signin');
|
||||
|
||||
const documentTitle = `example-${Date.now()}.pdf`;
|
||||
|
||||
// Sign in
|
||||
await page.getByLabel('Email').fill(TEST_USER.email);
|
||||
await page.getByLabel('Password', { exact: true }).fill(TEST_USER.password);
|
||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
||||
const user = await seedUser();
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
// Upload document
|
||||
const [fileChooser] = await Promise.all([
|
||||
@ -31,8 +35,8 @@ test(`[PR-718]: should be able to create a document`, async ({ page }) => {
|
||||
// Wait to be redirected to the edit page
|
||||
await page.waitForURL(/\/documents\/\d+/);
|
||||
|
||||
// Set title
|
||||
await expect(page.getByRole('heading', { name: 'Add Title' })).toBeVisible();
|
||||
// Set general settings
|
||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||
|
||||
await page.getByLabel('Title').fill(documentTitle);
|
||||
|
||||
@ -82,10 +86,12 @@ test('should be able to create a document with multiple recipients', async ({ pa
|
||||
|
||||
const documentTitle = `example-${Date.now()}.pdf`;
|
||||
|
||||
// Sign in
|
||||
await page.getByLabel('Email').fill(TEST_USER.email);
|
||||
await page.getByLabel('Password', { exact: true }).fill(TEST_USER.password);
|
||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
||||
const user = await seedUser();
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
// Upload document
|
||||
const [fileChooser] = await Promise.all([
|
||||
@ -103,7 +109,7 @@ test('should be able to create a document with multiple recipients', async ({ pa
|
||||
await page.waitForURL(/\/documents\/\d+/);
|
||||
|
||||
// Set title
|
||||
await expect(page.getByRole('heading', { name: 'Add Title' })).toBeVisible();
|
||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||
|
||||
await page.getByLabel('Title').fill(documentTitle);
|
||||
|
||||
@ -112,13 +118,12 @@ test('should be able to create a document with multiple recipients', async ({ pa
|
||||
// Add signers
|
||||
await expect(page.getByRole('heading', { name: 'Add Signers' })).toBeVisible();
|
||||
|
||||
await page.getByLabel('Email*').fill('user1@example.com');
|
||||
await page.getByLabel('Name').fill('User 1');
|
||||
|
||||
// Add 2 signers.
|
||||
await page.getByPlaceholder('Email').fill('user1@example.com');
|
||||
await page.getByPlaceholder('Name').fill('User 1');
|
||||
await page.getByRole('button', { name: 'Add Signer' }).click();
|
||||
|
||||
await page.getByLabel('Email*').nth(1).fill('user2@example.com');
|
||||
await page.getByLabel('Name').nth(1).fill('User 2');
|
||||
await page.getByRole('textbox', { name: 'Email', exact: true }).fill('user2@example.com');
|
||||
await page.getByRole('textbox', { name: 'Name', exact: true }).fill('User 2');
|
||||
|
||||
await page.getByRole('button', { name: 'Continue' }).click();
|
||||
|
||||
@ -177,10 +182,12 @@ test('should be able to create, send and sign a document', async ({ page }) => {
|
||||
|
||||
const documentTitle = `example-${Date.now()}.pdf`;
|
||||
|
||||
// Sign in
|
||||
await page.getByLabel('Email').fill(TEST_USER.email);
|
||||
await page.getByLabel('Password', { exact: true }).fill(TEST_USER.password);
|
||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
||||
const user = await seedUser();
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
// Upload document
|
||||
const [fileChooser] = await Promise.all([
|
||||
@ -198,7 +205,7 @@ test('should be able to create, send and sign a document', async ({ page }) => {
|
||||
await page.waitForURL(/\/documents\/\d+/);
|
||||
|
||||
// Set title
|
||||
await expect(page.getByRole('heading', { name: 'Add Title' })).toBeVisible();
|
||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||
|
||||
await page.getByLabel('Title').fill(documentTitle);
|
||||
|
||||
@ -207,8 +214,8 @@ test('should be able to create, send and sign a document', async ({ page }) => {
|
||||
// Add signers
|
||||
await expect(page.getByRole('heading', { name: 'Add Signers' })).toBeVisible();
|
||||
|
||||
await page.getByLabel('Email*').fill('user1@example.com');
|
||||
await page.getByLabel('Name').fill('User 1');
|
||||
await page.getByPlaceholder('Email').fill('user1@example.com');
|
||||
await page.getByPlaceholder('Name').fill('User 1');
|
||||
|
||||
await page.getByRole('button', { name: 'Continue' }).click();
|
||||
|
||||
@ -225,8 +232,9 @@ test('should be able to create, send and sign a document', async ({ page }) => {
|
||||
// Assert document was created
|
||||
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();
|
||||
await page.getByRole('link', { name: documentTitle }).click();
|
||||
await page.waitForURL(/\/documents\/\d+/);
|
||||
|
||||
const url = await page.url().split('/');
|
||||
const url = page.url().split('/');
|
||||
const documentId = url[url.length - 1];
|
||||
|
||||
const { token } = await getRecipientByEmail({
|
||||
@ -260,10 +268,12 @@ test('should be able to create, send with redirect url, sign a document and redi
|
||||
|
||||
const documentTitle = `example-${Date.now()}.pdf`;
|
||||
|
||||
// Sign in
|
||||
await page.getByLabel('Email').fill(TEST_USER.email);
|
||||
await page.getByLabel('Password', { exact: true }).fill(TEST_USER.password);
|
||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
||||
const user = await seedUser();
|
||||
|
||||
await apiSignin({
|
||||
page,
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
// Upload document
|
||||
const [fileChooser] = await Promise.all([
|
||||
@ -280,18 +290,19 @@ test('should be able to create, send with redirect url, sign a document and redi
|
||||
// Wait to be redirected to the edit page
|
||||
await page.waitForURL(/\/documents\/\d+/);
|
||||
|
||||
// Set title
|
||||
await expect(page.getByRole('heading', { name: 'Add Title' })).toBeVisible();
|
||||
|
||||
// Set title & advanced redirect
|
||||
await expect(page.getByRole('heading', { name: 'General' })).toBeVisible();
|
||||
await page.getByLabel('Title').fill(documentTitle);
|
||||
await page.getByRole('button', { name: 'Advanced Options' }).click();
|
||||
await page.getByLabel('Redirect URL').fill('https://documenso.com');
|
||||
|
||||
await page.getByRole('button', { name: 'Continue' }).click();
|
||||
|
||||
// Add signers
|
||||
await expect(page.getByRole('heading', { name: 'Add Signers' })).toBeVisible();
|
||||
|
||||
await page.getByLabel('Email*').fill('user1@example.com');
|
||||
await page.getByLabel('Name').fill('User 1');
|
||||
await page.getByPlaceholder('Email').fill('user1@example.com');
|
||||
await page.getByPlaceholder('Name').fill('User 1');
|
||||
|
||||
await page.getByRole('button', { name: 'Continue' }).click();
|
||||
|
||||
@ -299,11 +310,6 @@ test('should be able to create, send with redirect url, sign a document and redi
|
||||
await expect(page.getByRole('heading', { name: 'Add Fields' })).toBeVisible();
|
||||
await page.getByRole('button', { name: 'Continue' }).click();
|
||||
|
||||
// Add subject and send
|
||||
await expect(page.getByRole('heading', { name: 'Add Subject' })).toBeVisible();
|
||||
await page.getByRole('button', { name: 'Advanced Options' }).click();
|
||||
await page.getByLabel('Redirect URL').fill('https://documenso.com');
|
||||
|
||||
await page.getByRole('button', { name: 'Send' }).click();
|
||||
|
||||
await page.waitForURL('/documents');
|
||||
@ -311,8 +317,9 @@ test('should be able to create, send with redirect url, sign a document and redi
|
||||
// Assert document was created
|
||||
await expect(page.getByRole('link', { name: documentTitle })).toBeVisible();
|
||||
await page.getByRole('link', { name: documentTitle }).click();
|
||||
await page.waitForURL(/\/documents\/\d+/);
|
||||
|
||||
const url = await page.url().split('/');
|
||||
const url = page.url().split('/');
|
||||
const documentId = url[url.length - 1];
|
||||
|
||||
const { token } = await getRecipientByEmail({
|
||||
|
||||
@ -4,14 +4,14 @@ import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
|
||||
import { seedTeam, unseedTeam } from '@documenso/prisma/seed/teams';
|
||||
import { seedUser } from '@documenso/prisma/seed/users';
|
||||
|
||||
import { manualLogin } from '../fixtures/authentication';
|
||||
import { apiSignin } from '../fixtures/authentication';
|
||||
|
||||
test.describe.configure({ mode: 'parallel' });
|
||||
|
||||
test('[TEAMS]: create team', async ({ page }) => {
|
||||
const user = await seedUser();
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: user.email,
|
||||
redirectPath: '/settings/teams',
|
||||
@ -38,7 +38,7 @@ test('[TEAMS]: create team', async ({ page }) => {
|
||||
test('[TEAMS]: delete team', async ({ page }) => {
|
||||
const team = await seedTeam();
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: team.owner.email,
|
||||
redirectPath: `/t/${team.url}/settings`,
|
||||
@ -56,7 +56,7 @@ test('[TEAMS]: delete team', async ({ page }) => {
|
||||
test('[TEAMS]: update team', async ({ page }) => {
|
||||
const team = await seedTeam();
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: team.owner.email,
|
||||
});
|
||||
|
||||
@ -6,7 +6,7 @@ import { seedDocuments, seedTeamDocuments } from '@documenso/prisma/seed/documen
|
||||
import { seedTeamEmail, unseedTeam, unseedTeamEmail } from '@documenso/prisma/seed/teams';
|
||||
import { seedUser } from '@documenso/prisma/seed/users';
|
||||
|
||||
import { manualLogin, manualSignout } from '../fixtures/authentication';
|
||||
import { apiSignin, apiSignout } from '../fixtures/authentication';
|
||||
|
||||
test.describe.configure({ mode: 'parallel' });
|
||||
|
||||
@ -30,7 +30,7 @@ test('[TEAMS]: check team documents count', async ({ page }) => {
|
||||
|
||||
// Run the test twice, once with the team owner and once with a team member to ensure the counts are the same.
|
||||
for (const user of [team.owner, teamMember2]) {
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: user.email,
|
||||
redirectPath: `/t/${team.url}/documents`,
|
||||
@ -55,7 +55,7 @@ test('[TEAMS]: check team documents count', async ({ page }) => {
|
||||
await checkDocumentTabCount(page, 'Draft', 1);
|
||||
await checkDocumentTabCount(page, 'All', 3);
|
||||
|
||||
await manualSignout({ page });
|
||||
await apiSignout({ page });
|
||||
}
|
||||
|
||||
await unseedTeam(team.url);
|
||||
@ -126,7 +126,7 @@ test('[TEAMS]: check team documents count with internal team email', async ({ pa
|
||||
|
||||
// Run the test twice, one with the team owner and once with the team member email to ensure the counts are the same.
|
||||
for (const user of [team.owner, teamEmailMember]) {
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: user.email,
|
||||
redirectPath: `/t/${team.url}/documents`,
|
||||
@ -151,7 +151,7 @@ test('[TEAMS]: check team documents count with internal team email', async ({ pa
|
||||
await checkDocumentTabCount(page, 'Draft', 1);
|
||||
await checkDocumentTabCount(page, 'All', 3);
|
||||
|
||||
await manualSignout({ page });
|
||||
await apiSignout({ page });
|
||||
}
|
||||
|
||||
await unseedTeamEmail({ teamId: team.id });
|
||||
@ -216,7 +216,7 @@ test('[TEAMS]: check team documents count with external team email', async ({ pa
|
||||
},
|
||||
]);
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: teamMember2.email,
|
||||
redirectPath: `/t/${team.url}/documents`,
|
||||
@ -248,7 +248,7 @@ test('[TEAMS]: check team documents count with external team email', async ({ pa
|
||||
test('[TEAMS]: delete pending team document', async ({ page }) => {
|
||||
const { team, teamMember2: currentUser } = await seedTeamDocuments();
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: currentUser.email,
|
||||
redirectPath: `/t/${team.url}/documents?status=PENDING`,
|
||||
@ -266,7 +266,7 @@ test('[TEAMS]: delete pending team document', async ({ page }) => {
|
||||
test('[TEAMS]: resend pending team document', async ({ page }) => {
|
||||
const { team, teamMember2: currentUser } = await seedTeamDocuments();
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: currentUser.email,
|
||||
redirectPath: `/t/${team.url}/documents?status=PENDING`,
|
||||
|
||||
@ -4,14 +4,14 @@ import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
|
||||
import { seedTeam, seedTeamEmailVerification, unseedTeam } from '@documenso/prisma/seed/teams';
|
||||
import { seedUser, unseedUser } from '@documenso/prisma/seed/users';
|
||||
|
||||
import { manualLogin } from '../fixtures/authentication';
|
||||
import { apiSignin } from '../fixtures/authentication';
|
||||
|
||||
test.describe.configure({ mode: 'parallel' });
|
||||
|
||||
test('[TEAMS]: send team email request', async ({ page }) => {
|
||||
const team = await seedTeam();
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: team.owner.email,
|
||||
password: 'password',
|
||||
@ -57,7 +57,7 @@ test('[TEAMS]: delete team email', async ({ page }) => {
|
||||
createTeamEmail: true,
|
||||
});
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: team.owner.email,
|
||||
redirectPath: `/t/${team.url}/settings`,
|
||||
@ -86,7 +86,7 @@ test('[TEAMS]: team email owner removes access', async ({ page }) => {
|
||||
email: team.teamEmail.email,
|
||||
});
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: teamEmailOwner.email,
|
||||
redirectPath: `/settings/teams`,
|
||||
|
||||
@ -4,7 +4,7 @@ import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
|
||||
import { seedTeam, seedTeamInvite, unseedTeam } from '@documenso/prisma/seed/teams';
|
||||
import { seedUser } from '@documenso/prisma/seed/users';
|
||||
|
||||
import { manualLogin } from '../fixtures/authentication';
|
||||
import { apiSignin } from '../fixtures/authentication';
|
||||
|
||||
test.describe.configure({ mode: 'parallel' });
|
||||
|
||||
@ -13,7 +13,7 @@ test('[TEAMS]: update team member role', async ({ page }) => {
|
||||
createTeamMembers: 1,
|
||||
});
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: team.owner.email,
|
||||
password: 'password',
|
||||
@ -75,7 +75,7 @@ test('[TEAMS]: member can leave team', async ({ page }) => {
|
||||
|
||||
const teamMember = team.members[1];
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: teamMember.user.email,
|
||||
password: 'password',
|
||||
@ -97,7 +97,7 @@ test('[TEAMS]: owner cannot leave team', async ({ page }) => {
|
||||
createTeamMembers: 1,
|
||||
});
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: team.owner.email,
|
||||
password: 'password',
|
||||
|
||||
@ -3,7 +3,7 @@ import { expect, test } from '@playwright/test';
|
||||
import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
|
||||
import { seedTeam, seedTeamTransfer, unseedTeam } from '@documenso/prisma/seed/teams';
|
||||
|
||||
import { manualLogin } from '../fixtures/authentication';
|
||||
import { apiSignin } from '../fixtures/authentication';
|
||||
|
||||
test.describe.configure({ mode: 'parallel' });
|
||||
|
||||
@ -14,7 +14,7 @@ test('[TEAMS]: initiate and cancel team transfer', async ({ page }) => {
|
||||
|
||||
const teamMember = team.members[1];
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: team.owner.email,
|
||||
password: 'password',
|
||||
|
||||
@ -4,7 +4,7 @@ import { WEBAPP_BASE_URL } from '@documenso/lib/constants/app';
|
||||
import { seedTeam, unseedTeam } from '@documenso/prisma/seed/teams';
|
||||
import { seedTemplate } from '@documenso/prisma/seed/templates';
|
||||
|
||||
import { manualLogin } from '../fixtures/authentication';
|
||||
import { apiSignin } from '../fixtures/authentication';
|
||||
|
||||
test.describe.configure({ mode: 'parallel' });
|
||||
|
||||
@ -36,7 +36,7 @@ test('[TEMPLATES]: view templates', async ({ page }) => {
|
||||
teamId: team.id,
|
||||
});
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: owner.email,
|
||||
redirectPath: '/templates',
|
||||
@ -81,7 +81,7 @@ test('[TEMPLATES]: delete template', async ({ page }) => {
|
||||
teamId: team.id,
|
||||
});
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: owner.email,
|
||||
redirectPath: '/templates',
|
||||
@ -135,7 +135,7 @@ test('[TEMPLATES]: duplicate template', async ({ page }) => {
|
||||
teamId: team.id,
|
||||
});
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: owner.email,
|
||||
redirectPath: '/templates',
|
||||
@ -181,7 +181,7 @@ test('[TEMPLATES]: use template', async ({ page }) => {
|
||||
teamId: team.id,
|
||||
});
|
||||
|
||||
await manualLogin({
|
||||
await apiSignin({
|
||||
page,
|
||||
email: owner.email,
|
||||
redirectPath: '/templates',
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
import dotenv from 'dotenv';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Read environment variables from file.
|
||||
* https://github.com/motdotla/dotenv
|
||||
*/
|
||||
// require('dotenv').config();
|
||||
const ENV_FILES = ['.env', '.env.local', `.env.${process.env.NODE_ENV || 'development'}`];
|
||||
|
||||
ENV_FILES.forEach((file) => {
|
||||
dotenv.config({
|
||||
path: path.join(__dirname, `../../${file}`),
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
|
||||
Reference in New Issue
Block a user