diff --git a/playwright/tests/organization.smtp.spec.ts b/playwright/tests/organization.smtp.spec.ts new file mode 100644 index 00000000..6d5788c4 --- /dev/null +++ b/playwright/tests/organization.smtp.spec.ts @@ -0,0 +1,170 @@ +import { test, expect, type TestInfo } from '@playwright/test'; +import { MailDev } from 'maildev'; + +import * as utils from "../global-utils"; +import { createAccount, logUser } from './setups/user'; + +let users = utils.loadEnv(); + +let mailserver, user1Mails, user2Mails, user3Mails; + +test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => { + mailserver = new MailDev({ + port: process.env.MAILDEV_SMTP_PORT, + web: { port: process.env.MAILDEV_HTTP_PORT }, + }) + + await mailserver.listen(); + + await utils.startVaultwarden(browser, testInfo, { + SMTP_HOST: process.env.MAILDEV_HOST, + SMTP_FROM: process.env.VAULTWARDEN_SMTP_FROM, + }); + + user1Mails = mailserver.iterator(users.user1.email); + user2Mails = mailserver.iterator(users.user2.email); + user3Mails = mailserver.iterator(users.user3.email); +}); + +test.afterAll('Teardown', async ({}, testInfo: TestInfo) => { + utils.stopVaultwarden(testInfo); + utils.closeMails(mailserver, [user1Mails, user2Mails, user3Mails]); +}); + +test('Create user3', async ({ page }) => { + await createAccount(test, page, users.user3, user3Mails); +}); + +test('Invite users', async ({ page }) => { + await createAccount(test, page, users.user1, user1Mails); + await logUser(test, page, users.user1, user1Mails); + + await test.step('Create Org', async () => { + await page.getByRole('link', { name: 'New organisation' }).click(); + await page.getByLabel('Organisation name (required)').fill('Test'); + await page.getByRole('button', { name: 'Submit' }).click(); + await page.locator('div').filter({ hasText: 'Members' }).nth(2).click(); + }); + + await test.step('Invite user2', async () => { + await page.getByRole('button', { name: 'Invite member' }).click(); + await page.getByLabel('Email (required)').fill(users.user2.email); + await page.getByRole('tab', { name: 'Collections' }).click(); + await page.getByLabel('Permission').selectOption('edit'); + await page.getByLabel('Select collections').click(); + await page.getByLabel('Options list').getByText('Default collection').click(); + await page.getByRole('button', { name: 'Save' }).click(); + await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); + await page.locator('#toast-container').getByRole('button').click(); + }); + + await test.step('Invite user3', async () => { + await page.getByRole('button', { name: 'Invite member' }).click(); + await page.getByLabel('Email (required)').fill(users.user3.email); + await page.getByRole('tab', { name: 'Collections' }).click(); + await page.getByLabel('Permission').selectOption('edit'); + await page.getByLabel('Select collections').click(); + await page.getByLabel('Options list').getByText('Default collection').click(); + await page.getByRole('button', { name: 'Save' }).click(); + await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); + await page.locator('#toast-container').getByRole('button').click(); + }); +}); + +test('invited with new account', async ({ page }) => { + const { value: invited } = await user2Mails.next(); + expect(invited.subject).toContain("Join Test") + + await test.step('Create account', async () => { + await page.setContent(invited.html); + const link = await page.getByTestId("invite").getAttribute("href"); + await page.goto(link); + await expect(page).toHaveTitle(/Create account | Vaultwarden Web/); + + await page.getByLabel('Name').fill(users.user2.name); + await page.getByLabel('Master password\n (required)', { exact: true }).fill(users.user2.password); + await page.getByLabel('Re-type master password').fill(users.user2.password); + await page.getByRole('button', { name: 'Create account' }).click(); + + // Back to the login page + await expect(page).toHaveTitle('Vaultwarden Web'); + await expect(page.getByTestId("toast-message")).toHaveText(/Your new account has been created/); + await page.locator('#toast-container').getByRole('button').click(); + + const { value: welcome } = await user2Mails.next(); + expect(welcome.subject).toContain("Welcome") + }); + + await test.step('Login', async () => { + await page.getByLabel(/Email address/).fill(users.user2.email); + await page.getByRole('button', { name: 'Continue' }).click(); + + // Unlock page + await page.getByLabel('Master password').fill(users.user2.password); + await page.getByRole('button', { name: 'Log in with master password' }).click(); + + // We are now in the default vault page + await expect(page).toHaveTitle(/Vaultwarden Web/); + await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); + await page.locator('#toast-container').getByRole('button').click(); + + const { value: logged } = await user2Mails.next(); + expect(logged.subject).toContain("New Device Logged"); + }); + + const { value: accepted } = await user1Mails.next(); + expect(accepted.subject).toContain("Invitation to Test accepted") +}); + +test('invited with existing account', async ({ page }) => { + const { value: invited } = await user3Mails.next(); + expect(invited.subject).toContain("Join Test") + + await page.setContent(invited.html); + const link = await page.getByTestId("invite").getAttribute("href"); + + await page.goto(link); + + // We should be on login page with email prefilled + await expect(page).toHaveTitle(/Vaultwarden Web/); + await page.getByRole('button', { name: 'Continue' }).click(); + + // Unlock page + await page.getByLabel('Master password').fill(users.user3.password); + await page.getByRole('button', { name: 'Log in with master password' }).click(); + + // We are now in the default vault page + await expect(page).toHaveTitle(/Vaultwarden Web/); + await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); + await page.locator('#toast-container').getByRole('button').click(); + + const { value: logged } = await user3Mails.next(); + expect(logged.subject).toContain("New Device Logged") + + const { value: accepted } = await user1Mails.next(); + expect(accepted.subject).toContain("Invitation to Test accepted") +}); + +test('Confirm invited user', async ({ page }) => { + await logUser(test, page, users.user1, user1Mails); + await page.getByLabel('Switch products').click(); + await page.getByRole('link', { name: ' Admin Console' }).click(); + await page.getByRole('link', { name: 'Members' }).click(); + + await test.step('Accept user2', async () => { + await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click(); + await page.getByRole('menuitem', { name: 'Confirm' }).click(); + await page.getByRole('button', { name: 'Confirm' }).click(); + await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); + await page.locator('#toast-container').getByRole('button').click(); + + const { value: logged } = await user2Mails.next(); + expect(logged.subject).toContain("Invitation to Test confirmed"); + }); +}); + +test('Organization is visible', async ({ page }) => { + await logUser(test, page, users.user2, user2Mails); + await page.getByLabel('vault: Test').click(); + await expect(page.getByLabel('Filter: Default collection')).toBeVisible(); +}); diff --git a/playwright/tests/organization.spec.ts b/playwright/tests/organization.spec.ts index f3e0bef9..0b051760 100644 --- a/playwright/tests/organization.spec.ts +++ b/playwright/tests/organization.spec.ts @@ -6,38 +6,21 @@ import { createAccount, logUser } from './setups/user'; let users = utils.loadEnv(); -let mailserver, user1Mails, user2Mails, user3Mails; - test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => { - mailserver = new MailDev({ - port: process.env.MAILDEV_SMTP_PORT, - web: { port: process.env.MAILDEV_HTTP_PORT }, - }) - - await mailserver.listen(); - - await utils.startVaultwarden(browser, testInfo, { - SMTP_HOST: process.env.MAILDEV_HOST, - SMTP_FROM: process.env.VAULTWARDEN_SMTP_FROM, - }); - - user1Mails = mailserver.iterator(users.user1.email); - user2Mails = mailserver.iterator(users.user2.email); - user3Mails = mailserver.iterator(users.user3.email); + await utils.startVaultwarden(browser, testInfo); }); test.afterAll('Teardown', async ({}, testInfo: TestInfo) => { utils.stopVaultwarden(testInfo); - utils.closeMails(mailserver, [user1Mails, user2Mails, user3Mails]); }); test('Create user3', async ({ page }) => { - await createAccount(test, page, users.user3, user3Mails); + await createAccount(test, page, users.user3); }); test('Invite users', async ({ page }) => { - await createAccount(test, page, users.user1, user1Mails); - await logUser(test, page, users.user1, user1Mails); + await createAccount(test, page, users.user1); + await logUser(test, page, users.user1); await test.step('Create Org', async () => { await page.getByRole('link', { name: 'New organisation' }).click(); @@ -55,6 +38,8 @@ test('Invite users', async ({ page }) => { await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByRole('button', { name: 'Save' }).click(); await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); + await page.locator('#toast-container').getByRole('button').click(); + await expect(page.getByRole('row', { name: users.user2.email })).toHaveText(/Invited/); }); await test.step('Invite user3', async () => { @@ -66,99 +51,44 @@ test('Invite users', async ({ page }) => { await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByRole('button', { name: 'Save' }).click(); await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); + await page.locator('#toast-container').getByRole('button').click(); + await expect(page.getByRole('row', { name: users.user3.name })).toHaveText(/Needs confirmation/); + }); + + await test.step('Confirm existing user3', async () => { + await page.getByRole('row', { name: users.user3.name }).getByLabel('Options').click(); + await page.getByRole('menuitem', { name: 'Confirm' }).click(); + await page.getByRole('button', { name: 'Confirm' }).click(); + await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); + await page.locator('#toast-container').getByRole('button').click(); }); }); -test('invited with new account', async ({ page }) => { - const { value: invited } = await user2Mails.next(); - expect(invited.subject).toContain("Join Test") - - await test.step('Create account', async () => { - await page.setContent(invited.html); - const link = await page.getByTestId("invite").getAttribute("href"); - await page.goto(link); - await expect(page).toHaveTitle(/Create account | Vaultwarden Web/); - - await page.getByLabel('Name').fill(users.user2.name); - await page.getByLabel('Master password\n (required)', { exact: true }).fill(users.user2.password); - await page.getByLabel('Re-type master password').fill(users.user2.password); - await page.getByRole('button', { name: 'Create account' }).click(); - - // Back to the login page - await expect(page).toHaveTitle('Vaultwarden Web'); - await expect(page.getByTestId("toast-message")).toHaveText(/Your new account has been created/); - - const { value: welcome } = await user2Mails.next(); - expect(welcome.subject).toContain("Welcome") - }); - - await test.step('Login', async () => { - await page.getByLabel(/Email address/).fill(users.user2.email); - await page.getByRole('button', { name: 'Continue' }).click(); - - // Unlock page - await page.getByLabel('Master password').fill(users.user2.password); - await page.getByRole('button', { name: 'Log in with master password' }).click(); - - // We are now in the default vault page - await expect(page).toHaveTitle(/Vaultwarden Web/); - await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); - - const { value: logged } = await user2Mails.next(); - expect(logged.subject).toContain("New Device Logged"); - }); - - const { value: accepted } = await user1Mails.next(); - expect(accepted.subject).toContain("Invitation to Test accepted") -}); - -test('invited with existing account', async ({ page }) => { - const { value: invited } = await user3Mails.next(); - expect(invited.subject).toContain("Join Test") - - await page.setContent(invited.html); - const link = await page.getByTestId("invite").getAttribute("href"); - - await page.goto(link); - - // We should be on login page with email prefilled - await expect(page).toHaveTitle(/Vaultwarden Web/); - await page.getByRole('button', { name: 'Continue' }).click(); - - // Unlock page - await page.getByLabel('Master password').fill(users.user3.password); - await page.getByRole('button', { name: 'Log in with master password' }).click(); - - // We are now in the default vault page - await expect(page).toHaveTitle(/Vaultwarden Web/); - await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); - - const { value: logged } = await user3Mails.next(); - expect(logged.subject).toContain("New Device Logged") - - const { value: accepted } = await user1Mails.next(); - expect(accepted.subject).toContain("Invitation to Test accepted") +test('Create invited account', async ({ page }) => { + await createAccount(test, page, users.user2); }); test('Confirm invited user', async ({ page }) => { - await logUser(test, page, users.user1, user1Mails); + await logUser(test, page, users.user1); await page.getByLabel('Switch products').click(); await page.getByRole('link', { name: ' Admin Console' }).click(); await page.getByRole('link', { name: 'Members' }).click(); - await test.step('Accept user2', async () => { + await test.step('Confirm user2', async () => { await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click(); await page.getByRole('menuitem', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); - - const { value: logged } = await user2Mails.next(); - expect(logged.subject).toContain("Invitation to Test confirmed"); }); }); -test('Organization is visible', async ({ page }) => { - await logUser(test, page, users.user2, user2Mails); +test('Organization is visible', async ({ context, page }) => { + await logUser(test, page, users.user2); await page.getByLabel('vault: Test').click(); await expect(page.getByLabel('Filter: Default collection')).toBeVisible(); + + const page2 = await context.newPage(); + await logUser(test, page2, users.user3); + await page2.getByLabel('vault: Test').click(); + await expect(page2.getByLabel('Filter: Default collection')).toBeVisible(); }); diff --git a/playwright/tests/sso_organization.smtp.spec.ts b/playwright/tests/sso_organization.smtp.spec.ts new file mode 100644 index 00000000..e64d6d67 --- /dev/null +++ b/playwright/tests/sso_organization.smtp.spec.ts @@ -0,0 +1,146 @@ +import { test, expect, type TestInfo } from '@playwright/test'; +import { MailDev } from 'maildev'; + +import * as utils from "../global-utils"; +import { logNewUser, logUser } from './setups/sso'; + +let users = utils.loadEnv(); + +let mailServer, mail1Buffer, mail2Buffer, mail3Buffer; + +test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => { + mailServer = new MailDev({ + port: process.env.MAILDEV_SMTP_PORT, + web: { port: process.env.MAILDEV_HTTP_PORT }, + }) + + await mailServer.listen(); + + await utils.startVaultwarden(browser, testInfo, { + SMTP_HOST: process.env.MAILDEV_HOST, + SMTP_FROM: process.env.VAULTWARDEN_SMTP_FROM, + SSO_ENABLED: true, + SSO_ONLY: true, + }); + + mail1Buffer = mailServer.buffer(users.user1.email); + mail2Buffer = mailServer.buffer(users.user2.email); + mail3Buffer = mailServer.buffer(users.user3.email); +}); + +test.afterAll('Teardown', async ({}) => { + utils.stopVaultwarden(); + [mailServer, mail1Buffer, mail2Buffer, mail3Buffer].map((m) => m?.close()); +}); + +test('Create user3', async ({ page }) => { + await logNewUser(test, page, users.user3, { mailBuffer: mail3Buffer }); +}); + +test('Invite users', async ({ page }) => { + await logNewUser(test, page, users.user1, { mailBuffer: mail1Buffer }); + + await test.step('Create Org', async () => { + await page.getByRole('link', { name: 'New organisation' }).click(); + await page.getByLabel('Organisation name (required)').fill('Test'); + await page.getByRole('button', { name: 'Submit' }).click(); + await page.locator('div').filter({ hasText: 'Members' }).nth(2).click(); + }); + + await test.step('Invite user2', async () => { + await page.getByRole('button', { name: 'Invite member' }).click(); + await page.getByLabel('Email (required)').fill(users.user2.email); + await page.getByRole('tab', { name: 'Collections' }).click(); + await page.getByLabel('Permission').selectOption('edit'); + await page.getByLabel('Select collections').click(); + await page.getByLabel('Options list').getByText('Default collection').click(); + await page.getByRole('button', { name: 'Save' }).click(); + await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); + await page.locator('#toast-container').getByRole('button').click(); + }); + + await test.step('Invite user3', async () => { + await page.getByRole('button', { name: 'Invite member' }).click(); + await page.getByLabel('Email (required)').fill(users.user3.email); + await page.getByRole('tab', { name: 'Collections' }).click(); + await page.getByLabel('Permission').selectOption('edit'); + await page.getByLabel('Select collections').click(); + await page.getByLabel('Options list').getByText('Default collection').click(); + await page.getByRole('button', { name: 'Save' }).click(); + await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); + await page.locator('#toast-container').getByRole('button').click(); + }); +}); + +test.fail('invited with new account', async ({ page }) => { + const link = await test.step('Extract email link', async () => { + const invited = await mail2Buffer.next((m) => m.subject === "Join Test"); + await page.setContent(invited.html); + return await page.getByTestId("invite").getAttribute("href"); + }); + + await test.step('Redirect to Keycloak', async () => { + await page.goto(link); + }); + + await test.step('Keycloak login', async () => { + await expect(page.getByRole('heading', { name: 'Sign in to your account' })).toBeVisible(); + await page.getByLabel(/Username/).fill(users.user2.name); + await page.getByLabel('Password', { exact: true }).fill(users.user2.password); + await page.getByRole('button', { name: 'Sign In' }).click(); + }); + + await test.step('Create Vault account', async () => { + await expect(page.getByText('Set master password')).toBeVisible(); + await page.getByLabel('Master password', { exact: true }).fill(users.user2.password); + await page.getByLabel('Re-type master password').fill(users.user2.password); + await page.getByRole('button', { name: 'Submit' }).click(); + }); + + await test.step('Default vault page', async () => { + await expect(page).toHaveTitle(/Vaultwarden Web/); + await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); + await page.locator('#toast-container').getByRole('button').click(); + }); + + await test.step('Check mails', async () => { + await expect(mail2Buffer.next((m) => m.subject.includes("New Device Logged"))).resolves.toBeDefined(); + await expect(mail1Buffer.next((m) => m.subject === "Invitation to Test accepted")).resolves.toBeDefined(); + }); +}); + +test('invited with existing account', async ({ page }) => { + const link = await test.step('Extract email link', async () => { + const invited = await mail3Buffer.next((m) => m.subject === "Join Test"); + await page.setContent(invited.html); + return await page.getByTestId("invite").getAttribute("href"); + }); + + await test.step('Redirect to Keycloak', async () => { + await page.goto(link); + }); + + await test.step('Keycloak login', async () => { + await expect(page.getByRole('heading', { name: 'Sign in to your account' })).toBeVisible(); + await page.getByLabel(/Username/).fill(users.user3.name); + await page.getByLabel('Password', { exact: true }).fill(users.user3.password); + await page.getByRole('button', { name: 'Sign In' }).click(); + }); + + await test.step('Unlock vault', async () => { + await expect(page).toHaveTitle('Vaultwarden Web'); + await page.getByLabel('Master password').fill(users.user3.password); + await page.getByRole('button', { name: 'Unlock' }).click(); + }); + + await test.step('Default vault page', async () => { + await expect(page).toHaveTitle(/Vaultwarden Web/); + await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); + await page.locator('#toast-container').getByRole('button').click(); + }); + + await test.step('Check mails', async () => { + await expect(mail3Buffer.next((m) => m.subject.includes("New Device Logged"))).resolves.toBeDefined(); + await expect(mail1Buffer.next((m) => m.subject === "Invitation to Test accepted")).resolves.toBeDefined(); + }); +}); diff --git a/playwright/tests/sso_organization.spec.ts b/playwright/tests/sso_organization.spec.ts index 851627be..f9e73c0d 100644 --- a/playwright/tests/sso_organization.spec.ts +++ b/playwright/tests/sso_organization.spec.ts @@ -6,39 +6,23 @@ import { logNewUser, logUser } from './setups/sso'; let users = utils.loadEnv(); -let mailServer, mail1Buffer, mail2Buffer, mail3Buffer; - test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => { - mailServer = new MailDev({ - port: process.env.MAILDEV_SMTP_PORT, - web: { port: process.env.MAILDEV_HTTP_PORT }, - }) - - await mailServer.listen(); - await utils.startVaultwarden(browser, testInfo, { - SMTP_HOST: process.env.MAILDEV_HOST, - SMTP_FROM: process.env.VAULTWARDEN_SMTP_FROM, SSO_ENABLED: true, SSO_ONLY: true, }); - - mail1Buffer = mailServer.buffer(users.user1.email); - mail2Buffer = mailServer.buffer(users.user2.email); - mail3Buffer = mailServer.buffer(users.user3.email); }); test.afterAll('Teardown', async ({}) => { utils.stopVaultwarden(); - [mailServer, mail1Buffer, mail2Buffer, mail3Buffer].map((m) => m?.close()); }); -test('Create user2', async ({ page }) => { - await logNewUser(test, page, users.user2, { mailBuffer: mail2Buffer }); +test('Create user3', async ({ page }) => { + await logNewUser(test, page, users.user3); }); test('Invite users', async ({ page }) => { - await logNewUser(test, page, users.user1, { mailBuffer: mail1Buffer }); + await logNewUser(test, page, users.user1); await test.step('Create Org', async () => { await page.getByRole('link', { name: 'New organisation' }).click(); @@ -56,6 +40,8 @@ test('Invite users', async ({ page }) => { await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByRole('button', { name: 'Save' }).click(); await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); + await page.locator('#toast-container').getByRole('button').click(); + await expect(page.getByRole('row', { name: users.user2.email })).toHaveText(/Invited/); }); await test.step('Invite user3', async () => { @@ -67,76 +53,42 @@ test('Invite users', async ({ page }) => { await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByRole('button', { name: 'Save' }).click(); await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); + await page.locator('#toast-container').getByRole('button').click(); + await expect(page.getByRole('row', { name: users.user3.name })).toHaveText(/Needs confirmation/); + }); + + await test.step('Confirm existing user3', async () => { + await page.getByRole('row', { name: users.user3.name }).getByLabel('Options').click(); + await page.getByRole('menuitem', { name: 'Confirm' }).click(); + await page.getByRole('button', { name: 'Confirm' }).click(); + await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); + await page.locator('#toast-container').getByRole('button').click(); }); }); -test('invited with existing account', async ({ page }) => { - const link = await test.step('Extract email link', async () => { - const invited = await mail2Buffer.next((m) => m.subject === "Join Test"); - await page.setContent(invited.html); - return await page.getByTestId("invite").getAttribute("href"); - }); +test('Create invited account', async ({ page }) => { + await logNewUser(test, page, users.user2); +}); - await test.step('Redirect to Keycloak', async () => { - await page.goto(link); - }); +test('Confirm invited user', async ({ page }) => { + await logUser(test, page, users.user1); + await page.getByLabel('Switch products').click(); + await page.getByRole('link', { name: ' Admin Console' }).click(); + await page.getByRole('link', { name: 'Members' }).click(); - await test.step('Keycloak login', async () => { - await expect(page.getByRole('heading', { name: 'Sign in to your account' })).toBeVisible(); - await page.getByLabel(/Username/).fill(users.user2.name); - await page.getByLabel('Password', { exact: true }).fill(users.user2.password); - await page.getByRole('button', { name: 'Sign In' }).click(); - }); + await expect(page.getByRole('row', { name: users.user2.name })).toHaveText(/Needs confirmation/); - await test.step('Unlock vault', async () => { - await expect(page).toHaveTitle('Vaultwarden Web'); - await page.getByLabel('Master password').fill(users.user2.password); - await page.getByRole('button', { name: 'Unlock' }).click(); - }); - - await test.step('Default vault page', async () => { - await expect(page).toHaveTitle(/Vaultwarden Web/); - await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); - }); - - await test.step('Check mails', async () => { - await expect(mail2Buffer.next((m) => m.subject.includes("New Device Logged"))).resolves.toBeDefined(); - await expect(mail1Buffer.next((m) => m.subject === "Invitation to Test accepted")).resolves.toBeDefined(); + await test.step('Confirm user2', async () => { + await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click(); + await page.getByRole('menuitem', { name: 'Confirm' }).click(); + await page.getByRole('button', { name: 'Confirm' }).click(); + await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); + await page.locator('#toast-container').getByRole('button').click(); }); }); -test('invited with new account', async ({ page }) => { - const link = await test.step('Extract email link', async () => { - const invited = await mail3Buffer.next((m) => m.subject === "Join Test"); - await page.setContent(invited.html); - return await page.getByTestId("invite").getAttribute("href"); - }); - - await test.step('Redirect to Keycloak', async () => { - await page.goto(link); - }); - - await test.step('Keycloak login', async () => { - await expect(page.getByRole('heading', { name: 'Sign in to your account' })).toBeVisible(); - await page.getByLabel(/Username/).fill(users.user3.name); - await page.getByLabel('Password', { exact: true }).fill(users.user3.password); - await page.getByRole('button', { name: 'Sign In' }).click(); - }); - - await test.step('Create Vault account', async () => { - await expect(page.getByText('Set master password')).toBeVisible(); - await page.getByLabel('Master password', { exact: true }).fill(users.user3.password); - await page.getByLabel('Re-type master password').fill(users.user3.password); - await page.getByRole('button', { name: 'Submit' }).click(); - }); - - await test.step('Default vault page', async () => { - await expect(page).toHaveTitle(/Vaultwarden Web/); - await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); - }); - - await test.step('Check mails', async () => { - await expect(mail3Buffer.next((m) => m.subject.includes("New Device Logged"))).resolves.toBeDefined(); - await expect(mail1Buffer.next((m) => m.subject === "Invitation to Test accepted")).resolves.toBeDefined(); - }); +test('Organization is visible', async ({ page }) => { + await logUser(test, page, users.user2); + await page.getByLabel('vault: Test').click(); + await expect(page.getByLabel('Filter: Default collection')).toBeVisible(); }); diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs index 524ae55b..a0fa60e9 100644 --- a/src/api/core/accounts.rs +++ b/src/api/core/accounts.rs @@ -293,6 +293,8 @@ async fn post_set_password(data: Json, headers: Headers, mut co if CONFIG.mail_enabled() { mail::send_set_password(&user.email.to_lowercase(), &user.name).await?; + } else { + Membership::confirm_user_invitations(&user.uuid, &mut conn).await?; } user.save(&mut conn).await?; diff --git a/src/api/identity.rs b/src/api/identity.rs index 47541528..9fce5ca8 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -254,10 +254,6 @@ async fn _sso_login(data: ConnectData, user_id: &mut Option, conn: &mut user.name = user_name; } - if !CONFIG.mail_enabled() { - Membership::confirm_user_invitations(&user.uuid, conn).await?; - } - user.save(conn).await?; } diff --git a/src/db/models/organization.rs b/src/db/models/organization.rs index 4a04596f..f9039aff 100644 --- a/src/db/models/organization.rs +++ b/src/db/models/organization.rs @@ -805,6 +805,8 @@ impl Membership { }} } + // Should be used only when email are disabled. + // In Organizations::send_invite status is set to Accepted only if the user has a password. pub async fn confirm_user_invitations(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult { db_run! { conn: { diesel::update(users_organizations::table) @@ -814,13 +816,6 @@ impl Membership { .execute(conn) .map_res("Error confirming invitations") }} - .and_then(|updated| match updated { - 1 => Ok(()), - count => err!(format!( - "Failed to update users_organizations to accepted for user ({}) was expecting invited status (updated row: {})).", - user_uuid, count - )), - }) } pub async fn find_any_state_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec {