diff --git a/src/features/preferences/extension-adding-preference-tabs.test.tsx b/src/features/preferences/extension-adding-preference-tabs.test.tsx index 47810df727..06b2a2ea43 100644 --- a/src/features/preferences/extension-adding-preference-tabs.test.tsx +++ b/src/features/preferences/extension-adding-preference-tabs.test.tsx @@ -7,6 +7,8 @@ import type { IObservableValue } from "mobx"; import { runInAction, computed, observable } from "mobx"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; +import { getSingleElement, queryAllElements, querySingleElement } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import React from "react"; describe("preferences: extension adding preference tabs", () => { let builder: ApplicationBuilder; @@ -49,11 +51,43 @@ describe("preferences: extension adding preference tabs", () => { visible: computed(() => someObservable.get()), }, ], + + appPreferences: [ + { + title: "some-title", + id: "some-preference-item-id", + showInPreferencesTab: "some-preference-tab-id", + + components: { + Hint: () =>
, + Input: () => , + }, + }, + { + title: "some-other-title", + id: "some-other-preference-item-id", + showInPreferencesTab: "some-other-preference-tab-id", + + components: { + Hint: () => , + Input: () => , + }, + }, + { + title: "some-another-title", + id: "some-another-preference-item-id", + showInPreferencesTab: "some-preference-tab-id-with-controlled-visibility", + + components: { + Hint: () => , + Input: () => , + }, + }, + ], }, }; builder.extensions.enable(testExtension); - }); it("renders", () => { @@ -61,20 +95,25 @@ describe("preferences: extension adding preference tabs", () => { }); it("shows tabs in order", () => { - const actual = rendered.queryAllByTestId(/tab-link-for-extension-some-extension-nav-item-(.*)/).map(x => x.dataset.testid); + const actual = queryAllElements("preference-tab-link")( + rendered, + ).attributeValues.filter((value) => + value?.startsWith("extension-some-extension"), + ); expect(actual).toEqual([ - "tab-link-for-extension-some-extension-nav-item-some-other-preference-tab-id", - "tab-link-for-extension-some-extension-nav-item-some-preference-tab-id", + "extension-some-extension-some-other-preference-tab-id", + "extension-some-extension-some-preference-tab-id", ]); }); it("does not show hidden tab", () => { - const actual = rendered.queryByTestId( - "tab-link-for-extension-some-extension-nav-item-some-preference-tab-id-with-controlled-visibility", - ); + const actual = querySingleElement( + "preference-tab-link", + "extension-some-extension-some-preference-tab-id-with-controlled-visibility", + )(rendered); - expect(actual).not.toBeInTheDocument(); + expect(actual).toBeNull(); }); it("when item becomes visible, shows the tab", () => { @@ -82,11 +121,12 @@ describe("preferences: extension adding preference tabs", () => { someObservable.set(true); }); - const actual = rendered.queryByTestId( - "tab-link-for-extension-some-extension-nav-item-some-preference-tab-id-with-controlled-visibility", - ); + const actual = getSingleElement( + "preference-tab-link", + "extension-some-extension-some-preference-tab-id-with-controlled-visibility", + )(rendered); - expect(actual).toBeInTheDocument(); + expect(actual).not.toBeNull(); }); }); }); diff --git a/src/features/preferences/navigation-to-extension-specific-preferences.test.tsx b/src/features/preferences/navigation-to-extension-specific-preferences.test.tsx index cb44c1770c..7ae53037e5 100644 --- a/src/features/preferences/navigation-to-extension-specific-preferences.test.tsx +++ b/src/features/preferences/navigation-to-extension-specific-preferences.test.tsx @@ -7,8 +7,9 @@ import type { ApplicationBuilder } from "../../renderer/components/test-utils/ge import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import React from "react"; import "@testing-library/jest-dom/extend-expect"; -import extensionPreferencesRouteInjectable from "../../common/front-end-routing/routes/preferences/extension/extension-preferences-route.injectable"; import type { FakeExtensionOptions } from "../../renderer/components/test-utils/get-extension-fake"; +import { getSingleElement, queryAllElements, querySingleElement } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import logErrorInjectable from "../../common/log-error.injectable"; describe("preferences - navigation to extension specific preferences", () => { let builder: ApplicationBuilder; @@ -19,9 +20,14 @@ describe("preferences - navigation to extension specific preferences", () => { describe("given in preferences, when rendered", () => { let rendered: RenderResult; + let logErrorMock: jest.Mock; beforeEach(async () => { - builder.beforeWindowStart(() => { + logErrorMock = jest.fn(); + + builder.beforeWindowStart((windowDi) => { + windowDi.override(logErrorInjectable, () => logErrorMock); + builder.preferences.navigate(); }); @@ -33,7 +39,8 @@ describe("preferences - navigation to extension specific preferences", () => { }); it("does not show extension preferences yet", () => { - const page = rendered.queryByTestId("extension-preferences-page"); + // Todo: check if query is correct. + const page = querySingleElement("preference-page", "extension")(rendered); expect(page).toBeNull(); }); @@ -52,7 +59,7 @@ describe("preferences - navigation to extension specific preferences", () => { ); builder.preferences.navigation.click( - "extension-some-test-extension-id", + "some-test-extension-id", ); }); @@ -61,13 +68,19 @@ describe("preferences - navigation to extension specific preferences", () => { }); it("doesn't show preferences from unrelated extension", () => { - const actual = rendered.queryByTestId("extension-preference-item-for-some-other-preference-item-id"); + const actual = querySingleElement( + "preference-page", + "preference-item-for-extension-some-other-test-extension-id-page", + )(rendered); expect(actual).toBeNull(); }); it("shows preferences from related extension", () => { - const actual = rendered.getByTestId("extension-preference-item-for-some-preference-item-id"); + const actual = getSingleElement( + "preference-page", + "preference-item-for-extension-some-test-extension-id-page", + )(rendered); expect(actual).not.toBeNull(); }); @@ -104,21 +117,18 @@ describe("preferences - navigation to extension specific preferences", () => { expect(rendered.container).toMatchSnapshot(); }); - it("shows link for extension preferences", () => { - const actual = rendered.getByTestId("tab-link-for-extension-some-test-extension-id"); - - expect(actual).not.toBeNull(); - }); - it("link should not be active", () => { - const actual = rendered.getByTestId("tab-link-for-extension-some-test-extension-id"); + const actual = getSingleElement( + "preference-tab-link", + "some-test-extension-id", + )(rendered); expect(actual).not.toHaveClass("active"); }); describe("when navigating to extension preferences using navigation", () => { beforeEach(() => { - builder.preferences.navigation.click("extension-some-test-extension-id"); + builder.preferences.navigation.click("some-test-extension-id"); }); it("renders", () => { @@ -126,31 +136,23 @@ describe("preferences - navigation to extension specific preferences", () => { }); it("shows proper page title", () => { - const title = rendered.getByText("some-test-extension-id preferences"); + const title = getSingleElement("preference-page-title")(rendered); - expect(title).toBeInTheDocument(); + expect(title).toHaveTextContent("some-test-extension-id preferences"); }); - it("shows extension specific preferences", () => { - const page = rendered.getByTestId("extension-preferences-page"); + it("shows only extension specific preference items", () => { + const actual = queryAllElements( + "preference-item", + )(rendered).attributeValues; - expect(page).not.toBeNull(); - }); - - it("shows extension specific preference item", () => { - const actual = rendered.getByTestId("extension-preference-item-for-some-preference-item-id"); - - expect(actual).not.toBeNull(); - }); - - it("does not show unrelated preference tab items", () => { - const actual = rendered.queryByTestId("extension-preference-item-for-some-unrelated-preference-item-id"); - - expect(actual).toBeNull(); + expect(actual).toEqual([ + "preference-item-for-extension-some-test-extension-id-item-some-preference-item-id", + ]); }); it("link is active", () => { - const actual = rendered.getByTestId("tab-link-for-extension-some-test-extension-id"); + const actual = getSingleElement("preference-tab-link", "some-test-extension-id")(rendered); expect(actual).toHaveClass("active"); }); @@ -164,14 +166,21 @@ describe("preferences - navigation to extension specific preferences", () => { expect(rendered.baseElement).toMatchSnapshot(); }); - it("shows the error message about extension not being present", () => { - expect(rendered.getByTestId("error-for-extension-not-being-present")).toBeInTheDocument(); + it("does not show any preference page", () => { + const actual = querySingleElement("preference-page")(rendered); + + expect(actual).toBeNull(); }); - it("when extension is enabled again, does not show the error message anymore", () => { + it("when extension is enabled again, shows the preference page", () => { builder.extensions.enable(extensionStubWithExtensionSpecificPreferenceItems); - expect(rendered.queryByTestId("error-for-extension-not-being-present")).not.toBeInTheDocument(); + const actual = getSingleElement( + "preference-page", + "preference-item-for-extension-some-test-extension-id-page", + )(rendered); + + expect(actual).not.toBeNull(); }); }); }); @@ -179,90 +188,104 @@ describe("preferences - navigation to extension specific preferences", () => { describe("given extension with registered tab", () => { beforeEach(() => { - builder.extensions.enable(extensionStubWithWithRegisteredTab); + builder.extensions.enable(extensionStubWithRegisteredTab); + }); + + it("logs error", () => { + expect( + logErrorMock.mock.calls[0][0].startsWith( + "Tried to create preferences, but encountered references to unknown ids", + ), + ).toBe(true); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); }); it("shows extension tab in general area", () => { - const actual = rendered.getByTestId("tab-link-for-extension-registered-tab-page-id-nav-item-metrics-extension-tab"); + const generalTabGroup = getSingleElement( + "preference-tab-group", + "general-tab-group", + )(rendered); - expect(actual).toMatchSnapshot(); + const actual = getSingleElement( + "preference-tab-link", + "extension-registered-tab-page-id-metrics-extension-tab", + )(generalTabGroup); + + expect(actual).not.toBeNull(); }); - it("does not show custom settings block", () => { - const actual = rendered.queryByTestId("extension-settings"); + it("does not show tab group for extensions for there being no content", () => { + const actual = querySingleElement( + "preference-tab-group", + "extensions-tab-group", + )(rendered); - expect(actual).not.toBeInTheDocument(); + expect(actual).toBeNull(); }); describe("when navigating to specific extension tab", () => { beforeEach(() => { - builder.preferences.navigation.click("extension-registered-tab-page-id-nav-item-metrics-extension-tab"); + builder.preferences.navigation.click("extension-registered-tab-page-id-metrics-extension-tab"); }); + it("renders", () => { expect(rendered.container).toMatchSnapshot(); }); + it("shows related preferences for this tab", () => { const actual = rendered.getByTestId("metrics-preference-item-hint"); expect(actual).toBeInTheDocument(); }); + it("does not show unrelated preferences for this tab", () => { const actual = rendered.queryByTestId("survey-preference-item-hint"); expect(actual).not.toBeInTheDocument(); }); - it("shows page title", () => { - const pageTitle = rendered.queryByTestId("extension-preferences-page-title"); - expect(pageTitle).toBeInTheDocument(); + it("shows correct page title", () => { + const pageTitle = getSingleElement("preference-page-title")(rendered); + + expect(pageTitle).toHaveTextContent("Metrics tab"); }); - it("shows page title same as tab title", () => { - const pageTitle = rendered.queryByTestId("extension-preferences-page-title"); - const tabs = extensionStubWithWithRegisteredTab.rendererOptions?.appPreferenceTabs; - const tabTitle = tabs && tabs[0].title; - - expect(pageTitle?.innerHTML).toBe(tabTitle); - }); - }); - }); - - describe("given extension with few registered tabs", () => { - const tabs = [ - "tab-link-for-extension-hello-world-tab-page-id-nav-item-hello-extension-tab", - "tab-link-for-extension-hello-world-tab-page-id-nav-item-logs-extension-tab", - ]; - - beforeEach(() => { - builder.extensions.enable(extensionStubWithWithRegisteredTabs); - }); - - it.each(tabs)("shows '%s' tab in general area", (tab) => { - const tabElement = rendered.getByTestId(tab); - - expect(tabElement).toBeInTheDocument(); }); }); describe("given extensions with tabs having same id", () => { beforeEach(() => { - builder.extensions.enable(extensionStubWithWithRegisteredTab, extensionStubWithWithSameRegisteredTab); + builder.extensions.enable( + extensionStubWithRegisteredTab, + extensionStubWithSameRegisteredTab, + ); }); it("shows tab from the first extension", () => { - const actual = rendered.getByTestId("tab-link-for-extension-registered-tab-page-id-nav-item-metrics-extension-tab"); + const actual = getSingleElement( + "preference-tab-link", + "extension-registered-tab-page-id-metrics-extension-tab", + )(rendered); expect(actual).toBeInTheDocument(); }); it("shows tab from the second extension", () => { - const actual = rendered.getByTestId("tab-link-for-extension-duplicated-tab-page-id-nav-item-metrics-extension-tab"); + const actual = getSingleElement( + "preference-tab-link", + "extension-duplicated-tab-page-id-metrics-extension-tab", + )(rendered); expect(actual).toBeInTheDocument(); }); describe("when navigating to first extension tab", () => { beforeEach(() => { - builder.preferences.navigation.click("extension-registered-tab-page-id-nav-item-metrics-extension-tab"); + builder.preferences.navigation.click( + "extension-registered-tab-page-id-metrics-extension-tab", + ); }); it("renders", () => { @@ -270,21 +293,20 @@ describe("preferences - navigation to extension specific preferences", () => { }); it("shows related preferences for this tab", () => { - const actual = rendered.getByTestId("metrics-preference-item-hint"); + const actual = + queryAllElements("preference-item")(rendered).attributeValues; - expect(actual).toBeInTheDocument(); - }); - - it("does not show unrelated preferences for this tab", () => { - const actual = rendered.queryByTestId("another-metrics-preference-item-hint"); - - expect(actual).not.toBeInTheDocument(); + expect(actual).toEqual([ + "preference-item-for-extension-registered-tab-page-id-item-metrics-preference-item-id", + ]); }); }); describe("when navigating to second extension tab", () => { beforeEach(() => { - builder.preferences.navigation.click("extension-duplicated-tab-page-id-nav-item-metrics-extension-tab"); + builder.preferences.navigation.click( + "extension-duplicated-tab-page-id-metrics-extension-tab", + ); }); it("renders", () => { @@ -292,74 +314,16 @@ describe("preferences - navigation to extension specific preferences", () => { }); it("shows related preferences for this tab", () => { - const actual = rendered.getByTestId("another-metrics-preference-item-hint"); + const actual = + queryAllElements("preference-item")(rendered).attributeValues; - expect(actual).toBeInTheDocument(); - }); - - it("does not show unrelated preferences for this tab", () => { - const actual = rendered.queryByTestId("metrics-preference-item-hint"); - - expect(actual).not.toBeInTheDocument(); + expect(actual).toEqual([ + "preference-item-for-extension-duplicated-tab-page-id-item-another-metrics-preference-item-id", + ]); }); }); }); }); - - describe("when navigating to extension specific tab", () => { - let rendered: RenderResult; - - beforeEach(async () => { - builder.beforeWindowStart((windowDi) => { - const extensionRoute = windowDi.inject(extensionPreferencesRouteInjectable); - - const params = { parameters: { - extensionId: "duplicated-tab-page-id", - tabId: "metrics-extension-tab", - }}; - - builder.preferences.navigateTo(extensionRoute, params); - }); - - builder.extensions.enable(extensionStubWithWithSameRegisteredTab, extensionUsingSomeoneElseTab); - rendered = await builder.render(); - }); - - it("renders", () => { - expect(rendered.container).toMatchSnapshot(); - }); - - it("does render related preferences for specific tab", () => { - expect(rendered.getByTestId("another-metrics-preference-item-hint")).toBeInTheDocument(); - }); - - it("does not render related preferences for specific tab", () => { - expect(rendered.queryByTestId("my-preferences-item-hint")).not.toBeInTheDocument(); - }); - }); - - describe("when navigating to someone else extension specific tab", () => { - let rendered: RenderResult; - - beforeEach(async () => { - builder.beforeWindowStart((windowDi) => { - const extensionRoute = windowDi.inject(extensionPreferencesRouteInjectable); - const params = { parameters: { - extensionId: "extension-using-someone-else-tab-id", - tabId: "metrics-extension-tab", - }}; - - builder.preferences.navigateTo(extensionRoute, params); - }); - - builder.extensions.enable(extensionStubWithWithSameRegisteredTab, extensionUsingSomeoneElseTab); - rendered = await builder.render(); - }); - - it("renders", () => { - expect(rendered.container).toMatchSnapshot(); - }); - }); }); const extensionStubWithExtensionSpecificPreferenceItems: FakeExtensionOptions = { @@ -436,7 +400,7 @@ const extensionStubWithShowInPreferencesTab: FakeExtensionOptions = { }, }; -const extensionStubWithWithRegisteredTab: FakeExtensionOptions = { +const extensionStubWithRegisteredTab: FakeExtensionOptions = { id: "registered-tab-page-id", name: "registered-tab-page-id", @@ -482,47 +446,7 @@ const extensionStubWithWithRegisteredTab: FakeExtensionOptions = { }, }; -const extensionStubWithWithRegisteredTabs: FakeExtensionOptions = { - id: "hello-world-tab-page-id", - name: "hello-world-tab-page-id", - - rendererOptions: { - appPreferences: [ - { - title: "Hello world", - id: "hello-preference-item-id", - showInPreferencesTab: "hello-extension-tab", - - components: { - Hint: () => , - Input: () => , - }, - }, - { - title: "Logs", - id: "logs-preference-item-id", - showInPreferencesTab: "logs-extension-tab", - - components: { - Hint: () => , - Input: () => , - }, - }, - ], - - appPreferenceTabs: [{ - title: "Metrics tab", - id: "hello-extension-tab", - orderNumber: 100, - }, { - title: "Logs tab", - id: "logs-extension-tab", - orderNumber: 200, - }], - }, -}; - -const extensionStubWithWithSameRegisteredTab: FakeExtensionOptions = { +const extensionStubWithSameRegisteredTab: FakeExtensionOptions = { id: "duplicated-tab-page-id", name: "duplicated-tab-page-id", @@ -547,23 +471,3 @@ const extensionStubWithWithSameRegisteredTab: FakeExtensionOptions = { }], }, }; - -const extensionUsingSomeoneElseTab: FakeExtensionOptions = { - id: "extension-using-someone-else-tab-id", - name: "extension-using-someone-else-tab-id", - - rendererOptions: { - appPreferences: [ - { - title: "My preferences", - id: "my-preferences-item-id", - showInPreferencesTab: "metrics-extension-tab", - - components: { - Hint: () => , - Input: () => , - }, - }, - ], - }, -}; diff --git a/src/features/preferences/navigation-to-telemetry-preferences.test.tsx b/src/features/preferences/navigation-to-telemetry-preferences.test.tsx index 5997814336..675c3d4fce 100644 --- a/src/features/preferences/navigation-to-telemetry-preferences.test.tsx +++ b/src/features/preferences/navigation-to-telemetry-preferences.test.tsx @@ -9,7 +9,7 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get- import navigateToTelemetryPreferencesInjectable from "./common/navigate-to-telemetry-preferences.injectable"; import sentryDataSourceNameInjectable from "../../common/vars/sentry-dsn-url.injectable"; import type { FakeExtensionOptions } from "../../renderer/components/test-utils/get-extension-fake"; -import { getSingleElement, querySingleElement } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import { getSingleElement, queryAllElements, querySingleElement } from "../../renderer/components/test-utils/discovery-of-html-elements"; describe("preferences - navigation to telemetry preferences", () => { let builder: ApplicationBuilder; @@ -43,7 +43,10 @@ describe("preferences - navigation to telemetry preferences", () => { }); it("does not show link for telemetry preferences", () => { - const actual = rendered.queryByTestId("tab-link-for-telemetry"); + const actual = querySingleElement( + "preference-tab-link", + "telemetry", + )(rendered); expect(actual).toBeNull(); }); @@ -60,7 +63,10 @@ describe("preferences - navigation to telemetry preferences", () => { }); it("shows link for telemetry preferences", () => { - const actual = rendered.getByTestId("tab-link-for-telemetry"); + const actual = getSingleElement( + "preference-tab-link", + "telemetry", + )(rendered); expect(actual).not.toBeNull(); }); @@ -84,11 +90,12 @@ describe("preferences - navigation to telemetry preferences", () => { }); it("shows extension telemetry preference items", () => { - const actual = rendered.getByTestId( - "telemetry-preference-item-for-some-telemetry-preference-item-id", - ); + const actual = + queryAllElements("preference-item")(rendered).attributeValues; - expect(actual).not.toBeNull(); + expect(actual).toEqual([ + "preference-item-for-extension-some-test-extension-name-item-some-telemetry-preference-item-id", + ]); }); }); }); @@ -110,7 +117,10 @@ describe("preferences - navigation to telemetry preferences", () => { }, }); - const actual = rendered.queryByTestId("tab-link-for-telemetry"); + const actual = querySingleElement( + "preference-tab-link", + "telemetry", + )(rendered); expect(actual).toBeNull(); }); @@ -139,9 +149,11 @@ describe("preferences - navigation to telemetry preferences", () => { }); it("allows configuration of automatic error reporting", () => { - const actual = rendered.getByTestId("telemetry-preferences-for-automatic-error-reporting"); + const actual = queryAllElements( + "preference-item", + )(rendered).attributeValues; - expect(actual).not.toBeNull(); + expect(actual).toEqual(["automatic-error-reporting"]); }); }); }); @@ -168,9 +180,11 @@ describe("preferences - navigation to telemetry preferences", () => { }); it("does not allow configuration of automatic error reporting", () => { - const actual = rendered.queryByTestId("telemetry-preferences-for-automatic-error-reporting"); + const actual = queryAllElements( + "preference-item", + )(rendered).attributeValues; - expect(actual).toBeNull(); + expect(actual).toEqual([]); }); }); }); diff --git a/src/features/preferences/renderer/compliance-for-legacy-extension-api/extension-preference-item.tsx b/src/features/preferences/renderer/compliance-for-legacy-extension-api/extension-preference-item.tsx new file mode 100644 index 0000000000..65018b4db3 --- /dev/null +++ b/src/features/preferences/renderer/compliance-for-legacy-extension-api/extension-preference-item.tsx @@ -0,0 +1,35 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { SubTitle } from "../../../../renderer/components/layout/sub-title"; +import type { AppPreferenceRegistration } from "../../../../renderer/components/+preferences/app-preferences/app-preference-registration"; +import React from "react"; + +export interface ExtensionSettingsProps { + registration: AppPreferenceRegistration; +} + +export function ExtensionPreferenceItem({ registration }: ExtensionSettingsProps) { + const { + title, + id, + components: { Hint, Input }, + } = registration; + + return ( +