passbolt-styleguide
Version:
Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.
446 lines (369 loc) • 18.4 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.1.0
*/
import { waitForTrue } from "../../../../test/utils/waitFor";
import {
defaultResourceDto,
resourceStandaloneTotpDto,
} from "../../../shared/models/entity/resource/resourceEntity.test.data";
import { defaultAppContext } from "../../contexts/AppContext.test.data";
import { defaultProps, denyUiActionProps } from "./HomePage.test.data";
import HomePagePage from "./HomePage.test.page";
import { createMemoryHistory } from "history";
import { defaultResourceMetadataDto } from "../../../shared/models/entity/resource/metadata/resourceMetadataEntity.test.data";
import MetadataTypesSettingsEntity from "../../../shared/models/entity/metadata/metadataTypesSettingsEntity";
import {
defaultMetadataTypesSettingsV50FreshDto,
defaultMetadataTypesSettingsV6Dto,
} from "../../../shared/models/entity/metadata/metadataTypesSettingsEntity.test.data";
import ResourceTypesCollection from "../../../shared/models/entity/resourceType/resourceTypesCollection";
import {
resourceTypesV4CollectionDto,
resourceTypesV5CollectionDto,
} from "../../../shared/models/entity/resourceType/resourceTypesCollection.test.data";
import { defaultUserDto } from "../../../shared/models/entity/user/userEntity.test.data";
import { v4 as uuidv4 } from "uuid";
import MetadataKeysSettingsEntity from "../../../shared/models/entity/metadata/metadataKeysSettingsEntity";
import { defaultMetadataKeysSettingsDto } from "../../../shared/models/entity/metadata/metadataKeysSettingsEntity.test.data";
beforeEach(() => {
jest.clearAllMocks();
});
describe("HomePage", () => {
describe("As LU I can see an updated version of the resources", () => {
/**
* This test should be executed first as it's changing a static props we don't have control on
*/
it("should ask for resource initialisation only once", async () => {
expect.assertions(3);
const props = defaultProps();
expect(props.resourcesLocalStorageContext.updateLocalStorage).toHaveBeenCalledTimes(0);
new HomePagePage(props);
expect(props.resourcesLocalStorageContext.updateLocalStorage).toHaveBeenCalledTimes(1);
new HomePagePage(props);
expect(props.resourcesLocalStorageContext.updateLocalStorage).toHaveBeenCalledTimes(1);
});
});
describe("As LU I can see the quickaccess homepage sections", () => {
it("As LU I can see the quickaccess filters and groups sections", () => {
expect.assertions(3);
const page = new HomePagePage(defaultProps());
expect(page.browseListTitle).toStrictEqual("Browse");
expect(page.filtersSection?.textContent).toStrictEqual("Filters");
expect(page.groupsSection?.textContent).toStrictEqual("Groups");
});
it("As LU I can see the quickaccess tag section if enabled by API flags", () => {
expect.assertions(3);
const page = new HomePagePage(defaultProps());
expect(page.browseListTitle).toStrictEqual("Browse");
expect(page.hasTagFilterEntry).toBeTruthy();
expect(page.tagsSection?.textContent).toStrictEqual("Tags");
});
it("As LU I cannot see the quickaccess tag section if disabled by API flags", () => {
expect.assertions(2);
const data = {
siteSettings: {
getServerTimezone: () => "",
canIUse: () => false,
},
};
const context = defaultAppContext(data);
const page = new HomePagePage(defaultProps({ context }));
expect(page.browseListTitle).toStrictEqual("Browse");
expect(page.hasTagFilterEntry).toBeFalsy();
});
it("As LU I cannot see the quickaccess tag section if I am not allowed to", () => {
expect.assertions(2);
const page = new HomePagePage(denyUiActionProps());
expect(page.browseListTitle).toStrictEqual("Browse");
expect(page.hasTagFilterEntry).toBeFalsy();
});
});
describe("As LU I can see filtered resources on the quickaccess homepage", () => {
it("it should show suggested resources for the currently active URL", async () => {
expect.assertions(2);
const props = defaultProps({
resources: [
defaultResourceDto({
metadata: defaultResourceMetadataDto({
name: "apache",
uris: ["http://www.passbolt.com", "http://www.apache.org"],
}),
}),
defaultResourceDto(),
],
});
props.context.getOpenerTabId = () => 1;
props.context.port.addRequestListener("passbolt.active-tab.get-url", async () => "http://www.apache.org/");
const page = new HomePagePage(props);
await waitForTrue(() => page.suggestedResourcesEntries?.length > 0);
const suggestedResource = props.resources[0];
expect(page.suggestedResourcesEntries.length).toStrictEqual(1);
expect(page.getSuggestedResourceItem(0).textContent).toStrictEqual(
`${suggestedResource.metadata.name} (${suggestedResource.metadata.username})${suggestedResource.metadata.uris[0]}+1`,
);
});
it("it should show suggested OTP resources for the currently active URL", async () => {
expect.assertions(2);
const props = defaultProps({
resources: [
resourceStandaloneTotpDto({
metadata: defaultResourceMetadataDto({
name: "apache totp",
username: null,
uris: ["http://www.apache.org"],
resource_type_id: undefined,
}),
}),
defaultResourceDto(),
],
});
props.context.getOpenerTabId = () => 1;
props.context.port.addRequestListener("passbolt.active-tab.get-url", async () => "http://www.apache.org/");
const page = new HomePagePage(props);
await waitForTrue(() => page.suggestedResourcesEntries?.length > 0);
const suggestedResource = props.resources[0];
expect(page.suggestedResourcesEntries.length).toStrictEqual(1);
expect(page.getSuggestedResourceItem(0).textContent).toStrictEqual(
`${suggestedResource.metadata.name} ${suggestedResource.metadata.uris[0]}`,
);
});
it("it should show both password and OTP suggested resources for the currently active URL", async () => {
expect.assertions(1);
const props = defaultProps({
resources: [
defaultResourceDto({
metadata: defaultResourceMetadataDto({
name: "apache password",
uris: ["http://www.apache.org"],
}),
}),
resourceStandaloneTotpDto({
metadata: defaultResourceMetadataDto({
name: "apache totp",
uris: ["http://www.apache.org"],
resource_type_id: undefined,
}),
}),
defaultResourceDto(),
],
});
props.context.getOpenerTabId = () => 1;
props.context.port.addRequestListener("passbolt.active-tab.get-url", async () => "http://www.apache.org/");
const page = new HomePagePage(props);
await waitForTrue(() => page.suggestedResourcesEntries?.length > 1);
expect(page.suggestedResourcesEntries.length).toStrictEqual(2);
});
it("it should show a message telling there is no suggested resources for the currently active URL", async () => {
expect.assertions(2);
const props = defaultProps({
resources: [defaultResourceDto(), defaultResourceDto()],
});
props.context.getOpenerTabId = () => 1;
props.context.port.addRequestListener("passbolt.active-tab.get-url", async () => "about:blank");
const page = new HomePagePage(props);
expect(page.suggestedResourcesEntries.length).toStrictEqual(0);
expect(page.suggestedResourcesContent.textContent).toStrictEqual(
"No passwords found for the current page. You can use the search.",
);
});
it("it should filter resources by the search search", async () => {
expect.assertions(2);
const props = defaultProps({
resources: [
defaultResourceDto({ metadata: defaultResourceMetadataDto({ name: "test" }) }),
defaultResourceDto({ metadata: defaultResourceMetadataDto({ name: "other" }) }),
],
});
props.context.getOpenerTabId = () => 1;
props.context.port.addRequestListener("passbolt.active-tab.get-url", async () => "about:blank");
//triggers a search on the available resources
props.context.search = "test";
const page = new HomePagePage(props);
const expectedResource = props.resources[0];
expect(page.browsedResources.length).toStrictEqual(1);
expect(page.browsedResources[0].textContent).toStrictEqual(
`${expectedResource.metadata.name} (${expectedResource.metadata.username})${expectedResource.metadata.uris[0]}`,
);
});
it("it should show a message if the search does not give any results", () => {
expect.assertions(2);
const props = defaultProps({
resources: [defaultResourceDto(), defaultResourceDto()],
});
props.context.getOpenerTabId = () => 1;
props.context.port.addRequestListener("passbolt.active-tab.get-url", async () => "about:blank");
//triggers a search on the available resources
props.context.search = "test";
const page = new HomePagePage(props);
expect(page.browsedResources.length).toStrictEqual(0);
expect(page.browsedResourcesContent.textContent).toStrictEqual(
"No result match your search. Try with another search term.",
);
});
});
describe("As LU I can use resource to auto-fill the current page", () => {
it("I can click on a suggested resource to use it on the current tab then the quickaccess closes", async () => {
expect.assertions(3);
const expectedOpenerTabId = 1;
const suggestedResource = defaultResourceDto({ metadata: { name: "apache", uris: ["http://www.apache.org"] } });
const props = defaultProps({ resources: [suggestedResource] });
props.context.getOpenerTabId = () => expectedOpenerTabId;
props.context.port.addRequestListener(
"passbolt.active-tab.get-url",
async () => suggestedResource.metadata.uris[0],
);
props.context.port.addRequestListener(
"passbolt.quickaccess.use-resource-on-current-tab",
async (resourceId, openerTabId) => {
expect(resourceId).toStrictEqual(suggestedResource.id);
expect(openerTabId).toStrictEqual(expectedOpenerTabId);
},
);
const page = new HomePagePage(props);
await waitForTrue(() => page.suggestedResourcesEntries?.length > 0);
await page.clickOnSuggestedResource(0);
await waitForTrue(() => props.context.closeWindow.mock.calls.length > 0);
expect(props.context.closeWindow).toHaveBeenCalledTimes(1);
});
it("I can click on a searched resource to use it on the current tab then the quickaccess closes", async () => {
expect.assertions(1);
const expectedOpenerTabId = 1;
const searchedResource = defaultResourceDto({ metadata: { name: "apache", uris: ["http://www.apache.org"] } });
const props = defaultProps({ resources: [searchedResource] });
props.context.getOpenerTabId = () => expectedOpenerTabId;
props.context.search = "apache";
props.context.port.addRequestListener("passbolt.active-tab.get-url", async () => "about:blank");
props.history = createMemoryHistory();
const initialPath = props.history.location.pathname;
const page = new HomePagePage(props);
await waitForTrue(() => page.browsedResources.length > 0);
await page.clickOnBrowsedResource(0);
await waitForTrue(() => props.history.location.pathname !== initialPath);
expect(props.history.location.pathname).toStrictEqual(
`/webAccessibleResources/quickaccess/resources/view/${searchedResource.id}`,
);
});
it("If I cannot use a resource on the current tab, I should see an error message and the quickaccess should not close", async () => {
expect.assertions(2);
const originalWindowClose = window.close;
window.close = jest.fn();
const expectedOpenerTabId = 1;
const suggestedResource = defaultResourceDto({ metadata: { name: "apache", uris: ["http://www.apache.org"] } });
const props = defaultProps({ resources: [suggestedResource] });
props.context.getOpenerTabId = () => expectedOpenerTabId;
props.context.port.addRequestListener(
"passbolt.active-tab.get-url",
async () => suggestedResource.metadata.uris[0],
);
props.context.port.addRequestListener("passbolt.quickaccess.use-resource-on-current-tab", async () => {
throw new Error();
});
const page = new HomePagePage(props);
await waitForTrue(() => page.suggestedResourcesEntries?.length > 0);
await page.clickOnSuggestedResource(0);
await waitForTrue(() => page.useOnThisTabError);
expect(page.useOnThisTabError.textContent).toStrictEqual(
"Unable to use the password on this page. Copy and paste the information instead.",
);
expect(window.close).not.toHaveBeenCalled();
window.close = originalWindowClose;
});
it("should not close the quickacess and not show the error message if the user aborted the operation", async () => {
expect.assertions(2);
const originalWindowClose = window.close;
window.close = jest.fn();
const expectedOpenerTabId = 1;
const suggestedResource = defaultResourceDto({ metadata: { name: "apache", uris: ["http://www.apache.org"] } });
const expectedError = new Error();
expectedError.name = "UserAbortsOperationError";
const props = defaultProps({ resources: [suggestedResource] });
props.context.getOpenerTabId = () => expectedOpenerTabId;
props.context.port.addRequestListener(
"passbolt.active-tab.get-url",
async () => suggestedResource.metadata.uris[0],
);
let requestDone = false;
props.context.port.addRequestListener("passbolt.quickaccess.use-resource-on-current-tab", async () => {
requestDone = true;
throw expectedError;
});
const page = new HomePagePage(props);
await waitForTrue(() => page.suggestedResourcesEntries?.length > 0);
await page.clickOnSuggestedResource(0);
await waitForTrue(() => requestDone);
expect(page.useOnThisTabError).toBeNull();
expect(window.close).not.toHaveBeenCalled();
window.close = originalWindowClose;
});
});
describe("As LU I can create resource from the button", () => {
it("should display the button if metadata type settings and resource types are loaded", () => {
const props = defaultProps();
const page = new HomePagePage(props);
expect(page.createButton).toBeDefined();
});
it("should display the button if metadata type settings and resource types are loaded for v5", () => {
const metadataTypeSettingEntity = new MetadataTypesSettingsEntity(defaultMetadataTypesSettingsV6Dto());
const props = defaultProps({ metadataTypeSettings: metadataTypeSettingEntity });
const page = new HomePagePage(props);
expect(page.createButton).toBeDefined();
});
it("should display action aborted missing metadata keys if share metadata key is enforced and user has missing keys", async () => {
expect.assertions(2);
const props = defaultProps({
context: defaultAppContext({
loggedInUser: defaultUserDto({ missing_metadata_key_ids: [uuidv4()] }, { withRole: true }),
}),
metadataTypeSettings: new MetadataTypesSettingsEntity(defaultMetadataTypesSettingsV50FreshDto()),
metadataKeysSettings: new MetadataKeysSettingsEntity(
defaultMetadataKeysSettingsDto({ allow_usage_of_personal_keys: false }),
),
});
props.history = createMemoryHistory();
const initialPath = props.history.location.pathname;
const page = new HomePagePage(props);
expect(page.createButton).toBeDefined();
await page.clickOnCreateButton();
await waitForTrue(() => props.history.location.pathname !== initialPath);
expect(props.history.location.pathname).toStrictEqual(
`/webAccessibleResources/quickaccess/resources/action-aborted-missing-metadata-keys`,
);
});
it("should not display the button if metadata type settings are not loaded", () => {
const props = defaultProps({ metadataTypeSettings: null });
const page = new HomePagePage(props);
expect(page.createButton).toBeNull();
});
it("should not display the button if resource types are not loaded", () => {
const props = defaultProps({ resourceTypes: null });
const page = new HomePagePage(props);
expect(page.createButton).toBeNull();
});
it("should not display the button if metadata type settings default is v5 and only v4 resource types is available", () => {
const metadataTypeSettingEntity = new MetadataTypesSettingsEntity(defaultMetadataTypesSettingsV50FreshDto());
const resourceTypesCollection = new ResourceTypesCollection(resourceTypesV4CollectionDto());
const props = defaultProps({
metadataTypeSettings: metadataTypeSettingEntity,
resourceTypes: resourceTypesCollection,
});
const page = new HomePagePage(props);
expect(page.createButton).toBeNull();
});
it("should not display the button if metadata type settings default is v4 and only v5 resource types is available", () => {
const resourceTypesCollection = new ResourceTypesCollection(resourceTypesV5CollectionDto());
const props = defaultProps({ resourceTypes: resourceTypesCollection });
const page = new HomePagePage(props);
expect(page.createButton).toBeNull();
});
});
});