plotly / angular-plotly.js

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

"Plotly object not found on window" when unit testing a component that uses angular-plotly

lawand opened this issue · comments

Hello. I am trying to create a unit test for one of the component in a angular 10 project. When running the test, I get an error that says "Plotly object not found on window." with the following trace

      at new PlotlyViaWindowModule (../../../../projects/plotly/src/lib/plotly-via-window.module.ts:19:19)
      at _createClass (../../../../../packages/core/src/view/ng_module.ts:178:14)
      at _createProviderInstance (../../../../../packages/core/src/view/ng_module.ts:150:20)
      at initNgModule (../../../../../packages/core/src/view/ng_module.ts:77:24)
      at new NgModuleRef_ (../../../../../packages/core/src/view/refs.ts:409:5)
      at createNgModuleRef (../../../../../packages/core/src/view/refs.ts:391:10)
      at Object.debugCreateNgModuleRef [as createNgModuleRef] (../../../../../packages/core/src/view/services.ts:166:10)
      at NgModuleFactory_.Object.<anonymous>.NgModuleFactory_.create (../../../../../packages/core/src/view/entrypoint.ts:73:21)
      at TestBedViewEngine.Object.<anonymous>.TestBedViewEngine._initIfNeeded (../../../../../packages/core/testing/src/test_bed.ts:416:43)
      at TestBedViewEngine.Object.<anonymous>.TestBedViewEngine.createComponent (../../../../../packages/core/testing/src/test_bed.ts:598:10)
      at Function.Object.<anonymous>.TestBedViewEngine.createComponent (../../../../../packages/core/testing/src/test_bed.ts:245:36)
      at src/lib/measurements-lists/measurements-list/measurements-list.component.spec.ts:122:23
      at ../../../../node_modules/zone.js/dist/fake-async-test.js:610:34
      at ZoneDelegate.Object.<anonymous>.ZoneDelegate.invoke (../../../../node_modules/zone.js/dist/zone.js:386:30)
      at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvoke (../../../../node_modules/zone.js/dist/proxy.js:117:43)
      at ZoneDelegate.Object.<anonymous>.ZoneDelegate.invoke (../../../../node_modules/zone.js/dist/zone.js:385:36)
      at Zone.Object.<anonymous>.Zone.run (../../../../node_modules/zone.js/dist/zone.js:143:47)

Any idea about this? I would be happy to provide more info.

Thanks in advance

Hello, @lawand. I believe you gonna have to mock the Window object to use TestBed or other non-browser tools to test.
Check this code from plotly-component: https://github.com/plotly/angular-plotly.js/blob/master/projects/plotly/src/lib/plotly.component.specs.ts#L15

Or, as a simpler solution, you could use other module (such as PlotlyModule) in your tests to avoid the window object

@andrefarzat Thanks for the quick answer! So, mocking the Window object is about those two lines, right?

let windowSpy: jasmine.SpyObj<Window>;
windowSpy = jasmine.createSpyObj('Window', ['addEventListener', 'removeEventListener']);

I am using Jest, not Jasmine. Do you happen to know what would be the equivalent in jest? I am new to it.

Alternatively, I tried importing the PlotlyModule in my TestingModule but still gave the same error.

Thanks again in advance.

@lawand it would be these two lines indeed.
If you're using Jest, the spy is different. Searched on google and found this: https://stackoverflow.com/a/56999581/1327401

Also, maybe the plotly.js itself isn't included in the tests? If yes, maybe you could force the window.Plotly object to exists somehow?
Like:

import Plotly from 'plotly.js-dist';

window.Plotly = Plotly;

// The test code

I tried import Plotly from 'plotly.js-dist'; but it says Cannot find module 'plotly.js-dist'

Then I tried importing Plotly from 'plotly.js' and that gave an error when running the tests TypeError: window.URL.createObjectURL is not a function

This is the most relevant parts of the code

import Plotly from 'plotly.js';

let windowSpy;

describe('MeasurementsListComponent', () => {
  let component: MeasurementsListComponent;
  let fixture: ComponentFixture<MeasurementsListComponent>;

  beforeEach(fakeAsync(() => {
    windowSpy = jest.spyOn(window, "window", "get");

    TestBed.configureTestingModule({
      imports: [
        testingImports
      ],
      declarations: [MeasurementsListComponent]
    });

    fixture = TestBed.createComponent(MeasurementsListComponent);
    component = fixture.componentInstance;
  }));

  afterEach(() => {
    windowSpy.mockRestore();
  });

  it('should compile', () => {
    windowSpy.mockImplementation(() => ({
      addEventListener: () => {},
      removeEventListener: () => {},
      Plotly: Plotly,
      URL: {
        createObjectURL: () => {},
      }
    }));

    expect(component).toBeTruthy();
  });
});

I would greatly appreciate any further input

@lawand yeah, plotly.js is extremelly bound to the DOM. If you really need to the Plotly itself, I would recommend using another test lib which uses the browser to run the tests (such Jasmine). Otherwise, you will have to (1) mock everything that Plotly uses, or (2) mock Plotly object itself 😿

Well, the thing is that, the component I am testing does include plotly in the template, but I don't actually need to test that, I just wanna test some other stuff in the page. Any ideas on how to get the tests running?

Well, I usually have two approaches to front-end test: unit testing and styleguide (a.k.a design systems or storybooks).

With unit testing I test only the controller itself. The business logic and the behavior logic (e.g.: If some element must be displayed by a conditional, I write a test to the conditional, not to the *ngIf on the template)

And in the styleguide, I test the html/css. The appearance of the component. I might even include buttons or inputs with ngModel to change the attributes on the fly to test/see the modifiers/changes. Although, at the end, is a manual test.

if you're not familiar, check out the storybook approach: https://storybook.js.org/docs/angular/get-started/introduction

Closing this issue for inactivity. Feel free to reopen if the issue continues 😸

@andrefarzat Once again thanks for all the help.

For anyone reading this later, I solved the issue by simply not importing plotly into the testing module as that didn't break running the tests. And I didn't get the error message anymore.