Échec des tests angulaires avec échec de l'exécution de «envoyer» sur «XMLHttpRequest»

145

J'essaye de tester mon composant angulaire 4.1.0 -

export class CellComponent implements OnInit {
  lines: Observable<Array<ILine>>;
  @Input() dep: string;
  @Input() embedded: boolean;
  @Input() dashboard: boolean;
  constructor(
    public dataService: CellService,
    private route: ActivatedRoute,
    private router: Router, private store: Store<AppStore>) {
  }
}

Cependant, un simple test "devrait créer" jette cette erreur cryptique ...

NetworkError: échec de l'exécution de 'send' sur 'XMLHttpRequest': échec du chargement de 'ng: ///DynamicTestModule/module.ngfactory.js'.

j'ai donc trouvé cette question, qui suggère que le problème est que le composant a des @Input)_paramètres qui ne sont pas définis, cependant, si je modifie mon test comme ceci:

  it('should create', inject([CellComponent], (cmp: CellComponent) => {
    cmp.dep = '';
    cmp.embedded = false;
    cmp.dashboard = false;
    expect(cmp).toBeTruthy();
  }));

alors j'obtiens toujours le même problème, de même, si je supprime les @Input()annotations du composant, toujours pas de différence. Comment faire réussir ces tests?

George Edwards
la source
1
Pour créer un composant, vous devez fournir toutes les dépendances. Pouvez-vous montrer toute votre configuration de test? Je vais essayer de reproduire le problème sur plnkr
Aleksandr Petrovskij
1
J'ai eu ce même problème et j'ai trouvé les mêmes messages que vous. J'ai pu trouver une solution. J'ai fini par poster sur l'autre question mais vous pouvez jeter un oeil ici: stackoverflow.com/a/45419372/6739517 J'espère que ça aide!
Niles Tanner

Réponses:

342

C'est un problème du nouveau Angular Cli. Exécutez votre test avec --sourcemaps=falseet vous obtiendrez les bons messages d'erreur.

Voir les détails ici: https://github.com/angular/angular-cli/issues/7296

ÉDITER:

Le raccourci pour ceci est:

ng test -sm=false

À partir de angulaire 6, la commande est:

ng test --source-map=false

Penghui
la source
19
Tu es un héros absolu. Je me cognais la tête contre le mur de frustration face au manque d'informations des messages d'erreur des tests unitaires angulaires, jusqu'à ce que je trouve cela. Infiniment reconnaissant.
Alan Smith
1
Cette réponse a vraiment sauvé ma journée! J'étais sur le point d'abandonner le développement en général après avoir passé toute la journée et la nuit à essayer de résoudre ce problème juste pour que je puisse arrêter d'être la personne qui échouait à la construction
user1806692
Aujourd'hui, je suis tombé sur ce message d'erreur: HeadlessChrome 65.0.3325 (Mac OS X 10.13.4) ERROR {"message": "Erreur de script. \ Nat: 0: 0", "str": "Erreur de script. \ Nat: 0 : 0 "} Et la suppression de --sourcemap = false affiche plus d'informations.
penghui
11
ng test --source-map = false ... fonctionne dans Angular CLI 6
danday74
@ danday74 FTW! Après avoir écrit des fichiers de test compliqués, rester accroché est brutal.
Brad Richardson le
21

J'ai eu le même problème avec angualar cli 6, j'ai utilisé cette balise pour obtenir le bon message d'erreur:

ng test --source-map=false

Peut-être que cela aidera quelqu'un :).

Jmuhire
la source
8

Pour mon cas, il y avait un problème de données factices et dans le cas Array, je revenais stringde la simulation.

someApi = fixture.debugElement.injector.get(SomeApi);
spyOn(someApi, 'someMethod')
  .and.returnValue(Observable.of('this is not a string but array'));

Le message d'erreur est vraiment distrayant et n'indique pas l'erreur réelle. Running a ng test --source=falseindiqué l'erreur et la ligne correctes, et m'a aidé à la corriger rapidement.

Cela arrive souvent lorsque vous simulez des données incomplètes ou incorrectes.

Aniruddha Das
la source
7

Vous pouvez définir la propriété input () sur la valeur par défaut dans component.ts

@Input() tableColumns: Array<any> = [];  
@Input() pageObj: any = '';

OU

Modifiez votre fichier component.spec.ts de la manière suivante,

beforeEach(() => {  
   fixture = TestBed.createComponent(MyComponent);  
   component = fixture.componentInstance;  
   component.tableColumns = [];  
   component.pageObj = '';  
   fixture.detectChanges();  
});
Mangesh Daundkar
la source
4

Comme suggéré ci-dessus ici: https://stackoverflow.com/a/45570571/7085047 mon problème était dans mon ngOnInit. J'appelais un proxy de contrôleur REST généré par swagger. Il retournait null, et je m'abonnais à ce null, qui ne fonctionne pas ...

L'erreur est revenue:

Failed to load ng:///DynamicTestModule/MockNodeDashboardComponent_Host.ngfactory.js: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.

J'ai résolu le problème en utilisant ts-mockito: https://github.com/NagRock/ts-mockito

J'ai ajouté du code pour créer une instance fictive comme celle-ci:

import { mock, instance, when } from 'ts-mockito';
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';
import { MockScenario } from './vcmts-api-client/model/MockScenario';

const MockVcmtsnodemockresourceApi: VcmtsnodemockresourceApi = mock(VcmtsnodemockresourceApi);
const obs = Observable.create((observer: Observer<MockScenario[]>) => {
  observer.next(new Array<MockScenario>());
  observer.complete();
});
when(MockVcmtsnodemockresourceApi.getMockScenariosUsingGET()).thenReturn(obs);
const instanceMockVcmtsnodemockresourceApi: VcmtsnodemockresourceApi = instance(MockVcmtsnodemockresourceApi);

Et puis ajouté l'instance au tableau des fournisseurs du test comme ceci:

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      ...
      providers: [
        ...
        { provide: VcmtsnodemockresourceApi, useValue: instanceMockVcmtsnodemockresourceApi },
        ...
      ]        
    }).compileComponents();
  }));
Datum Geek
la source
Si vous avez une nouvelle question, posez-la en cliquant sur le bouton Poser une question . Incluez un lien vers cette question si cela permet de fournir un contexte. - De l'avis
Anton Balaniuc
semblait que mon symptôme était le même que l'OP, alors j'ai pensé que les gens pourraient trouver utile le correctif qui a fonctionné pour moi ...
Datum Geek
3

Cela peut être lié au fait que Chrome cache une erreur de test réelle. La zone de test va dérouter une usine http fictive qu'elle ne peut pas charger et c'est donc l'erreur qu'elle rapportera. Très probablement, l'erreur se situera autour de la zone ngOnInit où un objet attend, par exemple, des sous-objets et ils ne sont pas définis.

Pour essayer d'aller au fond de l'erreur, passez temporairement à PhantomJS qui semble moins souffrir de ces erreurs d'initialisation et cela vous signalera, espérons-le, l'erreur réelle. À plusieurs reprises, j'ai trouvé qu'un objet attendu lors de l'initialisation n'était pas complet. C'EST À DIRE:

    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;

    component.object = {}
// should be:
    component.object = {"innerObjectThatIsNeeded" : []}

La correction de l'objet a permis à PhantomJS de se terminer et à Chrome de passer au test suivant.

À part cela, je n'ai pas vu de solution pour supprimer le problème de Chrome. Comme toujours, essayez d'adopter une politique "supprimer le code, jusqu'à ce que l'erreur disparaisse" pour chasser l'erreur.

MISE À JOUR: Notez que c'est maintenant une réponse assez ancienne, je ne recommanderais plus d'utiliser PhantomJS (EOL). Les rapports de test du navigateur se sont beaucoup améliorés et si Chrome vous donne du chagrin, essayez Firefox, qui exécute également très bien les tests de nos jours.

PeterS
la source
2

J'ai aussi eu cette erreur, qui, à vrai dire, est assez peu bavarde.

C'était lié aux appels HTTP via mes services

J'utilise myService.ts avec 2 méthodes

get();
getAll();

Je me moque de ce service: mockMyService.ts

L'erreur était là parce que mon composant utilisait la méthode getAll () que j'ai oublié d'implémenter dans mockMyService, j'ai donc juste ajouté la méthode:

private mockObjects = [
{
  'id': '1',
  'champ1': 'TECH',
  'champ2': 2,
  'champ3': 'Data bidon'
},
{
  'id': '2',
  'champ1': 'TECH',
  'champ2': 2,
  'champ3': 'Data au pif'
},
{
  'id': '3',
  'champ1': 'FUNC',
  'champ2': 3,
  'champ3': 'Data quelconque'
},
 ];

getAll(): Observable<any> {
  return Observable.of(this.mockObjects);
}

L'erreur a disparu :)

Deunz
la source
2

J'ai rencontré le même problème et j'ai découvert que pour le résoudre, vous devez définir vos entrées pour le composant dans la méthode beforeEach comme indiqué ci-dessous:

beforeEach(() => {
    fixture = TestBed.createComponent(CellComponent );
    cmp = fixture.debugElement.componentInstance;
    cmp.dep = '';
    cmp.embedded = false;
    cmp.dashboard = false;
    fixture.detectChanges();
});

Cela résoudra certainement votre problème.

Jayant Patil
la source
1

Dans mon cas, le coupable a été observable.timeout(x).retry(y)appliqué quelque part sur l'Observable retourné au niveau de la classe de service, puis à nouveau dans le composant qui utilisait ce service.

Tout fonctionnait correctement dans le navigateur jusqu'à angular-cli 1.4. Puis a commencé à échouer lors des tests de Karma (avec une erreur aussi stupide). La solution était bien sûr de ranger ces opérateurs de timeout / retry.

Marcin R
la source
1

Pour moi, ce message apparaît quand un simulacre est faux dans mes tests: généralement vous fournissez mockService dans vos tests bootstrap. Si votre maquette est incomplète ou fausse, alors angulaire renvoie cette erreur stupide.

Plus d'informations sur mon cas ici

Rebolon
la source
0

Ce que je ferais, c'est:

Ajoutez console.log () s, ligne après ligne dans ngOnint () et découvrez jusqu'où il va, puis inspectez la ligne par laquelle il ne passera pas.

Ex:

ngOnInit() {
    this.route.paramMap
        .switchMap(params => {
            this.busy = true;
            this.updateErrors(null);

            console.log(params);

            **const id = params.get('id');**
            console.log(id);

            if (id === 'new') {
                this.editMode = true;
                return Observable.of(GroupComponent.newGroup());
            }
            return this.apiService.getGroup(id);
        })
    }

Cela a échoué sur mon test avec la même erreur dans ce post. Comme indiqué ci-dessus, j'avais deux console.logs. Le premier a réussi, mais le second non. J'ai donc réalisé que le problème était en ligne const id = params.get ('id'); et je l'ai réparé.

J'espère que cela aidera quelqu'un.

Josf
la source