Skip to content

Commit

Permalink
Add test for theme parameter.
Browse files Browse the repository at this point in the history
Also removes the (unused) props of the application root component
to avoid confusion.
  • Loading branch information
mbeckem committed Sep 18, 2023
1 parent 47b1525 commit 9046113
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 24 deletions.
10 changes: 4 additions & 6 deletions src/packages/runtime/CustomElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,9 @@ export interface CustomElementOptions {
openShadowRoot?: boolean;

/**
* Chakra theming object
* Chakra theming object.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
theme?: Record<string, any>;
theme?: Record<string, unknown>;
}

/**
Expand Down Expand Up @@ -321,6 +320,7 @@ class ElementState {
this.reactIntegration = new ReactIntegration({
rootNode: container,
container: shadowRoot,
theme: options.theme,
serviceLayer,
packages
});
Expand All @@ -332,9 +332,7 @@ class ElementState {
}

private render() {
this.reactIntegration?.render(this.options.component ?? emptyComponent, {
theme: this.options.theme
});
this.reactIntegration?.render(this.options.component ?? emptyComponent);
}

private initStyles() {
Expand Down
60 changes: 47 additions & 13 deletions src/packages/runtime/react-integration/ReactIntegration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@
import { createElement } from "react";
import { beforeEach, expect, it } from "vitest";
import { usePropertiesInternal, useServiceInternal, useServicesInternal } from "./hooks";
import { findByText } from "@testing-library/dom";
import { findByTestId, findByText } from "@testing-library/dom";
import { act } from "@testing-library/react";
import { Service, ServiceConstructor } from "../Service";
// eslint-disable-next-line import/no-relative-packages
import { UIWithProperties, UIWithService, UIWithServices } from "./test-data/test-package/UI";
import { ServiceLayer } from "../service-layer/ServiceLayer";
import { ReactIntegration } from "./ReactIntegration";
import { act } from "react-dom/test-utils";
import { PackageRepr } from "../service-layer/PackageRepr";
import { createConstructorFactory, ServiceRepr } from "../service-layer/ServiceRepr";
import { InterfaceSpec, ReferenceSpec } from "../service-layer/InterfaceSpec";
import { createEmptyI18n, PackageIntl } from "../i18n";
import { useTheme } from "@open-pioneer/chakra-integration";

interface TestProvider {
value: string;
Expand Down Expand Up @@ -46,7 +47,7 @@ it("should allow access to service via react hook", async () => {
});

act(() => {
integration.render(TestComponent, {});
integration.render(TestComponent);
});

const node = await findByText(wrapper, "Hello TEST");
Expand All @@ -65,7 +66,7 @@ it("should get error when using undefined service", async () => {

expect(() => {
act(() => {
integration.render(TestComponent, {});
integration.render(TestComponent);
});
}).toThrowErrorMatchingSnapshot();
});
Expand All @@ -92,7 +93,7 @@ it("should allow access to service with qualifier via react hook", async () => {
});

act(() => {
integration.render(TestComponent, {});
integration.render(TestComponent);
});

const node = await findByText(wrapper, "Hello TEST");
Expand Down Expand Up @@ -122,7 +123,7 @@ it("should deny access to service when the qualifier does not match", async () =

expect(() => {
act(() => {
integration.render(TestComponent, {});
integration.render(TestComponent);
});
}).toThrowErrorMatchingSnapshot();
});
Expand Down Expand Up @@ -165,7 +166,7 @@ it("should allow access to all services via react hook", async () => {
});

act(() => {
integration.render(TestComponent, {});
integration.render(TestComponent);
});

const node = await findByText(wrapper, /^Joined Values:/);
Expand All @@ -188,7 +189,7 @@ it("should deny access to all services if declaration is missing", async () => {

expect(() => {
act(() => {
integration.render(TestComponent, {});
integration.render(TestComponent);
});
}).toThrowErrorMatchingSnapshot();
});
Expand All @@ -206,7 +207,7 @@ it("should be able to read properties from react component", async () => {
});

act(() => {
integration.render(TestComponent, {});
integration.render(TestComponent);
});

const node = await findByText(wrapper, "Hello USER");
Expand All @@ -230,7 +231,7 @@ it("should provide the autogenerated useService hook", async () => {
});

act(() => {
integration.render(UIWithService, {});
integration.render(UIWithService);
});

const node = await findByText(wrapper, /^Test-UI:/);
Expand Down Expand Up @@ -261,7 +262,7 @@ it("should provide the autogenerated useServices hook", async () => {
});

act(() => {
integration.render(UIWithServices, {});
integration.render(UIWithServices);
});

const node = await findByText(wrapper, /^Test-UI:/);
Expand All @@ -278,7 +279,7 @@ it("should provide the autogenerated useProperties hook", async () => {
});

act(() => {
integration.render(UIWithProperties, {});
integration.render(UIWithProperties);
});

const node = await findByText(wrapper, /^Test-UI:/);
Expand All @@ -297,11 +298,42 @@ it("should throw error when requesting properties from an unknown package", asyn

expect(() => {
act(() => {
integration.render(TestComponent, {});
integration.render(TestComponent);
});
}).toThrowErrorMatchingSnapshot();
});

it("should apply the configured chakra theme", async () => {
const testTheme = {
colors: {
dummyColor: "#123456"
}
};
const { integration, wrapper } = createIntegration({
disablePackage: true,
theme: testTheme
});

function TestComponent() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const theme = useTheme() as any;
return createElement(
"div",
{
"data-testid": "test-div"
},
`Color: ${theme.colors.dummyColor}`
);
}

act(() => {
integration.render(TestComponent);
});

const node = await findByTestId(wrapper, "test-div");
expect(node.textContent).toBe("Color: #123456");
});

interface ServiceSpec {
name: string;
interfaces: InterfaceSpec[];
Expand All @@ -320,6 +352,7 @@ function createIntegration(options?: {
packageUiReferences?: ReferenceSpec[];
i18n?: PackageIntl;
services?: ServiceSpec[];
theme?: Record<string, unknown>;
}): TestIntegration {
const wrapper = document.createElement("div");
const packages = new Map<string, PackageRepr>();
Expand Down Expand Up @@ -354,6 +387,7 @@ function createIntegration(options?: {
const integration = new ReactIntegration({
container: wrapper,
rootNode: wrapper,
theme: options?.theme,
packages,
serviceLayer
});
Expand Down
11 changes: 6 additions & 5 deletions src/packages/runtime/react-integration/ReactIntegration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,20 @@ export interface ReactIntegrationOptions {
serviceLayer: ServiceLayer;
rootNode: HTMLDivElement;
container: Node;
theme: Record<string, unknown> | undefined;
}

export class ReactIntegration {
private containerNode: Node;
private theme: Record<string, unknown> | undefined;
private packages: Map<string, PackageRepr>;
private serviceLayer: ServiceLayer;
private root: Root;
private packageContext: PackageContextMethods;

constructor(options: ReactIntegrationOptions) {
this.containerNode = options.container;
this.theme = options.theme;
this.packages = options.packages;
this.serviceLayer = options.serviceLayer;
this.root = createRoot(options.rootNode);
Expand Down Expand Up @@ -85,18 +88,16 @@ export class ReactIntegration {
};
}

render(Component: ComponentType, props: Record<string, unknown>) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const customTheme = props.theme as Record<string, any>;
render(Component: ComponentType) {
this.root.render(
<StrictMode>
<CustomChakraProvider
container={this.containerNode}
colorMode="light"
theme={customTheme}
theme={this.theme}
>
<PackageContext.Provider value={this.packageContext}>
<Component {...props} />
<Component />
</PackageContext.Provider>
</CustomChakraProvider>
</StrictMode>
Expand Down

0 comments on commit 9046113

Please sign in to comment.