passbolt-styleguide
Version:
Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.
416 lines (315 loc) • 16 kB
JavaScript
/**
* Passbolt ~ Open source password manager for teams
* Copyright (c) Passbolt SA (https://www.passbolt.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Passbolt SA (https://www.passbolt.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.passbolt.com Passbolt(tm)
* @since 4.2.0
*/
import "../../../../../test/mocks/mockPortal";
import { defaultAppContext } from "../../../contexts/ApiAppContext.test.data";
import { defaultProps } from "./DisplayPasswordPoliciesAdministration.test.data";
import DisplayPasswordPoliciesAdministrationPage from "./DisplayPasswordPoliciesAdministration.test.page";
import { waitFor } from "@testing-library/dom";
import { defaultPasswordPoliciesDto } from "../../../../shared/models/passwordPolicies/PasswordPoliciesDto.test.data";
import { screen, waitForElementToBeRemoved } from "@testing-library/react";
async function waitForTrue(callback) {
return waitFor(() => {
if (!callback()) {
throw new Error("state has not changed yet");
}
});
}
/**
* Unit tests on DisplayPasswordPoliciesAdministration in regard of specifications
*/
describe("DisplayPasswordPoliciesAdministration", () => {
let page, props;
const context = defaultAppContext();
const settingsDto = defaultPasswordPoliciesDto();
beforeEach(() => {
jest.clearAllMocks();
jest.resetModules();
props = defaultProps();
props.context.port.addRequestListener("passbolt.password-policies.get-admin-settings", () => settingsDto);
page = new DisplayPasswordPoliciesAdministrationPage(context, props);
});
describe("As an administrator I can read password policies settings of my organization", () => {
it('As a logged in administrator I can see the "password policy" settings in the administration workspace ', async () => {
expect.assertions(4);
expect(page.exists()).toBeTruthy();
expect(page.saveSettingsButton).not.toBeNull();
expect(page.title.textContent).toBe("Password Policy");
expect(page.passphrasePolicyTitle.textContent).toBe("Password generator default settings");
});
it("As a logged in administrator I can see an help box in the password policy administration screen ", async () => {
expect.assertions(5);
expect(page.helpBox).not.toBeNull();
expect(page.helpBoxTitle.textContent).toBe("What is password policy?");
expect(page.helpBoxDescription.textContent).toBe(
"For more information about the password policy settings, checkout the dedicated page on the help website.",
);
expect(page.helpBoxButton.textContent).toEqual("Read the documentation");
expect(page.helpBoxButton.getAttribute("href")).toEqual(
"https://passbolt.com/docs/admin/password-configuration/password-policy/",
);
});
});
describe("As an administrator I can update the password policies settings of my organization", () => {
it("As a logged in administrator I can see the don't forget to save banner", async () => {
expect.assertions(2);
expect(page.settingsChangedBanner).toBeNull();
await page.togglePasswordPanel();
await page.setFormWith({
passwordLengthInput: 20,
});
expect(page.settingsChangedBanner).not.toBeNull();
});
it("As a logged in administrator I can save the current configuration", async () => {
expect.assertions(6);
const newPasswordLength = "20";
const newPassphraseWordCount = "20";
context.port.addRequestListener("passbolt.password-policies.save", (passwordSettingsDto) => {
const expectedPasswordGeneratorSettings = Object.assign({}, settingsDto.password_generator_settings, {
length: newPasswordLength,
});
const expectedPassphraseGeneratorSettings = Object.assign({}, settingsDto.passphrase_generator_settings, {
words: newPassphraseWordCount,
});
const expectedRequest = Object.assign({}, settingsDto, {
password_generator_settings: expectedPasswordGeneratorSettings,
passphrase_generator_settings: expectedPassphraseGeneratorSettings,
});
expect(passwordSettingsDto).toStrictEqual(expectedRequest);
return passwordSettingsDto;
});
const spyOnFeedback = jest.spyOn(props.actionFeedbackContext, "displaySuccess");
expect(page.settingsChangedBanner).toBeNull();
await page.togglePasswordPanel();
await page.togglePassphrasePanel();
await page.setFormWith({
passwordLengthInput: newPasswordLength,
passphraseWordCountInput: newPassphraseWordCount,
});
expect(page.settingsChangedBanner).not.toBeNull();
await page.clickOnSave();
await waitForTrue(() => spyOnFeedback.mock.calls.length > 0);
expect(spyOnFeedback).toHaveBeenCalledWith("The password policy settings were updated.");
expect(spyOnFeedback).toHaveBeenCalledTimes(1);
await waitForElementToBeRemoved(() => page.settingsChangedBanner);
expect(page.settingsChangedBanner).toBeNull();
expect(props.passwordPoliciesContext.setPolicies).toHaveBeenCalledTimes(1);
});
it("As a logged in administrator I should see an error notification if the configuration could not be saved", async () => {
expect.assertions(1);
const expectedErrorMessage = "Something wrong happened";
props.context.port.addRequestListener("passbolt.password-policies.save", () => {
throw new Error(expectedErrorMessage);
});
const spyOnFeddback = jest.spyOn(props.actionFeedbackContext, "displayError");
await page.togglePasswordPanel();
await page.setFormWith({
passwordLengthInput: 20,
});
await page.clickOnSave();
await waitForTrue(() => spyOnFeddback.mock.calls.length > 0);
expect(spyOnFeddback).toHaveBeenCalledWith(expectedErrorMessage);
});
it("As a logged in administrator I should see the expected entropy of the password configurator change based on the current configuration", async () => {
expect.assertions(2);
const defaultConfigurationEntropy = "116.0 bits";
const passwordEntropyWith20Chars = "128.9 bits";
await page.togglePasswordPanel();
expect(page.passwordEntropyValue).toContain(defaultConfigurationEntropy);
await page.setFormWith({
passwordLengthInput: "20",
});
expect(page.passwordEntropyValue).toContain(passwordEntropyWith20Chars);
});
it("As a logged in administrator I should see the expected entropy of the passphrase configurator change based on the current configuration", async () => {
expect.assertions(2);
const passphraseEntropyWith9Words = "130.6 bits";
const passphraseEntropyWith20Words = "290.2 bits";
await page.togglePassphrasePanel();
expect(page.passphraseEntropyValue).toContain(passphraseEntropyWith9Words);
await page.setFormWith({
passphraseWordCountInput: "20",
});
expect(page.passphraseEntropyValue).toContain(passphraseEntropyWith20Words);
});
it("As a logged in administrator I should see a warning message if the passphrase entropy is not high enough to be considered strong", async () => {
expect.assertions(1);
await page.togglePasswordPanel();
await page.togglePassphrasePanel();
await page.setFormWith({
passwordLengthInput: "20",
passphraseWordCountInput: "4",
});
expect(page.minimalPassphraseEntropyAdvisedWarning).not.toBeNull();
});
it("As a logged in administrator I should see a warning message if the password entropy is not high enough to be considered strong", async () => {
expect.assertions(1);
await page.togglePasswordPanel();
await page.togglePassphrasePanel();
await page.setFormWith({
passwordLengthInput: "8",
passphraseWordCountInput: "40",
});
expect(page.minimalPasswordEntropyAdvisedWarning).not.toBeNull();
});
it("As a logged in administrator I should see an error message if I try to save passphrase generator settings that leads to have entropies that are under the minimum Passbolt's requirement", async () => {
expect.assertions(1);
await page.togglePasswordPanel();
await page.togglePassphrasePanel();
await page.setFormWith({
passwordLengthInput: "20",
passphraseWordCountInput: "4",
});
await page.clickOnSave();
expect(page.minimalPassphraseEntropyError).not.toBeNull();
});
it("As a logged in administrator I should see an error message if I try to save password generator settings that leads to have entropies that are under the minimum Passbolt's requirement", async () => {
expect.assertions(1);
await page.togglePasswordPanel();
await page.togglePassphrasePanel();
await page.setFormWith({
passwordLengthInput: "8",
passphraseWordCountInput: "40",
});
await page.clickOnSave();
expect(page.minimalPasswordEntropyError).not.toBeNull();
});
it("As a logged in administrator I should see an error message if the words separator is too long", async () => {
expect.assertions(1);
await page.togglePassphrasePanel();
await page.setFormWith({
passphraseWordsSeparatorInput: "".padStart(11, " "),
});
await page.clickOnSave();
expect(page.wordsSeparatorErrorMessage).not.toBeNull();
});
it("As a logged in administrator I can toggle the external dictionary check", async () => {
expect.assertions(1);
await screen.findByRole("checkbox", {
name: /external services/i,
checked: true,
});
const currentToggleState = page.externalDictionaryCheck.checked;
await page.clickOnExternalDictionaryCheck();
expect(page.externalDictionaryCheck.checked).not.toBe(currentToggleState);
});
it("As a logged in administrator I can change the password mask to use by default", async () => {
const maskButtonsLength = 10;
expect.assertions(maskButtonsLength + 1);
await page.togglePasswordPanel();
const maskButtons = page.maskButtons;
expect(maskButtons.length).toStrictEqual(maskButtonsLength);
for (let i = 0; i < maskButtonsLength; i++) {
const isChecked = maskButtons[i].classList.contains("selected");
await page.clickOnMaskButton(maskButtons[i]);
expect(page.getMaskButton(i).classList.contains("selected")).not.toBe(isChecked);
}
});
it("As a logged in administrator I should see an error if I unselect all the password mask", async () => {
expect.assertions(1);
await page.togglePasswordPanel();
const maskButtons = page.activeMaskButtons;
for (let i = 0; i < maskButtons.length; i++) {
await page.clickOnMaskButton(maskButtons[i]);
}
await page.clickOnSave();
expect(page.maskError).not.toBeNull();
});
it("As a logged in administrator I can see the error messages associated to the secret length", async () => {
expect.assertions(2);
await page.togglePasswordPanel();
await page.togglePassphrasePanel();
await page.setFormWith({
passwordLengthInput: 1,
passphraseWordCountInput: 1,
});
await page.clickOnSave();
expect(page.passwordLengthError).not.toBeNull();
expect(page.passphraseLengthError).not.toBeNull();
});
it("As a logged in administrator I can choose passphrase as default generator", async () => {
expect.assertions(1);
await page.choosePassphraseAsDefaultGenerator();
expect(page.defaultGeneratorSelectedValue).toBe("Passphrase");
});
});
describe("As AD I should be warned that the source of the configuration is about to change", () => {
it("As a logged in administrator I should be warned if the current configuration source is the environment variable and that I'm about to change that.", async () => {
expect.assertions(1);
const currentSettings = defaultPasswordPoliciesDto({ source: "env" });
const props = defaultProps();
props.context.port.addRequestListener("passbolt.password-policies.get-admin-settings", () => currentSettings);
const page = new DisplayPasswordPoliciesAdministrationPage(context, props);
await waitForTrue(() => Boolean(page.sourceChangingBanner));
expect(page.sourceChangingBanner).not.toBeNull();
});
it("As a logged in administrator I should not be warned if the current configuration source the database.", async () => {
expect.assertions(1);
const currentSettings = defaultPasswordPoliciesDto({ source: "db" });
const props = defaultProps();
props.context.port.addRequestListener("passbolt.password-policies.get-admin-settings", () => currentSettings);
const page = new DisplayPasswordPoliciesAdministrationPage(context, props);
expect(page.sourceChangingBanner).toBeNull();
});
it("As a logged in administrator I should not be warned if the current configuration source is 'default'.", async () => {
expect.assertions(1);
const currentSettings = defaultPasswordPoliciesDto({ source: "default" });
const props = defaultProps();
props.context.port.addRequestListener("passbolt.password-policies.get-admin-settings", () => currentSettings);
const page = new DisplayPasswordPoliciesAdministrationPage(context, props);
expect(page.sourceChangingBanner).toBeNull();
});
});
describe("As AD I should not be able to see the source of the configuration", () => {
it("when it's coming from the default configuration", async () => {
expect.assertions(1);
const context = defaultAppContext();
const settingsDto = defaultPasswordPoliciesDto({
source: null,
});
const props = defaultProps();
props.context.port.addRequestListener("passbolt.password-policies.get-admin-settings", () => settingsDto);
page = new DisplayPasswordPoliciesAdministrationPage(context, props);
await waitForTrue(() => Boolean(page.settingsSource));
expect(page.settingsSource.textContent).toStrictEqual(
"This current configuration source is: default configuration.",
);
});
it("when it's coming from the database", async () => {
expect.assertions(1);
const context = defaultAppContext();
const settingsDto = defaultPasswordPoliciesDto({
source: "db",
});
const props = defaultProps();
props.context.port.addRequestListener("passbolt.password-policies.get-admin-settings", () => settingsDto);
page = new DisplayPasswordPoliciesAdministrationPage(context, props);
await waitForTrue(() => Boolean(page.settingsSource?.textContent?.includes("database")));
expect(page.settingsSource.textContent).toStrictEqual("This current configuration source is: database.");
});
it("when it's coming from a environment variables", async () => {
expect.assertions(1);
const context = defaultAppContext();
const settingsDto = defaultPasswordPoliciesDto({
source: "env",
});
const props = defaultProps();
props.context.port.addRequestListener("passbolt.password-policies.get-admin-settings", () => settingsDto);
page = new DisplayPasswordPoliciesAdministrationPage(context, props);
await waitForTrue(() => Boolean(page.settingsSource?.textContent?.includes("environment variables")));
expect(page.settingsSource.textContent).toStrictEqual(
"This current configuration source is: environment variables.",
);
});
});
});