Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swagger UI: Invariant Violation: Minified React error #37; visit http://facebook.github.io/react/docs/error-decoder.html?invariant=37 #3955

Closed
kopax opened this issue Nov 28, 2017 · 15 comments

Comments

@kopax
Copy link

kopax commented Nov 28, 2017

With the latest swagger-ui version, I have written the following test in my react 16 application using jest and enzyme v3 and catched the following error:

import React from 'react';
import { shallow } from 'enzyme';
import SwaggerUIPage from '../index';

describe('<SwaggerUIPage />', () => {
  it('should render the SwaggerUIPage text', () => {
    const renderedComponent = shallow(
      <SwaggerUIPage />
    );
    expect(renderedComponent.length).toEqual(1);
  });
});

This is the tested page

import React from 'react';
import { SwaggerUIBundle, SwaggerUIStandalonePreset } from "swagger-ui-dist"
import 'swagger-ui-dist/swagger-ui.css';
import { oAuthClient } from "../../../config/index";
export default class SwaggerUIPage extends React.PureComponent {

  state = {
    ui: null,
  }

  componentDidMount() {
    this.initializeUi();
  }

  initializeUi() {
    const { redirectUri } = oAuthClient;
    const ui = SwaggerUIBundle({
      url: `${redirectUri}/v2/api-docs`,
      dom_id: '#swagger-ui',
      oauth2RedirectUrl: redirectUri,
      presets: [
        SwaggerUIBundle.presets.apis,
        SwaggerUIStandalonePreset
      ],
      plugins: [
        SwaggerUIBundle.plugins.DownloadUrl,
      ],
    });
    this.setState({ ui }, this.initializeOAuth);
  }

  initializeOAuth() {
    const { clientId, clientSecret, accessTokenUri, redirectUri } = oAuthClient;
    // Method can be called in any place after calling constructor SwaggerUIBundle
    const oauth = this.state.ui.initOAuth({
      clientId,
      clientSecret,
      realm: 'api',
      tokenUrl: accessTokenUri,
      oauth2RedirectUrl: redirectUri,
      appName: 'backoffice',
      scopeSeparator: ' ',
      additionalQueryStringParams: { test: 'hello' },
      useBasicAuthenticationWithAccessCodeGrant: true,
      ...oAuthClient,
    });
  }



  render() {
    return (
      <div id="swagger-ui"/>
    );
  }

}

expected

test to pass:

result

error :

 FAIL  app/containers/platform/SwaggerUIPage/tests/index.test.js (5.973s)
  ● <SwaggerUIPage /> › should render the SwaggerUIPage text

    Invariant Violation: Minified React error #37; visit http://facebook.github.io/react/docs/error-decoder.html?invariant=37 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
      
      at r (node_modules/swagger-ui-dist/swagger-ui-bundle.js:1:70097)
      at Object._renderNewRootComponent (node_modules/swagger-ui-dist/swagger-ui-bundle.js:52:177941)
      at Object._renderSubtreeIntoContainer (node_modules/swagger-ui-dist/swagger-ui-bundle.js:52:178982)
      at Object.render (node_modules/swagger-ui-dist/swagger-ui-bundle.js:52:179109)
      at t.render (node_modules/swagger-ui-dist/swagger-ui-bundle.js:52:91695)
      at d (node_modules/swagger-ui-dist/swagger-ui-bundle.js:53:97589)
      at e.exports (node_modules/swagger-ui-dist/swagger-ui-bundle.js:53:97825)
      at SwaggerUIPage.initializeUi (app/containers/platform/SwaggerUIPage/index.js:26:126)
      at SwaggerUIPage.componentDidMount (app/containers/platform/SwaggerUIPage/index.js:21:12)
      at node_modules/enzyme/build/ShallowWrapper.js:123:20
      at Object.batchedUpdates (node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js:336:22)
      at new ShallowWrapper (node_modules/enzyme/build/ShallowWrapper.js:122:24)
      at shallow (node_modules/enzyme/build/shallow.js:19:10)
      at Object.<anonymous> (app/containers/platform/SwaggerUIPage/tests/index.test.js:11:49)
          at new Promise (<anonymous>)
      at Promise.resolve.then.el (node_modules/p-map/index.js:46:16)
          at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:188:7)
@shockey
Copy link
Contributor

shockey commented Nov 29, 2017

Hmm, this is weird. At first look, your component seems good.

Is it working when you actually view the application in your browser, or is it broken entirely? Just asking because you only mentioned your test failing.

Also, just an fyi - you should consider using swagger-ui instead of swagger-ui-dist when you're building with Webpack (I assume you are). Your application bundle will be smaller that way 😄 the bundle comes with everything pre-packed, so you can't take advantage of npm deduping dependencies and webpack sharing them between modules.

@kopax
Copy link
Author

kopax commented Nov 29, 2017

Is it working when you actually view the application in your browser, or is it broken entirely? Just asking because you only mentioned your test failing.

Yes it is working I created #3955 for reporting test failing on latest react/enzyme/jest versions and #3947 for support because my OAuth authentication process is incomplete with the implementation I shared here. I have read the documentation and all the related OAuth2 implementation issues.

I have swaggerui initialized on my screen:

image

I am using the code grant flow. No OAuth token retrivial is dispatched at any point. Am I missing something ? Is there anything to do with the store or redux or actions ? I don't have any callback.html view, this OAuth client is automatically approved.

Also, just an fyi - you should consider using swagger-ui instead of swagger-ui-dist when you're building with Webpack (I assume you are). Your application bundle will be smaller that way 😄 the bundle comes with everything pre-packed, so you can't take advantage of npm deduping dependencies and webpack sharing them between modules.

I am using webpack. I have understood that dist was for people who aren't willing to edit the sources code and swagger-ui good if you wish to customize. Thanks for informing me about the performance gain, I have now updated my dependency.

@shockey
Copy link
Contributor

shockey commented Jan 11, 2018

Hi @kopax, sorry for the delay here. I think this is due to you using the shallow Enzyme interface, which as far as I can tell, doesn't provide a DOM of any sort, so Swagger-UI is not able to find #swagger-ui.

Can you try using the Full DOM Rendering interface that Enzyme exposes, in this test? Docs here: http://airbnb.io/enzyme/docs/api/mount.html

Let me know where that gets you.

@kopax
Copy link
Author

kopax commented Jan 11, 2018

@shockey it does the same


 FAIL  app/platform-management/containers/SwaggerUIPage/tests/index.test.js
  ● <SwaggerUIPage /> › should render the SwaggerUIPage text

    Invariant Violation: Minified React error #37; visit http://facebook.github.io/react/docs/error-decoder.html?invariant=37 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
      
      at r (node_modules/swagger-ui-dist/swagger-ui-bundle.js:1:70097)
      at Object._renderNewRootComponent (node_modules/swagger-ui-dist/swagger-ui-bundle.js:52:177941)
      at Object._renderSubtreeIntoContainer (node_modules/swagger-ui-dist/swagger-ui-bundle.js:52:178982)
      at Object.render (node_modules/swagger-ui-dist/swagger-ui-bundle.js:52:179109)
      at t.render (node_modules/swagger-ui-dist/swagger-ui-bundle.js:52:91695)
      at d (node_modules/swagger-ui-dist/swagger-ui-bundle.js:53:97589)
      at e.exports (node_modules/swagger-ui-dist/swagger-ui-bundle.js:53:97825)
      at SwaggerUIPage.initializeUi (app/platform-management/containers/SwaggerUIPage/index.js:24:51)
      at SwaggerUIPage.componentDidMount (app/platform-management/containers/SwaggerUIPage/index.js:19:12)
      at commitLifeCycles (node_modules/react-dom/cjs/react-dom.development.js:11505:24)
      at commitAllLifeCycles (node_modules/react-dom/cjs/react-dom.development.js:12294:9)
      at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:1299:14)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:219:27)
      at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:126:9)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:87:17)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:36:27)
      at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:61:35)
      at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:1338:16)
      at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:1195:27)
      at commitAllWork (node_modules/react-dom/cjs/react-dom.development.js:12415:9)
      at workLoop (node_modules/react-dom/cjs/react-dom.development.js:12687:13)
      at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:1299:14)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:219:27)
      at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:126:9)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:87:17)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:36:27)
      at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:61:35)
      at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:1338:16)
      at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:1195:27)
      at performWork (node_modules/react-dom/cjs/react-dom.development.js:12800:7)
      at scheduleUpdateImpl (node_modules/react-dom/cjs/react-dom.development.js:13185:19)
      at scheduleUpdate (node_modules/react-dom/cjs/react-dom.development.js:13124:12)
      at scheduleTopLevelUpdate (node_modules/react-dom/cjs/react-dom.development.js:13395:5)
      at Object.updateContainer (node_modules/react-dom/cjs/react-dom.development.js:13425:7)
      at node_modules/react-dom/cjs/react-dom.development.js:17105:19
      at Object.unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:13256:14)
      at renderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:17104:17)
      at Object.render (node_modules/react-dom/cjs/react-dom.development.js:17129:12)
      at Object.render (node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js:212:50)
      at new ReactWrapper (node_modules/enzyme/build/ReactWrapper.js:98:16)
      at mount (node_modules/enzyme/build/mount.js:19:10)
      at Object.<anonymous> (app/platform-management/containers/SwaggerUIPage/tests/index.test.js:11:47)
          at new Promise (<anonymous>)
      at Promise.resolve.then.el (node_modules/p-map/index.js:46:16)
          at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:188:7)

  <SwaggerUIPage />
    ✕ should render the SwaggerUIPage text (67ms)



@colinfindlay-nz
Copy link

I'm seeing a similar error - and it seems to be cause by Swagger-UI including a dependency of React 15 (Rather than a peer dependency)
As you are using React 16, any attempt to reference components across versions cause React to explode with an Invariant Violation. :-/

Still searching for a solution...

@shockey
Copy link
Contributor

shockey commented Jan 25, 2018

@silver2k, please see #3714, #3970 and most importantly #3934 for more context and information on React 16 usage and the peerDependency thing.

The short answer: I don't see a way to move react to peerDependencies without seriously complicating the situation for non-React consumers of swagger-ui. I'm quite open to being wrong about this, or hearing about an entirely different solution.

@colinfindlay-nz
Copy link

colinfindlay-nz commented Jan 25, 2018

@shockey Thanks for the quick feedback. I wasn't suggesting you move to using a peerDependency - and I imagine splitting swagger-ui into frontend & lib modules is non-trivial.
I am currently looking into workarounds and will report back if I find something!

@shockey
Copy link
Contributor

shockey commented Feb 1, 2018

A possible way forward on this: create a swagger-ui-react flavor of Swagger-UI that exports a component and does not declare a hard react or react-dom dependency.

It would have to live in Swagger-UI core, havingswagger-ui-react consume the swagger-ui module would still not break the dependency chain.

@tommy5dollar
Copy link

I am also suffering from this error. Has anyone come up with a solution or a work-around yet?

@shockey
Copy link
Contributor

shockey commented Mar 2, 2019

Fixed!

We've just released swagger-ui-react, which declares React as a peer dependency.

@shockey shockey closed this as completed Mar 2, 2019
@kopax
Copy link
Author

kopax commented Mar 2, 2019

@shockey thanks a lot for solving this.

There is still one unresolved question that I'd like to get an answer. (Otherwise we cannot use swagger UI with our spring boot application)

I am using the code grant flow. No OAuth token retrieval is dispatched at any point. Am I missing something? Is there anything to do with the store or redux or actions? I don't have any callback.html view, this OAuth client is automatically approved.

We have secured endpoints with OAuth2, we need to authenticate using OAuth2 code grant strategy, could you please indicate how this can be configured?

@shockey
Copy link
Contributor

shockey commented Mar 2, 2019

@kopax, we don't currently have a documented way to do this with swagger-ui-react - if you hang tight for a couple of days, I'll open an issue for this next week!

@kopax
Copy link
Author

kopax commented Mar 2, 2019

Sure no problem @shockey and thank you. I hang still 2017, OAuth authorization strategies exist since the OAuth2 specification.

I tried swagger UI and even if I couldn't authenticate I really liked what I saw, the wait is justified, could you please post the link to the next issue so I can follow.

@p4535992
Copy link

p4535992 commented Sep 13, 2019

Hi i keep getting this error on a OSGI project where i put my swagger-ui (dist) resource .
Theres is some import javascript i missing?
here the html i'm trying to use:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Swagger UI</title>
    
	<script src="./jquery-external/requirejs/require.js"></script>	
    <script src="./jquery-dist/jquery.js" type="text/javascript"></script>  
    <link rel="stylesheet" type="text/css" href="./swagger-ui-dist/swagger-ui.css" >
    <link rel="icon" type="image/png" href="./swagger-ui-dist/favicon-32x32.png" sizes="32x32" />
    <link rel="icon" type="image/png" href="./swagger-ui-dist/favicon-16x16.png" sizes="16x16" />
    <style>
      html
      {
        box-sizing: border-box;
        overflow: -moz-scrollbars-vertical;
        overflow-y: scroll;
      }

      *,
      *:before,
      *:after
      {
        box-sizing: inherit;
      }

      body
      {
        margin:0;
        background: #fafafa;
      }
    </style>
    
</head>

<body class="swagger-section">
	<div id="header">
	    <div class="swagger-ui-wrap">
	        <a id="logo" href="http://swagger.io">swagger</a>
	        <form id="api_selector">
	            <div class="input"><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text"/></div>
	            <div class="input"><input placeholder="api_key" id="input_apiKey" name="apiKey" type="text"/></div>
	            <div class="input"><a id="explore" href="#" data-sw-translate>Explore</a></div>
	        </form>
	    </div>
	</div>

	<div id="message-bar" class="swagger-ui-wrap" data-sw-translate>&nbsp;</div>
	<div id="swagger-ui-container" class="swagger-ui-wrap"></div>

    <script src="./swagger-ui-dist/swagger-ui-bundle.js"> </script>
    <script src="./swagger-ui-dist/swagger-ui-standalone-preset.js"> </script>

    <script type="text/javascript">

    	window.onload = function() {
            var url = window.location.search.match(/url=([^&]+)/);
            if (url && url.length > 1) {
                url = decodeURIComponent(url[1]);
            } else {
                url = "/cxf/swagger/swagger.json";
            }

            // Pre load translate...
            if(window.SwaggerTranslator) {
                window.SwaggerTranslator.translate();
            }

            window.swaggerUi = new SwaggerUIBundle({
                url: url,
                dom_id: "swagger-ui-container",
                deepLinking: true,                
                presets: [
                  SwaggerUIBundle.presets.apis,
                  SwaggerUIStandalonePreset
                ],
                plugins: [
                  SwaggerUIBundle.plugins.DownloadUrl
                ],
                layout: "StandaloneLayout",
                supportedSubmitMethods: ["get", "post", "put", "delete", "patch"],
                onComplete: function(swaggerApi, swaggerUi){
                    if(typeof initOAuth == "function") {
                        initOAuth({
                            clientId: "your-client-id",
                            clientSecret: "your-client-secret",
                            realm: "your-realms",
                            appName: "your-app-name",
                            scopeSeparator: ","
                        });
                    }

                    if(window.SwaggerTranslator) {
                        window.SwaggerTranslator.translate();
                    }

                    $("pre code").each(function(i, e) {
                        hljs.highlightBlock(e)
                    });

                    addApiKeyAuthorization();
                },
                onFailure: function(data) {
                    log("Unable to Load SwaggerUI");
                },
                docExpansion: "none",
                apisSorter: "alpha",
                showRequestHeaders: false
                
            });

            function addApiKeyAuthorization(){
                var key = encodeURIComponent($("#input_apiKey")[0].value);
                if(key && key.trim() != "") {
                    var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("api_key", key, "query");
                    window.swaggerUi.api.clientAuthorizations.add("api_key", apiKeyAuth);
                    log("added key " + key);
                }
            }

            $("#input_apiKey").change(addApiKeyAuthorization);
            window.swaggerUi.load();

            function log() {
                if ("console" in window) {
                    console.log.apply(console, arguments);
                }
            }
        }
    </script>
</body>
</html>

@webron
Copy link
Contributor

webron commented Sep 13, 2019

@p4535992 please open a new issue following the issue template.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants