ngx-monaco-editor + Karma test runner - how to get monaco instance loaded into test suite?

1k views Asked by At

I am making use of @materia-ui/ngx-monaco-editor in my application and am having trouble getting the monaco globally installed lib to be recognized during unit test runs with Karma+Jasmine.

Component

import {
    Component,
    OnInit } from '@angular/core';
import { MonacoEditorLoaderService } from '@materia-ui/ngx-monaco-editor';
import { filter, take } from 'rxjs/operators';

@Component({
    selector: 'my-editor',
    templateUrl: './my-editor.component.html',
    styleUrls: ['./my-editor.component.scss']
})

export class MyEditorComponent implements OnInit {

    public modelUri: monaco.Uri;

    constructor(private monacoLoaderService: MonacoEditorLoaderService) {
        this.monacoLoaderService.isMonacoLoaded$.pipe(
            filter(isLoaded => isLoaded === true),
            take(1),
        ).subscribe(() => {
            this.monacoLoaderService.isMonacoLoaded$
                .pipe(
                    filter(isLoaded => isLoaded),
                    take(1)
                )
                .subscribe(() => {
                    // This seems to be the issue during test runs - monaco is not defined
                    monaco.languages.json.jsonDefaults.setDiagnosticsOptions({});
                })
            })
    }
}

In my component file, monaco is being resolved from interfaces exposed in the @materia-ui/ngx-monaco-editor:

enter image description here

Test Spec

describe('MyEditorComponent Test Suite:', () => {
    let component: MyEditorComponent;
    let fixture: ComponentFixture<MyEditorComponent>;
    let tagsService: TagsService;
    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [MyEditorComponent],
            providers: [ MonacoEditorLoaderService ],
            schemas: [CUSTOM_ELEMENTS_SCHEMA]

        }).compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(MyEditorComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it('Should create component', () => {
        expect(component).toBeTruthy();
    });
});

When it comes to unit testing my component, I get errors from Karma to tell me that monaco is not defined: enter image description here

I am struggling with getting Monaco to be correctly picked up by Karma, at least I believe that's my problem here.

When installing @materia-ui/ngx-monaco-editor the monaco-editor package is also installed, and so I have also tried adding the monaco-editor script into the scripts property of my test project config section in my angular.json file:

"test": {
    "builder": "@angular-devkit/build-angular:karma",
    "options": {
      "main": "src/test.ts",
      "karmaConfig": "./karma.conf.js",
      "polyfills": "src/polyfills.ts",
      "tsConfig": "src/tsconfig.spec.json",
      "stylePreprocessorOptions": {
        "includePaths": [
          "src/styles",
          "node_modules"
        ]
      },
      "scripts": [
        "node_modules/monaco-editor/esm/vs/editor/editor.main.js"
      ],
      ...
    }
}

This makes no difference, so what's the right approach here to get monaco registered and picked up in my test suite correctly?

UPDATE

Based on @Lucho's suggestion, I have replicated my issue in the following Stackblitz - https://stackblitz.com/edit/materia-ngx-monaco-editor-ng9-zdpc2h?file=src/app/app.component.ts

Note, that unlike in Lucho's approach, I am not providing the MONACO_PATH to a CDN path, and instead I am adding an entry in the assets property of my application and test project config section of the angular.json to ensure the monaco-editor library is made available

{
    "glob": "**/*",
    "input": "node_modules/monaco-editor",
    "output": "assets/monaco-editor/"
}

So, although I am attempting to provide this in the test section of the angular.json file, it seems perhaps its not being used somehow in the actual test run?

1

There are 1 answers

9
Lucho On

I managed to get one example working for you however it's ugly IMO but it gets the job done.

The ugly part is that i couldn't find a way to import monaco globally in stackblitz however i got it working through the CDN:

providers: [
    {
      provide: MONACO_PATH,
      useValue: "https://unpkg.com/[email protected]/min/vs"
    }
  ] 

Note: If you using Angular 8 below you have to take in consideration is that i found this ticket which forces you the version below 0.18.1.

Lastly the actual tests since I got it working through the CDN, unfortunately you have to consider the timing of getting resources so then you have to introduce some timeouts and let jasmine know when things have finished:

beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [AppModule],
      providers: [],
      declarations: []
    }).compileComponents();

    setTimeout(() => {
      fixture = TestBed.createComponent(AppComponent);
      component = fixture.componentInstance;
      fixture.detectChanges();
    }, 1000);
    jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
  }));

  it("Should create component", async(done: DoneFn) => {
    setTimeout(() => {
      expect(component).toBeTruthy();
      done();
    }, 2000);
  });

  it("Check if code in editor is populated", async(done: DoneFn) => {
    setTimeout(() => {
      let code = component.monacoComponent.editor.getValue();
      expect(code).toEqual(expectedCode);
      done();
    }, 2000);
  });

Here is a working stackblitz with the tests, ENJOY!