Hexastack / eazychart

EazyChart is a reactive chart library πŸ“ˆ, it allows you to easily add SVG charts in your React and Vue web applications.
https://eazychart.com
MIT License
23 stars 14 forks source link

fix: make jest ignore svg tags warnings #70

Closed G0maa closed 2 years ago

G0maa commented 2 years ago

Motivation

Using yarn test in /packages/ez-react/ yields in this specific warning The tag <sometag> is unrecognized in this browser.

Reference for solution: here

This solution ignores console.error() which has the text is unrecognized in this browser., kind of hacky I guess.

Other solutions which I stumbled upon: This one - Ignored because I don't know how to specify behavior depending on the error.

This other one - Adds another dependency, also fails tests by default.

Fixes #50

Type of change

Please delete options that are not relevant.

Checklist:

P.S: You got a really good configuration in mono-repo, git commit, CI pipeline : )

marrouchi commented 2 years ago

@G0maa Hello and thanks for your valuable contribution! Really awesome background check. The issue with this solution in my opinion is that we disable all the warning about dom inconsistency in react-dom : https://github.com/facebook/react/blob/2cf4352e1c81a5b8c3528519a128c20e8e65531d/packages/react-dom-bindings/src/client/ReactDOMComponent.js#L469

After giving it a deep thought, I suggest to replace the console.error by a console.log, the same way you did. This will avoid the printing of the whole debug backtrace lines which are preventing us from having a proper jest display :

console.error = (...args) => console.warn('Error: ', ...args);

Let me know what you think :)

G0maa commented 2 years ago

Using this

console.error = (...args) => console.log('Error: ', ...args);

Results in:

  ● Console

    console.log
      Warning: The tag <path> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.
          at path
          at shapeData (D:\3_Studies\MyGithubFolder\3_OtherVentures\OpenSourceContirbution\eazychart\packages\ez-react\src\components\shapes\LinePath.tsx:14:3)
          at Legend (D:\3_Studies\MyGithubFolder\3_OtherVentures\OpenSourceContirbution\eazychart\packages\ez-react\src\components\addons\legend\LegendProvider.tsx:10:3)
          at Tooltip (D:\3_Studies\MyGithubFolder\3_OtherVentures\OpenSourceContirbution\eazychart\packages\ez-react\src\components\addons\tooltip\TooltipProvider.tsx:15:3)
          at dimensions (D:\3_Studies\MyGithubFolder\3_OtherVentures\OpenSourceContirbution\eazychart\packages\ez-react\src\components\Chart.tsx:38:3)

      at console.Object.<anonymous>.console.error (tests/ignoreSvgTags.ts:4:30)

and using this

const ERROR = 'is unrecognized in this browser.';
console.error = (...args) => {
  if (args.toString().includes(ERROR))
    return console.log('Error: ', args[0].replace('%s', args[1]));
  else return console.log('Error: ', ...args);
};

Results in:

  ● Console

    console.log
      Error:  Warning: The tag <path> is unrecognized in this browser. If you meant to render a React component, start its name with an 
uppercase letter.%s

      at console.log [as error] (tests/ignoreSvgTags.ts:4:11)

This means that the svg warning gets somewhat minimized, while for all other warnings they'll get printed with less backtrace lines (as in the first example) in comparison to console.warn() or console.log().

Pick you poison πŸ‘€

P.S: I'm not sure if the return in the second code example is necessary or not.

G0maa commented 2 years ago

@marrouchi I kind of need an answer 😬

marrouchi commented 2 years ago

@G0maa Sorry it took me so long to respond. After some digging I think we need to set an SVG container with the right namespaceURI so that react-dom would bypass this check. This is just for some of the tests that are throwing the error. Here's an example :

it('renders an svg circle with the right coordinates', async () => {
    let wrapper: RenderResult;
    act(() => {
      const container = document.createElement('svg', {
        xmlns: 'http://www.w3.org/2000/svg',
      });
      wrapper = render(
        <Chart
          {...baseChartProps}
          scopedSlots={{
            LegendComponent: () => <>{null}</>,
            TooltipComponent: () => <>{null}</>,
          }}
        >
          <Point shapeDatum={pointA} />
        </Chart>,
        { container }
      );
    });
    await waitFor(() => {
      expect(wrapper.container.innerHTML).toMatchSnapshot();
    });
  });

To make it generic I suggest we create a custom function in tests/common.ts :

export const renderSVG = (
  ui: React.ReactElement,
  options?: Omit<RenderOptions, 'queries'>,
): RenderResult => {
    const container = document.createElement('svg', {
      xmlns: 'http://www.w3.org/2000/svg',
    });
   return render(ui, { ...options, container });
}

so that we have :

it('renders an svg circle with the right coordinates', async () => {
    let wrapper: RenderResult;
    act(() => {
      wrapper = renderSVG(
        <Chart
          {...baseChartProps}
          scopedSlots={{
            LegendComponent: () => <>{null}</>,
            TooltipComponent: () => <>{null}</>,
          }}
        >
          <Point shapeDatum={pointA} />
        </Chart>
      );
    });
    await waitFor(() => {
      expect(wrapper.container.innerHTML).toMatchSnapshot();
    });
  });
G0maa commented 2 years ago

When I used createElement I got this TS error:

No overload matches this call.
  Overload 1 of 3, '(tagName: keyof HTMLElementTagNameMap, options?: ElementCreationOptions | undefined): HTMLObjectElement | ... 61 more ... | HTMLVideoElement', gave the following error.
    Argument of type '"svg"' is not assignable to parameter of type 'keyof HTMLElementTagNameMap'.
  Overload 2 of 3, '(tagName: keyof HTMLElementDeprecatedTagNameMap, options?: ElementCreationOptions | undefined): HTMLElement | ... 7 more ... | HTMLParamElement', gave the following error.
    Argument of type '"svg"' is not assignable to parameter of type 'keyof HTMLElementDeprecatedTagNameMap'.
  Overload 3 of 3, '(tagName: string, options?: ElementCreationOptions | undefined): HTMLElement', gave the following error.
    Argument of type '{ xmlns: string; }' is not assignable to parameter of type 'ElementCreationOptions'.
      Object literal may only specify known properties, and 'xmlns' does not exist in type 'ElementCreationOptions'.ts(2769)

I tried to use createElementNS which has namespace URI as specified in the documentation, but I got this other TS error instead:

Type 'RenderResult<typeof import("d:/3_Studies/MyGithubFolder/3_OtherVentures/OpenSourceContirbution/eazychart/packages/ez-react/node_modules/@testing-library/dom/types/queries"), SVGSVGElement, HTMLElement>' is not assignable to type 'RenderResult<typeof import("d:/3_Studies/MyGithubFolder/3_OtherVentures/OpenSourceContirbution/eazychart/packages/ez-react/node_modules/@testing-library/dom/types/queries"), HTMLElement, HTMLElement>'.
  Type 'RenderResult<typeof import("d:/3_Studies/MyGithubFolder/3_OtherVentures/OpenSourceContirbution/eazychart/packages/ez-react/node_modules/@testing-library/dom/types/queries"), SVGSVGElement, HTMLElement>' is not assignable to type '{ container: HTMLElement; baseElement: HTMLElement; debug: (baseElement?: Element | DocumentFragment | (Element | DocumentFragment)[] | undefined, maxLength?: number | undefined, options?: PrettyFormatOptions | undefined) => void; rerender: (ui: ReactElement<...>) => void; unmount: () => void; asFragment: () => Docu...'.
    Types of property 'container' are incompatible.
      Type 'SVGSVGElement' is missing the following properties from type 'HTMLElement': accessKey, accessKeyLabel, autocapitalize, dir, and 20 more.ts(2322)
  );

I'm not really good with TS so I'm not sure what to do.

G0maa commented 2 years ago

After some thinking I just edited index.d.ts to have:

  Container extends Element | DocumentFragment = HTMLElement | SVGSVGElement,

instead of just HTMLElement.. Seemed easier to figure out than the first one 😬