"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
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.