diff --git a/.eslintrc.yml b/.eslintrc.yml index f65f43d3..70a0b06e 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -4,3 +4,4 @@ extends: rules: '@typescript-eslint/no-dynamic-delete': off 'import/namespace': off + 'jest/no-standalone-expect': off diff --git a/src/createSVG.ts b/src/createSVG.ts new file mode 100644 index 00000000..58512250 --- /dev/null +++ b/src/createSVG.ts @@ -0,0 +1,9 @@ +import { createElement } from 'react'; +import { renderToString } from 'react-dom/server'; + +import { PlotObject, PlotObjectProps } from './components/PlotObject'; + +export function createSVG(param: PlotObjectProps) { + const plot = createElement(PlotObject, param); + return renderToString(plot); +} diff --git a/src/index.ts b/src/index.ts index 7073e29b..a940e0fa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -38,3 +38,5 @@ export { usePlotControls, usePlotEvents, } from './contexts/plotController/plotControllerContext'; + +export * from './createSVG'; diff --git a/tests/serverside.test.tsx b/tests/serverside.test.tsx index 811dacf3..4f606acc 100644 --- a/tests/serverside.test.tsx +++ b/tests/serverside.test.tsx @@ -1,8 +1,16 @@ import { test, expect } from '@playwright/experimental-ct-react'; -import { ServerSide } from './utils'; + +import { InfraredPlotTest, ServerSide } from './utils'; test('should render a plot in server-side mode', async ({ mount }) => { - const plot = await mount(); - const html = await plot.innerHTML(); - expect(html).toContain('svg'); + const serverPlot = await mount(); + const clientPlot = await mount(); + const ServerHtml = await serverPlot.innerHTML(); + const ClientHtml = await clientPlot.innerHTML(); + expect(ServerHtml).toBe(ClientHtml); + + // compare screen shots + const serverImage = await serverPlot.screenshot(); + const clientImage = await clientPlot.screenshot(); + expect(serverImage).toStrictEqual(clientImage); }); diff --git a/tests/utils.tsx b/tests/utils.tsx index e6069be9..682bc725 100644 --- a/tests/utils.tsx +++ b/tests/utils.tsx @@ -1,7 +1,14 @@ -import { ReactNode, useState } from 'react'; -import { renderToStaticMarkup } from 'react-dom/server'; +import { ReactNode, useState, useEffect } from 'react'; +import { hydrate } from 'react-dom'; -import { Annotations, Plot, ScatterSeries } from '../src'; +import { + PlotObject, + PlotObjectPlot, + Annotations, + createSVG, + Plot, + ScatterSeries, +} from '../src'; import { Arrow } from '../src/components/Annotations/Arrow'; import { DirectedEllipse } from '../src/components/Annotations/DirectedEllipse'; import infrared from '../stories/data/infrared.json'; @@ -14,9 +21,38 @@ interface ChildrenProps { export function DefaultPlotTest({ children }: ChildrenProps) { return {children}; } +const plot: PlotObjectPlot = { + dimensions: DEFAULT_PLOT_CONFIG, + axes: [ + { + type: 'main', + position: 'bottom', + }, + { + type: 'main', + position: 'left', + }, + ], + content: [ + { + type: 'line', + data: infrared, + }, + ], +}; export function ServerSide() { - const html = renderToStaticMarkup(); - return
; + const [result, setResult] = useState(null); + + useEffect(() => { + const html = createSVG({ plot }); + const rootElement = document.querySelector('root'); + if (rootElement === null) throw new Error('Root element not found'); + rootElement.innerHTML = html; + const result = hydrate(, rootElement); + setResult(result); + }, []); + + return result; } export function InfraredPlotTest({ children }: ChildrenProps) { return (